diff --git a/.hgignore b/.hgignore index ee5ec9160d5..49620dba792 100644 --- a/.hgignore +++ b/.hgignore @@ -5,3 +5,5 @@ nbproject/private/ ^.hgtip ^.bridge2 .DS_Store +.metadata/ +.recommenders/ diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 07921d280f1..12ff6dcaf83 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -330,3 +330,4 @@ ce5c14d97d95084504c32b9320cb33cce4235588 jdk9-b83 1f345217c9bab05f192d00cf1665b3286c49ccdb jdk9-b85 2aa1daf98d3e2ee37f20f6858c53cc37020f6937 jdk9-b86 fd4f4f7561074dc0dbc1772c8489c7b902b6b8a9 jdk9-b87 +0bb87e05d83e1cf41cfb7ddeb2c8eaec539fd907 jdk9-b88 diff --git a/README-builds.html b/README-builds.html index b0cc892f9c4..d81549d5ce4 100644 --- a/README-builds.html +++ b/README-builds.html @@ -1,2492 +1,1386 @@ - - - OpenJDK Build README - - + + OpenJDK Build README + + +

OpenJDK

+ +

OpenJDK Build README

+ +
+ +

+ +

Introduction

+ +

This README file contains build instructions for the +OpenJDK. Building the source code for the OpenJDK +requires a certain degree of technical expertise.

+ +

!!!!!!!!!!!!!!! THIS IS A MAJOR RE-WRITE of this document. !!!!!!!!!!!!!

+ +

Some Headlines:

+ + + +
+ +

Contents

+ + + +
+ + + +
+ +

+ +

Use of Mercurial

+ +

The OpenJDK sources are maintained with the revision control system +Mercurial. If you are new to +Mercurial, please see the Beginner Guides or refer to the Mercurial Book. +The first few chapters of the book provide an excellent overview of Mercurial, +what it is and how it works.

+ +

For using Mercurial with the OpenJDK refer to the Developer Guide: Installing +and Configuring Mercurial section for more information.

+ +

+ +

Getting the Source

+ +

To get the entire set of OpenJDK Mercurial repositories use the script +get_source.sh located in the root repository:

+ +
  hg clone http://hg.openjdk.java.net/jdk9/jdk9 YourOpenJDK
+  cd YourOpenJDK
+  bash ./get_source.sh
+
+ +

Once you have all the repositories, keep in mind that each repository is its +own independent repository. You can also re-run ./get_source.sh anytime to +pull over all the latest changesets in all the repositories. This set of +nested repositories has been given the term "forest" and there are various +ways to apply the same hg command to each of the repositories. For +example, the script make/scripts/hgforest.sh can be used to repeat the +same hg command on every repository, e.g.

+ +
  cd YourOpenJDK
+  bash ./make/scripts/hgforest.sh status
+
+ +

+ +

Repositories

+ +

The set of repositories and what they contain:

+ + + +

Repository Source Guidelines

+ +

There are some very basic guidelines:

+ + + +
+ +

+ +

Building

+ +

The very first step in building the OpenJDK is making sure the system itself +has everything it needs to do OpenJDK builds. Once a system is setup, it +generally doesn't need to be done again.

+ +

Building the OpenJDK is now done with running a configure script which will +try and find and verify you have everything you need, followed by running +make, e.g.

- - - - - - - - -
- OpenJDK -
-

OpenJDK Build README

-
- - -
-

Introduction

-
- This README file contains build instructions for the - OpenJDK. - Building the source code for the - OpenJDK - requires - a certain degree of technical expertise. - - -

!!!!!!!!!!!!!!! THIS IS A MAJOR RE-WRITE of this document. !!!!!!!!!!!!!

-
- Some Headlines: - -
-
- - -
-

Contents

-
- -
- -
- - -
-

Use of Mercurial

-
- The OpenJDK sources are maintained with the revision control system - Mercurial. - If you are new to Mercurial, please see the - - Beginner Guides - or refer to the - Mercurial Book. - The first few chapters of the book provide an excellent overview of - Mercurial, what it is and how it works. -
- For using Mercurial with the OpenJDK refer to the - - Developer Guide: Installing and Configuring Mercurial - section for more information. - -

Getting the Source

-
- To get the entire set of OpenJDK Mercurial repositories - use the script get_source.sh located in the - root repository: -
- - hg clone http://hg.openjdk.java.net/jdk9/jdk9 - YourOpenJDK -
- cd YourOpenJDK -
- bash ./get_source.sh -
-
- Once you have all the repositories, keep in mind that each - repository is its own independent repository. - You can also re-run ./get_source.sh anytime to - pull over all the latest changesets in all the repositories. - This set of nested repositories has been given the term - "forest" and there are various ways to apply the same - hg command to each of the repositories. - For example, the script make/scripts/hgforest.sh - can be used to repeat the same hg - command on every repository, e.g. -
- - cd YourOpenJDK -
- bash ./make/scripts/hgforest.sh status -
-
-
- -

Repositories

-
-

The set of repositories and what they contain:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RepositoryContains
- . (root) - - common configure and makefile logic -
- hotspot - - source code and make files for building - the OpenJDK Hotspot Virtual Machine -
- langtools - - source code for the OpenJDK javac and language tools -
- jdk - - source code and make files for building - the OpenJDK runtime libraries and misc files -
- jaxp - - source code for the OpenJDK JAXP functionality -
- jaxws - - source code for the OpenJDK JAX-WS functionality -
- corba - - source code for the OpenJDK Corba functionality -
- nashorn - - source code for the OpenJDK JavaScript implementation -
-
- -

Repository Source Guidelines

-
- There are some very basic guidelines: - -
- -
- - -
-

Building

-
- The very first step in building the OpenJDK is making sure the - system itself has everything it needs to do OpenJDK builds. - Once a system is setup, it generally doesn't need to be done again. -
- Building the OpenJDK is now done with running a - configure - script which will try and find and verify you have everything - you need, followed by running - make, e.g. -
- - - bash ./configure
- make all -
-
-
- Where possible the configure script will attempt to located the - various components in the default locations or via component - specific variable settings. - When the normal defaults fail or components cannot be found, - additional configure options may be necessary to help configure - find the necessary tools for the build, or you may need to - re-visit the setup of your system due to missing software - packages. -
- NOTE: The configure script - file does not have - execute permissions and will need to be explicitly run with - bash, - see the source guidelines. - - -
-

System Setup

-
- Before even attempting to use a system to build the OpenJDK - there are some very basic system setups needed. - For all systems: - - And for specific systems: - - - - - - - - - - - - - - - - - -
LinuxSolarisWindowsMac OS X
- Install all the software development - packages needed including - alsa, - freetype, - cups, and - xrender. -
- See - specific system packages. -
- Install all the software development - packages needed including - Studio Compilers, - freetype, - cups, and - xrender. -
- See - specific system packages. -
- - - Install - XCode 4.5.2 - and also install the "Command line tools" found under the - preferences pane "Downloads" -
- -

Linux

-
- With Linux, try and favor the system packages over - building your own - or getting packages from other areas. - Most Linux builds should be possible with the system's - available packages. -
- Note that some Linux systems have a habit of pre-populating - your environment variables for you, for example JAVA_HOME - might get pre-defined for you to refer to the JDK installed on - your Linux system. - You will need to unset JAVA_HOME. - It's a good idea to run env and verify the - environment variables you are getting from the default system - settings make sense for building the OpenJDK. - -
- -

Solaris

-
-
Studio Compilers
-
- At a minimum, the - - Studio 12 Update 1 Compilers - (containing version 5.10 of the C and C++ compilers) is required, - including specific patches. -

- The Solaris SPARC patch list is: -

    -
  • - 118683-05: SunOS 5.10: Patch for profiling libraries and assembler -
  • -
  • - 119963-21: SunOS 5.10: Shared library patch for C++ -
  • -
  • - 120753-08: SunOS 5.10: Microtasking libraries (libmtsk) patch -
  • -
  • - 128228-09: Sun Studio 12 Update 1: Patch for Sun C++ Compiler -
  • -
  • - 141860-03: Sun Studio 12 Update 1: Patch for Compiler Common patch for Sun C C++ F77 F95 -
  • -
  • - 141861-05: Sun Studio 12 Update 1: Patch for Sun C Compiler -
  • -
  • - 142371-01: Sun Studio 12.1 Update 1: Patch for dbx -
  • -
  • - 143384-02: Sun Studio 12 Update 1: Patch for debuginfo handling -
  • -
  • - 143385-02: Sun Studio 12 Update 1: Patch for Compiler Common patch for Sun C C++ F77 F95 -
  • -
  • - 142369-01: Sun Studio 12.1: Patch for Performance Analyzer Tools -
  • -
-

- The Solaris X86 patch list is: -

    -
  • - 119961-07: SunOS 5.10_x86, x64, Patch for profiling libraries and assembler -
  • -
  • - 119964-21: SunOS 5.10_x86: Shared library patch for C++_x86 -
  • -
  • - 120754-08: SunOS 5.10_x86: Microtasking libraries (libmtsk) patch -
  • -
  • - 141858-06: Sun Studio 12 Update 1_x86: Sun Compiler Common patch for x86 backend -
  • -
  • - 128229-09: Sun Studio 12 Update 1_x86: Patch for C++ Compiler -
  • -
  • - 142363-05: Sun Studio 12 Update 1_x86: Patch for C Compiler -
  • -
  • - 142368-01: Sun Studio 12.1_x86: Patch for Performance Analyzer Tools -
  • -
-

- Place the bin directory in PATH. -

- The Oracle Solaris Studio Express compilers at: - - Oracle Solaris Studio Express Download site - are also an option, although these compilers have not - been extensively used yet. -

- -
- -

Windows

-
- -
Windows Unix Toolkit
-
- Building on Windows requires a Unix-like environment, notably a - Unix-like shell. - There are several such environments available of which - Cygwin and - MinGW/MSYS are - currently supported for - the OpenJDK build. One of the differences of these - systems from standard Windows tools 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. - -
CYGWIN
-
- 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 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. -

-

- The OpenJDK build requires CYGWIN version 1.7.16 or newer. - Information about CYGWIN can - be obtained from the CYGWIN website at - www.cygwin.com. -

-

- By default CYGWIN doesn't install all the tools required for building - the OpenJDK. - Along with the default installation, you need to install - the following tools. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Binary NameCategoryPackageDescription
ar.exeDevelbinutils - The GNU assembler, linker and binary utilities -
make.exeDevelmake - The GNU version of the 'make' utility built for CYGWIN -
m4.exeInterpretersm4 - GNU implementation of the traditional Unix macro - processor -
cpio.exeUtilscpio - A program to manage archives of files -
gawk.exeUtilsawk - Pattern-directed scanning and processing language -
file.exeUtilsfile - Determines file type using 'magic' numbers -
zip.exeArchivezip - Package and compress (archive) files -
unzip.exeArchiveunzip - Extract compressed files in a ZIP archive -
free.exeSystemprocps - Display amount of free and used memory in the system -
-
- Note that the CYGWIN software can conflict with other non-CYGWIN - software on your Windows system. - CYGWIN provides a - FAQ for - known issues and problems, of particular interest is the - section on - - BLODA (applications that interfere with CYGWIN). -
- -
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. - See MinGW/MSYS - for more information. -

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

-

- 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 -
-
- -
- -
Visual Studio 2013 Compilers
-
-

- The 32-bit and 64-bit OpenJDK Windows build requires - Microsoft Visual Studio C++ 2013 (VS2013) Professional - Edition or Express compiler. - The compiler and other tools are expected to reside - in the location defined by the variable - VS120COMNTOOLS which - is set by the Microsoft Visual Studio installer. -

-

- Only the C++ part of VS2013 is needed. - Try to let the installation go to the default - install directory. - Always reboot your system after installing VS2013. - The system environment variable VS120COMNTOOLS - should be - set in your environment. -

-

- Make sure that TMP and TEMP are also set - in the environment - and refer to Windows paths that exist, - like C:\temp, - not /tmp, not /cygdrive/c/temp, - and not C:/temp. - C:\temp is just an example, - it is assumed that this area is - private to the user, so by default - after installs you should - see a unique user path in these variables. -

-
- - -
- -

Mac OS X

-
- Make sure you get the right XCode version. -
- -
- - -
-

Configure

-
- The basic invocation of the configure script - looks like: -
- bash ./configure [options] -
- This will create an output directory containing the - "configuration" and setup an area for the build result. - This directory typically looks like: -
- build/linux-x64-normal-server-release -
- configure will try to figure out what system you are running on - and where all necessary build components are. - If you have all prerequisites for building installed, - it should find everything. - If it fails to detect any component automatically, - it will exit and inform you about the problem. - When this happens, read more below in - the configure options. -

- Some examples: -

- - - - - - - - - - - - - - - - - -
DescriptionConfigure Command Line
Windows 32bit build with freetype specified - bash ./configure --with-freetype=/cygdrive/c/freetype-i586 --with-target-bits=32 -
Debug 64bit Build - bash ./configure --enable-debug --with-target-bits=64 -
- - -

Configure Options

-
- Complete details on all the OpenJDK configure options can - be seen with: -
- bash ./configure --help=short -
- Use -help to see all the configure options - available. - - You can generate any number of different configurations, - e.g. debug, release, 32, 64, etc. - - Some of the more commonly used configure options are: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OpenJDK Configure OptionDescription
--enable-debug - set the debug level to fastdebug (this is a shorthand for - --with-debug-level=fastdebug) -
--with-alsa=path - select the location of the - Advanced Linux Sound Architecture (ALSA) -
- Version 0.9.1 or newer of the ALSA files are - required for building the OpenJDK on Linux. - These Linux files are usually available from an "alsa" - of "libasound" - development package, - and it's highly recommended that you try and use - the package provided by the particular version of Linux that - you are using. -
--with-boot-jdk=path - select the Bootstrap JDK -
--with-boot-jdk-jvmargs="args" - provide the JVM options to be used to run the - Bootstrap JDK -
--with-cacerts=path - select the path to the cacerts file. -
- See - http://en.wikipedia.org/wiki/Certificate_Authority - for a better understanding of the Certificate Authority (CA). - A certificates file named "cacerts" - represents a system-wide keystore with CA certificates. - In JDK and JRE - binary bundles, the "cacerts" file contains root CA certificates from - several public CAs (e.g., VeriSign, Thawte, and Baltimore). - The source contain a cacerts file - without CA root certificates. - Formal JDK builders will need to secure - permission from each public CA and include the certificates into their - own custom cacerts file. - Failure to provide a populated cacerts file - will result in verification errors of a certificate chain during runtime. - By default an empty cacerts file is provided and that should be - fine for most JDK developers. -
--with-cups=path - select the CUPS install location -
- The - Common UNIX Printing System (CUPS) Headers - are required for building the - OpenJDK on Solaris and Linux. - The Solaris header files can be obtained by installing - the package SFWcups from the Solaris Software - Companion CD/DVD, these often will be installed into the - directory /opt/sfw/cups. -
- The CUPS header files can always be downloaded from - www.cups.org. -
--with-cups-include=path - select the CUPS include directory location -
--with-debug-level=level - select the debug information level of release, - fastdebug, or slowdebug -
--with-dev-kit=path - select location of the compiler install or - developer install location -
--with-freetype=path - select the freetype files to use. -
- Expecting the - freetype libraries under - lib/ and the - headers under include/. -
- Version 2.3 or newer of FreeType is required. - On Unix systems required files can be available as part of your - distribution (while you still may need to upgrade them). - Note that you need development version of package that - includes both the FreeType library and header files. -
- You can always download latest FreeType version from the - FreeType website. -
- Building the freetype 2 libraries from scratch is also possible, - however on Windows refer to the - - Windows FreeType DLL build instructions. -
- Note that by default FreeType is built with byte code hinting - support disabled due to licensing restrictions. - In this case, text appearance and metrics are expected to - differ from Sun's official JDK build. - See - - the SourceForge FreeType2 Home Page - - for more information. -
--with-import-hotspot=path - select the location to find hotspot - binaries from a previous build to avoid building - hotspot -
--with-target-bits=arg - select 32 or 64 bit build -
--with-jvm-variants=variants - select the JVM variants to build from, comma - separated list that can include: - server, client, kernel, zero and zeroshark -
--with-memory-size=size - select the RAM size that GNU make will think - this system has -
--with-msvcr-dll=path - select the msvcr100.dll - file to include in the - Windows builds (C/C++ runtime library for - Visual Studio). -
- This is usually picked up automatically - from the redist - directories of Visual Studio 2013. -
--with-num-cores=cores - select the number of cores to use (processor - count or CPU count) -
--with-x=path - select the location of the X11 and xrender files. -
- The - XRender Extension Headers - are required for building the - OpenJDK on Solaris and Linux. -
- The Linux header files are usually available from a "Xrender" - development package, it's recommended that you try and use - the package provided by the particular distribution of Linux that - you are using. -
- The Solaris XRender header files 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 or - /usr/openwin/share/include/X11/extensions/Xrender.h -
-
- -
- - -
-

Make

-
- The basic invocation of the make utility - looks like: -
- make all -
- This will start the build to the output directory containing the - "configuration" that was created by the configure - script. Run make help for more information on - the available targets. -
- There are some of the make targets that - are of general interest: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Make TargetDescription
emptybuild everything but no images
allbuild everything including images
all-confbuild all configurations
imagescreate complete j2sdk and j2re images
installinstall the generated images locally, - typically in /usr/local
cleanremove all files generated by make, - but not those generated by configure
dist-cleanremove all files generated by both - and configure (basically killing the configuration)
helpgive some help on using make, - including some interesting make targets
-
-
- - -
-

Testing

-
- When the build is completed, you should see the generated - binaries and associated files in the j2sdk-image - directory in the output directory. - In particular, the - build/*/images/j2sdk-image/bin - directory should contain executables for the - OpenJDK tools and utilities for that configuration. - The testing tool jtreg will be needed - and can be found at: - - the jtreg site. - The provided regression tests in the repositories - can be run with the command: -
- cd test && make PRODUCT_HOME=`pwd`/../build/*/images/j2sdk-image all -
-
- - - - - - - - - - - - -
-

Appendix A: Hints and Tips

-
- -

FAQ

-
- -

- Q: The generated-configure.sh file looks horrible! - How are you going to edit it? -
- A: The generated-configure.sh file is generated (think - "compiled") by the autoconf tools. The source code is - in configure.ac and various .m4 files in common/autoconf, - which are much more readable. -

- -

- Q: - Why is the generated-configure.sh file checked in, - if it is generated? -
- A: - If it was not generated, every user would need to have the autoconf - tools installed, and re-generate the configure file - as the first step. - Our goal is to minimize the work needed to be done by the user - to start building OpenJDK, and to minimize - the number of external dependencies required. -

- -

- Q: - Do you require a specific version of autoconf for regenerating - generated-configure.sh? -
- A: - Yes, version 2.69 is required and should be easy - enough to aquire on all supported operating - systems. The reason for this is to avoid - large spurious changes in generated-configure.sh. -

- -

- Q: - How do you regenerate generated-configure.sh - after making changes to the input files? -
- A: - Regnerating generated-configure.sh - should always be done using the - script common/autoconf/autogen.sh to - ensure that the correct files get updated. This - script should also be run after mercurial tries to - merge generated-configure.sh as a - merge of the generated file is not guaranteed to - be correct. -

- -

- Q: - What are the files in common/makefiles/support/* for? - They look like gibberish. -
- A: - They are a somewhat ugly hack to compensate for command line length - limitations on certain platforms (Windows, Solaris). - Due to a combination of limitations in make and the shell, - command lines containing too many files will not work properly. - These - helper files are part of an elaborate hack that will compress the - command line in the makefile and then uncompress it safely. - We're - not proud of it, but it does fix the problem. - If you have any better suggestions, we're all ears! :-) -

- -

- Q: - I want to see the output of the commands that make runs, - like in the old build. How do I do that? -
- A: - You specify the LOG variable to make. There are - several log levels: -

-
-
    -
  • - warn — Default and very quiet. -
  • -
  • - info — Shows more progress information - than warn. -
  • -
  • - debug — Echos all command lines and - prints all macro calls for compilation definitions. -
  • -
  • - trace — Echos all $(shell) command - lines as well. -
  • -
-
- -

- Q: - When do I have to re-run configure? -
- A: - Normally you will run configure only once for creating a - configuration. - You need to re-run configuration only if you want to change any - configuration options, - or if you pull down changes to the configure script. -

- -

- Q: - I have added a new source file. Do I need to modify the makefiles? -
- A: - Normally, no. If you want to create e.g. a new native - library, - you will need to modify the makefiles. But for normal file - additions or removals, no changes are needed. There are certan - exceptions for some native libraries where the source files are spread - over many directories which also contain sources for other - libraries. In these cases it was simply easier to create include lists - rather than excludes. -

- -

- Q: - When I run configure --help, I see many strange options, - like --dvidir. What is this? -
- A: - Configure provides a slew of options by default, to all projects - that use autoconf. Most of them are not used in OpenJDK, - so you can safely ignore them. To list only OpenJDK specific features, - use configure --help=short instead. -

- -

- Q: - configure provides OpenJDK-specific features such as - --with-builddeps-server that are not - described in this document. What about those? -
- A: - Try them out if you like! But be aware that most of these are - experimental features. - Many of them don't do anything at all at the moment; the option - is just a placeholder. Others depend on - pieces of code or infrastructure that is currently - not ready for prime time. -

- -

- Q: - How will you make sure you don't break anything? -
- A: - We have a script that compares the result of the new build system - with the result of the old. For most part, we aim for (and achieve) - byte-by-byte identical output. There are however technical issues - with e.g. native binaries, which might differ in a byte-by-byte - comparison, even - when building twice with the old build system. - For these, we compare relevant aspects - (e.g. the symbol table and file size). - Note that we still don't have 100% - equivalence, but we're close. -

- -

- Q: - I noticed this thing X in the build that looks very broken by design. - Why don't you fix it? -
- A: - Our goal is to produce a build output that is as close as - technically possible to the old build output. - If things were weird in the old build, - they will be weird in the new build. - Often, things were weird before due to obscurity, - but in the new build system the weird stuff comes up to the surface. - The plan is to attack these things at a later stage, - after the new build system is established. -

- -

- Q: - The code in the new build system is not that well-structured. - Will you fix this? -
- A: - Yes! The new build system has grown bit by bit as we converted - the old system. When all of the old build system is converted, - we can take a step back and clean up the structure of the new build - system. Some of this we plan to do before replacing the old build - system and some will need to wait until after. -

- -

- Q: - Is anything able to use the results of the new build's default make target? -
- A: - Yes, this is the minimal (or roughly minimal) - set of compiled output needed for a developer to actually - execute the newly built JDK. The idea is that in an incremental - development fashion, when doing a normal make, - you should only spend time recompiling what's changed - (making it purely incremental) and only do the work that's - needed to actually run and test your code. - The packaging stuff that is part of the images - target is not needed for a normal developer who wants to - test his new code. Even if it's quite fast, it's still unnecessary. - We're targeting sub-second incremental rebuilds! ;-) - (Or, well, at least single-digit seconds...) -

- -

- Q: - I usually set a specific environment variable when building, - but I can't find the equivalent in the new build. - What should I do? -
- A: - It might very well be that we have neglected to add support for - an option that was actually used from outside the build system. - Email us and we will add support for it! -

- -
- -

Build Performance Tips

-
- -

Building OpenJDK requires a lot of horsepower. - Some of the build tools can be adjusted to utilize more or less - of resources such as - parallel threads and memory. - The configure script analyzes your system and selects reasonable - values for such options based on your hardware. - If you encounter resource problems, such as out of memory conditions, - you can modify the detected values with:

- - - -

It might also be necessary to specify the JVM arguments passed - to the Bootstrap JDK, using e.g. - --with-boot-jdk-jvmargs="-Xmx8G -enableassertions". - Doing this will override the default JVM arguments - passed to the Bootstrap JDK.

- - -

One of the top goals of the new build system is to improve the - build performance and decrease the time needed to build. This will - soon also apply to the java compilation when the Smart Javac wrapper - is fully supported.

- -

At the end of a successful execution of configure, - you will get a performance summary, - indicating how well the build will perform. Here you will - also get performance hints. - If you want to build fast, pay attention to those!

- -

Building with ccache

- -

The OpenJDK build supports building with ccache - when using gcc or clang. Using ccache can - radically speed up compilation of native code if - you often rebuild the same sources. Your milage - may vary however so we recommend evaluating it for - yourself. To enable it, make sure it's on the path - and configure with --enable-ccache.

- -

Building on local disk

- -

If you are using network shares, e.g. via NFS, for your source code, - make sure the build directory is situated on local disk. - The performance - penalty is extremely high for building on a network share, - close to unusable.

- -

Building only one JVM

- -

The old build builds multiple JVMs on 32-bit systems (client and - server; and on Windows kernel as well). In the new build we have - changed this default to only build server when it's available. This - improves build times for those not interested in multiple JVMs. To - mimic the old behavior on platforms that support it, - use --with-jvm-variants=client,server.

- -

Selecting the number of cores to build on

- -

By default, configure will analyze your machine and run the make - process in parallel with as many threads as you have cores. This - behavior can be overridden, either "permanently" (on a configure - basis) using --with-num-cores=N or for a single build - only (on a make basis), using make JOBS=N.

- -

If you want to make a slower build just this time, to save some CPU - power for other processes, you can run - e.g. make JOBS=2. This will force the makefiles - to only run 2 parallel processes, or even make JOBS=1 - which will disable parallelism.

- -

If you want to have it the other way round, namely having slow - builds default and override with fast if you're - impatient, you should call configure with - --with-num-cores=2, making 2 the default. - If you want to run with more - cores, run make JOBS=8

- -
- -

Troubleshooting

-
- -

Solving build problems

- -
- If the build fails (and it's not due to a compilation error in - a source file you've changed), the first thing you should do - is to re-run the build with more verbosity. - Do this by adding LOG=debug to your make command line. -
- The build log (with both stdout and stderr intermingled, - basically the same as you see on your console) can be found as - build.log in your build directory. -
- You can ask for help on build problems with the new build system - on either the - - build-dev - or the - - build-infra-dev - mailing lists. Please include the relevant parts - of the build log. -
- A build can fail for any number of reasons. - Most failures - are a result of trying to build in an environment in which all the - pre-build requirements have not been met. - The first step in - troubleshooting a build failure is to recheck that you have satisfied - all the pre-build requirements for your platform. - Scanning the configure log is a good first step, making - sure that what it found makes sense for your system. - Look for strange error messages or any difficulties that - configure had in finding things. -
- Some of the more common problems with builds are briefly - described - below, with suggestions for remedies. -
    -
  • - Corrupted Bundles on Windows: -
    - Some virus scanning software has been known to - corrupt the - downloading of zip bundles. - It may be necessary to disable the 'on access' or - 'real time' - virus scanning features to prevent this corruption. - This type of "real time" virus scanning can also - slow down the - build process significantly. - Temporarily disabling the feature, or excluding the build - output directory may be necessary to get correct and - faster builds. -
    -
  • -
  • - Slow Builds: -
    - If your build machine seems to be overloaded from too many - simultaneous C++ compiles, try setting the - JOBS=1 on the make command line. - Then try increasing the count slowly to an acceptable - level for your system. Also: -
    - Creating the javadocs can be very slow, - if you are running - javadoc, consider skipping that step. -
    - Faster CPUs, more RAM, and a faster DISK usually helps. - The VM build tends to be CPU intensive - (many C++ compiles), - and the rest of the JDK will often be disk intensive. -
    - Faster compiles are possible using a tool called - ccache. -
    -
    -
  • -
  • - File time issues: -
    - If you see warnings that refer to file time stamps, e.g. -
    - Warning message: - File `xxx' has modification time in - the future. -
    - Warning message: Clock skew detected. - Your build may - be incomplete. -
    - These warnings can occur when the clock on the build - machine is out of - sync with the timestamps on the source files. - Other errors, apparently - unrelated but in fact caused by the clock skew, - can occur along with - the clock skew warnings. - These secondary errors may tend to obscure the - fact that the true root cause of the problem - is an out-of-sync clock. -

    - If you see these warnings, reset the clock on the - build - machine, run "gmake clobber" - or delete the directory - containing the build output, and restart the - build from the beginning. -

    -
  • -
  • - Error message: - Trouble writing out table to disk -
    - Increase the amount of swap space on your build machine. - This could be caused by overloading the system and - it may be necessary to use: -
    - make JOBS=1 -
    - to reduce the load on the system. -
    -
  • -
  • - Error Message: - libstdc++ not found: -
    - This is caused by a missing libstdc++.a library. - This is installed as part of a specific package - (e.g. libstdc++.so.devel.386). - By default some 64-bit Linux versions (e.g. Fedora) - only install the 64-bit version of the libstdc++ package. - Various parts of the JDK build require a static - link of the C++ runtime libraries to allow for maximum - portability of the built images. -
    -
  • -
  • - Linux Error Message: - cannot restore segment prot after reloc -
    - This is probably an issue with SELinux (See - - http://en.wikipedia.org/wiki/SELinux). - Parts of the VM is built without the -fPIC for - performance reasons. -

    - To completely disable SELinux: -

      -
    1. $ su root
    2. -
    3. # system-config-securitylevel
    4. -
    5. In the window that appears, select the SELinux tab
    6. -
    7. Disable SELinux
    8. -
    -

    - Alternatively, instead of completely disabling it you could - disable just this one check. -

      -
    1. Select System->Administration->SELinux Management
    2. -
    3. In the SELinux Management Tool which appears, - select "Boolean" from the menu on the left
    4. -
    5. Expand the "Memory Protection" group
    6. -
    7. Check the first item, labeled - "Allow all unconfined executables to use - libraries requiring text relocation ..."
    8. -
    -
    -
  • -
  • - Windows Error Messages: -
    - *** fatal error - couldn't allocate heap, ... -
    - rm fails with "Directory not empty" -
    - unzip fails with "cannot create ... Permission denied" -
    - unzip fails with "cannot create ... Error 50" -
    -
    - The CYGWIN software can conflict with other non-CYGWIN - software. See the CYGWIN FAQ section on - - BLODA (applications that interfere with CYGWIN). -
    -
  • -
  • - Windows Error Message: spawn failed -
    - Try rebooting the system, or there could be some kind of - issue with the disk or disk partition being used. - Sometimes it comes with a "Permission Denied" message. -
    -
  • -
-
- -
- -
- - -
-

Appendix B: GNU make

-
- - The Makefiles in the OpenJDK are only valid when used with the - GNU version of the utility command make - (usually called gmake on Solaris). - A few notes about using GNU make: - -

- Information on GNU make, and access to ftp download sites, are - available on the - - GNU make web site - . - The latest source to GNU make is available at - - ftp.gnu.org/pub/gnu/make/. -

- -

Building GNU make

-
- 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 but is - basically done with: -
- bash ./configure -
- make -
-
- -
- - -
-

Appendix C: Build Environments

-
- -

Minimum Build Environments

-
- This file often describes specific requirements for what we - call the - "minimum build environments" (MBE) for this - specific release of the JDK. - What is listed below is what the Oracle Release - Engineering Team will use to build the Oracle JDK product. - Building with the MBE will hopefully generate the most compatible - bits that install on, and run correctly on, the most variations - of the same base OS and hardware architecture. - In some cases, these represent what is often called the - least common denominator, but each Operating System has different - aspects to it. -

- In all cases, the Bootstrap JDK version minimum is critical, - we cannot guarantee builds will work with older Bootstrap JDK's. - Also in all cases, more RAM and more processors is better, - the minimums listed below are simply recommendations. -

- With Solaris and Mac OS X, the version listed below is the - oldest release we can guarantee builds and works, and the - specific version of the compilers used could be critical. -

- With Windows the critical aspect is the Visual Studio compiler - used, which due to it's runtime, generally dictates what Windows - systems can do the builds and where the resulting bits can - be used.
- NOTE: We expect a change here off these older Windows OS releases - and to a 'less older' one, probably Windows 2008R2 X64. -

- With Linux, it was just a matter of picking a - stable distribution that is a good representative for Linux - in general.
- NOTE: We expect a change here from Fedora 9 to something else, - but it has not been completely determined yet, possibly - Ubuntu 12.04 X64, unbiased community feedback would be welcome on - what a good choice would be here. -

- It is understood that most developers will NOT be using these - specific versions, and in fact creating these specific versions - may be difficult due to the age of some of this software. - It is expected that developers are more often using the more - recent releases and distributions of these operating systems. -

- 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 older, newer, or unreleased OS versions. - Please report these types of problems as bugs so that they - can be dealt with accordingly. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Base OS and ArchitectureOSC/C++ CompilerBootstrap JDKProcessorsRAM MinimumDISK Needs
Linux X86 (32-bit) and X64 (64-bit)Oracle Enterprise Linux 6.4gcc 4.8.2 JDK 82 or more1 GB6 GB
Solaris SPARCV9 (64-bit)Solaris 10 Update 10Studio 12 Update 3 + patchesJDK 84 or more4 GB8 GB
Solaris X64 (64-bit)Solaris 10 Update 10Studio 12 Update 3 + patchesJDK 84 or more4 GB8 GB
Windows X86 (32-bit)Windows Server 2012 R2 x64Microsoft Visual Studio C++ 2013 Professional EditionJDK 82 or more2 GB6 GB
Windows X64 (64-bit)Windows Server 2012 R2 x64Microsoft Visual Studio C++ 2013 Professional EditionJDK 82 or more2 GB6 GB
Mac OS X X64 (64-bit)Mac OS X 10.9 "Mavericks"XCode 5.1.1 or newerJDK 82 or more4 GB6 GB
-
- - -
-

Specific Developer Build Environments

-
- We won't be listing all the possible environments, but - we will try to provide what information we have available to us. -

- NOTE: The community can help out by updating - this part of the document. - - -

Fedora

-
- After installing the latest - Fedora - 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.7.0-openjdk -
- yum install gcc gcc-c++ -
-

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

- export LANG=C -
- export PATH="/usr/lib/jvm/java-openjdk/bin:${PATH}" -
-
- - -

CentOS 5.5

-
- After installing - CentOS 5.5 - you need to make sure you have - the following Development bundles installed: -
-
    -
  • Development Libraries
  • -
  • Development Tools
  • -
  • Java Development
  • -
  • X Software Development (Including XFree86-devel)
  • -
-
-

- Plus the following packages: -

-
    -
  • cups devel: Cups Development Package
  • -
  • alsa devel: Alsa Development Package
  • -
  • Xi devel: libXi.so Development Package
  • -
-
-

- The freetype 2.3 packages don't seem to be available, - but the freetype 2.3 sources can be downloaded, built, - and installed easily enough from - - the freetype site. - Build and install with something like: -

- bash ./configure -
- make -
- sudo -u root make install -
-

- Mercurial packages could not be found easily, but a Google - search should find ones, and they usually include Python if - it's needed. -

- -

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: -
- aptitude build-dep openjdk-7 -
- aptitude install openjdk-7-jdk libmotif-dev -
-

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

- export LANG=C -
- export PATH="/usr/lib/jvm/java-7-openjdk/bin:${PATH}" -
-
- -

Ubuntu 12.04

-
- After installing Ubuntu 12.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-7 -
- sudo aptitude install openjdk-7-jdk -
-

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

- export LANG=C -
- export PATH="/usr/lib/jvm/java-7-openjdk/bin:${PATH}" -
-
- -

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: -
- sudo zypper source-install -d java-1_7_0-openjdk -
- sudo zypper install make -
-

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

- export LANG=C -
- export PATH="/usr/lib/jvm/java-1.7.0-openjdk/bin:$[PATH}" -
-

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

- export -n JAVA_HOME -
-
- -

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: -
- urpmi java-1.7.0-openjdk-devel 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: -

- export LANG=C -
- export PATH="/usr/lib/jvm/java-1.7.0-openjdk/bin:${PATH}" -
-
- -

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: -
- pfexec pkg install SUNWgmake SUNWj7dev - sunstudioexpress SUNWcups SUNWzip SUNWunzip SUNWxwhl - SUNWxorg-headers SUNWaudh SUNWfreetype2 -
-

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

- export LANG=C -
- export PATH="/opt/SunStudioExpress/bin:${PATH}" -
-
- -
- -
- - - - +
- -
-

End of OpenJDK README-builds.html document.
Please come again! -


+

- +

System Setup

+ +

Before even attempting to use a system to build the OpenJDK there are some very +basic system setups needed. For all systems:

+ + + +

And for specific systems:

+ + + +

+ +

Linux

+ +

With Linux, try and favor the system packages over building your own or getting +packages from other areas. Most Linux builds should be possible with the +system's available packages.

+ +

Note that some Linux systems have a habit of pre-populating your environment +variables for you, for example JAVA_HOME might get pre-defined for you to +refer to the JDK installed on your Linux system. You will need to unset +JAVA_HOME. It's a good idea to run env and verify the environment variables +you are getting from the default system settings make sense for building the +OpenJDK.

+ +

+ +

Solaris

+ +

+ +
Studio Compilers
+ +

At a minimum, the Studio 12 Update 1 Compilers (containing +version 5.10 of the C and C++ compilers) is required, including specific +patches.

+ +

The Solaris SPARC patch list is:

+ + + +

The Solaris X86 patch list is:

+ + + +

Place the bin directory in PATH.

+ +

The Oracle Solaris Studio Express compilers at: Oracle Solaris Studio Express +Download site are also an option, although these compilers +have not been extensively used yet.

+ +

+ +

Windows

+ +
Windows Unix Toolkit
+ +

Building on Windows requires a Unix-like environment, notably a Unix-like +shell. There are several such environments available of which +Cygwin and +MinGW/MSYS are currently supported for the +OpenJDK build. One of the differences of these systems from standard Windows +tools 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.

+ +

+ +
CYGWIN
+ +

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

+ +

The OpenJDK build requires CYGWIN version 1.7.16 or newer. Information about +CYGWIN can be obtained from the CYGWIN website at +www.cygwin.com.

+ +

By default CYGWIN doesn't install all the tools required for building the +OpenJDK. Along with the default installation, you need to install the following +tools.

+ +
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Binary NameCategoryPackageDescription
ar.exeDevelbinutilsThe GNU assembler, linker and binary utilities
make.exeDevelmakeThe GNU version of the 'make' utility built for CYGWIN
m4.exeInterpretersm4GNU implementation of the traditional Unix macro processor
cpio.exeUtilscpioA program to manage archives of files
gawk.exeUtilsawkPattern-directed scanning and processing language
file.exeUtilsfileDetermines file type using 'magic' numbers
zip.exeArchivezipPackage and compress (archive) files
unzip.exeArchiveunzipExtract compressed files in a ZIP archive
free.exeSystemprocpsDisplay amount of free and used memory in the system

+
+ +

Note that the CYGWIN software can conflict with other non-CYGWIN software on +your Windows system. CYGWIN provides a FAQ for known issues and problems, of particular interest is the +section on BLODA (applications that interfere with +CYGWIN).

+ +

+ +
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. See MinGW/MSYS for more information.

+ +

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.

+ +

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

+ +
Visual Studio 2013 Compilers
+ +

The 32-bit and 64-bit OpenJDK Windows build requires Microsoft Visual Studio +C++ 2013 (VS2013) Professional Edition or Express compiler. The compiler and +other tools are expected to reside in the location defined by the variable +VS120COMNTOOLS which is set by the Microsoft Visual Studio installer.

+ +

Only the C++ part of VS2013 is needed. Try to let the installation go to the +default install directory. Always reboot your system after installing VS2013. +The system environment variable VS120COMNTOOLS should be set in your +environment.

+ +

Make sure that TMP and TEMP are also set in the environment and refer to +Windows paths that exist, like C:\temp, not /tmp, not /cygdrive/c/temp, +and not C:/temp. C:\temp is just an example, it is assumed that this area +is private to the user, so by default after installs you should see a unique +user path in these variables.

+ +

+ +

Mac OS X

+ +

Make sure you get the right XCode version.

+ +
+ +

+ +

Configure

+ +

The basic invocation of the configure script looks like:

+ +
+

bash ./configure [options]

+
+ +

This will create an output directory containing the "configuration" and setup +an area for the build result. This directory typically looks like:

+ +
+

build/linux-x64-normal-server-release

+
+ +

configure will try to figure out what system you are running on and where all +necessary build components are. If you have all prerequisites for building +installed, it should find everything. If it fails to detect any component +automatically, it will exit and inform you about the problem. When this +happens, read more below in the configure options.

+ +

Some examples:

+ +
+

Windows 32bit build with freetype specified:
+ bash ./configure --with-freetype=/cygdrive/c/freetype-i586 --with-target- +bits=32

+ +

Debug 64bit Build:
+ bash ./configure --enable-debug --with-target-bits=64

+
+ +

+ +

Configure Options

+ +

Complete details on all the OpenJDK configure options can be seen with:

+ +
+

bash ./configure --help=short

+
+ +

Use -help to see all the configure options available. You can generate any +number of different configurations, e.g. debug, release, 32, 64, etc.

+ +

Some of the more commonly used configure options are:

+ +
+

--enable-debug
+ set the debug level to fastdebug (this is a shorthand for --with-debug- + level=fastdebug)

+
+ +

+ +
+

--with-alsa=path
+ select the location of the Advanced Linux Sound Architecture (ALSA)

+ +

Version 0.9.1 or newer of the ALSA files are required for building the + OpenJDK on Linux. These Linux files are usually available from an "alsa" of + "libasound" development package, and it's highly recommended that you try + and use the package provided by the particular version of Linux that you are + using.

+ +

--with-boot-jdk=path
+ select the Bootstrap JDK

+ +

--with-boot-jdk-jvmargs="args"
+ provide the JVM options to be used to run the Bootstrap JDK

+ +

--with-cacerts=path
+ select the path to the cacerts file.

+ +

See Certificate Authority on Wikipedia for a better understanding of the Certificate + Authority (CA). A certificates file named "cacerts" represents a system-wide + keystore with CA certificates. In JDK and JRE binary bundles, the "cacerts" + file contains root CA certificates from several public CAs (e.g., VeriSign, + Thawte, and Baltimore). The source contain a cacerts file without CA root + certificates. Formal JDK builders will need to secure permission from each + public CA and include the certificates into their own custom cacerts file. + Failure to provide a populated cacerts file will result in verification + errors of a certificate chain during runtime. By default an empty cacerts + file is provided and that should be fine for most JDK developers.

+
+ +

+ +
+

--with-cups=path
+ select the CUPS install location

+ +

The Common UNIX Printing System (CUPS) Headers are required for building the + OpenJDK on Solaris and Linux. The Solaris header files can be obtained by + installing the package SFWcups from the Solaris Software Companion + CD/DVD, these often will be installed into the directory /opt/sfw/cups.

+ +

The CUPS header files can always be downloaded from + www.cups.org.

+ +

--with-cups-include=path
+ select the CUPS include directory location

+ +

--with-debug-level=level
+ select the debug information level of release, fastdebug, or slowdebug

+ +

--with-dev-kit=path
+ select location of the compiler install or developer install location

+
+ +

+ +
+

--with-freetype=path
+ select the freetype files to use.

+ +

Expecting the freetype libraries under lib/ and the headers under + include/.

+ +

Version 2.3 or newer of FreeType is required. On Unix systems required files + can be available as part of your distribution (while you still may need to + upgrade them). Note that you need development version of package that + includes both the FreeType library and header files.

+ +

You can always download latest FreeType version from the FreeType + website. Building the freetype 2 libraries from + scratch is also possible, however on Windows refer to the Windows FreeType + DLL build instructions.

+ +

Note that by default FreeType is built with byte code hinting support + disabled due to licensing restrictions. In this case, text appearance and + metrics are expected to differ from Sun's official JDK build. See the + SourceForge FreeType2 Home Page + for more information.

+ +

--with-import-hotspot=path
+ select the location to find hotspot binaries from a previous build to avoid + building hotspot

+ +

--with-target-bits=arg
+ select 32 or 64 bit build

+ +

--with-jvm-variants=variants
+ select the JVM variants to build from, comma separated list that can + include: server, client, kernel, zero and zeroshark

+ +

--with-memory-size=size
+ select the RAM size that GNU make will think this system has

+ +

--with-msvcr-dll=path
+ select the msvcr100.dll file to include in the Windows builds (C/C++ + runtime library for Visual Studio).

+ +

This is usually picked up automatically from the redist directories of + Visual Studio 2013.

+ +

--with-num-cores=cores
+ select the number of cores to use (processor count or CPU count)

+
+ +

+ +
+

--with-x=path
+ select the location of the X11 and xrender files.

+ +

The XRender Extension Headers are required for building the OpenJDK on + Solaris and Linux. The Linux header files are usually available from a + "Xrender" development package, it's recommended that you try and use the + package provided by the particular distribution of Linux that you are using. + The Solaris XRender header files 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 or + /usr/openwin/share/include/X11/extensions/Xrender.h

+
+ +
+ +

+ +

Make

+ +

The basic invocation of the make utility looks like:

+ +
+

make all

+
+ +

This will start the build to the output directory containing the +"configuration" that was created by the configure script. Run make help for +more information on the available targets.

+ +

There are some of the make targets that are of general interest:

+ +
+

empty
+ build everything but no images

+ +

all
+ build everything including images

+ +

all-conf
+ build all configurations

+ +

images
+ create complete j2sdk and j2re images

+ +

install
+ install the generated images locally, typically in /usr/local

+ +

clean
+ remove all files generated by make, but not those generated by configure

+ +

dist-clean
+ remove all files generated by both and configure (basically killing the + configuration)

+ +

help
+ give some help on using make, including some interesting make targets

+
+ +
+ +

+ +

Testing

+ +

When the build is completed, you should see the generated binaries and +associated files in the j2sdk-image directory in the output directory. In +particular, the build/*/images/j2sdk-image/bin directory should contain +executables for the OpenJDK tools and utilities for that configuration. The +testing tool jtreg will be needed and can be found at: the jtreg +site. The provided regression tests in the +repositories can be run with the command:

+ +
+

cd test && make PRODUCT_HOME=`pwd`/../build/*/images/j2sdk-image all

+
+ +
+ +

+ +

Appendix A: Hints and Tips

+ +

+ +

FAQ

+ +

Q: The generated-configure.sh file looks horrible! How are you going to +edit it?
+A: The generated-configure.sh file is generated (think "compiled") by the +autoconf tools. The source code is in configure.ac and various .m4 files in +common/autoconf, which are much more readable.

+ +

Q: Why is the generated-configure.sh file checked in, if it is +generated?
+A: If it was not generated, every user would need to have the autoconf +tools installed, and re-generate the configure file as the first step. Our +goal is to minimize the work needed to be done by the user to start building +OpenJDK, and to minimize the number of external dependencies required.

+ +

Q: Do you require a specific version of autoconf for regenerating +generated-configure.sh?
+A: Yes, version 2.69 is required and should be easy enough to aquire on all +supported operating systems. The reason for this is to avoid large spurious +changes in generated-configure.sh.

+ +

Q: How do you regenerate generated-configure.sh after making changes to +the input files?
+A: Regnerating generated-configure.sh should always be done using the +script common/autoconf/autogen.sh to ensure that the correct files get +updated. This script should also be run after mercurial tries to merge +generated-configure.sh as a merge of the generated file is not guaranteed to +be correct.

+ +

Q: What are the files in common/makefiles/support/* for? They look like +gibberish.
+A: They are a somewhat ugly hack to compensate for command line length +limitations on certain platforms (Windows, Solaris). Due to a combination of +limitations in make and the shell, command lines containing too many files will +not work properly. These helper files are part of an elaborate hack that will +compress the command line in the makefile and then uncompress it safely. We're +not proud of it, but it does fix the problem. If you have any better +suggestions, we're all ears! :-)

+ +

Q: I want to see the output of the commands that make runs, like in the old +build. How do I do that?
+A: You specify the LOG variable to make. There are several log levels:

+ + + +

Q: When do I have to re-run configure?
+A: Normally you will run configure only once for creating a +configuration. You need to re-run configuration only if you want to change any +configuration options, or if you pull down changes to the configure script.

+ +

Q: I have added a new source file. Do I need to modify the makefiles?
+A: Normally, no. If you want to create e.g. a new native library, you will +need to modify the makefiles. But for normal file additions or removals, no +changes are needed. There are certan exceptions for some native libraries where +the source files are spread over many directories which also contain sources +for other libraries. In these cases it was simply easier to create include +lists rather than excludes.

+ +

Q: When I run configure --help, I see many strange options, like +--dvidir. What is this?
+A: Configure provides a slew of options by default, to all projects that +use autoconf. Most of them are not used in OpenJDK, so you can safely ignore +them. To list only OpenJDK specific features, use configure --help=short +instead.

+ +

Q: configure provides OpenJDK-specific features such as --with- +builddeps-server that are not described in this document. What about those?
+A: Try them out if you like! But be aware that most of these are +experimental features. Many of them don't do anything at all at the moment; the +option is just a placeholder. Others depend on pieces of code or infrastructure +that is currently not ready for prime time.

+ +

Q: How will you make sure you don't break anything?
+A: We have a script that compares the result of the new build system with +the result of the old. For most part, we aim for (and achieve) byte-by-byte +identical output. There are however technical issues with e.g. native binaries, +which might differ in a byte-by-byte comparison, even when building twice with +the old build system. For these, we compare relevant aspects (e.g. the symbol +table and file size). Note that we still don't have 100% equivalence, but we're +close.

+ +

Q: I noticed this thing X in the build that looks very broken by design. +Why don't you fix it?
+A: Our goal is to produce a build output that is as close as technically +possible to the old build output. If things were weird in the old build, they +will be weird in the new build. Often, things were weird before due to +obscurity, but in the new build system the weird stuff comes up to the surface. +The plan is to attack these things at a later stage, after the new build system +is established.

+ +

Q: The code in the new build system is not that well-structured. Will you +fix this?
+A: Yes! The new build system has grown bit by bit as we converted the old +system. When all of the old build system is converted, we can take a step back +and clean up the structure of the new build system. Some of this we plan to do +before replacing the old build system and some will need to wait until after.

+ +

Q: Is anything able to use the results of the new build's default make +target?
+A: Yes, this is the minimal (or roughly minimal) set of compiled output +needed for a developer to actually execute the newly built JDK. The idea is +that in an incremental development fashion, when doing a normal make, you +should only spend time recompiling what's changed (making it purely +incremental) and only do the work that's needed to actually run and test your +code. The packaging stuff that is part of the images target is not needed for +a normal developer who wants to test his new code. Even if it's quite fast, +it's still unnecessary. We're targeting sub-second incremental rebuilds! ;-) +(Or, well, at least single-digit seconds...)

+ +

Q: I usually set a specific environment variable when building, but I can't +find the equivalent in the new build. What should I do?
+A: It might very well be that we have neglected to add support for an +option that was actually used from outside the build system. Email us and we +will add support for it!

+ +

+ +

Build Performance Tips

+ +

Building OpenJDK requires a lot of horsepower. Some of the build tools can be +adjusted to utilize more or less of resources such as parallel threads and +memory. The configure script analyzes your system and selects reasonable +values for such options based on your hardware. If you encounter resource +problems, such as out of memory conditions, you can modify the detected values +with:

+ + + +

It might also be necessary to specify the JVM arguments passed to the Bootstrap +JDK, using e.g. --with-boot-jdk-jvmargs="-Xmx8G -enableassertions". Doing +this will override the default JVM arguments passed to the Bootstrap JDK.

+ +

One of the top goals of the new build system is to improve the build +performance and decrease the time needed to build. This will soon also apply to +the java compilation when the Smart Javac wrapper is fully supported.

+ +

At the end of a successful execution of configure, you will get a performance +summary, indicating how well the build will perform. Here you will also get +performance hints. If you want to build fast, pay attention to those!

+ +

Building with ccache

+ +

The OpenJDK build supports building with ccache when using gcc or clang. Using +ccache can radically speed up compilation of native code if you often rebuild +the same sources. Your milage may vary however so we recommend evaluating it +for yourself. To enable it, make sure it's on the path and configure with +--enable-ccache.

+ +

Building on local disk

+ +

If you are using network shares, e.g. via NFS, for your source code, make sure +the build directory is situated on local disk. The performance penalty is +extremely high for building on a network share, close to unusable.

+ +

Building only one JVM

+ +

The old build builds multiple JVMs on 32-bit systems (client and server; and on +Windows kernel as well). In the new build we have changed this default to only +build server when it's available. This improves build times for those not +interested in multiple JVMs. To mimic the old behavior on platforms that +support it, use --with-jvm-variants=client,server.

+ +

Selecting the number of cores to build on

+ +

By default, configure will analyze your machine and run the make process in +parallel with as many threads as you have cores. This behavior can be +overridden, either "permanently" (on a configure basis) using +--with-num-cores=N or for a single build only (on a make basis), using +make JOBS=N.

+ +

If you want to make a slower build just this time, to save some CPU power for +other processes, you can run e.g. make JOBS=2. This will force the makefiles +to only run 2 parallel processes, or even make JOBS=1 which will disable +parallelism.

+ +

If you want to have it the other way round, namely having slow builds default +and override with fast if you're impatient, you should call configure with +--with-num-cores=2, making 2 the default. If you want to run with more cores, +run make JOBS=8

+ +

+ +

Troubleshooting

+ +

Solving build problems

+ +

If the build fails (and it's not due to a compilation error in a source file +you've changed), the first thing you should do is to re-run the build with more +verbosity. Do this by adding LOG=debug to your make command line.

+ +

The build log (with both stdout and stderr intermingled, basically the same as +you see on your console) can be found as build.log in your build directory.

+ +

You can ask for help on build problems with the new build system on either the +build-dev or the +build-infra-dev +mailing lists. Please include the relevant parts of the build log.

+ +

A build can fail for any number of reasons. Most failures are a result of +trying to build in an environment in which all the pre-build requirements have +not been met. The first step in troubleshooting a build failure is to recheck +that you have satisfied all the pre-build requirements for your platform. +Scanning the configure log is a good first step, making sure that what it +found makes sense for your system. Look for strange error messages or any +difficulties that configure had in finding things.

+ +

Some of the more common problems with builds are briefly described below, with +suggestions for remedies.

+ + + +
+ +

+ +

Appendix B: GNU make

+ +

The Makefiles in the OpenJDK are only valid when used with the GNU version of +the utility command make (usually called gmake on Solaris). A few notes +about using GNU make:

+ + + +

Information on GNU make, and access to ftp download sites, are available on the +GNU make web site . The latest +source to GNU make is available at +ftp.gnu.org/pub/gnu/make/.

+ +

+ +

Building GNU make

+ +

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 but is basically done with:

+ +
  bash ./configure
+  make
+
+ +
+ +

+ +

Appendix C: Build Environments

+ +

Minimum Build Environments

+ +

This file often describes specific requirements for what we call the "minimum +build environments" (MBE) for this specific release of the JDK. What is listed +below is what the Oracle Release Engineering Team will use to build the Oracle +JDK product. Building with the MBE will hopefully generate the most compatible +bits that install on, and run correctly on, the most variations of the same +base OS and hardware architecture. In some cases, these represent what is often +called the least common denominator, but each Operating System has different +aspects to it.

+ +

In all cases, the Bootstrap JDK version minimum is critical, we cannot +guarantee builds will work with older Bootstrap JDK's. Also in all cases, more +RAM and more processors is better, the minimums listed below are simply +recommendations.

+ +

With Solaris and Mac OS X, the version listed below is the oldest release we +can guarantee builds and works, and the specific version of the compilers used +could be critical.

+ +

With Windows the critical aspect is the Visual Studio compiler used, which due +to it's runtime, generally dictates what Windows systems can do the builds and +where the resulting bits can be used.

+ +

NOTE: We expect a change here off these older Windows OS releases and to a +'less older' one, probably Windows 2008R2 X64.

+ +

With Linux, it was just a matter of picking a stable distribution that is a +good representative for Linux in general.

+ +

NOTE: We expect a change here from Fedora 9 to something else, but it has not +been completely determined yet, possibly Ubuntu 12.04 X64, unbiased community +feedback would be welcome on what a good choice would be here.

+ +

It is understood that most developers will NOT be using these specific +versions, and in fact creating these specific versions may be difficult due to +the age of some of this software. It is expected that developers are more often +using the more recent releases and distributions of these operating systems.

+ +

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 older, +newer, or unreleased OS versions. Please report these types of problems as bugs +so that they can be dealt with accordingly.

+ +
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Base OS and ArchitectureOSC/C++ CompilerBootstrap JDKProcessorsRAM MinimumDISK Needs
Linux X86 (32-bit) and X64 (64-bit)Oracle Enterprise Linux 6.4gcc 4.8.2 JDK 82 or more1 GB6 GB
Solaris SPARCV9 (64-bit)Solaris 10 Update 10Studio 12 Update 3 + patchesJDK 84 or more4 GB8 GB
Solaris X64 (64-bit)Solaris 10 Update 10Studio 12 Update 3 + patchesJDK 84 or more4 GB8 GB
Windows X86 (32-bit)Windows Server 2012 R2 x64Microsoft Visual Studio C++ 2013 Professional EditionJDK 82 or more2 GB6 GB
Windows X64 (64-bit)Windows Server 2012 R2 x64Microsoft Visual Studio C++ 2013 Professional EditionJDK 82 or more2 GB6 GB
Mac OS X X64 (64-bit)Mac OS X 10.9 "Mavericks"XCode 5.1.1 or newerJDK 82 or more4 GB6 GB

+
+ +
+ +

+ +

Specific Developer Build Environments

+ +

We won't be listing all the possible environments, but we will try to provide +what information we have available to us.

+ +

NOTE: The community can help out by updating this part of the document.

+ +

Fedora

+ +

After installing the latest Fedora 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.7.0-openjdk
+  yum install gcc gcc-c++
+
+ +

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

+ +
  export LANG=C
+  export PATH="/usr/lib/jvm/java-openjdk/bin:${PATH}"
+
+ +

CentOS 5.5

+ +

After installing CentOS 5.5 you need to make sure you +have the following Development bundles installed:

+ + + +

Plus the following packages:

+ + + +

The freetype 2.3 packages don't seem to be available, but the freetype 2.3 +sources can be downloaded, built, and installed easily enough from the +freetype site. Build and install +with something like:

+ +
  bash ./configure
+  make
+  sudo -u root make install
+
+ +

Mercurial packages could not be found easily, but a Google search should find +ones, and they usually include Python if it's needed.

+ +

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:

+ +
  aptitude build-dep openjdk-7
+  aptitude install openjdk-7-jdk libmotif-dev
+
+ +

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

+ +
  export LANG=C
+  export PATH="/usr/lib/jvm/java-7-openjdk/bin:${PATH}"
+
+ +

Ubuntu 12.04

+ +

After installing Ubuntu 12.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-7
+  sudo aptitude install openjdk-7-jdk
+
+ +

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

+ +
  export LANG=C
+  export PATH="/usr/lib/jvm/java-7-openjdk/bin:${PATH}"
+
+ +

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:

+ +
  sudo zypper source-install -d java-1_7_0-openjdk
+  sudo zypper install make
+
+ +

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

+ +
  export LANG=C
+  export PATH="/usr/lib/jvm/java-1.7.0-openjdk/bin:$[PATH}"
+
+ +

Finally, you need to unset the JAVA_HOME environment variable:

+ +
  export -n JAVA_HOME`
+
+ +

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:

+ +
  urpmi java-1.7.0-openjdk-devel 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:

+ +
  export LANG=C
+  export PATH="/usr/lib/jvm/java-1.7.0-openjdk/bin:${PATH}"
+
+ +

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:

+ +
  pfexec pkg install SUNWgmake SUNWj7dev sunstudioexpress SUNWcups SUNWzip
+    SUNWunzip SUNWxwhl SUNWxorg-headers SUNWaudh SUNWfreetype2
+
+ +

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

+ +
  export LANG=C
+  export PATH="/opt/SunStudioExpress/bin:${PATH}"
+
+ +
+ +

End of the OpenJDK build README document.

+ +

Please come again!

+ diff --git a/README-builds.md b/README-builds.md new file mode 100644 index 00000000000..21367477890 --- /dev/null +++ b/README-builds.md @@ -0,0 +1,1263 @@ +![OpenJDK](http://openjdk.java.net/images/openjdk.png) +# OpenJDK Build README + +***** + + +## Introduction + +This README file contains build instructions for the +[OpenJDK](http://openjdk.java.net). Building the source code for the OpenJDK +requires a certain degree of technical expertise. + +### !!!!!!!!!!!!!!! THIS IS A MAJOR RE-WRITE of this document. !!!!!!!!!!!!! + +Some Headlines: + + * The build is now a "`configure && make`" style build + * Any GNU make 3.81 or newer should work, except on Windows where 4.0 or newer + is recommended. + * The build should scale, i.e. more processors should cause the build to be + done in less wall-clock time + * Nested or recursive make invocations have been significantly reduced, + as has the total fork/exec or spawning of sub processes during the build + * Windows MKS usage is no longer supported + * Windows Visual Studio `vsvars*.bat` and `vcvars*.bat` files are run + automatically + * Ant is no longer used when building the OpenJDK + * Use of ALT_* environment variables for configuring the build is no longer + supported + +***** + +## Contents + + * [Introduction](#introduction) + * [Use of Mercurial](#hg) + * [Getting the Source](#get_source) + * [Repositories](#repositories) + * [Building](#building) + * [System Setup](#setup) + * [Linux](#linux) + * [Solaris](#solaris) + * [Mac OS X](#macosx) + * [Windows](#windows) + * [Configure](#configure) + * [Make](#make) + * [Testing](#testing) + +***** + + * [Appendix A: Hints and Tips](#hints) + * [FAQ](#faq) + * [Build Performance Tips](#performance) + * [Troubleshooting](#troubleshooting) + * [Appendix B: GNU Make Information](#gmake) + * [Appendix C: Build Environments](#buildenvironments) + +***** + + +## Use of Mercurial + +The OpenJDK sources are maintained with the revision control system +[Mercurial](http://mercurial.selenic.com/wiki/Mercurial). If you are new to +Mercurial, please see the [Beginner Guides](http://mercurial.selenic.com/wiki/ +BeginnersGuides) or refer to the [Mercurial Book](http://hgbook.red-bean.com/). +The first few chapters of the book provide an excellent overview of Mercurial, +what it is and how it works. + +For using Mercurial with the OpenJDK refer to the [Developer Guide: Installing +and Configuring Mercurial](http://openjdk.java.net/guide/ +repositories.html#installConfig) section for more information. + + +### Getting the Source + +To get the entire set of OpenJDK Mercurial repositories use the script +`get_source.sh` located in the root repository: + + hg clone http://hg.openjdk.java.net/jdk9/jdk9 YourOpenJDK + cd YourOpenJDK + bash ./get_source.sh + +Once you have all the repositories, keep in mind that each repository is its +own independent repository. You can also re-run `./get_source.sh` anytime to +pull over all the latest changesets in all the repositories. This set of +nested repositories has been given the term "forest" and there are various +ways to apply the same `hg` command to each of the repositories. For +example, the script `make/scripts/hgforest.sh` can be used to repeat the +same `hg` command on every repository, e.g. + + cd YourOpenJDK + bash ./make/scripts/hgforest.sh status + + +### Repositories + +The set of repositories and what they contain: + + * **. (root)** contains common configure and makefile logic + * **hotspot** contains source code and make files for building the OpenJDK + Hotspot Virtual Machine + * **langtools** contains source code for the OpenJDK javac and language tools + * **jdk** contains source code and make files for building the OpenJDK runtime + libraries and misc files + * **jaxp** contains source code for the OpenJDK JAXP functionality + * **jaxws** contains source code for the OpenJDK JAX-WS functionality + * **corba** contains source code for the OpenJDK Corba functionality + * **nashorn** contains source code for the OpenJDK JavaScript implementation + +### Repository Source Guidelines + +There are some very basic guidelines: + + * Use of whitespace in source files (.java, .c, .h, .cpp, and .hpp files) is + restricted. No TABs, no trailing whitespace on lines, and files should not + terminate in more than one blank line. + * Files with execute permissions should not be added to the source + repositories. + * All generated files need to be kept isolated from the files maintained or + managed by the source control system. The standard area for generated files + is the top level `build/` directory. + * The default build process should be to build the product and nothing else, + in one form, e.g. a product (optimized), debug (non-optimized, -g plus + assert logic), or fastdebug (optimized, -g plus assert logic). + * The `.hgignore` file in each repository must exist and should include + `^build/`, `^dist/` and optionally any `nbproject/private` directories. **It + should NEVER** include anything in the `src/` or `test/` or any managed + directory area of a repository. + * Directory names and file names should never contain blanks or non-printing + characters. + * Generated source or binary files should NEVER be added to the repository + (that includes `javah` output). There are some exceptions to this rule, in + particular with some of the generated configure scripts. + * Files not needed for typical building or testing of the repository should + not be added to the repository. + +***** + + +## Building + +The very first step in building the OpenJDK is making sure the system itself +has everything it needs to do OpenJDK builds. Once a system is setup, it +generally doesn't need to be done again. + +Building the OpenJDK is now done with running a `configure` script which will +try and find and verify you have everything you need, followed by running +`make`, e.g. + +> **`bash ./configure`** +> **`make all`** + +Where possible the `configure` script will attempt to located the various +components in the default locations or via component specific variable +settings. When the normal defaults fail or components cannot be found, +additional `configure` options may be necessary to help `configure` find the +necessary tools for the build, or you may need to re-visit the setup of your +system due to missing software packages. + +**NOTE:** The `configure` script file does not have execute permissions and +will need to be explicitly run with `bash`, see the source guidelines. + +***** + + +### System Setup + +Before even attempting to use a system to build the OpenJDK there are some very +basic system setups needed. For all systems: + + * Be sure the GNU make utility is version 3.81 (4.0 on windows) or newer, e.g. + run "`make -version`" + + + * Install a Bootstrap JDK. All OpenJDK builds require access to a previously + released JDK called the _bootstrap JDK_ or _boot JDK._ The general rule is + that the bootstrap JDK must be an instance of the previous major release of + the JDK. In addition, there may be a requirement to use a release at or + beyond a particular update level. + + **_Building JDK 9 requires JDK 8. JDK 9 developers should not use JDK 9 as + the boot JDK, to ensure that JDK 9 dependencies are not introduced into the + parts of the system that are built with JDK 8._** + + The JDK 8 binaries can be downloaded from Oracle's [JDK 8 download + site](http://www.oracle.com/technetwork/java/javase/downloads/index.html). + For build performance reasons it is very important that this bootstrap JDK + be made available on the local disk of the machine doing the build. You + should add its `bin` directory to the `PATH` environment variable. If + `configure` has any issues finding this JDK, you may need to use the + `configure` option `--with-boot-jdk`. + + * Ensure that GNU make, the Bootstrap JDK, and the compilers are all in your + PATH environment variable. + +And for specific systems: + + * **Linux** + + Install all the software development packages needed including + [alsa](#alsa), [freetype](#freetype), [cups](#cups), and + [xrender](#xrender). See [specific system packages](#SDBE). + + * **Solaris** + + Install all the software development packages needed including [Studio + Compilers](#studio), [freetype](#freetype), [cups](#cups), and + [xrender](#xrender). See [specific system packages](#SDBE). + + * **Windows** + + * Install one of [CYGWIN](#cygwin) or [MinGW/MSYS](#msys) + * Install [Visual Studio 2013](#vs2013) + + * **Mac OS X** + + Install [XCode 4.5.2](https://developer.apple.com/xcode/) and also + install the "Command line tools" found under the preferences pane + "Downloads" + + +#### Linux + +With Linux, try and favor the system packages over building your own or getting +packages from other areas. Most Linux builds should be possible with the +system's available packages. + +Note that some Linux systems have a habit of pre-populating your environment +variables for you, for example `JAVA_HOME` might get pre-defined for you to +refer to the JDK installed on your Linux system. You will need to unset +`JAVA_HOME`. It's a good idea to run `env` and verify the environment variables +you are getting from the default system settings make sense for building the +OpenJDK. + + +#### Solaris + + +##### Studio Compilers + +At a minimum, the [Studio 12 Update 1 Compilers](http://www.oracle.com/ +technetwork/server-storage/solarisstudio/downloads/index.htm) (containing +version 5.10 of the C and C++ compilers) is required, including specific +patches. + +The Solaris SPARC patch list is: + + * 118683-05: SunOS 5.10: Patch for profiling libraries and assembler + * 119963-21: SunOS 5.10: Shared library patch for C++ + * 120753-08: SunOS 5.10: Microtasking libraries (libmtsk) patch + * 128228-09: Sun Studio 12 Update 1: Patch for Sun C++ Compiler + * 141860-03: Sun Studio 12 Update 1: Patch for Compiler Common patch for Sun C + C++ F77 F95 + * 141861-05: Sun Studio 12 Update 1: Patch for Sun C Compiler + * 142371-01: Sun Studio 12.1 Update 1: Patch for dbx + * 143384-02: Sun Studio 12 Update 1: Patch for debuginfo handling + * 143385-02: Sun Studio 12 Update 1: Patch for Compiler Common patch for Sun C + C++ F77 F95 + * 142369-01: Sun Studio 12.1: Patch for Performance Analyzer Tools + +The Solaris X86 patch list is: + + * 119961-07: SunOS 5.10_x86, x64, Patch for profiling libraries and assembler + * 119964-21: SunOS 5.10_x86: Shared library patch for C++\_x86 + * 120754-08: SunOS 5.10_x86: Microtasking libraries (libmtsk) patch + * 141858-06: Sun Studio 12 Update 1_x86: Sun Compiler Common patch for x86 + backend + * 128229-09: Sun Studio 12 Update 1_x86: Patch for C++ Compiler + * 142363-05: Sun Studio 12 Update 1_x86: Patch for C Compiler + * 142368-01: Sun Studio 12.1_x86: Patch for Performance Analyzer Tools + +Place the `bin` directory in `PATH`. + +The Oracle Solaris Studio Express compilers at: [Oracle Solaris Studio Express +Download site](http://www.oracle.com/technetwork/server-storage/solarisstudio/ +downloads/index-jsp-142582.html) are also an option, although these compilers +have not been extensively used yet. + + +#### Windows + +##### Windows Unix Toolkit + +Building on Windows requires a Unix-like environment, notably a Unix-like +shell. There are several such environments available of which +[Cygwin](http://www.cygwin.com/) and +[MinGW/MSYS](http://www.mingw.org/wiki/MSYS) are currently supported for the +OpenJDK build. One of the differences of these systems from standard Windows +tools 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](http://en.wikipedia.org/wiki/8.3_filename). + + +###### CYGWIN + +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 `:` to a virtual directory +`/cygdrive/`. + +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 ""`. + +Note that the use of CYGWIN creates a unique problem with regards to setting +[`PATH`](#path). Normally on Windows the `PATH` variable contains directories +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. + +The OpenJDK build requires CYGWIN version 1.7.16 or newer. Information about +CYGWIN can be obtained from the CYGWIN website at +[www.cygwin.com](http://www.cygwin.com). + +By default CYGWIN doesn't install all the tools required for building the +OpenJDK. Along with the default installation, you need to install the following +tools. + +> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Binary NameCategoryPackageDescription
ar.exeDevelbinutilsThe GNU assembler, linker and binary utilities
make.exeDevelmakeThe GNU version of the 'make' utility built for CYGWIN
m4.exeInterpretersm4GNU implementation of the traditional Unix macro processor
cpio.exeUtilscpioA program to manage archives of files
gawk.exeUtilsawkPattern-directed scanning and processing language
file.exeUtilsfileDetermines file type using 'magic' numbers
zip.exeArchivezipPackage and compress (archive) files
unzip.exeArchiveunzipExtract compressed files in a ZIP archive
free.exeSystemprocpsDisplay amount of free and used memory in the system
+ +Note that the CYGWIN software can conflict with other non-CYGWIN software on +your Windows system. CYGWIN provides a [FAQ](http://cygwin.com/faq/ +faq.using.html) for known issues and problems, of particular interest is the +section on [BLODA (applications that interfere with +CYGWIN)](http://cygwin.com/faq/faq.using.html#faq.using.bloda). + + +###### 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`. See [MinGW/MSYS](http://www.mingw.org/ +wiki/MSYS) for more information. + +Like Cygwin, MinGW/MSYS can handle different types of path formats. They are +internally converted to paths with forward slashes and drive letters +`:` replaced by a virtual directory `/`. 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](http://mingw.org/wiki/ +Posix_path_conversion). + +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 + + +##### Visual Studio 2013 Compilers + +The 32-bit and 64-bit OpenJDK Windows build requires Microsoft Visual Studio +C++ 2013 (VS2013) Professional Edition or Express compiler. The compiler and +other tools are expected to reside in the location defined by the variable +`VS120COMNTOOLS` which is set by the Microsoft Visual Studio installer. + +Only the C++ part of VS2013 is needed. Try to let the installation go to the +default install directory. Always reboot your system after installing VS2013. +The system environment variable VS120COMNTOOLS should be set in your +environment. + +Make sure that TMP and TEMP are also set in the environment and refer to +Windows paths that exist, like `C:\temp`, not `/tmp`, not `/cygdrive/c/temp`, +and not `C:/temp`. `C:\temp` is just an example, it is assumed that this area +is private to the user, so by default after installs you should see a unique +user path in these variables. + + +#### Mac OS X + +Make sure you get the right XCode version. + +***** + + +### Configure + +The basic invocation of the `configure` script looks like: + +> **`bash ./configure [options]`** + +This will create an output directory containing the "configuration" and setup +an area for the build result. This directory typically looks like: + +> **`build/linux-x64-normal-server-release`** + +`configure` will try to figure out what system you are running on and where all +necessary build components are. If you have all prerequisites for building +installed, it should find everything. If it fails to detect any component +automatically, it will exit and inform you about the problem. When this +happens, read more below in [the `configure` options](#configureoptions). + +Some examples: + +> **Windows 32bit build with freetype specified:** +> `bash ./configure --with-freetype=/cygdrive/c/freetype-i586 --with-target- +bits=32` + +> **Debug 64bit Build:** +> `bash ./configure --enable-debug --with-target-bits=64` + + +#### Configure Options + +Complete details on all the OpenJDK `configure` options can be seen with: + +> **`bash ./configure --help=short`** + +Use `-help` to see all the `configure` options available. You can generate any +number of different configurations, e.g. debug, release, 32, 64, etc. + +Some of the more commonly used `configure` options are: + +> **`--enable-debug`** +> set the debug level to fastdebug (this is a shorthand for `--with-debug- + level=fastdebug`) + + +> **`--with-alsa=`**_path_ +> select the location of the Advanced Linux Sound Architecture (ALSA) + +> Version 0.9.1 or newer of the ALSA files are required for building the + OpenJDK on Linux. These Linux files are usually available from an "alsa" of + "libasound" development package, and it's highly recommended that you try + and use the package provided by the particular version of Linux that you are + using. + +> **`--with-boot-jdk=`**_path_ +> select the [Bootstrap JDK](#bootjdk) + +> **`--with-boot-jdk-jvmargs=`**"_args_" +> provide the JVM options to be used to run the [Bootstrap JDK](#bootjdk) + +> **`--with-cacerts=`**_path_ +> select the path to the cacerts file. + +> See [Certificate Authority on Wikipedia](http://en.wikipedia.org/wiki/ + Certificate_Authority) for a better understanding of the Certificate + Authority (CA). A certificates file named "cacerts" represents a system-wide + keystore with CA certificates. In JDK and JRE binary bundles, the "cacerts" + file contains root CA certificates from several public CAs (e.g., VeriSign, + Thawte, and Baltimore). The source contain a cacerts file without CA root + certificates. Formal JDK builders will need to secure permission from each + public CA and include the certificates into their own custom cacerts file. + Failure to provide a populated cacerts file will result in verification + errors of a certificate chain during runtime. By default an empty cacerts + file is provided and that should be fine for most JDK developers. + + +> **`--with-cups=`**_path_ +> select the CUPS install location + +> The Common UNIX Printing System (CUPS) Headers are required for building the + OpenJDK on Solaris and Linux. The Solaris header files can be obtained by + installing the package **SFWcups** from the Solaris Software Companion + CD/DVD, these often will be installed into the directory `/opt/sfw/cups`. + +> The CUPS header files can always be downloaded from + [www.cups.org](http://www.cups.org). + +> **`--with-cups-include=`**_path_ +> select the CUPS include directory location + +> **`--with-debug-level=`**_level_ +> select the debug information level of release, fastdebug, or slowdebug + +> **`--with-dev-kit=`**_path_ +> select location of the compiler install or developer install location + + +> **`--with-freetype=`**_path_ +> select the freetype files to use. + +> Expecting the freetype libraries under `lib/` and the headers under + `include/`. + +> Version 2.3 or newer of FreeType is required. On Unix systems required files + can be available as part of your distribution (while you still may need to + upgrade them). Note that you need development version of package that + includes both the FreeType library and header files. + +> You can always download latest FreeType version from the [FreeType + website](http://www.freetype.org). Building the freetype 2 libraries from + scratch is also possible, however on Windows refer to the [Windows FreeType + DLL build instructions](http://freetype.freedesktop.org/wiki/FreeType_DLL). + +> Note that by default FreeType is built with byte code hinting support + disabled due to licensing restrictions. In this case, text appearance and + metrics are expected to differ from Sun's official JDK build. See the + [SourceForge FreeType2 Home Page](http://freetype.sourceforge.net/freetype2) + for more information. + +> **`--with-import-hotspot=`**_path_ +> select the location to find hotspot binaries from a previous build to avoid + building hotspot + +> **`--with-target-bits=`**_arg_ +> select 32 or 64 bit build + +> **`--with-jvm-variants=`**_variants_ +> select the JVM variants to build from, comma separated list that can + include: server, client, kernel, zero and zeroshark + +> **`--with-memory-size=`**_size_ +> select the RAM size that GNU make will think this system has + +> **`--with-msvcr-dll=`**_path_ +> select the `msvcr100.dll` file to include in the Windows builds (C/C++ + runtime library for Visual Studio). + +> This is usually picked up automatically from the redist directories of + Visual Studio 2013. + +> **`--with-num-cores=`**_cores_ +> select the number of cores to use (processor count or CPU count) + + +> **`--with-x=`**_path_ +> select the location of the X11 and xrender files. + +> The XRender Extension Headers are required for building the OpenJDK on + Solaris and Linux. The Linux header files are usually available from a + "Xrender" development package, it's recommended that you try and use the + package provided by the particular distribution of Linux that you are using. + The Solaris XRender header files 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` or + `/usr/openwin/share/include/X11/extensions/Xrender.h` + +***** + + +### Make + +The basic invocation of the `make` utility looks like: + +> **`make all`** + +This will start the build to the output directory containing the +"configuration" that was created by the `configure` script. Run `make help` for +more information on the available targets. + +There are some of the make targets that are of general interest: + +> _empty_ +> build everything but no images + +> **`all`** +> build everything including images + +> **`all-conf`** +> build all configurations + +> **`images`** +> create complete j2sdk and j2re images + +> **`install`** +> install the generated images locally, typically in `/usr/local` + +> **`clean`** +> remove all files generated by make, but not those generated by `configure` + +> **`dist-clean`** +> remove all files generated by both and `configure` (basically killing the + configuration) + +> **`help`** +> give some help on using `make`, including some interesting make targets + +***** + + +## Testing + +When the build is completed, you should see the generated binaries and +associated files in the `j2sdk-image` directory in the output directory. In +particular, the `build/*/images/j2sdk-image/bin` directory should contain +executables for the OpenJDK tools and utilities for that configuration. The +testing tool `jtreg` will be needed and can be found at: [the jtreg +site](http://openjdk.java.net/jtreg/). The provided regression tests in the +repositories can be run with the command: + +> **``cd test && make PRODUCT_HOME=`pwd`/../build/*/images/j2sdk-image all``** + +***** + + +## Appendix A: Hints and Tips + + +### FAQ + +**Q:** The `generated-configure.sh` file looks horrible! How are you going to +edit it? +**A:** The `generated-configure.sh` file is generated (think "compiled") by the +autoconf tools. The source code is in `configure.ac` and various .m4 files in +common/autoconf, which are much more readable. + +**Q:** Why is the `generated-configure.sh` file checked in, if it is +generated? +**A:** If it was not generated, every user would need to have the autoconf +tools installed, and re-generate the `configure` file as the first step. Our +goal is to minimize the work needed to be done by the user to start building +OpenJDK, and to minimize the number of external dependencies required. + +**Q:** Do you require a specific version of autoconf for regenerating +`generated-configure.sh`? +**A:** Yes, version 2.69 is required and should be easy enough to aquire on all +supported operating systems. The reason for this is to avoid large spurious +changes in `generated-configure.sh`. + +**Q:** How do you regenerate `generated-configure.sh` after making changes to +the input files? +**A:** Regnerating `generated-configure.sh` should always be done using the +script `common/autoconf/autogen.sh` to ensure that the correct files get +updated. This script should also be run after mercurial tries to merge +`generated-configure.sh` as a merge of the generated file is not guaranteed to +be correct. + +**Q:** What are the files in `common/makefiles/support/*` for? They look like +gibberish. +**A:** They are a somewhat ugly hack to compensate for command line length +limitations on certain platforms (Windows, Solaris). Due to a combination of +limitations in make and the shell, command lines containing too many files will +not work properly. These helper files are part of an elaborate hack that will +compress the command line in the makefile and then uncompress it safely. We're +not proud of it, but it does fix the problem. If you have any better +suggestions, we're all ears! :-) + +**Q:** I want to see the output of the commands that make runs, like in the old +build. How do I do that? +**A:** You specify the `LOG` variable to make. There are several log levels: + + * **`warn`** -- Default and very quiet. + * **`info`** -- Shows more progress information than warn. + * **`debug`** -- Echos all command lines and prints all macro calls for + compilation definitions. + * **`trace`** -- Echos all $(shell) command lines as well. + +**Q:** When do I have to re-run `configure`? +**A:** Normally you will run `configure` only once for creating a +configuration. You need to re-run configuration only if you want to change any +configuration options, or if you pull down changes to the `configure` script. + +**Q:** I have added a new source file. Do I need to modify the makefiles? +**A:** Normally, no. If you want to create e.g. a new native library, you will +need to modify the makefiles. But for normal file additions or removals, no +changes are needed. There are certan exceptions for some native libraries where +the source files are spread over many directories which also contain sources +for other libraries. In these cases it was simply easier to create include +lists rather than excludes. + +**Q:** When I run `configure --help`, I see many strange options, like +`--dvidir`. What is this? +**A:** Configure provides a slew of options by default, to all projects that +use autoconf. Most of them are not used in OpenJDK, so you can safely ignore +them. To list only OpenJDK specific features, use `configure --help=short` +instead. + +**Q:** `configure` provides OpenJDK-specific features such as `--with- +builddeps-server` that are not described in this document. What about those? +**A:** Try them out if you like! But be aware that most of these are +experimental features. Many of them don't do anything at all at the moment; the +option is just a placeholder. Others depend on pieces of code or infrastructure +that is currently not ready for prime time. + +**Q:** How will you make sure you don't break anything? +**A:** We have a script that compares the result of the new build system with +the result of the old. For most part, we aim for (and achieve) byte-by-byte +identical output. There are however technical issues with e.g. native binaries, +which might differ in a byte-by-byte comparison, even when building twice with +the old build system. For these, we compare relevant aspects (e.g. the symbol +table and file size). Note that we still don't have 100% equivalence, but we're +close. + +**Q:** I noticed this thing X in the build that looks very broken by design. +Why don't you fix it? +**A:** Our goal is to produce a build output that is as close as technically +possible to the old build output. If things were weird in the old build, they +will be weird in the new build. Often, things were weird before due to +obscurity, but in the new build system the weird stuff comes up to the surface. +The plan is to attack these things at a later stage, after the new build system +is established. + +**Q:** The code in the new build system is not that well-structured. Will you +fix this? +**A:** Yes! The new build system has grown bit by bit as we converted the old +system. When all of the old build system is converted, we can take a step back +and clean up the structure of the new build system. Some of this we plan to do +before replacing the old build system and some will need to wait until after. + +**Q:** Is anything able to use the results of the new build's default make +target? +**A:** Yes, this is the minimal (or roughly minimal) set of compiled output +needed for a developer to actually execute the newly built JDK. The idea is +that in an incremental development fashion, when doing a normal make, you +should only spend time recompiling what's changed (making it purely +incremental) and only do the work that's needed to actually run and test your +code. The packaging stuff that is part of the `images` target is not needed for +a normal developer who wants to test his new code. Even if it's quite fast, +it's still unnecessary. We're targeting sub-second incremental rebuilds! ;-) +(Or, well, at least single-digit seconds...) + +**Q:** I usually set a specific environment variable when building, but I can't +find the equivalent in the new build. What should I do? +**A:** It might very well be that we have neglected to add support for an +option that was actually used from outside the build system. Email us and we +will add support for it! + + +### Build Performance Tips + +Building OpenJDK requires a lot of horsepower. Some of the build tools can be +adjusted to utilize more or less of resources such as parallel threads and +memory. The `configure` script analyzes your system and selects reasonable +values for such options based on your hardware. If you encounter resource +problems, such as out of memory conditions, you can modify the detected values +with: + + * **`--with-num-cores`** -- number of cores in the build system, e.g. + `--with-num-cores=8` + * **`--with-memory-size`** -- memory (in MB) available in the build system, + e.g. `--with-memory-size=1024` + +It might also be necessary to specify the JVM arguments passed to the Bootstrap +JDK, using e.g. `--with-boot-jdk-jvmargs="-Xmx8G -enableassertions"`. Doing +this will override the default JVM arguments passed to the Bootstrap JDK. + +One of the top goals of the new build system is to improve the build +performance and decrease the time needed to build. This will soon also apply to +the java compilation when the Smart Javac wrapper is fully supported. + +At the end of a successful execution of `configure`, you will get a performance +summary, indicating how well the build will perform. Here you will also get +performance hints. If you want to build fast, pay attention to those! + +#### Building with ccache + +The OpenJDK build supports building with ccache when using gcc or clang. Using +ccache can radically speed up compilation of native code if you often rebuild +the same sources. Your milage may vary however so we recommend evaluating it +for yourself. To enable it, make sure it's on the path and configure with +`--enable-ccache`. + +#### Building on local disk + +If you are using network shares, e.g. via NFS, for your source code, make sure +the build directory is situated on local disk. The performance penalty is +extremely high for building on a network share, close to unusable. + +#### Building only one JVM + +The old build builds multiple JVMs on 32-bit systems (client and server; and on +Windows kernel as well). In the new build we have changed this default to only +build server when it's available. This improves build times for those not +interested in multiple JVMs. To mimic the old behavior on platforms that +support it, use `--with-jvm-variants=client,server`. + +#### Selecting the number of cores to build on + +By default, `configure` will analyze your machine and run the make process in +parallel with as many threads as you have cores. This behavior can be +overridden, either "permanently" (on a `configure` basis) using +`--with-num-cores=N` or for a single build only (on a make basis), using +`make JOBS=N`. + +If you want to make a slower build just this time, to save some CPU power for +other processes, you can run e.g. `make JOBS=2`. This will force the makefiles +to only run 2 parallel processes, or even `make JOBS=1` which will disable +parallelism. + +If you want to have it the other way round, namely having slow builds default +and override with fast if you're impatient, you should call `configure` with +`--with-num-cores=2`, making 2 the default. If you want to run with more cores, +run `make JOBS=8` + + +### Troubleshooting + +#### Solving build problems + +If the build fails (and it's not due to a compilation error in a source file +you've changed), the first thing you should do is to re-run the build with more +verbosity. Do this by adding `LOG=debug` to your make command line. + +The build log (with both stdout and stderr intermingled, basically the same as +you see on your console) can be found as `build.log` in your build directory. + +You can ask for help on build problems with the new build system on either the +[build-dev](http://mail.openjdk.java.net/mailman/listinfo/build-dev) or the +[build-infra-dev](http://mail.openjdk.java.net/mailman/listinfo/build-infra-dev) +mailing lists. Please include the relevant parts of the build log. + +A build can fail for any number of reasons. Most failures are a result of +trying to build in an environment in which all the pre-build requirements have +not been met. The first step in troubleshooting a build failure is to recheck +that you have satisfied all the pre-build requirements for your platform. +Scanning the `configure` log is a good first step, making sure that what it +found makes sense for your system. Look for strange error messages or any +difficulties that `configure` had in finding things. + +Some of the more common problems with builds are briefly described below, with +suggestions for remedies. + + * **Corrupted Bundles on Windows:** + Some virus scanning software has been known to corrupt the downloading of + zip bundles. It may be necessary to disable the 'on access' or 'real time' + virus scanning features to prevent this corruption. This type of 'real time' + virus scanning can also slow down the build process significantly. + Temporarily disabling the feature, or excluding the build output directory + may be necessary to get correct and faster builds. + + * **Slow Builds:** + If your build machine seems to be overloaded from too many simultaneous C++ + compiles, try setting the `JOBS=1` on the `make` command line. Then try + increasing the count slowly to an acceptable level for your system. Also: + + Creating the javadocs can be very slow, if you are running javadoc, consider + skipping that step. + + Faster CPUs, more RAM, and a faster DISK usually helps. The VM build tends + to be CPU intensive (many C++ compiles), and the rest of the JDK will often + be disk intensive. + + Faster compiles are possible using a tool called + [ccache](http://ccache.samba.org/). + + * **File time issues:** + If you see warnings that refer to file time stamps, e.g. + + > _Warning message:_ ` File 'xxx' has modification time in the future.` + > _Warning message:_ ` Clock skew detected. Your build may be incomplete.` + + These warnings can occur when the clock on the build machine is out of sync + with the timestamps on the source files. Other errors, apparently unrelated + but in fact caused by the clock skew, can occur along with the clock skew + warnings. These secondary errors may tend to obscure the fact that the true + root cause of the problem is an out-of-sync clock. + + If you see these warnings, reset the clock on the build machine, run + "`gmake clobber`" or delete the directory containing the build output, and + restart the build from the beginning. + + * **Error message: `Trouble writing out table to disk`** + Increase the amount of swap space on your build machine. This could be + caused by overloading the system and it may be necessary to use: + + > `make JOBS=1` + + to reduce the load on the system. + + * **Error Message: `libstdc++ not found`:** + This is caused by a missing libstdc++.a library. This is installed as part + of a specific package (e.g. libstdc++.so.devel.386). By default some 64-bit + Linux versions (e.g. Fedora) only install the 64-bit version of the + libstdc++ package. Various parts of the JDK build require a static link of + the C++ runtime libraries to allow for maximum portability of the built + images. + + * **Linux Error Message: `cannot restore segment prot after reloc`** + This is probably an issue with SELinux (See [SELinux on + Wikipedia](http://en.wikipedia.org/wiki/SELinux)). Parts of the VM is built + without the `-fPIC` for performance reasons. + + To completely disable SELinux: + + 1. `$ su root` + 2. `# system-config-securitylevel` + 3. `In the window that appears, select the SELinux tab` + 4. `Disable SELinux` + + Alternatively, instead of completely disabling it you could disable just + this one check. + + 1. Select System->Administration->SELinux Management + 2. In the SELinux Management Tool which appears, select "Boolean" from the + menu on the left + 3. Expand the "Memory Protection" group + 4. Check the first item, labeled "Allow all unconfined executables to use + libraries requiring text relocation ..." + + * **Windows Error Messages:** + `*** fatal error - couldn't allocate heap, ... ` + `rm fails with "Directory not empty"` + `unzip fails with "cannot create ... Permission denied"` + `unzip fails with "cannot create ... Error 50"` + + The CYGWIN software can conflict with other non-CYGWIN software. See the + CYGWIN FAQ section on [BLODA (applications that interfere with + CYGWIN)](http://cygwin.com/faq/faq.using.html#faq.using.bloda). + + * **Windows Error Message: `spawn failed`** + Try rebooting the system, or there could be some kind of issue with the disk + or disk partition being used. Sometimes it comes with a "Permission Denied" + message. + +***** + + +## Appendix B: GNU make + +The Makefiles in the OpenJDK are only valid when used with the GNU version of +the utility command `make` (usually called `gmake` on Solaris). A few notes +about using GNU make: + + * You need GNU make version 3.81 or newer. On Windows 4.0 or newer is + recommended. If the GNU make utility on your systems is not of a suitable + version, see "[Building GNU make](#buildgmake)". + * Place the location of the GNU make binary in the `PATH`. + * **Solaris:** Do NOT use `/usr/bin/make` on Solaris. If your Solaris system + has the software from the Solaris Developer Companion CD installed, you + should try and use `gmake` which will be located in either the `/usr/bin`, + `/opt/sfw/bin` or `/usr/sfw/bin` directory. + * **Windows:** Make sure you start your build inside a bash shell. + * **Mac OS X:** The XCode "command line tools" must be installed on your Mac. + +Information on GNU make, and access to ftp download sites, are available on the +[GNU make web site ](http://www.gnu.org/software/make/make.html). The latest +source to GNU make is available at +[ftp.gnu.org/pub/gnu/make/](http://ftp.gnu.org/pub/gnu/make/). + + +### Building GNU make + +First step is to get the GNU make 3.81 or newer source from +[ftp.gnu.org/pub/gnu/make/](http://ftp.gnu.org/pub/gnu/make/). Building is a +little different depending on the OS but is basically done with: + + bash ./configure + make + +***** + + +## Appendix C: Build Environments + +### Minimum Build Environments + +This file often describes specific requirements for what we call the "minimum +build environments" (MBE) for this specific release of the JDK. What is listed +below is what the Oracle Release Engineering Team will use to build the Oracle +JDK product. Building with the MBE will hopefully generate the most compatible +bits that install on, and run correctly on, the most variations of the same +base OS and hardware architecture. In some cases, these represent what is often +called the least common denominator, but each Operating System has different +aspects to it. + +In all cases, the Bootstrap JDK version minimum is critical, we cannot +guarantee builds will work with older Bootstrap JDK's. Also in all cases, more +RAM and more processors is better, the minimums listed below are simply +recommendations. + +With Solaris and Mac OS X, the version listed below is the oldest release we +can guarantee builds and works, and the specific version of the compilers used +could be critical. + +With Windows the critical aspect is the Visual Studio compiler used, which due +to it's runtime, generally dictates what Windows systems can do the builds and +where the resulting bits can be used. + +**NOTE: We expect a change here off these older Windows OS releases and to a +'less older' one, probably Windows 2008R2 X64.** + +With Linux, it was just a matter of picking a stable distribution that is a +good representative for Linux in general. + +**NOTE: We expect a change here from Fedora 9 to something else, but it has not +been completely determined yet, possibly Ubuntu 12.04 X64, unbiased community +feedback would be welcome on what a good choice would be here.** + +It is understood that most developers will NOT be using these specific +versions, and in fact creating these specific versions may be difficult due to +the age of some of this software. It is expected that developers are more often +using the more recent releases and distributions of these operating systems. + +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 older, +newer, or unreleased OS versions. Please report these types of problems as bugs +so that they can be dealt with accordingly. + +> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Base OS and ArchitectureOSC/C++ CompilerBootstrap JDKProcessorsRAM MinimumDISK Needs
Linux X86 (32-bit) and X64 (64-bit)Oracle Enterprise Linux 6.4gcc 4.8.2 JDK 82 or more1 GB6 GB
Solaris SPARCV9 (64-bit)Solaris 10 Update 10Studio 12 Update 3 + patchesJDK 84 or more4 GB8 GB
Solaris X64 (64-bit)Solaris 10 Update 10Studio 12 Update 3 + patchesJDK 84 or more4 GB8 GB
Windows X86 (32-bit)Windows Server 2012 R2 x64Microsoft Visual Studio C++ 2013 Professional EditionJDK 82 or more2 GB6 GB
Windows X64 (64-bit)Windows Server 2012 R2 x64Microsoft Visual Studio C++ 2013 Professional EditionJDK 82 or more2 GB6 GB
Mac OS X X64 (64-bit)Mac OS X 10.9 "Mavericks"XCode 5.1.1 or newerJDK 82 or more4 GB6 GB
+ +***** + + +### Specific Developer Build Environments + +We won't be listing all the possible environments, but we will try to provide +what information we have available to us. + +**NOTE: The community can help out by updating this part of the document.** + +#### Fedora + +After installing the latest [Fedora](http://fedoraproject.org) 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.7.0-openjdk + yum install gcc gcc-c++ + +In addition, it's necessary to set a few environment variables for the build: + + export LANG=C + export PATH="/usr/lib/jvm/java-openjdk/bin:${PATH}" + +#### CentOS 5.5 + +After installing [CentOS 5.5](http://www.centos.org/) you need to make sure you +have the following Development bundles installed: + + * Development Libraries + * Development Tools + * Java Development + * X Software Development (Including XFree86-devel) + +Plus the following packages: + + * cups devel: Cups Development Package + * alsa devel: Alsa Development Package + * Xi devel: libXi.so Development Package + +The freetype 2.3 packages don't seem to be available, but the freetype 2.3 +sources can be downloaded, built, and installed easily enough from [the +freetype site](http://downloads.sourceforge.net/freetype). Build and install +with something like: + + bash ./configure + make + sudo -u root make install + +Mercurial packages could not be found easily, but a Google search should find +ones, and they usually include Python if it's needed. + +#### Debian 5.0 (Lenny) + +After installing [Debian](http://debian.org) 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-7 + aptitude install openjdk-7-jdk libmotif-dev + +In addition, it's necessary to set a few environment variables for the build: + + export LANG=C + export PATH="/usr/lib/jvm/java-7-openjdk/bin:${PATH}" + +#### Ubuntu 12.04 + +After installing [Ubuntu](http://ubuntu.org) 12.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-7 + sudo aptitude install openjdk-7-jdk + +In addition, it's necessary to set a few environment variables for the build: + + export LANG=C + export PATH="/usr/lib/jvm/java-7-openjdk/bin:${PATH}" + +#### OpenSUSE 11.1 + +After installing [OpenSUSE](http://opensuse.org) 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_7_0-openjdk + sudo zypper install make + +In addition, it is necessary to set a few environment variables for the build: + + export LANG=C + export PATH="/usr/lib/jvm/java-1.7.0-openjdk/bin:$[PATH}" + +Finally, you need to unset the `JAVA_HOME` environment variable: + + export -n JAVA_HOME` + +#### Mandriva Linux One 2009 Spring + +After installing [Mandriva](http://mandriva.org) 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.7.0-openjdk-devel 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: + + export LANG=C + export PATH="/usr/lib/jvm/java-1.7.0-openjdk/bin:${PATH}" + +#### OpenSolaris 2009.06 + +After installing [OpenSolaris](http://opensolaris.org) 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 SUNWj7dev sunstudioexpress SUNWcups SUNWzip + SUNWunzip SUNWxwhl SUNWxorg-headers SUNWaudh SUNWfreetype2 + +In addition, it is necessary to set a few environment variables for the build: + + export LANG=C + export PATH="/opt/SunStudioExpress/bin:${PATH}" + +***** + +End of the OpenJDK build README document. + +Please come again! diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index a5d5797f584..fa15ac3bf9f 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -410,6 +410,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_FUNDAMENTAL_TOOLS], BASIC_REQUIRE_PROGS(NAWK, [nawk gawk awk]) BASIC_REQUIRE_PROGS(PRINTF, printf) BASIC_REQUIRE_PROGS(RM, rm) + BASIC_REQUIRE_PROGS(RMDIR, rmdir) BASIC_REQUIRE_PROGS(SH, sh) BASIC_REQUIRE_PROGS(SORT, sort) BASIC_REQUIRE_PROGS(TAIL, tail) diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4 index 35f5d63d39b..524103eb013 100644 --- a/common/autoconf/boot-jdk.m4 +++ b/common/autoconf/boot-jdk.m4 @@ -305,6 +305,16 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK], BOOT_JDK_SOURCETARGET="-source 8 -target 8" AC_SUBST(BOOT_JDK_SOURCETARGET) AC_SUBST(JAVAC_FLAGS) + + # Check if the boot jdk is 32 or 64 bit + if "$JAVA" -d64 -version > /dev/null 2>&1; then + BOOT_JDK_BITS="64" + else + BOOT_JDK_BITS="32" + fi + AC_MSG_CHECKING([if Boot JDK is 32 or 64 bits]) + AC_MSG_RESULT([$BOOT_JDK_BITS]) + AC_SUBST(BOOT_JDK_BITS) ]) AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], @@ -341,7 +351,7 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], # Maximum amount of heap memory. # Maximum stack size. JVM_MAX_HEAP=`expr $MEMORY_SIZE / 2` - if test "x$BUILD_NUM_BITS" = x32; then + if test "x$BOOT_JDK_BITS" = "x32"; then if test "$JVM_MAX_HEAP" -gt "1100"; then JVM_MAX_HEAP=1100 elif test "$JVM_MAX_HEAP" -lt "512"; then @@ -349,10 +359,7 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], fi STACK_SIZE=768 else - # Running Javac on a JVM on a 64-bit machine, takes more space since 64-bit - # pointers are used. Apparently, we need to increase the heap and stack - # space for the jvm. More specifically, when running javac to build huge - # jdk batch + # Running a 64 bit JVM allows for and requires a bigger heap if test "$JVM_MAX_HEAP" -gt "1600"; then JVM_MAX_HEAP=1600 elif test "$JVM_MAX_HEAP" -lt "512"; then diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4 index b5911b789a7..e2fa4f566cf 100644 --- a/common/autoconf/build-performance.m4 +++ b/common/autoconf/build-performance.m4 @@ -328,12 +328,23 @@ AC_DEFUN_ONCE([BPERF_SETUP_SMART_JAVAC], AC_ARG_ENABLE([sjavac], [AS_HELP_STRING([--enable-sjavac], [use sjavac to do fast incremental compiles @<:@disabled@:>@])], - [ENABLE_SJAVAC="${enableval}"], [ENABLE_SJAVAC='no']) + [ENABLE_SJAVAC="${enableval}"], [ENABLE_SJAVAC="no"]) if test "x$JVM_ARG_OK" = "xfalse"; then AC_MSG_WARN([Could not set -Xms${MS_VALUE}M -Xmx${MX_VALUE}M, disabling sjavac]) - ENABLE_SJAVAC=no; + ENABLE_SJAVAC="no" fi AC_MSG_CHECKING([whether to use sjavac]) AC_MSG_RESULT([$ENABLE_SJAVAC]) AC_SUBST(ENABLE_SJAVAC) + + AC_ARG_ENABLE([javac-server], [AS_HELP_STRING([--enable-javac-server], + [use only the server part of sjavac for faster javac compiles @<:@disabled@:>@])], + [ENABLE_JAVAC_SERVER="${enableval}"], [ENABLE_JAVAC_SERVER="no"]) + if test "x$JVM_ARG_OK" = "xfalse"; then + AC_MSG_WARN([Could not set -Xms${MS_VALUE}M -Xmx${MX_VALUE}M, disabling javac server]) + ENABLE_JAVAC_SERVER="no" + fi + AC_MSG_CHECKING([whether to use javac server]) + AC_MSG_RESULT([$ENABLE_JAVAC_SERVER]) + AC_SUBST(ENABLE_JAVAC_SERVER) ]) diff --git a/common/autoconf/compare.sh.in b/common/autoconf/compare.sh.in index 3e426776535..b7bf2b4cecb 100644 --- a/common/autoconf/compare.sh.in +++ b/common/autoconf/compare.sh.in @@ -66,7 +66,7 @@ export STRIP="@STRIP@ @STRIPFLAGS@" export TEE="@TEE@" export UNIQ="@UNIQ@" export UNPACK200="@FIXPATH@ @BOOT_JDK@/bin/unpack200" -export UNZIP="@UNZIP@" +export UNARCHIVE="@UNZIP@ -q" export SRC_ROOT="@TOPDIR@" export OUTPUT_ROOT="@OUTPUT_ROOT@" diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index ac326867966..47d1b441dff 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -632,6 +632,7 @@ LIBOBJS CFLAGS_CCACHE CCACHE USE_PRECOMPILED_HEADER +ENABLE_JAVAC_SERVER ENABLE_SJAVAC SJAVAC_SERVER_JAVA_FLAGS SJAVAC_SERVER_JAVA @@ -815,6 +816,7 @@ JAXWS_TOPDIR JAXP_TOPDIR CORBA_TOPDIR LANGTOOLS_TOPDIR +BOOT_JDK_BITS JAVAC_FLAGS BOOT_JDK_SOURCETARGET JARSIGNER @@ -968,6 +970,7 @@ TAR TAIL SORT SH +RMDIR RM PRINTF NAWK @@ -1115,6 +1118,7 @@ with_jobs with_boot_jdk_jvmargs with_sjavac_server_java enable_sjavac +enable_javac_server enable_precompiled_headers enable_ccache with_ccache_dir @@ -1146,6 +1150,7 @@ MV NAWK PRINTF RM +RMDIR SH SORT TAIL @@ -1864,6 +1869,8 @@ Optional Features: --with-freetype, disabled otherwise] --enable-sjavac use sjavac to do fast incremental compiles [disabled] + --enable-javac-server use only the server part of sjavac for faster javac + compiles [disabled] --disable-precompiled-headers disable using precompiled headers when compiling C++ [enabled] @@ -2025,6 +2032,7 @@ Some influential environment variables: NAWK Override default value for NAWK PRINTF Override default value for PRINTF RM Override default value for RM + RMDIR Override default value for RMDIR SH Override default value for SH SORT Override default value for SORT TAIL Override default value for TAIL @@ -4587,7 +4595,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1444643341 +DATE_WHEN_GENERATED=1445964676 ############################################################################### # @@ -9511,6 +9519,209 @@ $as_echo "$tool_specified" >&6; } + # Publish this variable in the help. + + + if [ -z "${RMDIR+x}" ]; then + # The variable is not set by user, try to locate tool using the code snippet + for ac_prog in rmdir +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_RMDIR+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $RMDIR in + [\\/]* | ?:[\\/]*) + ac_cv_path_RMDIR="$RMDIR" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_RMDIR="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +RMDIR=$ac_cv_path_RMDIR +if test -n "$RMDIR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RMDIR" >&5 +$as_echo "$RMDIR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$RMDIR" && break +done + + else + # The variable is set, but is it from the command line or the environment? + + # Try to remove the string !RMDIR! from our list. + try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!RMDIR!/} + if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then + # If it failed, the variable was not from the command line. Ignore it, + # but warn the user (except for BASH, which is always set by the calling BASH). + if test "xRMDIR" != xBASH; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of RMDIR from the environment. Use command line variables instead." >&5 +$as_echo "$as_me: WARNING: Ignoring value of RMDIR from the environment. Use command line variables instead." >&2;} + fi + # Try to locate tool using the code snippet + for ac_prog in rmdir +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_RMDIR+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $RMDIR in + [\\/]* | ?:[\\/]*) + ac_cv_path_RMDIR="$RMDIR" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_RMDIR="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +RMDIR=$ac_cv_path_RMDIR +if test -n "$RMDIR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RMDIR" >&5 +$as_echo "$RMDIR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$RMDIR" && break +done + + else + # If it succeeded, then it was overridden by the user. We will use it + # for the tool. + + # First remove it from the list of overridden variables, so we can test + # for unknown variables in the end. + CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var" + + # Check if we try to supply an empty value + if test "x$RMDIR" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool RMDIR= (no value)" >&5 +$as_echo "$as_me: Setting user supplied tool RMDIR= (no value)" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RMDIR" >&5 +$as_echo_n "checking for RMDIR... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 +$as_echo "disabled" >&6; } + else + # Check if the provided tool contains a complete path. + tool_specified="$RMDIR" + tool_basename="${tool_specified##*/}" + if test "x$tool_basename" = "x$tool_specified"; then + # A command without a complete path is provided, search $PATH. + { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool RMDIR=$tool_basename" >&5 +$as_echo "$as_me: Will search for user supplied tool RMDIR=$tool_basename" >&6;} + # Extract the first word of "$tool_basename", so it can be a program name with args. +set dummy $tool_basename; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_RMDIR+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $RMDIR in + [\\/]* | ?:[\\/]*) + ac_cv_path_RMDIR="$RMDIR" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_RMDIR="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +RMDIR=$ac_cv_path_RMDIR +if test -n "$RMDIR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RMDIR" >&5 +$as_echo "$RMDIR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$RMDIR" = x; then + as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5 + fi + else + # Otherwise we believe it is a complete path. Use it as it is. + { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool RMDIR=$tool_specified" >&5 +$as_echo "$as_me: Will use user supplied tool RMDIR=$tool_specified" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RMDIR" >&5 +$as_echo_n "checking for RMDIR... " >&6; } + if test ! -x "$tool_specified"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + as_fn_error $? "User supplied tool RMDIR=$tool_specified does not exist or is not executable" "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5 +$as_echo "$tool_specified" >&6; } + fi + fi + fi + fi + + + + if test "x$RMDIR" = x; then + as_fn_error $? "Could not find required tool for RMDIR" "$LINENO" 5 + fi + + + + + # Publish this variable in the help. @@ -26920,6 +27131,18 @@ $as_echo "$tool_specified" >&6; } + # Check if the boot jdk is 32 or 64 bit + if "$JAVA" -d64 -version > /dev/null 2>&1; then + BOOT_JDK_BITS="64" + else + BOOT_JDK_BITS="32" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Boot JDK is 32 or 64 bits" >&5 +$as_echo_n "checking if Boot JDK is 32 or 64 bits... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BOOT_JDK_BITS" >&5 +$as_echo "$BOOT_JDK_BITS" >&6; } + + ############################################################################### # @@ -53099,7 +53322,7 @@ $as_echo_n "checking flags for boot jdk java command for big workloads... " >&6; # Maximum amount of heap memory. # Maximum stack size. JVM_MAX_HEAP=`expr $MEMORY_SIZE / 2` - if test "x$BUILD_NUM_BITS" = x32; then + if test "x$BOOT_JDK_BITS" = "x32"; then if test "$JVM_MAX_HEAP" -gt "1100"; then JVM_MAX_HEAP=1100 elif test "$JVM_MAX_HEAP" -lt "512"; then @@ -53107,10 +53330,7 @@ $as_echo_n "checking flags for boot jdk java command for big workloads... " >&6; fi STACK_SIZE=768 else - # Running Javac on a JVM on a 64-bit machine, takes more space since 64-bit - # pointers are used. Apparently, we need to increase the heap and stack - # space for the jvm. More specifically, when running javac to build huge - # jdk batch + # Running a 64 bit JVM allows for and requires a bigger heap if test "$JVM_MAX_HEAP" -gt "1600"; then JVM_MAX_HEAP=1600 elif test "$JVM_MAX_HEAP" -lt "512"; then @@ -53299,13 +53519,13 @@ fi if test "${enable_sjavac+set}" = set; then : enableval=$enable_sjavac; ENABLE_SJAVAC="${enableval}" else - ENABLE_SJAVAC='no' + ENABLE_SJAVAC="no" fi if test "x$JVM_ARG_OK" = "xfalse"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not set -Xms${MS_VALUE}M -Xmx${MX_VALUE}M, disabling sjavac" >&5 $as_echo "$as_me: WARNING: Could not set -Xms${MS_VALUE}M -Xmx${MX_VALUE}M, disabling sjavac" >&2;} - ENABLE_SJAVAC=no; + ENABLE_SJAVAC="no" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use sjavac" >&5 $as_echo_n "checking whether to use sjavac... " >&6; } @@ -53313,6 +53533,24 @@ $as_echo_n "checking whether to use sjavac... " >&6; } $as_echo "$ENABLE_SJAVAC" >&6; } + # Check whether --enable-javac-server was given. +if test "${enable_javac_server+set}" = set; then : + enableval=$enable_javac_server; ENABLE_JAVAC_SERVER="${enableval}" +else + ENABLE_JAVAC_SERVER="no" +fi + + if test "x$JVM_ARG_OK" = "xfalse"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not set -Xms${MS_VALUE}M -Xmx${MX_VALUE}M, disabling javac server" >&5 +$as_echo "$as_me: WARNING: Could not set -Xms${MS_VALUE}M -Xmx${MX_VALUE}M, disabling javac server" >&2;} + ENABLE_JAVAC_SERVER="no" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use javac server" >&5 +$as_echo_n "checking whether to use javac server... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENABLE_JAVAC_SERVER" >&5 +$as_echo "$ENABLE_JAVAC_SERVER" >&6; } + + # Can the C/C++ compiler use precompiled headers? diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 4b6983a54a3..8731756c772 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -245,6 +245,7 @@ MEMORY_SIZE:=@MEMORY_SIZE@ # Enable sjavac support = use a javac server, # multi core javac compilation and dependency tracking. ENABLE_SJAVAC:=@ENABLE_SJAVAC@ +ENABLE_JAVAC_SERVER:=@ENABLE_JAVAC_SERVER@ # Store sjavac server synchronization files here, and # the sjavac server log files. SJAVAC_SERVER_DIR=$(MAKESUPPORT_OUTPUTDIR)/javacservers @@ -504,6 +505,7 @@ PATCH:=@PATCH@ PRINTF:=@PRINTF@ PWD:=@THEPWDCMD@ RM:=@RM@ +RMDIR:=@RMDIR@ SED:=@SED@ SH:=@SH@ SORT:=@SORT@ diff --git a/common/bin/compare.sh b/common/bin/compare.sh index 77d51c41df0..7952b2b6abb 100644 --- a/common/bin/compare.sh +++ b/common/bin/compare.sh @@ -51,8 +51,6 @@ else STAT_PRINT_SIZE="-c %s" fi -UNARCHIVE="$UNZIP -q" - COMPARE_EXCEPTIONS_INCLUDE="$SRC_ROOT/common/bin/compare_exceptions.sh.incl" if [ ! -e "$COMPARE_EXCEPTIONS_INCLUDE" ]; then echo "Error: Cannot locate the exceptions file, it should have been here: $COMPARE_EXCEPTIONS_INCLUDE" diff --git a/common/bin/update-build-readme.sh b/common/bin/update-build-readme.sh new file mode 100644 index 00000000000..9d1968a4c60 --- /dev/null +++ b/common/bin/update-build-readme.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# Get an absolute path to this script, since that determines the top-level +# directory. +this_script_dir=`dirname $0` +TOPDIR=`cd $this_script_dir/../.. > /dev/null && pwd` + +GREP=grep +MD_FILE=$TOPDIR/README-builds.md +HTML_FILE=$TOPDIR/README-builds.html + +# Locate the markdown processor tool and check that it is the correct version. +locate_markdown_processor() { + if [ -z "$MARKDOWN" ]; then + MARKDOWN=`which markdown 2> /dev/null` + if [ -z "$MARKDOWN" ]; then + echo "Error: Cannot locate markdown processor" 1>&2 + exit 1 + fi + fi + + # Test version + MARKDOWN_VERSION=`$MARKDOWN -version | $GREP version` + if [ "x$MARKDOWN_VERSION" != "xThis is Markdown, version 1.0.1." ]; then + echo "Error: Expected markdown version 1.0.1." 1>&2 + echo "Actual version found: $MARKDOWN_VERSION" 1>&2 + echo "Download markdown here: https://daringfireball.net/projects/markdown/" 1>&2 + exit 1 + fi + +} + +# Verify that the source markdown file looks sound. +verify_source_code() { + TOO_LONG_LINES=`$GREP -E -e '^.{80}.+$' $MD_FILE` + if [ "x$TOO_LONG_LINES" != x ]; then + echo "Warning: The following lines are longer than 80 characters:" + $GREP -E -e '^.{80}.+$' $MD_FILE + fi +} + +# Convert the markdown file to html format. +process_source() { + echo "Generating html file from markdown" + cat > $HTML_FILE << END + + + OpenJDK Build README + + +END + markdown $MD_FILE >> $HTML_FILE + cat >> $HTML_FILE < + +END + echo "Done" +} + +locate_markdown_processor +verify_source_code +process_source diff --git a/corba/.hgtags b/corba/.hgtags index 05ed676d17e..18dffcd5e71 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -330,3 +330,4 @@ df70bb200356fec686681f0295c50cc3ed43c3b3 jdk9-b84 3ec06af1368924469f7ce60a00324bac55eaeecc jdk9-b85 0a3f0d25c201b40575a7c3920fce4d6f4d3ae310 jdk9-b86 a5c40ac9b916ff44d512ee764fa919ed2097e149 jdk9-b87 +00f48ecbc09915f793d9e5ad74ab0b25f2549bf5 jdk9-b88 diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java index 0c3ff08a7ad..c9d6320f65a 100644 --- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java +++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java @@ -567,6 +567,11 @@ public class IIOPInputStream // XXX I18N, logging needed. throw new NotActiveException("defaultReadObjectDelegate"); + if (!currentClassDesc.forClass().isAssignableFrom( + currentObject.getClass())) { + throw new IOException("Object Type mismatch"); + } + // The array will be null unless fields were retrieved // remotely because of a serializable version difference. // Bug fix for 4365188. See the definition of @@ -1063,6 +1068,9 @@ public class IIOPInputStream int spBase = spClass; // current top of stack + if (currentClass.getName().equals("java.lang.String")) { + return this.readUTF(); + } /* The object's classes should be processed from supertype to subtype * Push all the clases of the current object onto a stack. * Note that only the serializable classes are represented @@ -2257,6 +2265,27 @@ public class IIOPInputStream try { Class fieldCl = fields[i].getClazz(); + if ((objectValue != null) + && (!fieldCl.isAssignableFrom( + objectValue.getClass()))) { + throw new IllegalArgumentException("Field mismatch"); + } + Field classField = null; + try { + classField = cl.getDeclaredField(fields[i].getName()); + } catch (NoSuchFieldException nsfEx) { + throw new IllegalArgumentException(nsfEx); + } catch (SecurityException secEx) { + throw new IllegalArgumentException(secEx.getCause()); + } + Class declaredFieldClass = classField.getType(); + + // check input field type is a declared field type + // input field is a subclass of the declared field + if (!declaredFieldClass.isAssignableFrom(fieldCl)) { + throw new IllegalArgumentException( + "Field Type mismatch"); + } if (objectValue != null && !fieldCl.isInstance(objectValue)) { throw new IllegalArgumentException(); } diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/IIOPOutputStream.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/IIOPOutputStream.java index 1ca9e118cfd..a8fcb186c8b 100644 --- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/IIOPOutputStream.java +++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/IIOPOutputStream.java @@ -559,6 +559,10 @@ public class IIOPOutputStream * Push all the clases of the current object onto a stack. * Remember the stack pointer where this set of classes is being pushed. */ + if (currentClassDesc.forClass().getName().equals("java.lang.String")) { + this.writeUTF((String)obj); + return; + } int stackMark = classDescStack.size(); try { ObjectStreamClass next; diff --git a/corba/src/jdk.rmic/share/classes/sun/rmi/rmic/iiop/StubGenerator.java b/corba/src/jdk.rmic/share/classes/sun/rmi/rmic/iiop/StubGenerator.java index 0d41c1edb90..bceb86cf774 100644 --- a/corba/src/jdk.rmic/share/classes/sun/rmi/rmic/iiop/StubGenerator.java +++ b/corba/src/jdk.rmic/share/classes/sun/rmi/rmic/iiop/StubGenerator.java @@ -446,6 +446,9 @@ public class StubGenerator extends sun.rmi.rmic.iiop.Generator { if (emitPermissionCheck) { // produce the following generated code for example + // + // private transient boolean _instantiated = false; + // // private static Void checkPermission() { // SecurityManager sm = System.getSecurityManager(); // if (sm != null) { @@ -460,11 +463,21 @@ public class StubGenerator extends sun.rmi.rmic.iiop.Generator { // // public _XXXXX_Stub() { // this(checkPermission()); + // _instantiated = true; + // } + // + // private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { + // checkPermission(); + // s.defaultReadObject(); + // _instantiated = true; // } // // where XXXXX is the name of the remote interface p.pln(); + p.plnI("private transient boolean _instantiated = false;"); + p.pln(); + p.pO(); p.plnI("private static Void checkPermission() {"); p.plnI("SecurityManager sm = System.getSecurityManager();"); p.pln("if (sm != null) {"); @@ -481,13 +494,23 @@ public class StubGenerator extends sun.rmi.rmic.iiop.Generator { p.pO(); p.pI(); - p.pln("private " + currentClass + "(Void ignore) { }"); + p.plnI("private " + currentClass + "(Void ignore) { }"); p.pln(); + p.pO(); p.plnI("public " + currentClass + "() { "); p.pln("this(checkPermission());"); + p.pln("_instantiated = true;"); p.pOln("}"); p.pln(); + p.plnI("private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {"); + p.plnI("checkPermission();"); + p.pO(); + p.pln("s.defaultReadObject();"); + p.pln("_instantiated = true;"); + p.pOln("}"); + p.pln(); + //p.pO(); } if (!emitPermissionCheck) { @@ -894,6 +917,7 @@ public class StubGenerator extends sun.rmi.rmic.iiop.Generator { String paramNames[] = method.getArgumentNames(); Type returnType = method.getReturnType(); ValueType[] exceptions = getStubExceptions(method,false); + boolean hasIOException = false; addNamesInUse(method); addNameInUse("_type_ids"); @@ -921,6 +945,13 @@ public class StubGenerator extends sun.rmi.rmic.iiop.Generator { p.plnI(" {"); // Now create the method body... + if (emitPermissionCheck) { + p.pln("if ((System.getSecurityManager() != null) && (!_instantiated)) {"); + p.plnI(" throw new java.io.IOError(new java.io.IOException(\"InvalidObject \"));"); + p.pOln("}"); + p.pln(); + } + if (localStubs) { writeLocalStubMethodBody(p,method,theType); diff --git a/hotspot/.hgtags b/hotspot/.hgtags index e1a9f80ec13..57ffaf65cc0 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -490,3 +490,4 @@ e9e63d93bbfe2c6c23447e2c1f5cc71c98671cba jdk9-b79 03845376ea9dbf9690b6a9cfb4ed63f8cc0541c0 jdk9-b85 1ae4191359d811a51512f17dca80ffe79837a5ff jdk9-b86 d7ffd16382fe7071181b967932b47cff6d1312e1 jdk9-b87 +bc48b669bc6610fac97e16593050c0f559cf6945 jdk9-b88 diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java index c8b771d8aaf..ca0b982a48a 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java @@ -67,9 +67,6 @@ public class ImmutableOopMapSet extends VMObject { } } - public void visitValueLocation(Address valueAddr) { - } - public void visitNarrowOopLocation(Address narrowOopAddr) { addressVisitor.visitCompOopAddress(narrowOopAddr); } @@ -216,9 +213,9 @@ public class ImmutableOopMapSet extends VMObject { } } - // We want narow oop, value and oop oop_types - OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[]{ - OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.VALUE_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE + // We want narow oop and oop oop_types + OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] { + OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE }; { @@ -231,8 +228,6 @@ public class ImmutableOopMapSet extends VMObject { // to detect in the debugging system // assert(Universe::is_heap_or_null(*loc), "found non oop pointer"); visitor.visitOopLocation(loc); - } else if (omv.getType() == OopMapValue.OopTypes.VALUE_VALUE) { - visitor.visitValueLocation(loc); } else if (omv.getType() == OopMapValue.OopTypes.NARROWOOP_VALUE) { visitor.visitNarrowOopLocation(loc); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java index 2fa04b9741f..3d6e125ff45 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java @@ -49,7 +49,6 @@ public class OopMapValue { // Types of OopValues static int UNUSED_VALUE; static int OOP_VALUE; - static int VALUE_VALUE; static int NARROWOOP_VALUE; static int CALLEE_SAVED_VALUE; static int DERIVED_OOP_VALUE; @@ -73,7 +72,6 @@ public class OopMapValue { REGISTER_MASK_IN_PLACE = db.lookupIntConstant("OopMapValue::register_mask_in_place").intValue(); UNUSED_VALUE = db.lookupIntConstant("OopMapValue::unused_value").intValue(); OOP_VALUE = db.lookupIntConstant("OopMapValue::oop_value").intValue(); - VALUE_VALUE = db.lookupIntConstant("OopMapValue::value_value").intValue(); NARROWOOP_VALUE = db.lookupIntConstant("OopMapValue::narrowoop_value").intValue(); CALLEE_SAVED_VALUE = db.lookupIntConstant("OopMapValue::callee_saved_value").intValue(); DERIVED_OOP_VALUE = db.lookupIntConstant("OopMapValue::derived_oop_value").intValue(); @@ -82,7 +80,6 @@ public class OopMapValue { public static abstract class OopTypes { public static final OopTypes UNUSED_VALUE = new OopTypes() { int getValue() { return OopMapValue.UNUSED_VALUE; }}; public static final OopTypes OOP_VALUE = new OopTypes() { int getValue() { return OopMapValue.OOP_VALUE; }}; - public static final OopTypes VALUE_VALUE = new OopTypes() { int getValue() { return OopMapValue.VALUE_VALUE; }}; public static final OopTypes NARROWOOP_VALUE = new OopTypes() { int getValue() { return OopMapValue.NARROWOOP_VALUE; }}; public static final OopTypes CALLEE_SAVED_VALUE = new OopTypes() { int getValue() { return OopMapValue.CALLEE_SAVED_VALUE; }}; public static final OopTypes DERIVED_OOP_VALUE = new OopTypes() { int getValue() { return OopMapValue.DERIVED_OOP_VALUE; }}; @@ -105,7 +102,6 @@ public class OopMapValue { // Querying public boolean isOop() { return (getValue() & TYPE_MASK_IN_PLACE) == OOP_VALUE; } - public boolean isValue() { return (getValue() & TYPE_MASK_IN_PLACE) == VALUE_VALUE; } public boolean isNarrowOop() { return (getValue() & TYPE_MASK_IN_PLACE) == NARROWOOP_VALUE; } public boolean isCalleeSaved() { return (getValue() & TYPE_MASK_IN_PLACE) == CALLEE_SAVED_VALUE; } public boolean isDerivedOop() { return (getValue() & TYPE_MASK_IN_PLACE) == DERIVED_OOP_VALUE; } @@ -117,7 +113,6 @@ public class OopMapValue { int which = (getValue() & TYPE_MASK_IN_PLACE); if (which == UNUSED_VALUE) return OopTypes.UNUSED_VALUE; else if (which == OOP_VALUE) return OopTypes.OOP_VALUE; - else if (which == VALUE_VALUE) return OopTypes.VALUE_VALUE; else if (which == NARROWOOP_VALUE) return OopTypes.NARROWOOP_VALUE; else if (which == CALLEE_SAVED_VALUE) return OopTypes.CALLEE_SAVED_VALUE; else if (which == DERIVED_OOP_VALUE) return OopTypes.DERIVED_OOP_VALUE; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java index 6153fba3d25..3170b24837e 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java @@ -31,6 +31,5 @@ import sun.jvm.hotspot.debugger.*; public interface OopMapVisitor { public void visitOopLocation(Address oopAddr); public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr); - public void visitValueLocation(Address valueAddr); public void visitNarrowOopLocation(Address narrowOopAddr); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java index 2bde98074ff..75e4372b0e5 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,21 +52,19 @@ public class Method extends Metadata { } private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("Method"); + type = db.lookupType("Method"); constMethod = type.getAddressField("_constMethod"); methodData = type.getAddressField("_method_data"); methodCounters = type.getAddressField("_method_counters"); - methodSize = new CIntField(type.getCIntegerField("_method_size"), 0); accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); code = type.getAddressField("_code"); vtableIndex = new CIntField(type.getCIntegerField("_vtable_index"), 0); - bytecodeOffset = type.getSize(); /* - interpreterEntry = type.getAddressField("_interpreter_entry"); fromCompiledCodeEntryPoint = type.getAddressField("_from_compiled_code_entry_point"); - + interpreterEntry = type.getAddressField("_from_interpreted_entry"); */ + objectInitializerName = null; classInitializerName = null; } @@ -77,16 +75,22 @@ public class Method extends Metadata { public boolean isMethod() { return true; } + // Not a Method field, used to keep type. + private static Type type; + // Fields private static AddressField constMethod; private static AddressField methodData; private static AddressField methodCounters; - private static CIntField methodSize; private static CIntField accessFlags; private static CIntField vtableIndex; - private static long bytecodeOffset; private static AddressField code; + /* + private static AddressCField fromCompiledCodeEntryPoint; + private static AddressField interpreterEntry; + */ + // constant method names - , // Initialized lazily to avoid initialization ordering dependencies between Method and SymbolTable @@ -106,11 +110,6 @@ public class Method extends Metadata { } - /* - private static AddressCField interpreterEntry; - private static AddressCField fromCompiledCodeEntryPoint; - */ - // Accessors for declared fields public ConstMethod getConstMethod() { Address addr = constMethod.getValue(getAddress()); @@ -128,7 +127,6 @@ public class Method extends Metadata { return (MethodCounters) VMObjectFactory.newObject(MethodCounters.class, addr); } /** WARNING: this is in words, not useful in this system; use getObjectSize() instead */ - public long getMethodSize() { return methodSize.getValue(this); } public long getMaxStack() { return getConstMethod().getMaxStack(); } public long getMaxLocals() { return getConstMethod().getMaxLocals(); } public long getSizeOfParameters() { return getConstMethod().getSizeOfParameters(); } @@ -265,7 +263,7 @@ public class Method extends Metadata { } public long getSize() { - return getMethodSize(); + return type.getSize() + (isNative() ? 2: 0); } public void printValueOn(PrintStream tty) { @@ -273,7 +271,6 @@ public class Method extends Metadata { } public void iterateFields(MetadataVisitor visitor) { - visitor.doCInt(methodSize, true); visitor.doCInt(accessFlags, true); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java index b1ee998dcd2..ab536d20f5d 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java @@ -536,9 +536,6 @@ public abstract class Frame implements Cloneable { } } - public void visitValueLocation(Address valueAddr) { - } - public void visitNarrowOopLocation(Address compOopAddr) { addressVisitor.visitCompOopAddress(compOopAddr); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java index 9f4c2d2e3b8..342a96d6e36 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java @@ -1220,9 +1220,6 @@ public class HTMLGenerator implements /* imports */ ClassConstants { oms = new OopMapStream(map, OopMapValue.OopTypes.NARROWOOP_VALUE); buf.append(omvIterator.iterate(oms, "NarrowOops:", false)); - oms = new OopMapStream(map, OopMapValue.OopTypes.VALUE_VALUE); - buf.append(omvIterator.iterate(oms, "Values:", false)); - oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); buf.append(omvIterator.iterate(oms, "Callee saved:", true)); diff --git a/hotspot/make/bsd/makefiles/compiler1.make b/hotspot/make/bsd/makefiles/compiler1.make index 0057814a087..d303bfc1ca4 100644 --- a/hotspot/make/bsd/makefiles/compiler1.make +++ b/hotspot/make/bsd/makefiles/compiler1.make @@ -28,4 +28,7 @@ TYPE=COMPILER1 VM_SUBDIR = client +# We don't support the JVMCI in a client VM. +INCLUDE_JVMCI := false + CFLAGS += -DCOMPILER1 diff --git a/hotspot/make/bsd/makefiles/gcc.make b/hotspot/make/bsd/makefiles/gcc.make index 6844d6169ae..21876523ee1 100644 --- a/hotspot/make/bsd/makefiles/gcc.make +++ b/hotspot/make/bsd/makefiles/gcc.make @@ -149,6 +149,7 @@ ifeq ($(USE_CLANG), true) PCH_FLAG/sharedRuntimeTrig.o = $(PCH_FLAG/NO_PCH) PCH_FLAG/sharedRuntimeTrans.o = $(PCH_FLAG/NO_PCH) PCH_FLAG/unsafe.o = $(PCH_FLAG/NO_PCH) + PCH_FLAG/jvmciCompilerToVM.o = $(PCH_FLAG/NO_PCH) endif else # ($(USE_CLANG), true) @@ -313,10 +314,11 @@ endif # Work around some compiler bugs. ifeq ($(USE_CLANG), true) - # Clang <= 6.1 + # Clang < 6 | <= 6.1 | <= 7.0 ifeq ($(shell expr \ $(CC_VER_MAJOR) \< 6 \| \ - \( $(CC_VER_MAJOR) = 6 \& $(CC_VER_MINOR) \<= 1 \) \ + \( $(CC_VER_MAJOR) = 6 \& $(CC_VER_MINOR) \<= 1 \) \| \ + \( $(CC_VER_MAJOR) = 7 \& $(CC_VER_MINOR) \<= 0 \) \ ), 1) OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) OPT_CFLAGS/unsafe.o += -O1 diff --git a/hotspot/make/bsd/makefiles/jsig.make b/hotspot/make/bsd/makefiles/jsig.make index 8c0c1b8a5e5..6a9cebbb337 100644 --- a/hotspot/make/bsd/makefiles/jsig.make +++ b/hotspot/make/bsd/makefiles/jsig.make @@ -62,7 +62,7 @@ endif $(LIBJSIG): $(JSIGSRCDIR)/jsig.c $(LIBJSIG_MAPFILE) @echo $(LOG_INFO) Making signal interposition lib... $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ - $(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) -o $@ $< + $(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) $(EXTRA_CFLAGS) -o $@ $< ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) ifeq ($(OS_VENDOR), Darwin) $(DSYMUTIL) $@ diff --git a/hotspot/make/bsd/makefiles/minimal1.make b/hotspot/make/bsd/makefiles/minimal1.make index 03845fd12b7..d453e789877 100644 --- a/hotspot/make/bsd/makefiles/minimal1.make +++ b/hotspot/make/bsd/makefiles/minimal1.make @@ -38,6 +38,7 @@ INCLUDE_ALL_GCS := false INCLUDE_NMT := false INCLUDE_TRACE := false INCLUDE_CDS := false +INCLUDE_JVMCI := false CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" CFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" diff --git a/hotspot/make/excludeSrc.make b/hotspot/make/excludeSrc.make index 0bc759f25b7..dac7372c6fc 100644 --- a/hotspot/make/excludeSrc.make +++ b/hotspot/make/excludeSrc.make @@ -106,6 +106,25 @@ ifeq ($(INCLUDE_NMT), false) memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp endif +ifneq (,$(findstring $(Platform_arch_model), x86_64, sparc)) + # JVMCI is supported only on x86_64 and SPARC. +else + INCLUDE_JVMCI := false +endif + +ifeq ($(INCLUDE_JVMCI), false) + CXXFLAGS += -DINCLUDE_JVMCI=0 + CFLAGS += -DINCLUDE_JVMCI=0 + + jvmci_dir := $(HS_COMMON_SRC)/share/vm/jvmci + jvmci_dir_alt := $(HS_ALT_SRC)/share/vm/jvmci + jvmci_exclude := $(notdir $(wildcard $(jvmci_dir)/*.cpp)) \ + $(notdir $(wildcard $(jvmci_dir_alt)/*.cpp)) + Src_Files_EXCLUDE += $(jvmci_exclude) \ + jvmciCodeInstaller_aarch64.cpp jvmciCodeInstaller_ppc.cpp jvmciCodeInstaller_sparc.cpp \ + jvmciCodeInstaller_x86.cpp +endif + -include $(HS_ALT_MAKE)/excludeSrc.make .PHONY: $(HS_ALT_MAKE)/excludeSrc.make diff --git a/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk b/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk new file mode 100644 index 00000000000..15c55012cc8 --- /dev/null +++ b/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk @@ -0,0 +1,122 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# 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. +# + +default: all + +include $(SPEC) +include MakeBase.gmk +include JavaCompilation.gmk +include SetupJavaCompilers.gmk + +GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.vm.ci +SRC_DIR := $(HOTSPOT_TOPDIR)/src/jdk.vm.ci/share/classes + +################################################################################ +# Compile the annotation processor + +$(eval $(call SetupJavaCompilation, BUILD_JVMCI_OPTIONS, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := $(SRC_DIR)/jdk.vm.ci.options/src \ + $(SRC_DIR)/jdk.vm.ci.options.processor/src \ + $(SRC_DIR)/jdk.vm.ci.inittimer/src, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jvmci_options, \ + JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.options.jar, \ +)) + +$(eval $(call SetupJavaCompilation, BUILD_JVMCI_SERVICE, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := $(SRC_DIR)/jdk.vm.ci.service/src \ + $(SRC_DIR)/jdk.vm.ci.service.processor/src, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jvmci_service, \ + JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.service.jar, \ +)) + +################################################################################ + +PROC_SRC_SUBDIRS := \ + jdk.vm.ci.compiler \ + jdk.vm.ci.hotspot \ + jdk.vm.ci.hotspot.amd64 \ + jdk.vm.ci.hotspot.sparc \ + # + +PROC_SRC_DIRS := $(patsubst %, $(SRC_DIR)/%/src, $(PROC_SRC_SUBDIRS)) + +PROC_SRCS := $(filter %.java, $(call CacheFind, $(PROC_SRC_DIRS))) + +ALL_SRC_DIRS := $(wildcard $(SRC_DIR)/*/src) +SOURCEPATH := $(call PathList, $(ALL_SRC_DIRS)) +PROCESSOR_PATH := $(call PathList, \ + $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.options.jar \ + $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.service.jar) + +$(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) \ + $(BUILD_JVMCI_OPTIONS) $(BUILD_JVMCI_SERVICE) + $(MKDIR) -p $(@D) + $(eval $(call ListPathsSafely,PROC_SRCS,$(@D)/_gensrc_proc_files)) + $(JAVA_SMALL) $(NEW_JAVAC) \ + -XDignore.symbol.file \ + -sourcepath $(SOURCEPATH) \ + -implicit:none \ + -proc:only \ + -processorpath $(PROCESSOR_PATH) \ + -d $(GENSRC_DIR) \ + -s $(GENSRC_DIR) \ + @$(@D)/_gensrc_proc_files + $(TOUCH) $@ + +TARGETS += $(GENSRC_DIR)/_gensrc_proc_done + +################################################################################ + +$(GENSRC_DIR)/META-INF/services/jdk.vm.ci.options.OptionDescriptors: \ + $(GENSRC_DIR)/_gensrc_proc_done + $(MKDIR) -p $(@D) + ($(CD) $(GENSRC_DIR)/META-INF/jvmci.options && \ + $(RM) -f $@; \ + for i in $$(ls); do \ + echo $${i}_OptionDescriptors >> $@; \ + done) + +TARGETS += $(GENSRC_DIR)/META-INF/services/jdk.vm.ci.options.OptionDescriptors + +################################################################################ + +$(GENSRC_DIR)/_providers_converted: $(GENSRC_DIR)/_gensrc_proc_done + $(MKDIR) -p $(GENSRC_DIR)/META-INF/services + ($(CD) $(GENSRC_DIR)/META-INF/jvmci.providers && \ + for i in $$($(LS)); do \ + c=$$($(CAT) $$i | $(TR) -d '\n\r'); \ + $(ECHO) $$i >> $(GENSRC_DIR)/META-INF/services/$$c; \ + done) + $(TOUCH) $@ + +TARGETS += $(GENSRC_DIR)/_providers_converted + +################################################################################ + +all: $(TARGETS) + +.PHONY: default all diff --git a/hotspot/make/linux/makefiles/compiler1.make b/hotspot/make/linux/makefiles/compiler1.make index 0057814a087..d303bfc1ca4 100644 --- a/hotspot/make/linux/makefiles/compiler1.make +++ b/hotspot/make/linux/makefiles/compiler1.make @@ -28,4 +28,7 @@ TYPE=COMPILER1 VM_SUBDIR = client +# We don't support the JVMCI in a client VM. +INCLUDE_JVMCI := false + CFLAGS += -DCOMPILER1 diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index 85aa5c33ded..b69a8b6a1e7 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -213,12 +213,16 @@ ifeq ($(USE_CLANG),) # Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit # conversions which might affect the values. Only enable it in earlier versions. ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" + # GCC < 4.3 WARNING_FLAGS += -Wconversion endif ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 8 \) \))" "1" + # GCC >= 4.8 # This flag is only known since GCC 4.3. Gcc 4.8 contains a fix so that with templates no # warnings are issued: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11856 WARNING_FLAGS += -Wtype-limits + # GCC < 4.8 don't accept this flag for C++. + WARNING_FLAGS += -Wno-format-zero-length endif endif diff --git a/hotspot/make/linux/makefiles/minimal1.make b/hotspot/make/linux/makefiles/minimal1.make index 03845fd12b7..d453e789877 100644 --- a/hotspot/make/linux/makefiles/minimal1.make +++ b/hotspot/make/linux/makefiles/minimal1.make @@ -38,6 +38,7 @@ INCLUDE_ALL_GCS := false INCLUDE_NMT := false INCLUDE_TRACE := false INCLUDE_CDS := false +INCLUDE_JVMCI := false CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" CFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" diff --git a/hotspot/make/solaris/makefiles/compiler1.make b/hotspot/make/solaris/makefiles/compiler1.make index 0057814a087..d303bfc1ca4 100644 --- a/hotspot/make/solaris/makefiles/compiler1.make +++ b/hotspot/make/solaris/makefiles/compiler1.make @@ -28,4 +28,7 @@ TYPE=COMPILER1 VM_SUBDIR = client +# We don't support the JVMCI in a client VM. +INCLUDE_JVMCI := false + CFLAGS += -DCOMPILER1 diff --git a/hotspot/make/windows/build_vm_def.sh b/hotspot/make/windows/build_vm_def.sh index 3d905198cb6..05298eaa3f3 100644 --- a/hotspot/make/windows/build_vm_def.sh +++ b/hotspot/make/windows/build_vm_def.sh @@ -52,6 +52,7 @@ UNIQ="$MKS_HOME/uniq.exe" CAT="$MKS_HOME/cat.exe" RM="$MKS_HOME/rm.exe" DUMPBIN="link.exe /dump" +export VS_UNICODE_OUTPUT= if [ "$1" = "-nosa" ]; then echo EXPORTS > vm.def diff --git a/hotspot/make/windows/create_obj_files.sh b/hotspot/make/windows/create_obj_files.sh index e99ca829e6d..1bdf4d8c7a0 100644 --- a/hotspot/make/windows/create_obj_files.sh +++ b/hotspot/make/windows/create_obj_files.sh @@ -111,6 +111,7 @@ esac COMPILER2_SPECIFIC_FILES="opto libadt bcEscapeAnalyzer.cpp c2_* runtime_*" COMPILER1_SPECIFIC_FILES="c1_*" +JVMCI_SPECIFIC_FILES="*jvmci* *JVMCI*" SHARK_SPECIFIC_FILES="shark" ZERO_SPECIFIC_FILES="zero" @@ -119,11 +120,11 @@ Src_Files_EXCLUDE="jsig.c jvmtiEnvRecommended.cpp jvmtiEnvStub.cpp" # Exclude per type. case "${TYPE}" in - "compiler1") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; + "compiler1") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; "compiler2") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;; "tiered") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;; - "zero") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; - "shark") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES}" ;; + "zero") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; + "shark") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES}" ;; esac # Special handling of arch model. diff --git a/hotspot/make/windows/makefiles/compile.make b/hotspot/make/windows/makefiles/compile.make index 0ca02a18a96..aa1063d6eb1 100644 --- a/hotspot/make/windows/makefiles/compile.make +++ b/hotspot/make/windows/makefiles/compile.make @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ CXX=cl.exe # /nologo Supress copyright message at every cl.exe startup # /W3 Warning level 3 # /Zi Include debugging information +# /d2Zi+ Extended debugging symbols for optimized code (/Zo in VS2013 Update 3 and later) # /WX Treat any warning error as a fatal error # /MD Use dynamic multi-threaded runtime (msvcrt.dll or msvc*NN.dll) # /MTd Use static multi-threaded runtime debug versions @@ -57,7 +58,7 @@ CXX_FLAGS=$(EXTRA_CFLAGS) /nologo /W3 /WX # Let's add debug information when Full Debug Symbols is enabled !if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1" -CXX_FLAGS=$(CXX_FLAGS) /Zi +CXX_FLAGS=$(CXX_FLAGS) /Zi /d2Zi+ !endif # Based on BUILDARCH we add some flags and select the default compiler name diff --git a/hotspot/make/windows/makefiles/projectcreator.make b/hotspot/make/windows/makefiles/projectcreator.make index 6947402a0a9..180851d835e 100644 --- a/hotspot/make/windows/makefiles/projectcreator.make +++ b/hotspot/make/windows/makefiles/projectcreator.make @@ -145,6 +145,10 @@ ProjectCreatorIDEOptionsIgnoreCompiler1=\ -ignorePath_TARGET tiered \ -ignorePath_TARGET c1_ +ProjectCreatorIDEOptionsIgnoreJVMCI=\ + -ignorePath_TARGET src/share/vm/jvmci \ + -ignorePath_TARGET vm/jvmci + ProjectCreatorIDEOptionsIgnoreCompiler2=\ -ignorePath_TARGET compiler2 \ -ignorePath_TARGET tiered \ @@ -165,6 +169,8 @@ ProjectCreatorIDEOptionsIgnoreCompiler2=\ ################################################## ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ -define_compiler1 COMPILER1 \ + -define_compiler1 INCLUDE_JVMCI=0 \ +$(ProjectCreatorIDEOptionsIgnoreJVMCI:TARGET=compiler1) \ $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=compiler1) ################################################## diff --git a/hotspot/make/windows/makefiles/vm.make b/hotspot/make/windows/makefiles/vm.make index 65fbf2a0ae7..9381c5b097d 100644 --- a/hotspot/make/windows/makefiles/vm.make +++ b/hotspot/make/windows/makefiles/vm.make @@ -40,7 +40,7 @@ CXX_FLAGS=$(CXX_FLAGS) /homeparams !endif !if "$(Variant)" == "compiler1" -CXX_FLAGS=$(CXX_FLAGS) /D "COMPILER1" +CXX_FLAGS=$(CXX_FLAGS) /D "COMPILER1" /D INCLUDE_JVMCI=0 !endif !if "$(Variant)" == "compiler2" @@ -152,6 +152,7 @@ VM_PATH=$(VM_PATH);../generated/adfiles VM_PATH=$(VM_PATH);../generated/jvmtifiles VM_PATH=$(VM_PATH);../generated/tracefiles VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/c1 +VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/jvmci VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/compiler VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/code VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/interpreter @@ -163,6 +164,7 @@ VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/gc/serial VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/gc/cms VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/gc/g1 VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/asm +VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/logging VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/memory VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/oops VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/prims @@ -232,6 +234,9 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi {$(COMMONSRC)\share\vm\classfile}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{$(COMMONSRC)\share\vm\jvmci}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + {$(COMMONSRC)\share\vm\gc\parallel}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< @@ -250,6 +255,9 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi {$(COMMONSRC)\share\vm\asm}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{$(COMMONSRC)\share\vm\logging}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + {$(COMMONSRC)\share\vm\memory}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< @@ -330,6 +338,9 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi {$(ALTSRC)\share\vm\asm}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{$(ALTSRC)\share\vm\logging}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + {$(ALTSRC)\share\vm\memory}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index eb42df45806..dabc578fe08 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -1039,6 +1039,7 @@ class HandlerImpl { bool leading_membar(const MemBarNode *barrier); bool is_card_mark_membar(const MemBarNode *barrier); + bool is_CAS(int opcode); MemBarNode *leading_to_normal(MemBarNode *leading); MemBarNode *normal_to_leading(const MemBarNode *barrier); @@ -1057,6 +1058,9 @@ class HandlerImpl { bool unnecessary_volatile(const Node *barrier); bool needs_releasing_store(const Node *store); + // predicate controlling translation of CompareAndSwapX + bool needs_acquiring_load_exclusive(const Node *load); + // predicate controlling translation of StoreCM bool unnecessary_storestore(const Node *storecm); %} @@ -1088,15 +1092,58 @@ source %{ // str // dmb ish // + // We can also use ldaxr and stlxr to implement compare and swap CAS + // sequences. These are normally translated to an instruction + // sequence like the following + // + // dmb ish + // retry: + // ldxr rval raddr + // cmp rval rold + // b.ne done + // stlxr rval, rnew, rold + // cbnz rval retry + // done: + // cset r0, eq + // dmb ishld + // + // Note that the exclusive store is already using an stlxr + // instruction. That is required to ensure visibility to other + // threads of the exclusive write (assuming it succeeds) before that + // of any subsequent writes. + // + // The following instruction sequence is an improvement on the above + // + // retry: + // ldaxr rval raddr + // cmp rval rold + // b.ne done + // stlxr rval, rnew, rold + // cbnz rval retry + // done: + // cset r0, eq + // + // We don't need the leading dmb ish since the stlxr guarantees + // visibility of prior writes in the case that the swap is + // successful. Crucially we don't have to worry about the case where + // the swap is not successful since no valid program should be + // relying on visibility of prior changes by the attempting thread + // in the case where the CAS fails. + // + // Similarly, we don't need the trailing dmb ishld if we substitute + // an ldaxr instruction since that will provide all the guarantees we + // require regarding observation of changes made by other threads + // before any change to the CAS address observed by the load. + // // In order to generate the desired instruction sequence we need to // be able to identify specific 'signature' ideal graph node // sequences which i) occur as a translation of a volatile reads or - // writes and ii) do not occur through any other translation or - // graph transformation. We can then provide alternative aldc - // matching rules which translate these node sequences to the - // desired machine code sequences. Selection of the alternative - // rules can be implemented by predicates which identify the - // relevant node sequences. + // writes or CAS operations and ii) do not occur through any other + // translation or graph transformation. We can then provide + // alternative aldc matching rules which translate these node + // sequences to the desired machine code sequences. Selection of the + // alternative rules can be implemented by predicates which identify + // the relevant node sequences. // // The ideal graph generator translates a volatile read to the node // sequence @@ -1163,6 +1210,15 @@ source %{ // get if it is fed and feeds a cpuorder membar and if its feed // membar also feeds an acquiring load. // + // Finally an inlined (Unsafe) CAS operation is translated to the + // following ideal graph + // + // MemBarRelease + // MemBarCPUOrder + // CompareAndSwapX {CardMark}-optional + // MemBarCPUOrder + // MemBarAcquire + // // So, where we can identify these volatile read and write // signatures we can choose to plant either of the above two code // sequences. For a volatile read we can simply plant a normal @@ -1177,6 +1233,14 @@ source %{ // and MemBarVolatile and instead plant a simple stlr // instruction. // + // when we recognise a CAS signature we can choose to plant a dmb + // ish as a translation for the MemBarRelease, the conventional + // macro-instruction sequence for the CompareAndSwap node (which + // uses ldxr) and then a dmb ishld for the MemBarAcquire. + // Alternatively, we can elide generation of the dmb instructions + // and plant the alternative CompareAndSwap macro-instruction + // sequence (which uses ldaxr). + // // Of course, the above only applies when we see these signature // configurations. We still want to plant dmb instructions in any // other cases where we may see a MemBarAcquire, MemBarRelease or @@ -1194,7 +1258,8 @@ source %{ // relevant dmb instructions. // - // graph traversal helpers used for volatile put/get optimization + // graph traversal helpers used for volatile put/get and CAS + // optimization // 1) general purpose helpers @@ -1220,16 +1285,19 @@ source %{ return NULL; } - if (!ctl || !mem || !ctl->is_Proj() || !mem->is_Proj()) + if (!ctl || !mem || !ctl->is_Proj() || !mem->is_Proj()) { return NULL; + } membar = ctl->lookup(0); - if (!membar || !membar->is_MemBar()) + if (!membar || !membar->is_MemBar()) { return NULL; + } - if (mem->lookup(0) != membar) + if (mem->lookup(0) != membar) { return NULL; + } return membar->as_MemBar(); } @@ -1259,8 +1327,9 @@ source %{ } } - if (child == NULL) + if (child == NULL) { return NULL; + } for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { x = mem->fast_out(i); @@ -1283,15 +1352,18 @@ source %{ { int opcode = barrier->Opcode(); // if this is a release membar we are ok - if (opcode == Op_MemBarRelease) + if (opcode == Op_MemBarRelease) { return true; + } // if its a cpuorder membar . . . - if (opcode != Op_MemBarCPUOrder) + if (opcode != Op_MemBarCPUOrder) { return false; + } // then the parent has to be a release membar MemBarNode *parent = parent_membar(barrier); - if (!parent) + if (!parent) { return false; + } opcode = parent->Opcode(); return opcode == Op_MemBarRelease; } @@ -1314,11 +1386,13 @@ source %{ bool is_card_mark_membar(const MemBarNode *barrier) { - if (!UseG1GC && !(UseConcMarkSweepGC && UseCondCardMark)) + if (!UseG1GC && !(UseConcMarkSweepGC && UseCondCardMark)) { return false; + } - if (barrier->Opcode() != Op_MemBarVolatile) + if (barrier->Opcode() != Op_MemBarVolatile) { return false; + } ProjNode *mem = barrier->proj_out(TypeFunc::Memory); @@ -1333,8 +1407,8 @@ source %{ } - // 3) helper predicates to traverse volatile put graphs which may - // contain GC barrier subgraphs + // 3) helper predicates to traverse volatile put or CAS graphs which + // may contain GC barrier subgraphs // Preamble // -------- @@ -1404,8 +1478,7 @@ source %{ // currently being unmarked in which case the volatile put graph // will look slightly different // - // MemBarRelease - // MemBarCPUOrder___________________________________________ + // MemBarRelease____________________________________________ // || \\ Ctl \ Ctl \ \\ Mem \ // || StoreN/P[mo_release] CastP2X If LoadB | // | \ / \ | @@ -1419,7 +1492,7 @@ source %{ // memory flow includes the following subgraph: // // MemBarRelease - // MemBarCPUOrder + // {MemBarCPUOrder} // | \ . . . // | StoreX[mo_release] . . . // | / @@ -1431,8 +1504,48 @@ source %{ // detected starting from any candidate MemBarRelease, // StoreX[mo_release] or MemBarVolatile. // + // A simple variation on this normal case occurs for an unsafe CAS + // operation. The basic graph for a non-object CAS is + // + // MemBarRelease + // || + // MemBarCPUOrder + // || \\ . . . + // || CompareAndSwapX + // || | + // || SCMemProj + // | \ / + // | MergeMem + // | / + // MemBarCPUOrder + // || + // MemBarAcquire + // + // The same basic variations on this arrangement (mutatis mutandis) + // occur when a card mark is introduced. i.e. we se the same basic + // shape but the StoreP/N is replaced with CompareAndSawpP/N and the + // tail of the graph is a pair comprising a MemBarCPUOrder + + // MemBarAcquire. + // + // So, in the case of a CAS the normal graph has the variant form + // + // MemBarRelease + // MemBarCPUOrder + // | \ . . . + // | CompareAndSwapX . . . + // | | + // | SCMemProj + // | / . . . + // MergeMem + // | + // MemBarCPUOrder + // MemBarAcquire + // + // This graph can also easily be detected starting from any + // candidate MemBarRelease, CompareAndSwapX or MemBarAcquire. + // // the code below uses two helper predicates, leading_to_normal and - // normal_to_leading to identify this configuration, one validating + // normal_to_leading to identify these normal graphs, one validating // the layout starting from the top membar and searching down and // the other validating the layout starting from the lower membar // and searching up. @@ -1450,7 +1563,9 @@ source %{ // they are only inserted for object puts. This significantly // complicates the task of identifying whether a MemBarRelease, // StoreX[mo_release] or MemBarVolatile forms part of a volatile put - // when using these GC configurations (see below). + // when using these GC configurations (see below). It adds similar + // complexity to the task of identifying whether a MemBarRelease, + // CompareAndSwapX or MemBarAcquire forms part of a CAS. // // In both cases the post-write subtree includes an auxiliary // MemBarVolatile (StoreLoad barrier) separating the object put and @@ -1489,7 +1604,8 @@ source %{ // (LoadB) from the card. Ctl and Mem are fed to the If via an // intervening StoreLoad barrier (MemBarVolatile). // - // So, with CMS we may see a node graph which looks like this + // So, with CMS we may see a node graph for a volatile object store + // which looks like this // // MemBarRelease // MemBarCPUOrder_(leading)__________________ @@ -1524,6 +1640,55 @@ source %{ // from the StoreCM into the trailing membar (n.b. the latter // proceeds via a Phi associated with the If region). // + // The graph for a CAS varies slightly, the obvious difference being + // that the StoreN/P node is replaced by a CompareAndSwapP/N node + // and the trailing MemBarVolatile by a MemBarCPUOrder + + // MemBarAcquire pair. The other important difference is that the + // CompareAndSwap node's SCMemProj is not merged into the card mark + // membar - it still feeds the trailing MergeMem. This also means + // that the card mark membar receives its Mem feed directly from the + // leading membar rather than via a MergeMem. + // + // MemBarRelease + // MemBarCPUOrder__(leading)_________________________ + // || \\ C \ + // MemBarVolatile (card mark) CompareAndSwapN/P CastP2X + // C | || M | | + // | LoadB | ______/| + // | | | / | + // | Cmp | / SCMemProj + // | / | / | + // If | / / + // | \ | / / + // IfFalse IfTrue | / / + // \ / \ |/ prec / + // \ / StoreCM / + // \ / | / + // Region . . . / + // | \ / + // | . . . \ / Bot + // | MergeMem + // | | + // MemBarCPUOrder + // MemBarAcquire (trailing) + // + // This has a slightly different memory subgraph to the one seen + // previously but the core of it is the same as for the CAS normal + // sungraph + // + // MemBarRelease + // MemBarCPUOrder____ + // || \ . . . + // MemBarVolatile CompareAndSwapX . . . + // | \ | + // . . . SCMemProj + // | / . . . + // MergeMem + // | + // MemBarCPUOrder + // MemBarAcquire + // + // // G1 is quite a lot more complicated. The nodes inserted on behalf // of G1 may comprise: a pre-write graph which adds the old value to // the SATB queue; the releasing store itself; and, finally, a @@ -1575,12 +1740,16 @@ source %{ // n.b. the LoadB in this subgraph is not the card read -- it's a // read of the SATB queue active flag. // + // Once again the CAS graph is a minor variant on the above with the + // expected substitutions of CompareAndSawpX for StoreN/P and + // MemBarCPUOrder + MemBarAcquire for trailing MemBarVolatile. + // // The G1 post-write subtree is also optional, this time when the // new value being written is either null or can be identified as a // newly allocated (young gen) object with no intervening control // flow. The latter cannot happen but the former may, in which case - // the card mark membar is omitted and the memory feeds from the - // leading membar and the StoreN/P are merged direct into the + // the card mark membar is omitted and the memory feeds form the + // leading membar and the SToreN/P are merged direct into the // trailing membar as per the normal subgraph. So, the only special // case which arises is when the post-write subgraph is generated. // @@ -1668,47 +1837,84 @@ source %{ // value check has been elided the total number of Phis is 2 // otherwise it is 3. // + // The CAS graph when using G1GC also includes a pre-write subgraph + // and an optional post-write subgraph. Teh sam evarioations are + // introduced as for CMS with conditional card marking i.e. the + // StoreP/N is swapped for a CompareAndSwapP/N, the tariling + // MemBarVolatile for a MemBarCPUOrder + MemBarAcquire pair and the + // Mem feed from the CompareAndSwapP/N includes a precedence + // dependency feed to the StoreCM and a feed via an SCMemProj to the + // trailing membar. So, as before the configuration includes the + // normal CAS graph as a subgraph of the memory flow. + // // So, the upshot is that in all cases the volatile put graph will // include a *normal* memory subgraph betwen the leading membar and - // its child membar. When that child is not a card mark membar then - // it marks the end of a volatile put subgraph. If the child is a - // card mark membar then the normal subgraph will form part of a - // volatile put subgraph if and only if the child feeds an - // AliasIdxBot Mem feed to a trailing barrier via a MergeMem. That - // feed is either direct (for CMS) or via 2 or 3 Phi nodes merging - // the leading barrier memory flow (for G1). + // its child membar, either a volatile put graph (including a + // releasing StoreX) or a CAS graph (including a CompareAndSwapX). + // When that child is not a card mark membar then it marks the end + // of the volatile put or CAS subgraph. If the child is a card mark + // membar then the normal subgraph will form part of a volatile put + // subgraph if and only if the child feeds an AliasIdxBot Mem feed + // to a trailing barrier via a MergeMem. That feed is either direct + // (for CMS) or via 2 or 3 Phi nodes merging the leading barrier + // memory flow (for G1). // // The predicates controlling generation of instructions for store // and barrier nodes employ a few simple helper functions (described - // below) which identify the presence or absence of these subgraph - // configurations and provide a means of traversing from one node in - // the subgraph to another. + // below) which identify the presence or absence of all these + // subgraph configurations and provide a means of traversing from + // one node in the subgraph to another. + + // is_CAS(int opcode) + // + // return true if opcode is one of the possible CompareAndSwapX + // values otherwise false. + + bool is_CAS(int opcode) + { + return (opcode == Op_CompareAndSwapI || + opcode == Op_CompareAndSwapL || + opcode == Op_CompareAndSwapN || + opcode == Op_CompareAndSwapP); + } // leading_to_normal // - //graph traversal helper which detects the normal case Mem feed - // from a release membar (or, optionally, its cpuorder child) to a - // dependent volatile membar i.e. it ensures that the following Mem - // flow subgraph is present. + //graph traversal helper which detects the normal case Mem feed from + // a release membar (or, optionally, its cpuorder child) to a + // dependent volatile membar i.e. it ensures that one or other of + // the following Mem flow subgraph is present. // // MemBarRelease - // MemBarCPUOrder + // MemBarCPUOrder {leading} // | \ . . . // | StoreN/P[mo_release] . . . // | / // MergeMem // | - // MemBarVolatile + // MemBarVolatile {trailing or card mark} // - // if the correct configuration is present returns the volatile + // MemBarRelease + // MemBarCPUOrder {leading} + // | \ . . . + // | CompareAndSwapX . . . + // | + // . . . SCMemProj + // \ | + // | MergeMem + // | / + // MemBarCPUOrder + // MemBarAcquire {trailing} + // + // if the correct configuration is present returns the trailing // membar otherwise NULL. // // the input membar is expected to be either a cpuorder membar or a // release membar. in the latter case it should not have a cpu membar // child. // - // the returned membar may be a card mark membar rather than a - // trailing membar. + // the returned value may be a card mark or trailing membar + // MemBarNode *leading_to_normal(MemBarNode *leading) { @@ -1719,54 +1925,103 @@ source %{ // check the mem flow ProjNode *mem = leading->proj_out(TypeFunc::Memory); - if (!mem) + if (!mem) { return NULL; + } Node *x = NULL; StoreNode * st = NULL; + LoadStoreNode *cas = NULL; MergeMemNode *mm = NULL; for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { x = mem->fast_out(i); if (x->is_MergeMem()) { - if (mm != NULL) + if (mm != NULL) { return NULL; + } // two merge mems is one too many mm = x->as_MergeMem(); } else if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) { - // two releasing stores is one too many - if (st != NULL) + // two releasing stores/CAS nodes is one too many + if (st != NULL || cas != NULL) { return NULL; + } st = x->as_Store(); + } else if (is_CAS(x->Opcode())) { + if (st != NULL || cas != NULL) { + return NULL; + } + cas = x->as_LoadStore(); } } - if (!mm || !st) + // must have a store or a cas + if (!st && !cas) { return NULL; + } - bool found = false; - // ensure the store feeds the merge - for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { - if (st->fast_out(i) == mm) { - found = true; - break; + // must have a merge if we also have st + if (st && !mm) { + return NULL; + } + + Node *y = NULL; + if (cas) { + // look for an SCMemProj + for (DUIterator_Fast imax, i = cas->fast_outs(imax); i < imax; i++) { + x = cas->fast_out(i); + if (x->is_Proj()) { + y = x; + break; + } + } + if (y == NULL) { + return NULL; + } + // the proj must feed a MergeMem + for (DUIterator_Fast imax, i = y->fast_outs(imax); i < imax; i++) { + x = y->fast_out(i); + if (x->is_MergeMem()) { + mm = x->as_MergeMem(); + break; + } + } + if (mm == NULL) + return NULL; + } else { + // ensure the store feeds the existing mergemem; + for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { + if (st->fast_out(i) == mm) { + y = st; + break; + } + } + if (y == NULL) { + return NULL; } } - if (!found) - return NULL; - - MemBarNode *mbvol = NULL; - // ensure the merge feeds a volatile membar + MemBarNode *mbar = NULL; + // ensure the merge feeds to the expected type of membar for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { x = mm->fast_out(i); - if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) { - mbvol = x->as_MemBar(); + if (x->is_MemBar()) { + int opcode = x->Opcode(); + if (opcode == Op_MemBarVolatile && st) { + mbar = x->as_MemBar(); + } else if (cas && opcode == Op_MemBarCPUOrder) { + MemBarNode *y = x->as_MemBar(); + y = child_membar(y); + if (y != NULL && y->Opcode() == Op_MemBarAcquire) { + mbar = y; + } + } break; } } - return mbvol; + return mbar; } // normal_to_leading @@ -1774,7 +2029,7 @@ source %{ // graph traversal helper which detects the normal case Mem feed // from either a card mark or a trailing membar to a preceding // release membar (optionally its cpuorder child) i.e. it ensures - // that the following Mem flow subgraph is present. + // that one or other of the following Mem flow subgraphs is present. // // MemBarRelease // MemBarCPUOrder {leading} @@ -1783,7 +2038,19 @@ source %{ // | / // MergeMem // | - // MemBarVolatile + // MemBarVolatile {card mark or trailing} + // + // MemBarRelease + // MemBarCPUOrder {leading} + // | \ . . . + // | CompareAndSwapX . . . + // | + // . . . SCMemProj + // \ | + // | MergeMem + // | / + // MemBarCPUOrder + // MemBarAcquire {trailing} // // this predicate checks for the same flow as the previous predicate // but starting from the bottom rather than the top. @@ -1797,51 +2064,116 @@ source %{ MemBarNode *normal_to_leading(const MemBarNode *barrier) { // input must be a volatile membar - assert(barrier->Opcode() == Op_MemBarVolatile, "expecting a volatile membar"); + assert((barrier->Opcode() == Op_MemBarVolatile || + barrier->Opcode() == Op_MemBarAcquire), + "expecting a volatile or an acquire membar"); Node *x; + bool is_cas = barrier->Opcode() == Op_MemBarAcquire; + + // if we have an acquire membar then it must be fed via a CPUOrder + // membar + + if (is_cas) { + // skip to parent barrier which must be a cpuorder + x = parent_membar(barrier); + if (x->Opcode() != Op_MemBarCPUOrder) + return NULL; + } else { + // start from the supplied barrier + x = (Node *)barrier; + } // the Mem feed to the membar should be a merge - x = barrier->in(TypeFunc::Memory); + x = x ->in(TypeFunc::Memory); if (!x->is_MergeMem()) return NULL; MergeMemNode *mm = x->as_MergeMem(); - // the AliasIdxBot slice should be another MemBar projection - x = mm->in(Compile::AliasIdxBot); + if (is_cas) { + // the merge should be fed from the CAS via an SCMemProj node + x = NULL; + for (uint idx = 1; idx < mm->req(); idx++) { + if (mm->in(idx)->Opcode() == Op_SCMemProj) { + x = mm->in(idx); + break; + } + } + if (x == NULL) { + return NULL; + } + // check for a CAS feeding this proj + x = x->in(0); + int opcode = x->Opcode(); + if (!is_CAS(opcode)) { + return NULL; + } + // the CAS should get its mem feed from the leading membar + x = x->in(MemNode::Memory); + } else { + // the merge should get its Bottom mem feed from the leading membar + x = mm->in(Compile::AliasIdxBot); + } + // ensure this is a non control projection - if (!x->is_Proj() || x->is_CFG()) + if (!x->is_Proj() || x->is_CFG()) { return NULL; + } // if it is fed by a membar that's the one we want x = x->in(0); - if (!x->is_MemBar()) + if (!x->is_MemBar()) { return NULL; + } MemBarNode *leading = x->as_MemBar(); // reject invalid candidates - if (!leading_membar(leading)) + if (!leading_membar(leading)) { return NULL; + } - // ok, we have a leading ReleaseMembar, now for the sanity clauses + // ok, we have a leading membar, now for the sanity clauses - // the leading membar must feed Mem to a releasing store + // the leading membar must feed Mem to a releasing store or CAS ProjNode *mem = leading->proj_out(TypeFunc::Memory); StoreNode *st = NULL; + LoadStoreNode *cas = NULL; for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { x = mem->fast_out(i); if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) { + // two stores or CASes is one too many + if (st != NULL || cas != NULL) { + return NULL; + } st = x->as_Store(); - break; + } else if (is_CAS(x->Opcode())) { + if (st != NULL || cas != NULL) { + return NULL; + } + cas = x->as_LoadStore(); } } - if (st == NULL) - return NULL; - // the releasing store has to feed the same merge - for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { - if (st->fast_out(i) == mm) - return leading; + // we should not have both a store and a cas + if (st == NULL & cas == NULL) { + return NULL; + } + + if (st == NULL) { + // nothing more to check + return leading; + } else { + // we should not have a store if we started from an acquire + if (is_cas) { + return NULL; + } + + // the store should feed the merge we used to get here + for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { + if (st->fast_out(i) == mm) { + return leading; + } + } } return NULL; @@ -1865,8 +2197,8 @@ source %{ // Bot | / // MergeMem // | - // MemBarVolatile (trailing) - // + // | + // MemBarVolatile {trailing} // // 2) // MemBarRelease/CPUOrder (leading) @@ -1884,7 +2216,8 @@ source %{ // Bot | / // MergeMem // | - // MemBarVolatile (trailing) + // MemBarVolatile {trailing} + // // // 3) // MemBarRelease/CPUOrder (leading) @@ -1905,7 +2238,8 @@ source %{ // Bot | / // MergeMem // | - // MemBarVolatile (trailing) + // | + // MemBarVolatile {trailing} // // configuration 1 is only valid if UseConcMarkSweepGC && // UseCondCardMark @@ -1955,8 +2289,9 @@ source %{ break; } } - if (!phi) + if (!phi) { return NULL; + } // look for another merge below this phi feed = phi; } else { @@ -1969,7 +2304,7 @@ source %{ assert(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge"); MemBarNode *trailing = NULL; - // be sure we have a volatile membar below the merge + // be sure we have a trailing membar the merge for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { x = mm->fast_out(i); if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) { @@ -1984,24 +2319,32 @@ source %{ // trailing_to_card_mark // // graph traversal helper which detects extra, non-normal Mem feed - // from a trailing membar to a preceding card mark volatile membar - // i.e. it identifies whether one of the three possible extra GC - // post-write Mem flow subgraphs is present + // from a trailing volatile membar to a preceding card mark volatile + // membar i.e. it identifies whether one of the three possible extra + // GC post-write Mem flow subgraphs is present // // this predicate checks for the same flow as the previous predicate // but starting from the bottom rather than the top. // - // if the configurationis present returns the card mark membar + // if the configuration is present returns the card mark membar // otherwise NULL + // + // n.b. the supplied membar is expected to be a trailing + // MemBarVolatile i.e. the caller must ensure the input node has the + // correct opcode MemBarNode *trailing_to_card_mark(const MemBarNode *trailing) { - assert(!is_card_mark_membar(trailing), "not expecting a card mark membar"); + assert(trailing->Opcode() == Op_MemBarVolatile, + "expecting a volatile membar"); + assert(!is_card_mark_membar(trailing), + "not expecting a card mark membar"); - Node *x = trailing->in(TypeFunc::Memory); // the Mem feed to the membar should be a merge - if (!x->is_MergeMem()) + Node *x = trailing->in(TypeFunc::Memory); + if (!x->is_MergeMem()) { return NULL; + } MergeMemNode *mm = x->as_MergeMem(); @@ -2054,13 +2397,15 @@ source %{ } // the proj has to come from the card mark membar x = x->in(0); - if (!x->is_MemBar()) + if (!x->is_MemBar()) { return NULL; + } MemBarNode *card_mark_membar = x->as_MemBar(); - if (!is_card_mark_membar(card_mark_membar)) + if (!is_card_mark_membar(card_mark_membar)) { return NULL; + } return card_mark_membar; } @@ -2068,7 +2413,7 @@ source %{ // trailing_to_leading // // graph traversal helper which checks the Mem flow up the graph - // from a (non-card mark) volatile membar attempting to locate and + // from a (non-card mark) trailing membar attempting to locate and // return an associated leading membar. it first looks for a // subgraph in the normal configuration (relying on helper // normal_to_leading). failing that it then looks for one of the @@ -2081,22 +2426,35 @@ source %{ // if the configuration is valid returns the cpuorder member for // preference or when absent the release membar otherwise NULL. // - // n.b. the input membar is expected to be a volatile membar but - // must *not* be a card mark membar. + // n.b. the input membar is expected to be either a volatile or + // acquire membar but in the former case must *not* be a card mark + // membar. MemBarNode *trailing_to_leading(const MemBarNode *trailing) { - assert(!is_card_mark_membar(trailing), "not expecting a card mark membar"); + assert((trailing->Opcode() == Op_MemBarAcquire || + trailing->Opcode() == Op_MemBarVolatile), + "expecting an acquire or volatile membar"); + assert((trailing->Opcode() != Op_MemBarVolatile || + !is_card_mark_membar(trailing)), + "not expecting a card mark membar"); MemBarNode *leading = normal_to_leading(trailing); - if (leading) + if (leading) { return leading; + } + + // nothing more to do if this is an acquire + if (trailing->Opcode() == Op_MemBarAcquire) { + return NULL; + } MemBarNode *card_mark_membar = trailing_to_card_mark(trailing); - if (!card_mark_membar) + if (!card_mark_membar) { return NULL; + } return normal_to_leading(card_mark_membar); } @@ -2105,10 +2463,12 @@ source %{ bool unnecessary_acquire(const Node *barrier) { - // assert barrier->is_MemBar(); - if (UseBarriersForVolatile) + assert(barrier->is_MemBar(), "expecting a membar"); + + if (UseBarriersForVolatile) { // we need to plant a dmb return false; + } // a volatile read derived from bytecode (or also from an inlined // SHA field read via LibraryCallKit::load_field_from_object) @@ -2140,8 +2500,9 @@ bool unnecessary_acquire(const Node *barrier) // // where * tags node we were passed // and |k means input k - if (x->is_DecodeNarrowPtr()) + if (x->is_DecodeNarrowPtr()) { x = x->in(1); + } return (x->is_Load() && x->as_Load()->is_acquire()); } @@ -2167,8 +2528,9 @@ bool unnecessary_acquire(const Node *barrier) return false; ctl = parent->proj_out(TypeFunc::Control); mem = parent->proj_out(TypeFunc::Memory); - if (!ctl || !mem) + if (!ctl || !mem) { return false; + } // ensure the proj nodes both feed a LoadX[mo_acquire] LoadNode *ld = NULL; for (DUIterator_Fast imax, i = ctl->fast_outs(imax); i < imax; i++) { @@ -2180,38 +2542,46 @@ bool unnecessary_acquire(const Node *barrier) } } // it must be an acquiring load - if (! ld || ! ld->is_acquire()) - return false; - for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { - x = mem->fast_out(i); - // if we see the same load we drop it and stop searching - if (x == ld) { - ld = NULL; - break; + if (ld && ld->is_acquire()) { + + for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { + x = mem->fast_out(i); + // if we see the same load we drop it and stop searching + if (x == ld) { + ld = NULL; + break; + } + } + // we must have dropped the load + if (ld == NULL) { + // check for a child cpuorder membar + MemBarNode *child = child_membar(barrier->as_MemBar()); + if (child && child->Opcode() == Op_MemBarCPUOrder) + return true; } } - // we must have dropped the load - if (ld) - return false; - // check for a child cpuorder membar - MemBarNode *child = child_membar(barrier->as_MemBar()); - if (!child || child->Opcode() != Op_MemBarCPUOrder) - return false; - return true; + // final option for unnecessary mebar is that it is a trailing node + // belonging to a CAS + + MemBarNode *leading = trailing_to_leading(barrier->as_MemBar()); + + return leading != NULL; } bool needs_acquiring_load(const Node *n) { - // assert n->is_Load(); - if (UseBarriersForVolatile) + assert(n->is_Load(), "expecting a load"); + if (UseBarriersForVolatile) { // we use a normal load and a dmb return false; + } LoadNode *ld = n->as_Load(); - if (!ld->is_acquire()) + if (!ld->is_acquire()) { return false; + } // check if this load is feeding an acquire membar // @@ -2261,20 +2631,23 @@ bool needs_acquiring_load(const Node *n) membar = parent_membar(ld); - if (!membar || !membar->Opcode() == Op_MemBarCPUOrder) + if (!membar || !membar->Opcode() == Op_MemBarCPUOrder) { return false; + } // ensure that there is a CPUOrder->Acquire->CPUOrder membar chain membar = child_membar(membar); - if (!membar || !membar->Opcode() == Op_MemBarAcquire) + if (!membar || !membar->Opcode() == Op_MemBarAcquire) { return false; + } membar = child_membar(membar); - if (!membar || !membar->Opcode() == Op_MemBarCPUOrder) + if (!membar || !membar->Opcode() == Op_MemBarCPUOrder) { return false; + } return true; } @@ -2285,9 +2658,10 @@ bool unnecessary_release(const Node *n) n->Opcode() == Op_MemBarRelease), "expecting a release membar"); - if (UseBarriersForVolatile) + if (UseBarriersForVolatile) { // we need to plant a dmb return false; + } // if there is a dependent CPUOrder barrier then use that as the // leading @@ -2303,12 +2677,14 @@ bool unnecessary_release(const Node *n) // must start with a normal feed MemBarNode *child_barrier = leading_to_normal(barrier); - if (!child_barrier) + if (!child_barrier) { return false; + } - if (!is_card_mark_membar(child_barrier)) + if (!is_card_mark_membar(child_barrier)) { // this is the trailing membar and we are done return true; + } // must be sure this card mark feeds a trailing membar MemBarNode *trailing = card_mark_to_trailing(child_barrier); @@ -2318,17 +2694,19 @@ bool unnecessary_release(const Node *n) bool unnecessary_volatile(const Node *n) { // assert n->is_MemBar(); - if (UseBarriersForVolatile) + if (UseBarriersForVolatile) { // we need to plant a dmb return false; + } MemBarNode *mbvol = n->as_MemBar(); // first we check if this is part of a card mark. if so then we have // to generate a StoreLoad barrier - if (is_card_mark_membar(mbvol)) + if (is_card_mark_membar(mbvol)) { return false; + } // ok, if it's not a card mark then we still need to check if it is // a trailing membar of a volatile put hgraph. @@ -2341,29 +2719,33 @@ bool unnecessary_volatile(const Node *n) bool needs_releasing_store(const Node *n) { // assert n->is_Store(); - if (UseBarriersForVolatile) + if (UseBarriersForVolatile) { // we use a normal store and dmb combination return false; + } StoreNode *st = n->as_Store(); // the store must be marked as releasing - if (!st->is_release()) + if (!st->is_release()) { return false; + } // the store must be fed by a membar Node *x = st->lookup(StoreNode::Memory); - if (! x || !x->is_Proj()) + if (! x || !x->is_Proj()) { return false; + } ProjNode *proj = x->as_Proj(); x = proj->lookup(0); - if (!x || !x->is_MemBar()) + if (!x || !x->is_MemBar()) { return false; + } MemBarNode *barrier = x->as_MemBar(); @@ -2372,24 +2754,76 @@ bool needs_releasing_store(const Node *n) // volatile put graph. // reject invalid candidates - if (!leading_membar(barrier)) + if (!leading_membar(barrier)) { return false; + } // does this lead a normal subgraph? MemBarNode *mbvol = leading_to_normal(barrier); - if (!mbvol) + if (!mbvol) { return false; + } // all done unless this is a card mark - if (!is_card_mark_membar(mbvol)) + if (!is_card_mark_membar(mbvol)) { return true; + } // we found a card mark -- just make sure we have a trailing barrier return (card_mark_to_trailing(mbvol) != NULL); } +// predicate controlling translation of CAS +// +// returns true if CAS needs to use an acquiring load otherwise false + +bool needs_acquiring_load_exclusive(const Node *n) +{ + assert(is_CAS(n->Opcode()), "expecting a compare and swap"); + if (UseBarriersForVolatile) { + return false; + } + + // CAS nodes only ought to turn up in inlined unsafe CAS operations +#ifdef ASSERT + LoadStoreNode *st = n->as_LoadStore(); + + // the store must be fed by a membar + + Node *x = st->lookup(StoreNode::Memory); + + assert (x && x->is_Proj(), "CAS not fed by memory proj!"); + + ProjNode *proj = x->as_Proj(); + + x = proj->lookup(0); + + assert (x && x->is_MemBar(), "CAS not fed by membar!"); + + MemBarNode *barrier = x->as_MemBar(); + + // the barrier must be a cpuorder mmebar fed by a release membar + + assert(barrier->Opcode() == Op_MemBarCPUOrder, + "CAS not fed by cpuorder membar!"); + + MemBarNode *b = parent_membar(barrier); + assert ((b != NULL && b->Opcode() == Op_MemBarRelease), + "CAS not fed by cpuorder+release membar pair!"); + + // does this lead a normal subgraph? + MemBarNode *mbar = leading_to_normal(barrier); + + assert(mbar != NULL, "CAS not embedded in normal graph!"); + + assert(mbar->Opcode() == Op_MemBarAcquire, "trailing membar should be an acquire"); +#endif // ASSERT + // so we can just return true here + return true; +} + // predicate controlling translation of StoreCM // // returns true if a StoreStore must precede the card write otherwise @@ -2403,14 +2837,16 @@ bool unnecessary_storestore(const Node *storecm) // and the associated card mark when we are using CMS without // conditional card marking - if (!UseConcMarkSweepGC || UseCondCardMark) + if (!UseConcMarkSweepGC || UseCondCardMark) { return true; + } // if we are implementing volatile puts using barriers then the // object put as an str so we must insert the dmb ishst - if (UseBarriersForVolatile) + if (UseBarriersForVolatile) { return false; + } // we can omit the dmb ishst if this StoreCM is part of a volatile // put because in thta case the put will be implemented by stlr @@ -2422,19 +2858,22 @@ bool unnecessary_storestore(const Node *storecm) Node *x = storecm->in(StoreNode::Memory); - if (!x->is_Proj()) + if (!x->is_Proj()) { return false; + } x = x->in(0); - if (!x->is_MemBar()) + if (!x->is_MemBar()) { return false; + } MemBarNode *leading = x->as_MemBar(); // reject invalid candidates - if (!leading_membar(leading)) + if (!leading_membar(leading)) { return false; + } // we can omit the StoreStore if it is the head of a normal subgraph return (leading_to_normal(leading) != NULL); @@ -3024,6 +3463,10 @@ const bool Matcher::match_rule_supported(int opcode) { return true; // Per default match rules are supported. } +const int Matcher::float_pressure(int default_pressure_threshold) { + return default_pressure_threshold; +} + int Matcher::regnum_to_fpu_offset(int regnum) { Unimplemented(); @@ -8365,9 +8808,13 @@ instruct storeIConditional(indirect mem, iRegINoSp oldval, iRegINoSp newval, rFl // XXX No flag versions for CompareAndSwap{I,L,P,N} because matcher // can't match them +// standard CompareAndSwapX when we are using barriers +// these have higher priority than the rules selected by a predicate + instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapI mem (Binary oldval newval))); + ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8385,6 +8832,7 @@ instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoS instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapL mem (Binary oldval newval))); + ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8402,6 +8850,7 @@ instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoS instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); + ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8419,6 +8868,7 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapN mem (Binary oldval newval))); + ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8433,6 +8883,84 @@ instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoS ins_pipe(pipe_slow); %} +// alternative CompareAndSwapX when we are eliding barriers + +instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ + + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapI mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + + effect(KILL cr); + + format %{ + "cmpxchgw_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" + "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval), + aarch64_enc_cset_eq(res)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{ + + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapL mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + + effect(KILL cr); + + format %{ + "cmpxchg_acq $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" + "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval), + aarch64_enc_cset_eq(res)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ + + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + + effect(KILL cr); + + format %{ + "cmpxchg_acq $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" + "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval), + aarch64_enc_cset_eq(res)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ + + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + + effect(KILL cr); + + format %{ + "cmpxchgw_acq $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" + "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval), + aarch64_enc_cset_eq(res)); + + ins_pipe(pipe_slow); +%} + instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{ match(Set prev (GetAndSetI mem newv)); @@ -13286,6 +13814,25 @@ instruct cmpP_imm0_branch(cmpOp cmp, iRegP op1, immP0 op2, label labl, rFlagsReg ins_pipe(pipe_cmp_branch); %} +instruct cmpP_narrowOop_imm0_branch(cmpOp cmp, iRegN oop, immP0 zero, label labl, rFlagsReg cr) %{ + match(If cmp (CmpP (DecodeN oop) zero)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cb$cmp $oop, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + if (cond == Assembler::EQ) + __ cbzw($oop$$Register, *L); + else + __ cbnzw($oop$$Register, *L); + %} + ins_pipe(pipe_cmp_branch); +%} + // Conditional Far Branch // Conditional Far Branch Unsigned // TODO: fixme @@ -14662,6 +15209,102 @@ instruct vdiv2D(vecX dst, vecX src1, vecX src2) ins_pipe(pipe_class_default); %} +// --------------------------------- SQRT ------------------------------------- + +instruct vsqrt2D(vecX dst, vecX src) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (SqrtVD src)); + format %{ "fsqrt $dst, $src\t# vector (2D)" %} + ins_encode %{ + __ fsqrt(as_FloatRegister($dst$$reg), __ T2D, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +// --------------------------------- ABS -------------------------------------- + +instruct vabs2F(vecD dst, vecD src) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (AbsVF src)); + ins_cost(INSN_COST * 3); + format %{ "fabs $dst,$src\t# vector (2S)" %} + ins_encode %{ + __ fabs(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vabs4F(vecX dst, vecX src) +%{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (AbsVF src)); + ins_cost(INSN_COST * 3); + format %{ "fabs $dst,$src\t# vector (4S)" %} + ins_encode %{ + __ fabs(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vabs2D(vecX dst, vecX src) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (AbsVD src)); + ins_cost(INSN_COST * 3); + format %{ "fabs $dst,$src\t# vector (2D)" %} + ins_encode %{ + __ fabs(as_FloatRegister($dst$$reg), __ T2D, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +// --------------------------------- NEG -------------------------------------- + +instruct vneg2F(vecD dst, vecD src) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (NegVF src)); + ins_cost(INSN_COST * 3); + format %{ "fneg $dst,$src\t# vector (2S)" %} + ins_encode %{ + __ fneg(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vneg4F(vecX dst, vecX src) +%{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (NegVF src)); + ins_cost(INSN_COST * 3); + format %{ "fneg $dst,$src\t# vector (4S)" %} + ins_encode %{ + __ fneg(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vneg2D(vecX dst, vecX src) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (NegVD src)); + ins_cost(INSN_COST * 3); + format %{ "fneg $dst,$src\t# vector (2D)" %} + ins_encode %{ + __ fneg(as_FloatRegister($dst$$reg), __ T2D, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + // --------------------------------- AND -------------------------------------- instruct vand8B(vecD dst, vecD src1, vecD src2) diff --git a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp index f1678f7aa1a..dcd99c341ce 100644 --- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp @@ -2311,6 +2311,12 @@ public: #define MSG "invalid arrangement" +#define ASSERTION (T == T2S || T == T4S || T == T2D) + INSN(fsqrt, 1, 0b11111); + INSN(fabs, 0, 0b01111); + INSN(fneg, 1, 0b01111); +#undef ASSERTION + #define ASSERTION (T == T8B || T == T16B || T == T4H || T == T8H || T == T2S || T == T4S) INSN(rev64, 0, 0b00000); #undef ASSERTION diff --git a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp index 3aad200efe2..7ab673f2151 100644 --- a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp @@ -68,10 +68,11 @@ define_pd_global(intx, RegisterCostAreaRatio, 16000); // Peephole and CISC spilling both break the graph, and so makes the // scheduler sick. -define_pd_global(bool, OptoPeephole, true); +define_pd_global(bool, OptoPeephole, false); define_pd_global(bool, UseCISCSpill, true); define_pd_global(bool, OptoScheduling, false); define_pd_global(bool, OptoBundling, false); +define_pd_global(bool, OptoRegScheduling, false); define_pd_global(intx, ReservedCodeCacheSize, 48*M); define_pd_global(intx, NonProfiledCodeHeapSize, 21*M); diff --git a/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp index b30a4a6df10..103b936b5b4 100644 --- a/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp @@ -51,13 +51,15 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from // calling compiled code to calling interpreted code. // mov rmethod, 0 // jmp -4 # to self - address mark = cbuf.insts_mark(); // Get mark within main instrs section. + if (mark == NULL) { + mark = cbuf.insts_mark(); // Get mark within main instrs section. + } // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a stub. diff --git a/hotspot/src/cpu/aarch64/vm/cppInterpreterGenerator_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/cppInterpreterGenerator_aarch64.hpp index a8d1f94fca1..662d2849efc 100644 --- a/hotspot/src/cpu/aarch64/vm/cppInterpreterGenerator_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/cppInterpreterGenerator_aarch64.hpp @@ -30,5 +30,6 @@ void generate_more_monitors(); void generate_deopt_handling(); + void lock_method(void); #endif // CPU_AARCH64_VM_CPPINTERPRETERGENERATOR_AARCH64_HPP diff --git a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp index 8207dc9fa4e..e770da27179 100644 --- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp @@ -55,10 +55,17 @@ define_pd_global(intx, CodeEntryAlignment, 16); define_pd_global(intx, OptoLoopAlignment, 16); define_pd_global(intx, InlineFrequencyCount, 100); -define_pd_global(intx, StackYellowPages, 2); -define_pd_global(intx, StackRedPages, 1); +#define DEFAULT_STACK_YELLOW_PAGES (2) +#define DEFAULT_STACK_RED_PAGES (1) +#define DEFAULT_STACK_SHADOW_PAGES (4 DEBUG_ONLY(+5)) -define_pd_global(intx, StackShadowPages, 4 DEBUG_ONLY(+5)); +#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES +#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES +#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES + +define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); +define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); +define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp index 8f0f543ae9d..8fe6b38f0c0 100644 --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp @@ -42,6 +42,11 @@ // Implementation of InterpreterMacroAssembler +void InterpreterMacroAssembler::jump_to_entry(address entry) { + assert(entry, "Entry must have been generated by now"); + b(entry); +} + #ifndef CC_INTERP void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { @@ -1542,14 +1547,14 @@ void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register ca if (MethodData::profile_arguments()) { Label done; int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); - add(mdp, mdp, off_to_args); for (int i = 0; i < TypeProfileArgsLimit; i++) { if (i > 0 || MethodData::profile_return()) { // If return value type is profiled we may have no argument to profile - ldr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); + ldr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset()))); sub(tmp, tmp, i*TypeStackSlotEntries::per_arg_count()); cmp(tmp, TypeStackSlotEntries::per_arg_count()); + add(rscratch1, mdp, off_to_args); br(Assembler::LT, done); } ldr(tmp, Address(callee, Method::const_offset())); @@ -1557,26 +1562,27 @@ void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register ca // stack offset o (zero based) from the start of the argument // list, for n arguments translates into offset n - o - 1 from // the end of the argument list - ldr(rscratch1, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args)); + ldr(rscratch1, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i)))); sub(tmp, tmp, rscratch1); sub(tmp, tmp, 1); Address arg_addr = argument_address(tmp); ldr(tmp, arg_addr); - Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args); + Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))); profile_obj_type(tmp, mdo_arg_addr); int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); - add(mdp, mdp, to_add); off_to_args += to_add; } if (MethodData::profile_return()) { - ldr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); + ldr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset()))); sub(tmp, tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count()); } + add(rscratch1, mdp, off_to_args); bind(done); + mov(mdp, rscratch1); if (MethodData::profile_return()) { // We're right after the type profile for the last diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp index 7d30ee0d16e..5cdfdecf2d3 100644 --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp @@ -66,6 +66,8 @@ class InterpreterMacroAssembler: public MacroAssembler { void load_earlyret_value(TosState state); + void jump_to_entry(address entry); + #ifdef CC_INTERP void save_bcp() { /* not needed in c++ interpreter and harmless */ } void restore_bcp() { /* not needed in c++ interpreter and harmless */ } diff --git a/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp index ffff3a20826..3d886570a5a 100644 --- a/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp @@ -41,14 +41,13 @@ private: address generate_native_entry(bool synchronized); address generate_abstract_entry(void); address generate_math_entry(AbstractInterpreter::MethodKind kind); - address generate_jump_to_normal_entry(void); - address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } - address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } + address generate_accessor_entry(void) { return NULL; } + address generate_empty_entry(void) { return NULL; } void generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs); address generate_Reference_get_entry(); address generate_CRC32_update_entry(); address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); - void lock_method(void); + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } void generate_stack_overflow_check(void); void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); diff --git a/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp index dd078da8f51..96a967fb961 100644 --- a/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp @@ -236,17 +236,6 @@ void InterpreterGenerator::generate_transcendental_entry(AbstractInterpreter::Me __ blrt(rscratch1, gpargs, fpargs, rtype); } -// Jump into normal path for accessor and empty entry to jump to normal entry -// The "fast" optimization don't update compilation count therefore can disable inlining -// for these functions that should be inlined. -address InterpreterGenerator::generate_jump_to_normal_entry(void) { - address entry_point = __ pc(); - - assert(Interpreter::entry_for_kind(Interpreter::zerolocals) != NULL, "should already be generated"); - __ b(Interpreter::entry_for_kind(Interpreter::zerolocals)); - return entry_point; -} - // Abstract method entry // Attempt to execute abstract method. Throw exception address InterpreterGenerator::generate_abstract_entry(void) { diff --git a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp new file mode 100644 index 00000000000..c9467bfb23c --- /dev/null +++ b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_aarch64.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + Unimplemented(); + return 0; +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + Unimplemented(); +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + Unimplemented(); +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + return NULL; +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return false; +} diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index e423476065f..a827da7a5be 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -1709,6 +1709,20 @@ int MacroAssembler::corrected_idivq(Register result, Register ra, Register rb, return idivq_offset; } +void MacroAssembler::membar(Membar_mask_bits order_constraint) { + address prev = pc() - NativeMembar::instruction_size; + if (prev == code()->last_membar()) { + NativeMembar *bar = NativeMembar_at(prev); + // We are merging two memory barrier instructions. On AArch64 we + // can do this simply by ORing them together. + bar->set_kind(bar->get_kind() | order_constraint); + BLOCK_COMMENT("merged membar"); + } else { + code()->set_last_membar(pc()); + dmb(Assembler::barrier(order_constraint)); + } +} + // MacroAssembler routines found actually to be needed void MacroAssembler::push(Register src) @@ -2238,7 +2252,7 @@ void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[]) ttyLocker ttyl; ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg); - assert(false, err_msg("DEBUG MESSAGE: %s", msg)); + assert(false, "DEBUG MESSAGE: %s", msg); } } @@ -2286,18 +2300,30 @@ void MacroAssembler::c_stub_prolog(int gp_arg_count, int fp_arg_count, int ret_t } #endif -void MacroAssembler::push_CPU_state() { - push(0x3fffffff, sp); // integer registers except lr & sp +void MacroAssembler::push_CPU_state(bool save_vectors) { + push(0x3fffffff, sp); // integer registers except lr & sp + if (!save_vectors) { for (int i = 30; i >= 0; i -= 2) stpd(as_FloatRegister(i), as_FloatRegister(i+1), Address(pre(sp, -2 * wordSize))); + } else { + for (int i = 30; i >= 0; i -= 2) + stpq(as_FloatRegister(i), as_FloatRegister(i+1), + Address(pre(sp, -4 * wordSize))); + } } -void MacroAssembler::pop_CPU_state() { - for (int i = 0; i < 32; i += 2) - ldpd(as_FloatRegister(i), as_FloatRegister(i+1), - Address(post(sp, 2 * wordSize))); +void MacroAssembler::pop_CPU_state(bool restore_vectors) { + if (!restore_vectors) { + for (int i = 0; i < 32; i += 2) + ldpd(as_FloatRegister(i), as_FloatRegister(i+1), + Address(post(sp, 2 * wordSize))); + } else { + for (int i = 0; i < 32; i += 2) + ldpq(as_FloatRegister(i), as_FloatRegister(i+1), + Address(post(sp, 4 * wordSize))); + } pop(0x3fffffff, sp); // integer registers except lr & sp } @@ -3027,6 +3053,24 @@ SkipIfEqual::~SkipIfEqual() { _masm->bind(_label); } +void MacroAssembler::addptr(const Address &dst, int32_t src) { + Address adr; + switch(dst.getMode()) { + case Address::base_plus_offset: + // This is the expected mode, although we allow all the other + // forms below. + adr = form_address(rscratch2, dst.base(), dst.offset(), LogBytesPerWord); + break; + default: + lea(rscratch2, dst); + adr = Address(rscratch2); + break; + } + ldr(rscratch1, adr); + add(rscratch1, rscratch1, src); + str(rscratch1, adr); +} + void MacroAssembler::cmpptr(Register src1, Address src2) { unsigned long offset; adrp(rscratch1, src2, offset); @@ -3063,11 +3107,15 @@ void MacroAssembler::store_check(Register obj) { if (UseCondCardMark) { Label L_already_dirty; + membar(StoreLoad); ldrb(rscratch2, Address(obj, rscratch1)); cbz(rscratch2, L_already_dirty); strb(zr, Address(obj, rscratch1)); bind(L_already_dirty); } else { + if (UseConcMarkSweepGC && CMSPrecleaningEnabled) { + membar(StoreStore); + } strb(zr, Address(obj, rscratch1)); } } diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index 1fbba6f9b18..563a24a1238 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -152,6 +152,13 @@ class MacroAssembler: public Assembler { strw(scratch, a); } + void bind(Label& L) { + Assembler::bind(L); + code()->clear_last_membar(); + } + + void membar(Membar_mask_bits order_constraint); + // Frame creation and destruction shared between JITs. void build_frame(int framesize); void remove_frame(int framesize); @@ -777,8 +784,8 @@ public: DEBUG_ONLY(void verify_heapbase(const char* msg);) - void push_CPU_state(); - void pop_CPU_state() ; + void push_CPU_state(bool save_vectors = false); + void pop_CPU_state(bool restore_vectors = false) ; // Round up to a power of two void round_to(Register reg, int modulus); @@ -908,13 +915,7 @@ public: // Arithmetics - void addptr(Address dst, int32_t src) { - lea(rscratch2, dst); - ldr(rscratch1, Address(rscratch2)); - add(rscratch1, rscratch1, src); - str(rscratch1, Address(rscratch2)); - } - + void addptr(const Address &dst, int32_t src); void cmpptr(Register src1, Address src2); // Various forms of CAS diff --git a/hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp index cf2563f8623..ba8c3cc31b9 100644 --- a/hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp @@ -50,7 +50,7 @@ void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_ #ifdef ASSERT static int check_nonzero(const char* xname, int x) { - assert(x != 0, err_msg("%s should be nonzero", xname)); + assert(x != 0, "%s should be nonzero", xname); return x; } #define NONZERO(x) check_nonzero(#x, x) @@ -407,7 +407,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, } default: - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } diff --git a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp index 457cfbc941a..60e26e08270 100644 --- a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp @@ -101,6 +101,12 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { static bool maybe_cpool_ref(address instr) { return is_adrp_at(instr) || is_ldr_literal_at(instr); } + + bool is_Membar() { + unsigned int insn = uint_at(0); + return Instruction_aarch64::extract(insn, 31, 12) == 0b11010101000000110011 && + Instruction_aarch64::extract(insn, 7, 0) == 0b10111111; + } }; inline NativeInstruction* nativeInstruction_at(address address) { @@ -487,4 +493,15 @@ inline NativeCallTrampolineStub* nativeCallTrampolineStub_at(address addr) { return (NativeCallTrampolineStub*)addr; } +class NativeMembar : public NativeInstruction { +public: + unsigned int get_kind() { return Instruction_aarch64::extract(uint_at(0), 11, 8); } + void set_kind(int order_kind) { Instruction_aarch64::patch(addr_at(0), 11, 8, order_kind); } +}; + +inline NativeMembar *NativeMembar_at(address addr) { + assert(nativeInstruction_at(addr)->is_Membar(), "no membar found"); + return (NativeMembar*)addr; +} + #endif // CPU_AARCH64_VM_NATIVEINST_AARCH64_HPP diff --git a/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp index e9819bd13c5..3ab4f0b7b2c 100644 --- a/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp @@ -102,12 +102,5 @@ void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffe } } -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { - if (NativeInstruction::maybe_cpool_ref(addr())) { - address old_addr = old_addr_for(addr(), src, dest); - MacroAssembler::pd_patch_instruction(addr(), MacroAssembler::target_addr_for_insn(old_addr)); - } -} - void metadata_Relocation::pd_fix_value(address x) { } diff --git a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp index f18563b84bb..7f6487a37aa 100644 --- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp @@ -75,8 +75,8 @@ class SimpleRuntimeFrame { // FIXME -- this is used by C1 class RegisterSaver { public: - static OopMap* save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words); - static void restore_live_registers(MacroAssembler* masm); + static OopMap* save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors = false); + static void restore_live_registers(MacroAssembler* masm, bool restore_vectors = false); // Offsets into the register save area // Used by deoptimization when it is managing result register @@ -108,7 +108,17 @@ class RegisterSaver { }; -OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words) { +OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) { +#ifdef COMPILER2 + if (save_vectors) { + // Save upper half of vector registers + int vect_words = 32 * 8 / wordSize; + additional_frame_words += vect_words; + } +#else + assert(!save_vectors, "vectors are generated only by C2"); +#endif + int frame_size_in_bytes = round_to(additional_frame_words*wordSize + reg_save_size*BytesPerInt, 16); // OopMap frame size is in compiler stack slots (jint's) not bytes or words @@ -122,7 +132,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ // Save registers, fpu state, and flags. __ enter(); - __ push_CPU_state(); + __ push_CPU_state(save_vectors); // Set an oopmap for the call site. This oopmap will map all // oop-registers and debug-info registers as callee-saved. This @@ -139,14 +149,14 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ // register slots are 8 bytes // wide, 32 floating-point // registers - oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset + additional_frame_slots), r->as_VMReg()); } } for (int i = 0; i < FloatRegisterImpl::number_of_registers; i++) { FloatRegister r = as_FloatRegister(i); - int sp_offset = 2 * i; + int sp_offset = save_vectors ? (4 * i) : (2 * i); oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), r->as_VMReg()); } @@ -154,8 +164,11 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ return oop_map; } -void RegisterSaver::restore_live_registers(MacroAssembler* masm) { - __ pop_CPU_state(); +void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_vectors) { +#ifndef COMPILER2 + assert(!restore_vectors, "vectors are generated only by C2"); +#endif + __ pop_CPU_state(restore_vectors); __ leave(); } @@ -177,9 +190,9 @@ void RegisterSaver::restore_result_registers(MacroAssembler* masm) { } // Is vector's size (in bytes) bigger than a size saved by default? -// 16 bytes XMM registers are saved by default using fxsave/fxrstor instructions. +// 8 bytes vector registers are saved by default on AArch64. bool SharedRuntime::is_wide_vector(int size) { - return size > 16; + return size > 8; } // The java_calling_convention describes stack locations as ideal slots on // a frame with no abi restrictions. Since we must observe abi restrictions @@ -460,11 +473,11 @@ static void gen_c2i_adapter(MacroAssembler *masm, } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Note: r13 contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled @@ -1146,7 +1159,7 @@ static void rt_call(MacroAssembler* masm, address dest, int gpargs, int fpargs, assert((unsigned)gpargs < 256, "eek!"); assert((unsigned)fpargs < 32, "eek!"); __ lea(rscratch1, RuntimeAddress(dest)); - __ mov(rscratch2, (gpargs << 6) | (fpargs << 2) | type); + if (UseBuiltinSim) __ mov(rscratch2, (gpargs << 6) | (fpargs << 2) | type); __ blrt(rscratch1, rscratch2); __ maybe_isb(); } @@ -1194,7 +1207,7 @@ static void gen_special_dispatch(MacroAssembler* masm, } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg_res("unexpected intrinsic id %d", iid)); + fatal("unexpected intrinsic id %d", iid); } if (member_reg != noreg) { @@ -1521,14 +1534,13 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, int vep_offset = ((intptr_t)__ pc()) - start; - // Generate stack overflow check - // If we have to make this method not-entrant we'll overwrite its // first instruction with a jump. For this action to be legal we // must ensure that this first instruction is a B, BL, NOP, BKPT, // SVC, HVC, or SMC. Make it a NOP. __ nop(); + // Generate stack overflow check if (UseStackBanging) { __ bang_stack_with_offset(StackShadowPages*os::vm_page_size()); } else { @@ -1709,23 +1721,20 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // need to spill before we call out int c_arg = total_c_args - total_in_args; - // Pre-load a static method's oop into r20. Used both by locking code and - // the normal JNI call code. + // Pre-load a static method's oop into c_rarg1. if (method->is_static() && !is_critical_native) { // load oop into a register - __ movoop(oop_handle_reg, + __ movoop(c_rarg1, JNIHandles::make_local(method->method_holder()->java_mirror()), /*immediate*/true); // Now handlize the static class mirror it's known not-null. - __ str(oop_handle_reg, Address(sp, klass_offset)); + __ str(c_rarg1, Address(sp, klass_offset)); map->set_oop(VMRegImpl::stack2reg(klass_slot_offset)); // Now get the handle - __ lea(oop_handle_reg, Address(sp, klass_offset)); - // store the klass handle as second argument - __ mov(c_rarg1, oop_handle_reg); + __ lea(c_rarg1, Address(sp, klass_offset)); // and protect the arg if we must spill c_arg--; } @@ -1740,19 +1749,13 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ set_last_Java_frame(sp, noreg, (address)the_pc, rscratch1); - - // We have all of the arguments setup at this point. We must not touch any register - // argument registers at this point (what if we save/restore them there are no oop? - + Label dtrace_method_entry, dtrace_method_entry_done; { - SkipIfEqual skip(masm, &DTraceMethodProbes, false); - // protect the args we've loaded - save_args(masm, total_c_args, c_arg, out_regs); - __ mov_metadata(c_rarg1, method()); - __ call_VM_leaf( - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), - rthread, c_rarg1); - restore_args(masm, total_c_args, c_arg, out_regs); + unsigned long offset; + __ adrp(rscratch1, ExternalAddress((address)&DTraceMethodProbes), offset); + __ ldrb(rscratch1, Address(rscratch1, offset)); + __ cbnzw(rscratch1, dtrace_method_entry); + __ bind(dtrace_method_entry_done); } // RedefineClasses() tracing support for obsolete method entry @@ -1782,7 +1785,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, if (method->is_synchronized()) { assert(!is_critical_native, "unhandled"); - const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); // Get the handle (the 2nd argument) @@ -1838,7 +1840,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Finally just about ready to make the JNI call - // get JNIEnv* which is first argument to native if (!is_critical_native) { __ lea(c_rarg0, Address(rthread, in_bytes(JavaThread::jni_environment_offset()))); @@ -1879,9 +1880,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Unpack native results. switch (ret_type) { - case T_BOOLEAN: __ ubfx(r0, r0, 0, 8); break; + case T_BOOLEAN: __ ubfx(r0, r0, 0, 8); break; case T_CHAR : __ ubfx(r0, r0, 0, 16); break; - case T_BYTE : __ sbfx(r0, r0, 0, 8); break; + case T_BYTE : __ sbfx(r0, r0, 0, 8); break; case T_SHORT : __ sbfx(r0, r0, 0, 16); break; case T_INT : __ sbfx(r0, r0, 0, 32); break; case T_DOUBLE : @@ -1904,14 +1905,17 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Thread A is resumed to finish this native method, but doesn't block here since it // didn't see any synchronization is progress, and escapes. __ mov(rscratch1, _thread_in_native_trans); - __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); - __ stlrw(rscratch1, rscratch2); if(os::is_MP()) { if (UseMembar) { + __ strw(rscratch1, Address(rthread, JavaThread::thread_state_offset())); + // Force this write out before the read below __ dmb(Assembler::SY); } else { + __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); + __ stlrw(rscratch1, rscratch2); + // Write serialization page so VM thread can do a pseudo remote membar. // We use the current thread pointer to calculate a thread specific // offset to write to within the page. This minimizes bus traffic @@ -1920,54 +1924,23 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, } } - Label after_transition; - // check for safepoint operation in progress and/or pending suspend requests + Label safepoint_in_progress, safepoint_in_progress_done; { - Label Continue; - - { unsigned long offset; - __ adrp(rscratch1, - ExternalAddress((address)SafepointSynchronize::address_of_state()), - offset); - __ ldrw(rscratch1, Address(rscratch1, offset)); - } - __ cmpw(rscratch1, SafepointSynchronize::_not_synchronized); - - Label L; - __ br(Assembler::NE, L); + assert(SafepointSynchronize::_not_synchronized == 0, "fix this code"); + unsigned long offset; + __ adrp(rscratch1, + ExternalAddress((address)SafepointSynchronize::address_of_state()), + offset); + __ ldrw(rscratch1, Address(rscratch1, offset)); + __ cbnzw(rscratch1, safepoint_in_progress); __ ldrw(rscratch1, Address(rthread, JavaThread::suspend_flags_offset())); - __ cbz(rscratch1, Continue); - __ bind(L); - - // Don't use call_VM as it will see a possible pending exception and forward it - // and never return here preventing us from clearing _last_native_pc down below. - // - save_native_result(masm, ret_type, stack_slots); - __ mov(c_rarg0, rthread); -#ifndef PRODUCT - assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); -#endif - if (!is_critical_native) { - __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); - } else { - __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans_and_transition))); - } - __ blrt(rscratch1, 1, 0, 1); - __ maybe_isb(); - // Restore any method result value - restore_native_result(masm, ret_type, stack_slots); - - if (is_critical_native) { - // The call above performed the transition to thread_in_Java so - // skip the transition logic below. - __ b(after_transition); - } - - __ bind(Continue); + __ cbnzw(rscratch1, safepoint_in_progress); + __ bind(safepoint_in_progress_done); } // change thread state + Label after_transition; __ mov(rscratch1, _thread_in_Java); __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); __ stlrw(rscratch1, rscratch2); @@ -2024,16 +1997,15 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, } __ bind(done); - } + + Label dtrace_method_exit, dtrace_method_exit_done; { - SkipIfEqual skip(masm, &DTraceMethodProbes, false); - save_native_result(masm, ret_type, stack_slots); - __ mov_metadata(c_rarg1, method()); - __ call_VM_leaf( - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), - rthread, c_rarg1); - restore_native_result(masm, ret_type, stack_slots); + unsigned long offset; + __ adrp(rscratch1, ExternalAddress((address)&DTraceMethodProbes), offset); + __ ldrb(rscratch1, Address(rscratch1, offset)); + __ cbnzw(rscratch1, dtrace_method_exit); + __ bind(dtrace_method_exit_done); } __ reset_last_Java_frame(false, true); @@ -2082,7 +2054,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Slow path locking & unlocking if (method->is_synchronized()) { - // BEGIN Slow path lock + __ block_comment("Slow path lock {"); __ bind(slow_path_lock); // has last_Java_frame setup. No exceptions so do vanilla call not call_VM @@ -2109,9 +2081,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, #endif __ b(lock_done); - // END Slow path lock + __ block_comment("} Slow path lock"); - // BEGIN Slow path unlock + __ block_comment("Slow path unlock {"); __ bind(slow_path_unlock); // If we haven't already saved the native result we must save it now as xmm registers @@ -2149,7 +2121,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, } __ b(unlock_done); - // END Slow path unlock + __ block_comment("} Slow path unlock"); } // synchronized @@ -2162,6 +2134,69 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // and continue __ b(reguard_done); + // SLOW PATH safepoint + { + __ block_comment("safepoint {"); + __ bind(safepoint_in_progress); + + // Don't use call_VM as it will see a possible pending exception and forward it + // and never return here preventing us from clearing _last_native_pc down below. + // + save_native_result(masm, ret_type, stack_slots); + __ mov(c_rarg0, rthread); +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + if (!is_critical_native) { + __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); + } else { + __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans_and_transition))); + } + __ blrt(rscratch1, 1, 0, 1); + __ maybe_isb(); + // Restore any method result value + restore_native_result(masm, ret_type, stack_slots); + + if (is_critical_native) { + // The call above performed the transition to thread_in_Java so + // skip the transition logic above. + __ b(after_transition); + } + + __ b(safepoint_in_progress_done); + __ block_comment("} safepoint"); + } + + // SLOW PATH dtrace support + { + __ block_comment("dtrace entry {"); + __ bind(dtrace_method_entry); + + // We have all of the arguments setup at this point. We must not touch any register + // argument registers at this point (what if we save/restore them there are no oop? + + save_args(masm, total_c_args, c_arg, out_regs); + __ mov_metadata(c_rarg1, method()); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), + rthread, c_rarg1); + restore_args(masm, total_c_args, c_arg, out_regs); + __ b(dtrace_method_entry_done); + __ block_comment("} dtrace entry"); + } + + { + __ block_comment("dtrace exit {"); + __ bind(dtrace_method_exit); + save_native_result(masm, ret_type, stack_slots); + __ mov_metadata(c_rarg1, method()); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), + rthread, c_rarg1); + restore_native_result(masm, ret_type, stack_slots); + __ b(dtrace_method_exit_done); + __ block_comment("} dtrace exit"); + } __ flush(); @@ -2742,7 +2777,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP); // Save registers, fpu state, and flags - map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); + map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words, save_vectors); // The following is basically a call_VM. However, we need the precise // address of the call in order to generate an oopmap. Hence, we do all the @@ -2793,7 +2828,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t __ bind(noException); // Normal exit, restore registers and exit. - RegisterSaver::restore_live_registers(masm); + RegisterSaver::restore_live_registers(masm, save_vectors); __ ret(lr); diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 56799453938..2eb119125f2 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -746,6 +746,9 @@ class StubGenerator: public StubCodeGenerator { const Register count = end; // 'end' register contains bytes count now __ mov(scratch, (address)ct->byte_map_base); __ add(start, start, scratch); + if (UseConcMarkSweepGC) { + __ membar(__ StoreStore); + } __ BIND(L_loop); __ strb(zr, Address(start, count)); __ subs(count, count, 1); @@ -2395,6 +2398,274 @@ class StubGenerator: public StubCodeGenerator { return start; } + /*** + * Arguments: + * + * Inputs: + * c_rarg0 - int adler + * c_rarg1 - byte* buff + * c_rarg2 - int len + * + * Output: + * c_rarg0 - int adler result + */ + address generate_updateBytesAdler32() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "updateBytesAdler32"); + address start = __ pc(); + + Label L_simple_by1_loop, L_nmax, L_nmax_loop, L_by16, L_by16_loop, L_by1_loop, L_do_mod, L_combine, L_by1; + + // Aliases + Register adler = c_rarg0; + Register s1 = c_rarg0; + Register s2 = c_rarg3; + Register buff = c_rarg1; + Register len = c_rarg2; + Register nmax = r4; + Register base = r5; + Register count = r6; + Register temp0 = rscratch1; + Register temp1 = rscratch2; + Register temp2 = r7; + + // Max number of bytes we can process before having to take the mod + // 0x15B0 is 5552 in decimal, the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + unsigned long BASE = 0xfff1; + unsigned long NMAX = 0x15B0; + + __ mov(base, BASE); + __ mov(nmax, NMAX); + + // s1 is initialized to the lower 16 bits of adler + // s2 is initialized to the upper 16 bits of adler + __ ubfx(s2, adler, 16, 16); // s2 = ((adler >> 16) & 0xffff) + __ uxth(s1, adler); // s1 = (adler & 0xffff) + + // The pipelined loop needs at least 16 elements for 1 iteration + // It does check this, but it is more effective to skip to the cleanup loop + __ cmp(len, 16); + __ br(Assembler::HS, L_nmax); + __ cbz(len, L_combine); + + __ bind(L_simple_by1_loop); + __ ldrb(temp0, Address(__ post(buff, 1))); + __ add(s1, s1, temp0); + __ add(s2, s2, s1); + __ subs(len, len, 1); + __ br(Assembler::HI, L_simple_by1_loop); + + // s1 = s1 % BASE + __ subs(temp0, s1, base); + __ csel(s1, temp0, s1, Assembler::HS); + + // s2 = s2 % BASE + __ lsr(temp0, s2, 16); + __ lsl(temp1, temp0, 4); + __ sub(temp1, temp1, temp0); + __ add(s2, temp1, s2, ext::uxth); + + __ subs(temp0, s2, base); + __ csel(s2, temp0, s2, Assembler::HS); + + __ b(L_combine); + + __ bind(L_nmax); + __ subs(len, len, nmax); + __ sub(count, nmax, 16); + __ br(Assembler::LO, L_by16); + + __ bind(L_nmax_loop); + + __ ldp(temp0, temp1, Address(__ post(buff, 16))); + + __ add(s1, s1, temp0, ext::uxtb); + __ ubfx(temp2, temp0, 8, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 16, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 24, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 32, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 40, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 48, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ add(s2, s2, s1); + __ add(s1, s1, temp0, Assembler::LSR, 56); + __ add(s2, s2, s1); + + __ add(s1, s1, temp1, ext::uxtb); + __ ubfx(temp2, temp1, 8, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 16, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 24, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 32, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 40, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 48, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ add(s2, s2, s1); + __ add(s1, s1, temp1, Assembler::LSR, 56); + __ add(s2, s2, s1); + + __ subs(count, count, 16); + __ br(Assembler::HS, L_nmax_loop); + + // s1 = s1 % BASE + __ lsr(temp0, s1, 16); + __ lsl(temp1, temp0, 4); + __ sub(temp1, temp1, temp0); + __ add(temp1, temp1, s1, ext::uxth); + + __ lsr(temp0, temp1, 16); + __ lsl(s1, temp0, 4); + __ sub(s1, s1, temp0); + __ add(s1, s1, temp1, ext:: uxth); + + __ subs(temp0, s1, base); + __ csel(s1, temp0, s1, Assembler::HS); + + // s2 = s2 % BASE + __ lsr(temp0, s2, 16); + __ lsl(temp1, temp0, 4); + __ sub(temp1, temp1, temp0); + __ add(temp1, temp1, s2, ext::uxth); + + __ lsr(temp0, temp1, 16); + __ lsl(s2, temp0, 4); + __ sub(s2, s2, temp0); + __ add(s2, s2, temp1, ext:: uxth); + + __ subs(temp0, s2, base); + __ csel(s2, temp0, s2, Assembler::HS); + + __ subs(len, len, nmax); + __ sub(count, nmax, 16); + __ br(Assembler::HS, L_nmax_loop); + + __ bind(L_by16); + __ adds(len, len, count); + __ br(Assembler::LO, L_by1); + + __ bind(L_by16_loop); + + __ ldp(temp0, temp1, Address(__ post(buff, 16))); + + __ add(s1, s1, temp0, ext::uxtb); + __ ubfx(temp2, temp0, 8, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 16, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 24, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 32, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 40, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 48, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ add(s2, s2, s1); + __ add(s1, s1, temp0, Assembler::LSR, 56); + __ add(s2, s2, s1); + + __ add(s1, s1, temp1, ext::uxtb); + __ ubfx(temp2, temp1, 8, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 16, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 24, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 32, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 40, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 48, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ add(s2, s2, s1); + __ add(s1, s1, temp1, Assembler::LSR, 56); + __ add(s2, s2, s1); + + __ subs(len, len, 16); + __ br(Assembler::HS, L_by16_loop); + + __ bind(L_by1); + __ adds(len, len, 15); + __ br(Assembler::LO, L_do_mod); + + __ bind(L_by1_loop); + __ ldrb(temp0, Address(__ post(buff, 1))); + __ add(s1, temp0, s1); + __ add(s2, s2, s1); + __ subs(len, len, 1); + __ br(Assembler::HS, L_by1_loop); + + __ bind(L_do_mod); + // s1 = s1 % BASE + __ lsr(temp0, s1, 16); + __ lsl(temp1, temp0, 4); + __ sub(temp1, temp1, temp0); + __ add(temp1, temp1, s1, ext::uxth); + + __ lsr(temp0, temp1, 16); + __ lsl(s1, temp0, 4); + __ sub(s1, s1, temp0); + __ add(s1, s1, temp1, ext:: uxth); + + __ subs(temp0, s1, base); + __ csel(s1, temp0, s1, Assembler::HS); + + // s2 = s2 % BASE + __ lsr(temp0, s2, 16); + __ lsl(temp1, temp0, 4); + __ sub(temp1, temp1, temp0); + __ add(temp1, temp1, s2, ext::uxth); + + __ lsr(temp0, temp1, 16); + __ lsl(s2, temp0, 4); + __ sub(s2, s2, temp0); + __ add(s2, s2, temp1, ext:: uxth); + + __ subs(temp0, s2, base); + __ csel(s2, temp0, s2, Assembler::HS); + + // Combine lower bits and higher bits + __ bind(L_combine); + __ orr(s1, s1, s2, Assembler::LSL, 16); // adler = s1 | (s2 << 16) + + __ ret(lr); + + return start; + } + /** * Arguments: * @@ -3613,6 +3884,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(); } + // generate Adler32 intrinsics code + if (UseAdler32Intrinsics) { + StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32(); + } + // Safefetch stubs. generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry, &StubRoutines::_safefetch32_fault_pc, diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp index da9e973d83e..fb339033869 100644 --- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp @@ -535,7 +535,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) { // r0 // c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs) // rscratch1, rscratch2 (scratch regs) -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { // synchronize method const Address access_flags(rmethod, Method::access_flags_offset()); const Address monitor_block_top( @@ -721,8 +721,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // generate a vanilla interpreter entry as the slow path __ bind(slow_path); - (void) generate_normal_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); return entry; } #endif // INCLUDE_ALL_GCS @@ -779,12 +778,10 @@ address InterpreterGenerator::generate_CRC32_update_entry() { // generate a vanilla native entry as the slow path __ bind(slow_path); - - (void) generate_native_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); return entry; } - return generate_native_entry(false); + return NULL; } /** @@ -841,12 +838,10 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret // generate a vanilla native entry as the slow path __ bind(slow_path); - - (void) generate_native_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); return entry; } - return generate_native_entry(false); + return NULL; } void InterpreterGenerator::bang_stack_shadow_pages(bool native_call) { diff --git a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp index daf6163142f..37c0e5bbb63 100644 --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp @@ -178,9 +178,8 @@ void VM_Version::get_processor_features() { warning("UseCRC32 specified, but not supported on this CPU"); } - if (UseAdler32Intrinsics) { - warning("Adler32Intrinsics not available on this CPU."); - FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); + if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) { + FLAG_SET_DEFAULT(UseAdler32Intrinsics, true); } if (auxv & HWCAP_AES) { diff --git a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp index d797ef6eb8c..d41e391b4bc 100644 --- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp @@ -60,6 +60,7 @@ define_pd_global(intx, LoopUnrollLimit, 60); define_pd_global(bool, OptoPeephole, false); define_pd_global(bool, UseCISCSpill, false); define_pd_global(bool, OptoBundling, false); +define_pd_global(bool, OptoRegScheduling, false); // GL: // Detected a problem with unscaled compressed oops and // narrow_oop_use_complex_address() == false. diff --git a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp index 762a329e259..41b5125f06e 100644 --- a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp @@ -94,10 +94,12 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { const int IC_pos_in_java_to_interp_stub = 8; #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* = NULL*/) { #ifdef COMPILER2 - // Get the mark within main instrs section which is set to the address of the call. - address call_addr = cbuf.insts_mark(); + if (mark == NULL) { + // Get the mark within main instrs section which is set to the address of the call. + mark = cbuf.insts_mark(); + } // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a stub. @@ -117,7 +119,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { // Create a static stub relocation which relates this stub // with the call instruction at insts_call_instruction_offset in the // instructions code-section. - __ relocate(static_stub_Relocation::spec(call_addr)); + __ relocate(static_stub_Relocation::spec(mark)); const int stub_start_offset = __ offset(); // Now, create the stub's code: diff --git a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp index 238f50ee3d4..fac126363a0 100644 --- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp @@ -41,6 +41,18 @@ define_pd_global(bool, ImplicitNullChecks, true); // Generate code for impli define_pd_global(bool, TrapBasedNullChecks, true); define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs passed to check cast. +#define DEFAULT_STACK_YELLOW_PAGES (6) +#define DEFAULT_STACK_RED_PAGES (1) +#define DEFAULT_STACK_SHADOW_PAGES (6 DEBUG_ONLY(+2)) + +#define MIN_STACK_YELLOW_PAGES (1) +#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES +#define MIN_STACK_SHADOW_PAGES (1) + +define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); +define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); +define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); + // Use large code-entry alignment. define_pd_global(intx, CodeEntryAlignment, 128); define_pd_global(intx, OptoLoopAlignment, 16); diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp index f32d8e590c1..be9c8da7124 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp @@ -46,7 +46,7 @@ void InterpreterMacroAssembler::null_check_throw(Register a, int offset, Registe MacroAssembler::null_check_throw(a, offset, temp_reg, exception_entry); } -void InterpreterMacroAssembler::branch_to_entry(address entry, Register Rscratch) { +void InterpreterMacroAssembler::jump_to_entry(address entry, Register Rscratch) { assert(entry, "Entry must have been generated by now"); if (is_within_range_of_b(entry, pc())) { b(entry); diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp index 571f87e45cd..9692e65225c 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp @@ -39,7 +39,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void null_check_throw(Register a, int offset, Register temp_reg); - void branch_to_entry(address entry, Register Rscratch); + void jump_to_entry(address entry, Register Rscratch); // Handy address generation macros. #define thread_(field_name) in_bytes(JavaThread::field_name ## _offset()), R16_thread diff --git a/hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp b/hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp index 29cac0e2c89..02a6931b662 100644 --- a/hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp @@ -31,12 +31,12 @@ private: address generate_abstract_entry(void); - address generate_jump_to_normal_entry(void); - address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } - address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } + address generate_accessor_entry(void) { return NULL; } + address generate_empty_entry(void) { return NULL; } address generate_Reference_get_entry(void); address generate_CRC32_update_entry(); address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } #endif // CPU_PPC_VM_INTERPRETERGENERATOR_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp index 7f301e255b0..08e4a4fc54f 100644 --- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp @@ -427,18 +427,6 @@ address AbstractInterpreterGenerator::generate_result_handler_for(BasicType type return entry; } -// Call an accessor method (assuming it is resolved, otherwise drop into -// vanilla (slow path) entry. -address InterpreterGenerator::generate_jump_to_normal_entry(void) { - address entry = __ pc(); - address normal_entry = Interpreter::entry_for_kind(Interpreter::zerolocals); - assert(normal_entry != NULL, "should already be generated."); - __ branch_to_entry(normal_entry, R11_scratch1); - __ flush(); - - return entry; -} - // Abstract method entry. // address InterpreterGenerator::generate_abstract_entry(void) { @@ -529,13 +517,13 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // regular method entry code to generate the NPE. // - address entry = __ pc(); - - const int referent_offset = java_lang_ref_Reference::referent_offset; - guarantee(referent_offset > 0, "referent offset not initialized"); - if (UseG1GC) { - Label slow_path; + address entry = __ pc(); + + const int referent_offset = java_lang_ref_Reference::referent_offset; + guarantee(referent_offset > 0, "referent offset not initialized"); + + Label slow_path; // Debugging not possible, so can't use __ skip_if_jvmti_mode(slow_path, GR31_SCRATCH); @@ -577,13 +565,11 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // Generate regular method entry. __ bind(slow_path); - __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1); - __ flush(); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1); return entry; - } else { - return generate_jump_to_normal_entry(); } + + return NULL; } void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) { diff --git a/hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp b/hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp new file mode 100644 index 00000000000..cab965e3cc9 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_ppc.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + Unimplemented(); + return 0; +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + Unimplemented(); +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + Unimplemented(); +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + return NULL; +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return false; +} diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 703818d0a51..3310f37f57a 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -594,13 +594,6 @@ void MacroAssembler::bxx64_patchable(address dest, relocInfo::relocType rt, bool "can't identify emitted call"); } else { // variant 1: -#if defined(ABI_ELFv2) - nop(); - calculate_address_from_global_toc(R12, dest, true, true, false); - mtctr(R12); - nop(); - nop(); -#else mr(R0, R11); // spill R11 -> R0. // Load the destination address into CTR, @@ -610,7 +603,6 @@ void MacroAssembler::bxx64_patchable(address dest, relocInfo::relocType rt, bool mtctr(R11); mr(R11, R0); // spill R11 <- R0. nop(); -#endif // do the call/jump if (link) { @@ -4292,7 +4284,7 @@ const char* stop_types[] = { static void stop_on_request(int tp, const char* msg) { tty->print("PPC assembly code requires stop: (%s) %s\n", stop_types[tp%/*stop_end*/4], msg); - guarantee(false, err_msg("PPC assembly code requires stop: %s", msg)); + guarantee(false, "PPC assembly code requires stop: %s", msg); } // Call a C-function that prints output. diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp index 5c9d2f1622a..980c043f9e7 100644 --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp @@ -60,7 +60,7 @@ void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_ #ifdef ASSERT static int check_nonzero(const char* xname, int x) { - assert(x != 0, err_msg("%s should be nonzero", xname)); + assert(x != 0, "%s should be nonzero", xname); return x; } #define NONZERO(x) check_nonzero(#x, x) @@ -434,7 +434,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, } default: - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } diff --git a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp index 6a8b9a479af..ecca49af2ef 100644 --- a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp @@ -149,7 +149,7 @@ void NativeCall::verify() { if (!NativeCall::is_call_at(addr)) { tty->print_cr("not a NativeCall at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr - 20, addr + 20, tty); - fatal(err_msg("not a NativeCall at " PTR_FORMAT, p2i(addr))); + fatal("not a NativeCall at " PTR_FORMAT, p2i(addr)); } } #endif // ASSERT @@ -162,7 +162,7 @@ void NativeFarCall::verify() { if (!NativeFarCall::is_far_call_at(addr)) { tty->print_cr("not a NativeFarCall at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr, 20, 20, tty); - fatal(err_msg("not a NativeFarCall at " PTR_FORMAT, p2i(addr))); + fatal("not a NativeFarCall at " PTR_FORMAT, p2i(addr)); } } #endif // ASSERT @@ -308,7 +308,7 @@ void NativeMovConstReg::verify() { ! MacroAssembler::is_bl(*((int*) addr))) { tty->print_cr("not a NativeMovConstReg at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr, 20, 20, tty); - fatal(err_msg("not a NativeMovConstReg at " PTR_FORMAT, p2i(addr))); + fatal("not a NativeMovConstReg at " PTR_FORMAT, p2i(addr)); } } } @@ -346,7 +346,7 @@ void NativeJump::verify() { if (!NativeJump::is_jump_at(addr)) { tty->print_cr("not a NativeJump at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr, 20, 20, tty); - fatal(err_msg("not a NativeJump at " PTR_FORMAT, p2i(addr))); + fatal("not a NativeJump at " PTR_FORMAT, p2i(addr)); } } #endif // ASSERT diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index 5e0e977e287..d5f6486056b 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -2064,6 +2064,10 @@ const bool Matcher::match_rule_supported(int opcode) { return true; // Per default match rules are supported. } +const int Matcher::float_pressure(int default_pressure_threshold) { + return default_pressure_threshold; +} + int Matcher::regnum_to_fpu_offset(int regnum) { // No user for this method? Unimplemented(); diff --git a/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp b/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp index 69dc0551f7b..f075c714748 100644 --- a/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp @@ -125,8 +125,5 @@ address Relocation::pd_get_address_from_code() { void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { -} - void metadata_Relocation::pd_fix_value(address x) { } diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index f3b02e0bf9f..e6853776063 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -475,9 +475,8 @@ void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_siz // Is vector's size (in bytes) bigger than a size saved by default? bool SharedRuntime::is_wide_vector(int size) { - ResourceMark rm; // Note, MaxVectorSize == 8 on PPC64. - assert(size <= 8, err_msg_res("%d bytes vectors are not supported", size)); + assert(size <= 8, "%d bytes vectors are not supported", size); return size > 8; } #ifdef COMPILER2 @@ -957,11 +956,11 @@ static address gen_c2i_adapter(MacroAssembler *masm, return c2i_entrypoint; } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Load method's entry-point from method. __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); @@ -1631,7 +1630,7 @@ static void gen_special_dispatch(MacroAssembler* masm, } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg_res("unexpected intrinsic id %d", iid)); + fatal("unexpected intrinsic id %d", iid); } if (member_reg != noreg) { diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index 8809e163067..1f0d252229d 100644 --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp @@ -841,7 +841,7 @@ class StubGenerator: public StubCodeGenerator { // Only called by MacroAssembler::verify_oop static void verify_oop_helper(const char* message, oop o) { if (!o->is_oop_or_null()) { - fatal(message); + fatal("%s", message); } ++ StubRoutines::_verify_oop_count; } diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp index b6d8e26b18d..361e637d253 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp @@ -620,7 +620,7 @@ inline bool math_entry_available(AbstractInterpreter::MethodKind kind) { address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { if (!math_entry_available(kind)) { NOT_PRODUCT(__ should_not_reach_here();) - return Interpreter::entry_for_kind(Interpreter::zerolocals); + return NULL; } address entry = __ pc(); @@ -1126,14 +1126,6 @@ address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { generate_fixed_frame(false, Rsize_of_parameters, Rsize_of_locals); -#ifdef FAST_DISPATCH - __ unimplemented("Fast dispatch in generate_normal_entry"); -#if 0 - __ set((intptr_t)Interpreter::dispatch_table(), IdispatchTables); - // Set bytecode dispatch table base. -#endif -#endif - // -------------------------------------------------------------------------- // Zero out non-parameter locals. // Note: *Always* zero out non-parameter locals as Sparc does. It's not @@ -1266,9 +1258,8 @@ address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { * int java.util.zip.CRC32.update(int crc, int b) */ address InterpreterGenerator::generate_CRC32_update_entry() { - address start = __ pc(); // Remember stub start address (is rtn value). - if (UseCRC32Intrinsics) { + address start = __ pc(); // Remember stub start address (is rtn value). Label slow_path; // Safepoint check @@ -1313,11 +1304,11 @@ address InterpreterGenerator::generate_CRC32_update_entry() { // Generate a vanilla native entry as the slow path. BLOCK_COMMENT("} CRC32_update"); BIND(slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native), R11_scratch1); + return start; } - (void) generate_native_entry(false); - - return start; + return NULL; } // CRC32 Intrinsics. @@ -1327,9 +1318,8 @@ address InterpreterGenerator::generate_CRC32_update_entry() { * int java.util.zip.CRC32.updateByteBuffer(int crc, long* buf, int off, int len) */ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { - address start = __ pc(); // Remember stub start address (is rtn value). - if (UseCRC32Intrinsics) { + address start = __ pc(); // Remember stub start address (is rtn value). Label slow_path; // Safepoint check @@ -1406,11 +1396,11 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret // Generate a vanilla native entry as the slow path. BLOCK_COMMENT("} CRC32_updateBytes(Buffer)"); BIND(slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native), R11_scratch1); + return start; } - (void) generate_native_entry(false); - - return start; + return NULL; } // These should never be compiled since the interpreter will prefer diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp index 42ed9b6b992..d4fd95ebce1 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp @@ -389,7 +389,7 @@ class Assembler : public AbstractAssembler { static void assert_signed_range(intptr_t x, int nbits) { assert(nbits == 32 || (-(1 << nbits-1) <= x && x < ( 1 << nbits-1)), - err_msg("value out of range: x=" INTPTR_FORMAT ", nbits=%d", x, nbits)); + "value out of range: x=" INTPTR_FORMAT ", nbits=%d", x, nbits); } static void assert_signed_word_disp_range(intptr_t x, int nbits) { diff --git a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp index 3fc18fa4dd0..39592b6e0eb 100644 --- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp @@ -64,6 +64,7 @@ define_pd_global(bool, OptoPeephole, false); define_pd_global(bool, UseCISCSpill, false); define_pd_global(bool, OptoBundling, false); define_pd_global(bool, OptoScheduling, true); +define_pd_global(bool, OptoRegScheduling, false); #ifdef _LP64 // We need to make sure that all generated code is within diff --git a/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp index b6021917710..d56af1661b1 100644 --- a/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp @@ -53,14 +53,15 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { -#ifdef COMPILER2 +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from calling // compiled code to calling interpreted code. // set (empty), G5 // jmp -1 - address mark = cbuf.insts_mark(); // Get mark within main instrs section. + if (mark == NULL) { + mark = cbuf.insts_mark(); // Get mark within main instrs section. + } MacroAssembler _masm(&cbuf); @@ -80,12 +81,11 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { __ delayed()->nop(); + assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size"); + // Update current stubs pointer and restore code_end. __ end_a_stub(); return base; -#else - ShouldNotReachHere(); -#endif } #undef __ diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp b/hotspot/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp index 2dc68c74f63..70d7000b3c8 100644 --- a/hotspot/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp @@ -31,6 +31,7 @@ void generate_more_monitors(); void generate_deopt_handling(); + void lock_method(void); void adjust_callers_stack(Register args); void generate_compute_interpreter_state(const Register state, const Register prev_state, diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp index 4a84b6c3387..8fd601277c7 100644 --- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp @@ -468,7 +468,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_jump_to_normal_entry(); + return NULL; } // @@ -1164,7 +1164,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register } // Find preallocated monitor and lock method (C++ interpreter) // -void InterpreterGenerator::lock_method(void) { +void CppInterpreterGenerator::lock_method() { // Lock the current method. // Destroys registers L2_scratch, L3_scratch, O0 // diff --git a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp index 9446fdbc2c7..36f660b554b 100644 --- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp @@ -52,19 +52,27 @@ define_pd_global(intx, OptoLoopAlignment, 16); // = 4*wordSize define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC define_pd_global(intx, InlineSmallCode, 1500); +#define DEFAULT_STACK_YELLOW_PAGES (2) +#define DEFAULT_STACK_RED_PAGES (1) + #ifdef _LP64 // Stack slots are 2X larger in LP64 than in the 32 bit VM. define_pd_global(intx, ThreadStackSize, 1024); define_pd_global(intx, VMThreadStackSize, 1024); -define_pd_global(intx, StackShadowPages, 10 DEBUG_ONLY(+1)); +#define DEFAULT_STACK_SHADOW_PAGES (10 DEBUG_ONLY(+1)) #else define_pd_global(intx, ThreadStackSize, 512); define_pd_global(intx, VMThreadStackSize, 512); -define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+1)); -#endif +#define DEFAULT_STACK_SHADOW_PAGES (3 DEBUG_ONLY(+1)) +#endif // _LP64 -define_pd_global(intx, StackYellowPages, 2); -define_pd_global(intx, StackRedPages, 1); +#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES +#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES +#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES + +define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); +define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); +define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); @@ -82,6 +90,7 @@ define_pd_global(uintx, TypeProfileLevel, 111); \ product(intx, UseVIS, 99, \ "Highest supported VIS instructions set on Sparc") \ + range(0, 99) \ \ product(bool, UseCBCond, false, \ "Use compare and branch instruction on SPARC") \ @@ -91,12 +100,14 @@ define_pd_global(uintx, TypeProfileLevel, 111); \ product(intx, BlockZeroingLowLimit, 2048, \ "Minimum size in bytes when block zeroing will be used") \ + range(1, max_jint) \ \ product(bool, UseBlockCopy, false, \ "Use special cpu instructions for block copy") \ \ product(intx, BlockCopyLowLimit, 2048, \ "Minimum size in bytes when block copy will be used") \ + range(1, max_jint) \ \ develop(bool, UseV8InstrsOnly, false, \ "Use SPARC-V8 Compliant instruction subset") \ @@ -108,9 +119,11 @@ define_pd_global(uintx, TypeProfileLevel, 111); "Do not use swap instructions, but only CAS (in a loop) on SPARC")\ \ product(uintx, ArraycopySrcPrefetchDistance, 0, \ - "Distance to prefetch source array in arracopy") \ + "Distance to prefetch source array in arraycopy") \ + constraint(ArraycopySrcPrefetchDistanceConstraintFunc, AfterErgo) \ \ product(uintx, ArraycopyDstPrefetchDistance, 0, \ - "Distance to prefetch destination array in arracopy") \ + "Distance to prefetch destination array in arraycopy") \ + constraint(ArraycopyDstPrefetchDistanceConstraintFunc, AfterErgo) \ #endif // CPU_SPARC_VM_GLOBALS_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index e69dba4d531..b53156f1393 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -59,6 +59,13 @@ const Address InterpreterMacroAssembler::d_tmp(FP, (frame::interpreter_frame_d_s #endif // CC_INTERP +void InterpreterMacroAssembler::jump_to_entry(address entry) { + assert(entry, "Entry must have been generated by now"); + AddressLiteral al(entry); + jump_to(al, G3_scratch); + delayed()->nop(); +} + void InterpreterMacroAssembler::compute_extra_locals_size_in_bytes(Register args_size, Register locals_size, Register delta) { // Note: this algorithm is also used by C1's OSR entry sequence. // Any changes should also be applied to CodeEmitter::emit_osr_entry(). @@ -1643,26 +1650,73 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. +#if INCLUDE_JVMCI + if (MethodProfileWidth == 0) { + update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); + } +#else update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); - bind (profile_continue); +#endif + bind(profile_continue); } } -void InterpreterMacroAssembler::record_klass_in_profile_helper( - Register receiver, Register scratch, - int start_row, Label& done, bool is_virtual_call) { +#if INCLUDE_JVMCI +void InterpreterMacroAssembler::profile_called_method(Register method, Register scratch) { + assert_different_registers(method, scratch); + if (ProfileInterpreter && MethodProfileWidth > 0) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + Label done; + record_item_in_profile_helper(method, scratch, 0, done, MethodProfileWidth, + &VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset())); + bind(done); + + update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); + bind(profile_continue); + } +} +#endif // INCLUDE_JVMCI + +void InterpreterMacroAssembler::record_klass_in_profile_helper(Register receiver, Register scratch, + Label& done, bool is_virtual_call) { if (TypeProfileWidth == 0) { if (is_virtual_call) { increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); } - return; - } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + increment_mdp_data_at(in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()), scratch); + } +#endif + } else { + int non_profiled_offset = -1; + if (is_virtual_call) { + non_profiled_offset = in_bytes(CounterData::count_offset()); + } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()); + } +#endif - int last_row = VirtualCallData::row_limit() - 1; + record_item_in_profile_helper(receiver, scratch, 0, done, TypeProfileWidth, + &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); + } +} + +void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, + Register scratch, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset) { + int last_row = total_rows - 1; assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the receiver and for null. + // Test this row for both the item and for null. // Take any of three different outcomes: - // 1. found receiver => increment count and goto done + // 1. found item => increment count and goto done // 2. found null => keep looking for case 1, maybe allocate this cell // 3. found something else => keep looking for cases 1 and 2 // Case 3 is handled by a recursive call. @@ -1670,28 +1724,28 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( Label next_test; bool test_for_null_also = (row == start_row); - // See if the receiver is receiver[n]. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); - test_mdp_data_at(recvr_offset, receiver, next_test, scratch); + // See if the item is item[n]. + int item_offset = in_bytes(item_offset_fn(row)); + test_mdp_data_at(item_offset, item, next_test, scratch); // delayed()->tst(scratch); - // The receiver is receiver[n]. Increment count[n]. - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); + // The receiver is item[n]. Increment count[n]. + int count_offset = in_bytes(item_count_offset_fn(row)); increment_mdp_data_at(count_offset, scratch); ba_short(done); bind(next_test); if (test_for_null_also) { Label found_null; - // Failed the equality check on receiver[n]... Test for null. + // Failed the equality check on item[n]... Test for null. if (start_row == last_row) { // The only thing left to do is handle the null case. - if (is_virtual_call) { + if (non_profiled_offset >= 0) { brx(Assembler::zero, false, Assembler::pn, found_null); delayed()->nop(); - // Receiver did not match any saved receiver and there is no empty row for it. + // Item did not match any saved item and there is no empty row for it. // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); + increment_mdp_data_at(non_profiled_offset, scratch); ba_short(done); bind(found_null); } else { @@ -1705,21 +1759,22 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( delayed()->nop(); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, scratch, start_row + 1, done, is_virtual_call); + record_item_in_profile_helper(item, scratch, start_row + 1, done, total_rows, + item_offset_fn, item_count_offset_fn, non_profiled_offset); - // Found a null. Keep searching for a matching receiver, + // Found a null. Keep searching for a matching item, // but remember that this is an empty (unused) slot. bind(found_null); } } - // In the fall-through case, we found no matching receiver, but we - // observed the receiver[start_row] is NULL. + // In the fall-through case, we found no matching item, but we + // observed the item[start_row] is NULL. - // Fill in the receiver field and increment the count. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); - set_mdp_data_at(recvr_offset, receiver); - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); + // Fill in the item field and increment the count. + int item_offset = in_bytes(item_offset_fn(start_row)); + set_mdp_data_at(item_offset, item); + int count_offset = in_bytes(item_count_offset_fn(start_row)); mov(DataLayout::counter_increment, scratch); set_mdp_data_at(count_offset, scratch); if (start_row > 0) { @@ -1732,7 +1787,7 @@ void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, assert(ProfileInterpreter, "must be profiling"); Label done; - record_klass_in_profile_helper(receiver, scratch, 0, done, is_virtual_call); + record_klass_in_profile_helper(receiver, scratch, done, is_virtual_call); bind (done); } @@ -1788,7 +1843,7 @@ void InterpreterMacroAssembler::profile_null_seen(Register scratch) { // The method data pointer needs to be updated. int mdp_delta = in_bytes(BitData::bit_data_size()); if (TypeProfileCasts) { - mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size()); } update_mdp_by_constant(mdp_delta); @@ -1806,7 +1861,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register klass, int mdp_delta = in_bytes(BitData::bit_data_size()); if (TypeProfileCasts) { - mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size()); // Record the object type. record_klass_in_profile(klass, scratch, false); @@ -1828,7 +1883,7 @@ void InterpreterMacroAssembler::profile_typecheck_failed(Register scratch) { int count_offset = in_bytes(CounterData::count_offset()); // Back up the address, since we have already bumped the mdp. - count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); + count_offset -= in_bytes(ReceiverTypeData::receiver_type_data_size()); // *Decrement* the counter. We expect to see zero or small negatives. increment_mdp_data_at(count_offset, scratch, true); diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp index 042cccd2ec2..b944bf089c3 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp @@ -30,6 +30,8 @@ // This file specializes the assember with interpreter-specific macros +typedef ByteSize (*OffsetFunction)(uint); + REGISTER_DECLARATION( Register, Otos_i , O0); // tos for ints, etc REGISTER_DECLARATION( Register, Otos_l , O0); // for longs REGISTER_DECLARATION( Register, Otos_l1, O0); // for 1st part of longs @@ -80,6 +82,8 @@ class InterpreterMacroAssembler: public MacroAssembler { InterpreterMacroAssembler(CodeBuffer* c) : MacroAssembler(c) {} + void jump_to_entry(address entry); + #ifndef CC_INTERP virtual void load_earlyret_value(TosState state); @@ -299,7 +303,11 @@ class InterpreterMacroAssembler: public MacroAssembler { void record_klass_in_profile(Register receiver, Register scratch, bool is_virtual_call); void record_klass_in_profile_helper(Register receiver, Register scratch, - int start_row, Label& done, bool is_virtual_call); + Label& done, bool is_virtual_call); + void record_item_in_profile_helper(Register item, + Register scratch, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset); void update_mdp_by_offset(int offset_of_disp, Register scratch); void update_mdp_by_offset(Register reg, int offset_of_disp, @@ -312,6 +320,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_call(Register scratch); void profile_final_call(Register scratch); void profile_virtual_call(Register receiver, Register scratch, bool receiver_can_be_null = false); + void profile_called_method(Register method, Register scratch) NOT_JVMCI_RETURN; void profile_ret(TosState state, Register return_bci, Register scratch); void profile_null_seen(Register scratch); void profile_typecheck(Register klass, Register scratch); diff --git a/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp b/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp index de4997bce7a..287e9f2971a 100644 --- a/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp @@ -34,11 +34,9 @@ address generate_abstract_entry(void); // there are no math intrinsics on sparc address generate_math_entry(AbstractInterpreter::MethodKind kind) { return NULL; } - address generate_jump_to_normal_entry(void); - address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } - address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } + address generate_accessor_entry(void) { return NULL; } + address generate_empty_entry(void) { return NULL; } address generate_Reference_get_entry(void); - void lock_method(void); void save_native_result(void); void restore_native_result(void); @@ -48,4 +46,5 @@ // Not supported address generate_CRC32_update_entry() { return NULL; } address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } #endif // CPU_SPARC_VM_INTERPRETERGENERATOR_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp index f8d8f590c99..c5fc75d049f 100644 --- a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp @@ -241,15 +241,6 @@ void InterpreterGenerator::generate_counter_overflow(Label& Lcontinue) { // Various method entries -address InterpreterGenerator::generate_jump_to_normal_entry(void) { - address entry = __ pc(); - assert(Interpreter::entry_for_kind(Interpreter::zerolocals) != NULL, "should already be generated"); - AddressLiteral al(Interpreter::entry_for_kind(Interpreter::zerolocals)); - __ jump_to(al, G3_scratch); - __ delayed()->nop(); - return entry; -} - // Abstract method entry // Attempt to execute abstract method. Throw exception // diff --git a/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp b/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp new file mode 100644 index 00000000000..10da55791d3 --- /dev/null +++ b/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_sparc.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + if (inst->is_call() || inst->is_jump()) { + return pc_offset + NativeCall::instruction_size; + } else if (inst->is_call_reg()) { + return pc_offset + NativeCallReg::instruction_size; + } else if (inst->is_sethi()) { + return pc_offset + NativeFarCall::instruction_size; + } else { + fatal("unsupported type of instruction for call site"); + return 0; + } +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + address pc = _instructions->start() + pc_offset; + Handle obj = HotSpotObjectConstantImpl::object(constant); + jobject value = JNIHandles::make_local(obj()); + if (HotSpotObjectConstantImpl::compressed(constant)) { +#ifdef _LP64 + int oop_index = _oop_recorder->find_index(value); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + _instructions->relocate(pc, rspec, 1); +#else + fatal("compressed oop on 32bit"); +#endif + } else { + NativeMovConstReg* move = nativeMovConstReg_at(pc); + move->set_data((intptr_t) value); + + // We need two relocations: one on the sethi and one on the add. + int oop_index = _oop_recorder->find_index(value); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + _instructions->relocate(pc + NativeMovConstReg::sethi_offset, rspec); + _instructions->relocate(pc + NativeMovConstReg::add_offset, rspec); + } +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + address pc = _instructions->start() + pc_offset; + NativeInstruction* inst = nativeInstruction_at(pc); + NativeInstruction* inst1 = nativeInstruction_at(pc + 4); + if(inst->is_sethi() && inst1->is_nop()) { + address const_start = _constants->start(); + address dest = _constants->start() + data_offset; + if(_constants_size > 0) { + _instructions->relocate(pc + NativeMovConstReg::sethi_offset, internal_word_Relocation::spec((address) dest)); + _instructions->relocate(pc + NativeMovConstReg::add_offset, internal_word_Relocation::spec((address) dest)); + } + TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset); + }else { + int const_size = align_size_up(_constants->end()-_constants->start(), CodeEntryAlignment); + NativeMovRegMem* load = nativeMovRegMem_at(pc); + // This offset must match with SPARCLoadConstantTableBaseOp.emitCode + load->set_offset(- (const_size - data_offset + Assembler::min_simm13())); + TRACE_jvmci_3("relocating ld at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset); + } +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + fatal("CodeInstaller::pd_relocate_CodeBlob - sparc unimp"); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + address pc = (address) inst; + if (inst->is_call()) { + NativeCall* call = nativeCall_at(pc); + call->set_destination((address) foreign_call_destination); + _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec()); + } else if (inst->is_sethi()) { + NativeJump* jump = nativeJump_at(pc); + jump->set_jump_destination((address) foreign_call_destination); + _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec()); + } else { + fatal(err_msg("unknown call or jump instruction at " PTR_FORMAT, p2i(pc))); + } + TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst)); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { +#ifdef ASSERT + Method* method = NULL; + // we need to check, this might also be an unresolved method + if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { + method = getMethodFromHotSpotMethod(hotspot_method); + } +#endif + switch (_next_call_type) { + case INLINE_INVOKE: + break; + case INVOKEVIRTUAL: + case INVOKEINTERFACE: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc)); + break; + } + case INVOKESTATIC: { + assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_static_call_stub()); + _instructions->relocate(call->instruction_address(), relocInfo::static_call_type); + break; + } + case INVOKESPECIAL: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type); + break; + } + default: + fatal("invalid _next_call_type value"); + break; + } +} + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + switch (mark) { + case POLL_NEAR: + fatal("unimplemented"); + break; + case POLL_FAR: + _instructions->relocate(pc, relocInfo::poll_type); + break; + case POLL_RETURN_NEAR: + fatal("unimplemented"); + break; + case POLL_RETURN_FAR: + _instructions->relocate(pc, relocInfo::poll_return_type); + break; + default: + fatal("invalid mark value"); + break; + } +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + if (jvmci_reg < RegisterImpl::number_of_registers) { + return as_Register(jvmci_reg)->as_VMReg(); + } else { + jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers; + floatRegisterNumber += MAX2(0, floatRegisterNumber-32); // Beginning with f32, only every second register is going to be addressed + if (floatRegisterNumber < FloatRegisterImpl::number_of_registers) { + return as_FloatRegister(floatRegisterNumber)->as_VMReg(); + } + ShouldNotReachHere(); + return NULL; + } +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return !hotspotRegister->is_FloatRegister(); +} diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index 84fa71cb119..2647d327bd5 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -1596,7 +1596,7 @@ void MacroAssembler::debug(char* msg, RegistersForDebugging* regs) { else { ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg); } - assert(false, err_msg("DEBUG MESSAGE: %s", msg)); + assert(false, "DEBUG MESSAGE: %s", msg); } diff --git a/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp b/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp index eabafbebc3b..aa4e4c16bb7 100644 --- a/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp @@ -61,8 +61,8 @@ inline void fill_subword(void* start, void* end, int value) { " sub %[offset], %[end], %[offset]\n\t" // offset := start - end " sllx %[offset], 2, %[offset]\n\t" // scale offset for instruction size of 4 " add %[offset], 40, %[offset]\n\t" // offset += 10 * instruction size - " rd %pc, %[pc]\n\t" // dispatch on scaled offset - " jmpl %[pc]+%[offset], %g0\n\t" + " rd %%pc, %[pc]\n\t" // dispatch on scaled offset + " jmpl %[pc]+%[offset], %%g0\n\t" " nop\n\t" // DISPATCH: no direct reference, but without it the store block may be elided. "1:\n\t" @@ -108,7 +108,7 @@ void memset_with_concurrent_readers(void* to, int value, size_t size) { // Unroll loop x8. " sub %[aend], %[ato], %[temp]\n\t" " cmp %[temp], 56\n\t" // cc := (aligned_end - aligned_to) > 7 words - " ba %xcc, 2f\n\t" // goto TEST always + " ba %%xcc, 2f\n\t" // goto TEST always " sub %[aend], 56, %[temp]\n\t" // limit := aligned_end - 7 words // LOOP: "1:\n\t" // unrolled x8 store loop top @@ -123,7 +123,7 @@ void memset_with_concurrent_readers(void* to, int value, size_t size) { " stx %[xvalue], [%[ato]-8]\n\t" // TEST: "2:\n\t" - " bgu,a %xcc, 1b\n\t" // goto LOOP if more than 7 words remaining + " bgu,a %%xcc, 1b\n\t" // goto LOOP if more than 7 words remaining " add %[ato], 64, %[ato]\n\t" // aligned_to += 8, for next iteration // Fill remaining < 8 full words. // Dispatch on (aligned_end - aligned_to). @@ -132,8 +132,8 @@ void memset_with_concurrent_readers(void* to, int value, size_t size) { " sub %[ato], %[aend], %[ato]\n\t" // offset := aligned_to - aligned_end " srax %[ato], 1, %[ato]\n\t" // scale offset for instruction size of 4 " add %[ato], 40, %[ato]\n\t" // offset += 10 * instruction size - " rd %pc, %[temp]\n\t" // dispatch on scaled offset - " jmpl %[temp]+%[ato], %g0\n\t" + " rd %%pc, %[temp]\n\t" // dispatch on scaled offset + " jmpl %[temp]+%[ato], %%g0\n\t" " nop\n\t" // DISPATCH: no direct reference, but without it the store block may be elided. "3:\n\t" diff --git a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp index ba1f5c90753..5246059b470 100644 --- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp @@ -56,7 +56,7 @@ void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_ #ifdef ASSERT static int check_nonzero(const char* xname, int x) { - assert(x != 0, err_msg("%s should be nonzero", xname)); + assert(x != 0, "%s should be nonzero", xname); return x; } #define NONZERO(x) check_nonzero(#x, x) @@ -453,7 +453,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, } default: - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } diff --git a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp index eaf543e128b..44e0470133e 100644 --- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp @@ -53,6 +53,7 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { bool is_nop() { return long_at(0) == nop_instruction(); } bool is_call() { return is_op(long_at(0), Assembler::call_op); } + bool is_call_reg() { return is_op(long_at(0), Assembler::arith_op); } bool is_sethi() { return (is_op2(long_at(0), Assembler::sethi_op2) && inv_rd(long_at(0)) != G0); } @@ -415,6 +416,19 @@ inline NativeCall* nativeCall_at(address instr) { return call; } +class NativeCallReg: public NativeInstruction { + public: + enum Sparc_specific_constants { + instruction_size = 8, + return_address_offset = 8, + instruction_offset = 0 + }; + + address next_instruction_address() const { + return addr_at(instruction_size); + } +}; + // The NativeFarCall is an abstraction for accessing/manipulating native call-anywhere // instructions in the sparcv9 vm. Used to call native methods which may be loaded // anywhere in the address space, possibly out of reach of a call instruction. diff --git a/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp b/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp index 28d7f917562..a9f2421c0fb 100644 --- a/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp @@ -197,8 +197,5 @@ address Relocation::pd_get_address_from_code() { void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { -} - void metadata_Relocation::pd_fix_value(address x) { } diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index 2c4e892f467..449488b94c9 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -43,6 +43,9 @@ #include "compiler/compileBroker.hpp" #include "shark/sharkCompiler.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif #define __ masm-> @@ -316,7 +319,7 @@ void RegisterSaver::restore_result_registers(MacroAssembler* masm) { // 8 bytes FP registers are saved by default on SPARC. bool SharedRuntime::is_wide_vector(int size) { // Note, MaxVectorSize == 8 on SPARC. - assert(size <= 8, err_msg_res("%d bytes vectors are not supported", size)); + assert(size <= 8, "%d bytes vectors are not supported", size); return size > 8; } @@ -464,7 +467,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, break; default: - fatal(err_msg_res("unknown basic type %d", sig_bt[i])); + fatal("unknown basic type %d", sig_bt[i]); break; } } @@ -513,10 +516,10 @@ class AdapterGenerator { const VMRegPair *regs, Label& skip_fixup); void gen_i2c_adapter(int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs); + // VMReg max_arg, + int comp_args_on_stack, // VMRegStackSlots + const BasicType *sig_bt, + const VMRegPair *regs); AdapterGenerator(MacroAssembler *_masm) : masm(_masm) {} }; @@ -760,13 +763,11 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg __ bind(L_fail); } -void AdapterGenerator::gen_i2c_adapter( - int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs) { - +void AdapterGenerator::gen_i2c_adapter(int total_args_passed, + // VMReg max_arg, + int comp_args_on_stack, // VMRegStackSlots + const BasicType *sig_bt, + const VMRegPair *regs) { // Generate an I2C adapter: adjust the I-frame to make space for the C-frame // layout. Lesp was saved by the calling I-frame and will be restored on // return. Meanwhile, outgoing arg space is all owned by the callee @@ -990,6 +991,21 @@ void AdapterGenerator::gen_i2c_adapter( // Jump to the compiled code just as if compiled code was doing it. __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // check if this call should be routed towards a specific entry point + __ ld(Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), G1); + __ cmp(G0, G1); + Label no_alternative_target; + __ br(Assembler::equal, false, Assembler::pn, no_alternative_target); + __ delayed()->nop(); + + __ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()), G3); + __ st_ptr(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); + + __ bind(no_alternative_target); + } +#endif // INCLUDE_JVMCI // 6243940 We might end up in handle_wrong_method if // the callee is deoptimized as we race thru here. If that @@ -1006,6 +1022,15 @@ void AdapterGenerator::gen_i2c_adapter( __ delayed()->nop(); } +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { + AdapterGenerator agen(masm); + agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs); +} + // --------------------------------------------------------------- AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, int total_args_passed, @@ -1016,9 +1041,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm AdapterFingerPrint* fingerprint) { address i2c_entry = __ pc(); - AdapterGenerator agen(masm); - - agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs); + gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); // ------------------------------------------------------------------------- @@ -1063,7 +1086,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm } address c2i_entry = __ pc(); - + AdapterGenerator agen(masm); agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, L_skip_fixup); __ flush(); @@ -1859,7 +1882,7 @@ static void gen_special_dispatch(MacroAssembler* masm, } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg_res("unexpected intrinsic id %d", iid)); + fatal("unexpected intrinsic id %d", iid); } if (member_reg != noreg) { @@ -2916,6 +2939,11 @@ void SharedRuntime::generate_deopt_blob() { pad += StackShadowPages*16 + 32; } #endif +#if INCLUDE_JVMCI + if (EnableJVMCI) { + pad += 1000; // Increase the buffer size when compiling for JVMCI + } +#endif #ifdef _LP64 CodeBuffer buffer("deopt_blob", 2100+pad, 512); #else @@ -2982,6 +3010,45 @@ void SharedRuntime::generate_deopt_blob() { __ ba(cont); __ delayed()->mov(Deoptimization::Unpack_deopt, L0deopt_mode); + +#if INCLUDE_JVMCI + Label after_fetch_unroll_info_call; + int implicit_exception_uncommon_trap_offset = 0; + int uncommon_trap_offset = 0; + + if (EnableJVMCI) { + masm->block_comment("BEGIN implicit_exception_uncommon_trap"); + implicit_exception_uncommon_trap_offset = __ offset() - start; + + __ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()), O7); + __ st_ptr(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); + __ add(O7, -8, O7); + + uncommon_trap_offset = __ offset() - start; + + // Save everything in sight. + (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); + __ set_last_Java_frame(SP, NULL); + + __ ld(G2_thread, in_bytes(JavaThread::pending_deoptimization_offset()), O1); + __ sub(G0, 1, L1); + __ st(L1, G2_thread, in_bytes(JavaThread::pending_deoptimization_offset())); + + __ mov((int32_t)Deoptimization::Unpack_reexecute, L0deopt_mode); + __ mov(G2_thread, O0); + __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)); + __ delayed()->nop(); + oop_maps->add_gc_map( __ offset()-start, map->deep_copy()); + __ get_thread(); + __ add(O7, 8, O7); + __ reset_last_Java_frame(); + + __ ba(after_fetch_unroll_info_call); + __ delayed()->nop(); // Delay slot + masm->block_comment("END implicit_exception_uncommon_trap"); + } // EnableJVMCI +#endif // INCLUDE_JVMCI + int exception_offset = __ offset() - start; // restore G2, the trampoline destroyed it @@ -3004,6 +3071,7 @@ void SharedRuntime::generate_deopt_blob() { int exception_in_tls_offset = __ offset() - start; // No need to update oop_map as each call to save_live_registers will produce identical oopmap + // Opens a new stack frame (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); // Restore G2_thread @@ -3035,7 +3103,12 @@ void SharedRuntime::generate_deopt_blob() { // Reexecute entry, similar to c2 uncommon trap // int reexecute_offset = __ offset() - start; - +#if INCLUDE_JVMCI && !defined(COMPILER1) + if (EnableJVMCI && UseJVMCICompiler) { + // JVMCI does not use this kind of deoptimization + __ should_not_reach_here(); + } +#endif // No need to update oop_map as each call to save_live_registers will produce identical oopmap (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); @@ -3059,6 +3132,11 @@ void SharedRuntime::generate_deopt_blob() { __ reset_last_Java_frame(); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + __ bind(after_fetch_unroll_info_call); + } +#endif // NOTE: we know that only O0/O1 will be reloaded by restore_result_registers // so this move will survive @@ -3124,6 +3202,12 @@ void SharedRuntime::generate_deopt_blob() { masm->flush(); _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_words); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset); + _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); + } +#endif } #ifdef COMPILER2 diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 04491901ddb..886a9c30d02 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -1098,7 +1098,7 @@ void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { Register r = as_Register(ra_->get_encode(this)); CodeSection* consts_section = __ code()->consts(); int consts_size = consts_section->align_at_start(consts_section->size()); - assert(constant_table.size() == consts_size, err_msg("must be: %d == %d", constant_table.size(), consts_size)); + assert(constant_table.size() == consts_size, "must be: %d == %d", constant_table.size(), consts_size); if (UseRDPCForConstantTableBase) { // For the following RDPC logic to work correctly the consts @@ -1860,6 +1860,10 @@ const bool Matcher::match_rule_supported(int opcode) { return true; // Per default match rules are supported. } +const int Matcher::float_pressure(int default_pressure_threshold) { + return default_pressure_threshold; +} + int Matcher::regnum_to_fpu_offset(int regnum) { return regnum - 32; // The FP registers are in the second chunk } diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index e9ffb17136e..703a1b0f30c 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -204,6 +204,20 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) { address entry = __ pc(); __ get_constant_pool_cache(LcpoolCache); // load LcpoolCache +#if INCLUDE_JVMCI + // Check if we need to take lock at entry of synchronized method. + if (UseJVMCICompiler) { + Label L; + Address pending_monitor_enter_addr(G2_thread, JavaThread::pending_monitorenter_offset()); + __ ldbool(pending_monitor_enter_addr, Gtemp); // Load if pending monitor enter + __ cmp_and_br_short(Gtemp, G0, Assembler::equal, Assembler::pn, L); + // Clear flag. + __ stbool(G0, pending_monitor_enter_addr); + // Take lock. + lock_method(); + __ bind(L); + } +#endif { Label L; Address exception_addr(G2_thread, Thread::pending_exception_offset()); __ ld_ptr(exception_addr, Gtemp); // Load pending exception. @@ -349,7 +363,7 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile // Allocate monitor and lock method (asm interpreter) // ebx - Method* // -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { __ ld(Lmethod, in_bytes(Method::access_flags_offset()), O0); // Load access flags. #ifdef ASSERT @@ -779,14 +793,14 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // Generate regular method entry __ bind(slow_path); - (void) generate_normal_entry(false); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); return entry; } #endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_jump_to_normal_entry(); + return NULL; } // diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.hpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.hpp index 9b6cd216fbb..43d7cef64f4 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.hpp @@ -37,9 +37,9 @@ #ifdef _LP64 // The sethi() instruction generates lots more instructions when shell // stack limit is unlimited, so that's why this is much bigger. - const static int InterpreterCodeSize = 210 * K; + const static int InterpreterCodeSize = 260 * K; #else - const static int InterpreterCodeSize = 180 * K; + const static int InterpreterCodeSize = 230 * K; #endif #endif // CPU_SPARC_VM_TEMPLATEINTERPRETER_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index 8909c404003..48da68c0cba 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -2949,12 +2949,14 @@ void TemplateTable::prepare_invoke(int byte_no, void TemplateTable::generate_vtable_call(Register Rrecv, Register Rindex, Register Rret) { + Register Rtemp = G4_scratch; Register Rcall = Rindex; assert_different_registers(Rcall, G5_method, Gargs, Rret); // get target Method* & entry point __ lookup_virtual_method(Rrecv, Rindex, G5_method); __ profile_arguments_type(G5_method, Rcall, Gargs, true); + __ profile_called_method(G5_method, Rtemp); __ call_from_interpreter(Rcall, Gargs, Rret); } @@ -3211,6 +3213,7 @@ void TemplateTable::invokeinterface(int byte_no) { assert_different_registers(Rcall, G5_method, Gargs, Rret); __ profile_arguments_type(G5_method, Rcall, Gargs, true); + __ profile_called_method(G5_method, Rscratch); __ call_from_interpreter(Rcall, Gargs, Rret); } @@ -3486,7 +3489,8 @@ void TemplateTable::checkcast() { Register RspecifiedKlass = O4; // Check for casting a NULL - __ br_null_short(Otos_i, Assembler::pn, is_null); + __ br_null(Otos_i, false, Assembler::pn, is_null); + __ delayed()->nop(); // Get value klass in RobjKlass __ load_klass(Otos_i, RobjKlass); // get value klass @@ -3542,7 +3546,8 @@ void TemplateTable::instanceof() { Register RspecifiedKlass = O4; // Check for casting a NULL - __ br_null_short(Otos_i, Assembler::pt, is_null); + __ br_null(Otos_i, false, Assembler::pt, is_null); + __ delayed()->nop(); // Get value klass in RobjKlass __ load_klass(Otos_i, RobjKlass); // get value klass diff --git a/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp b/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp index 56805aed838..e0be8b60ff9 100644 --- a/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp @@ -37,10 +37,11 @@ /******************************/ \ /* JavaFrameAnchor */ \ /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _flags, int) - -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + volatile_nonstatic_field(JavaFrameAnchor, _flags, int) \ + static_field(VM_Version, _features, int) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + declare_toplevel_type(VM_Version) #define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ /******************************/ \ @@ -78,7 +79,11 @@ declare_c2_constant(R_G4_num) \ declare_c2_constant(R_G5_num) \ declare_c2_constant(R_G6_num) \ - declare_c2_constant(R_G7_num) + declare_c2_constant(R_G7_num) \ + declare_constant(VM_Version::vis1_instructions_m) \ + declare_constant(VM_Version::vis2_instructions_m) \ + declare_constant(VM_Version::vis3_instructions_m) \ + declare_constant(VM_Version::cbcond_instructions_m) #define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index c9b0690c648..0438025fed3 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -40,10 +40,6 @@ void VM_Version::initialize() { PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes(); PrefetchFieldsAhead = prefetch_fields_ahead(); - assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 1, "invalid value"); - if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0; - if( AllocatePrefetchInstr > 1 ) AllocatePrefetchInstr = 0; - // Allocation prefetch settings intx cache_line_size = prefetch_data_size(); if( cache_line_size > AllocatePrefetchStepSize ) @@ -59,13 +55,6 @@ void VM_Version::initialize() { AllocatePrefetchDistance = allocate_prefetch_distance(); AllocatePrefetchStyle = allocate_prefetch_style(); - assert((AllocatePrefetchDistance % AllocatePrefetchStepSize) == 0 && - (AllocatePrefetchDistance > 0), "invalid value"); - if ((AllocatePrefetchDistance % AllocatePrefetchStepSize) != 0 || - (AllocatePrefetchDistance <= 0)) { - AllocatePrefetchDistance = AllocatePrefetchStepSize; - } - if (AllocatePrefetchStyle == 3 && !has_blk_init()) { warning("BIS instructions are not available on this CPU"); FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1); @@ -73,13 +62,6 @@ void VM_Version::initialize() { guarantee(VM_Version::has_v9(), "only SPARC v9 is supported"); - assert(ArraycopySrcPrefetchDistance < 4096, "invalid value"); - if (ArraycopySrcPrefetchDistance >= 4096) - ArraycopySrcPrefetchDistance = 4064; - assert(ArraycopyDstPrefetchDistance < 4096, "invalid value"); - if (ArraycopyDstPrefetchDistance >= 4096) - ArraycopyDstPrefetchDistance = 4064; - UseSSE = 0; // Only on x86 and x64 _supports_cx8 = has_v9(); diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp index d1c40e6488e..c21a6ee13d5 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp @@ -29,6 +29,7 @@ #include "runtime/vm_version.hpp" class VM_Version: public Abstract_VM_Version { + friend class VMStructs; protected: enum Feature_Flag { v8_instructions = 0, diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index c7d743c9324..c66c6022bd1 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -733,11 +733,11 @@ address Assembler::locate_operand(address inst, WhichOperand which) { // these asserts are somewhat nonsensical #ifndef _LP64 assert(which == imm_operand || which == disp32_operand, - err_msg("which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip))); + "which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip)); #else assert((which == call32_operand || which == imm_operand) && is_64bit || which == narrow_oop_operand && !is_64bit, - err_msg("which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip))); + "which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip)); #endif // _LP64 return ip; @@ -770,6 +770,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x55: // andnps case 0x56: // orps case 0x57: // xorps + case 0x59: //mulpd case 0x6E: // movd case 0x7E: // movd case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush @@ -877,21 +878,35 @@ address Assembler::locate_operand(address inst, WhichOperand which) { // Check second byte NOT_LP64(assert((0xC0 & *ip) == 0xC0, "shouldn't have LDS and LES instructions")); + int vex_opcode; // First byte if ((0xFF & *inst) == VEX_3bytes) { + vex_opcode = VEX_OPCODE_MASK & *ip; ip++; // third byte is_64bit = ((VEX_W & *ip) == VEX_W); + } else { + vex_opcode = VEX_OPCODE_0F; } ip++; // opcode // To find the end of instruction (which == end_pc_operand). - switch (0xFF & *ip) { - case 0x61: // pcmpestri r, r/a, #8 - case 0x70: // pshufd r, r/a, #8 - case 0x73: // psrldq r, #8 - tail_size = 1; // the imm8 - break; - default: - break; + switch (vex_opcode) { + case VEX_OPCODE_0F: + switch (0xFF & *ip) { + case 0x70: // pshufd r, r/a, #8 + case 0x71: // ps[rl|ra|ll]w r, #8 + case 0x72: // ps[rl|ra|ll]d r, #8 + case 0x73: // ps[rl|ra|ll]q r, #8 + case 0xC2: // cmp[ps|pd|ss|sd] r, r, r/a, #8 + case 0xC4: // pinsrw r, r, r/a, #8 + case 0xC5: // pextrw r/a, r, #8 + case 0xC6: // shufp[s|d] r, r, r/a, #8 + tail_size = 1; // the imm8 + break; + } + break; + case VEX_OPCODE_0F_3A: + tail_size = 1; + break; } ip++; // skip opcode debug_only(has_disp32 = true); // has both kinds of operands! @@ -1604,6 +1619,85 @@ void Assembler::cpuid() { emit_int8((unsigned char)0xA2); } +// Opcode / Instruction Op / En 64 - Bit Mode Compat / Leg Mode Description Implemented +// F2 0F 38 F0 / r CRC32 r32, r / m8 RM Valid Valid Accumulate CRC32 on r / m8. v +// F2 REX 0F 38 F0 / r CRC32 r32, r / m8* RM Valid N.E. Accumulate CRC32 on r / m8. - +// F2 REX.W 0F 38 F0 / r CRC32 r64, r / m8 RM Valid N.E. Accumulate CRC32 on r / m8. - +// +// F2 0F 38 F1 / r CRC32 r32, r / m16 RM Valid Valid Accumulate CRC32 on r / m16. v +// +// F2 0F 38 F1 / r CRC32 r32, r / m32 RM Valid Valid Accumulate CRC32 on r / m32. v +// +// F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E. Accumulate CRC32 on r / m64. v +void Assembler::crc32(Register crc, Register v, int8_t sizeInBytes) { + assert(VM_Version::supports_sse4_2(), ""); + int8_t w = 0x01; + Prefix p = Prefix_EMPTY; + + emit_int8((int8_t)0xF2); + switch (sizeInBytes) { + case 1: + w = 0; + break; + case 2: + case 4: + break; + LP64_ONLY(case 8:) + // This instruction is not valid in 32 bits + // Note: + // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + // + // Page B - 72 Vol. 2C says + // qwreg2 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : 11 qwreg1 qwreg2 + // mem64 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : mod qwreg r / m + // F0!!! + // while 3 - 208 Vol. 2A + // F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E.Accumulate CRC32 on r / m64. + // + // the 0 on a last bit is reserved for a different flavor of this instruction : + // F2 REX.W 0F 38 F0 / r CRC32 r64, r / m8 RM Valid N.E.Accumulate CRC32 on r / m8. + p = REX_W; + break; + default: + assert(0, "Unsupported value for a sizeInBytes argument"); + break; + } + LP64_ONLY(prefix(crc, v, p);) + emit_int8((int8_t)0x0F); + emit_int8(0x38); + emit_int8((int8_t)(0xF0 | w)); + emit_int8(0xC0 | ((crc->encoding() & 0x7) << 3) | (v->encoding() & 7)); +} + +void Assembler::crc32(Register crc, Address adr, int8_t sizeInBytes) { + assert(VM_Version::supports_sse4_2(), ""); + InstructionMark im(this); + int8_t w = 0x01; + Prefix p = Prefix_EMPTY; + + emit_int8((int8_t)0xF2); + switch (sizeInBytes) { + case 1: + w = 0; + break; + case 2: + case 4: + break; + LP64_ONLY(case 8:) + // This instruction is not valid in 32 bits + p = REX_W; + break; + default: + assert(0, "Unsupported value for a sizeInBytes argument"); + break; + } + LP64_ONLY(prefix(crc, adr, p);) + emit_int8((int8_t)0x0F); + emit_int8(0x38); + emit_int8((int8_t)(0xF0 | w)); + emit_operand(crc, adr); +} + void Assembler::cvtdq2pd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); emit_simd_arith_nonds(0xE6, dst, src, VEX_SIMD_F3, /* no_mask_reg */ false, /* legacy_mode */ true); @@ -2399,7 +2493,7 @@ void Assembler::movsbl(Register dst, Address src) { // movsxb void Assembler::movsbl(Register dst, Register src) { // movsxb NOT_LP64(assert(src->has_byte_register(), "must have byte register")); - int encode = prefix_and_encode(dst->encoding(), src->encoding(), true); + int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true); emit_int8(0x0F); emit_int8((unsigned char)0xBE); emit_int8((unsigned char)(0xC0 | encode)); @@ -2516,7 +2610,7 @@ void Assembler::movzbl(Register dst, Address src) { // movzxb void Assembler::movzbl(Register dst, Register src) { // movzxb NOT_LP64(assert(src->has_byte_register(), "must have byte register")); - int encode = prefix_and_encode(dst->encoding(), src->encoding(), true); + int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true); emit_int8(0x0F); emit_int8((unsigned char)0xB6); emit_int8(0xC0 | encode); @@ -2951,6 +3045,15 @@ void Assembler::pextrq(Register dst, XMMRegister src, int imm8) { emit_int8(imm8); } +void Assembler::pextrw(Register dst, XMMRegister src, int imm8) { + assert(VM_Version::supports_sse2(), ""); + int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ true, + VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + emit_int8((unsigned char)0xC5); + emit_int8((unsigned char)(0xC0 | encode)); + emit_int8(imm8); +} + void Assembler::pinsrd(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, /* no_mask_reg */ true, @@ -2969,6 +3072,15 @@ void Assembler::pinsrq(XMMRegister dst, Register src, int imm8) { emit_int8(imm8); } +void Assembler::pinsrw(XMMRegister dst, Register src, int imm8) { + assert(VM_Version::supports_sse2(), ""); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, /* no_mask_reg */ true, + VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + emit_int8((unsigned char)0xC4); + emit_int8((unsigned char)(0xC0 | encode)); + emit_int8(imm8); +} + void Assembler::pmovzxbw(XMMRegister dst, Address src) { assert(VM_Version::supports_sse4_1(), ""); if (VM_Version::supports_evex()) { @@ -3984,6 +4096,16 @@ void Assembler::mulpd(XMMRegister dst, XMMRegister src) { } } +void Assembler::mulpd(XMMRegister dst, Address src) { + _instruction_uses_vl = true; + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + if (VM_Version::supports_evex()) { + emit_simd_arith_q(0x59, dst, src, VEX_SIMD_66); + } else { + emit_simd_arith(0x59, dst, src, VEX_SIMD_66); + } +} + void Assembler::mulps(XMMRegister dst, XMMRegister src) { _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); @@ -4172,6 +4294,26 @@ void Assembler::vandps(XMMRegister dst, XMMRegister nds, Address src, int vector emit_vex_arith(0x54, dst, nds, src, VEX_SIMD_NONE, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_dq); } +void Assembler::unpckhpd(XMMRegister dst, XMMRegister src) { + _instruction_uses_vl = true; + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + if (VM_Version::supports_evex()) { + emit_simd_arith_q(0x15, dst, src, VEX_SIMD_66); + } else { + emit_simd_arith(0x15, dst, src, VEX_SIMD_66); + } +} + +void Assembler::unpcklpd(XMMRegister dst, XMMRegister src) { + _instruction_uses_vl = true; + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + if (VM_Version::supports_evex()) { + emit_simd_arith_q(0x14, dst, src, VEX_SIMD_66); + } else { + emit_simd_arith(0x14, dst, src, VEX_SIMD_66); + } +} + void Assembler::xorpd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); if (VM_Version::supports_avx512dq()) { @@ -4792,8 +4934,9 @@ void Assembler::vpsrad(XMMRegister dst, XMMRegister src, XMMRegister shift, int } -// AND packed integers +// logical operations packed integers void Assembler::pand(XMMRegister dst, XMMRegister src) { + _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); emit_simd_arith(0xDB, dst, src, VEX_SIMD_66); } @@ -4814,6 +4957,17 @@ void Assembler::vpand(XMMRegister dst, XMMRegister nds, Address src, int vector_ emit_vex_arith(0xDB, dst, nds, src, VEX_SIMD_66, vector_len); } +void Assembler::pandn(XMMRegister dst, XMMRegister src) { + _instruction_uses_vl = true; + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + if (VM_Version::supports_evex()) { + emit_simd_arith_q(0xDF, dst, src, VEX_SIMD_66); + } + else { + emit_simd_arith(0xDF, dst, src, VEX_SIMD_66); + } +} + void Assembler::por(XMMRegister dst, XMMRegister src) { _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); @@ -6223,6 +6377,14 @@ void Assembler::shldl(Register dst, Register src) { emit_int8((unsigned char)(0xC0 | src->encoding() << 3 | dst->encoding())); } +// 0F A4 / r ib +void Assembler::shldl(Register dst, Register src, int8_t imm8) { + emit_int8(0x0F); + emit_int8((unsigned char)0xA4); + emit_int8((unsigned char)(0xC0 | src->encoding() << 3 | dst->encoding())); + emit_int8(imm8); +} + void Assembler::shrdl(Register dst, Register src) { emit_int8(0x0F); emit_int8((unsigned char)0xAD); @@ -6362,12 +6524,12 @@ int Assembler::prefixq_and_encode(int reg_enc) { return reg_enc; } -int Assembler::prefix_and_encode(int dst_enc, int src_enc, bool byteinst) { +int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { if (dst_enc < 8) { if (src_enc >= 8) { prefix(REX_B); src_enc -= 8; - } else if (byteinst && src_enc >= 4) { + } else if ((src_is_byte && src_enc >= 4) || (dst_is_byte && dst_enc >= 4)) { prefix(REX); } } else { @@ -6408,6 +6570,40 @@ void Assembler::prefix(Register reg) { } } +void Assembler::prefix(Register dst, Register src, Prefix p) { + if (src->encoding() >= 8) { + p = (Prefix)(p | REX_B); + } + if (dst->encoding() >= 8) { + p = (Prefix)( p | REX_R); + } + if (p != Prefix_EMPTY) { + // do not generate an empty prefix + prefix(p); + } +} + +void Assembler::prefix(Register dst, Address adr, Prefix p) { + if (adr.base_needs_rex()) { + if (adr.index_needs_rex()) { + assert(false, "prefix(Register dst, Address adr, Prefix p) does not support handling of an X"); + } else { + prefix(REX_B); + } + } else { + if (adr.index_needs_rex()) { + assert(false, "prefix(Register dst, Address adr, Prefix p) does not support handling of an X"); + } + } + if (dst->encoding() >= 8) { + p = (Prefix)(p | REX_R); + } + if (p != Prefix_EMPTY) { + // do not generate an empty prefix + prefix(p); + } +} + void Assembler::prefix(Address adr) { if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 3b3781c58f5..ed039c552d1 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -506,7 +506,8 @@ class Assembler : public AbstractAssembler { VEX_3bytes = 0xC4, VEX_2bytes = 0xC5, - EVEX_4bytes = 0x62 + EVEX_4bytes = 0x62, + Prefix_EMPTY = 0x0 }; enum VexPrefix { @@ -535,7 +536,8 @@ class Assembler : public AbstractAssembler { VEX_OPCODE_NONE = 0x0, VEX_OPCODE_0F = 0x1, VEX_OPCODE_0F_38 = 0x2, - VEX_OPCODE_0F_3A = 0x3 + VEX_OPCODE_0F_3A = 0x3, + VEX_OPCODE_MASK = 0x1F }; enum AvxVectorLen { @@ -611,10 +613,15 @@ private: int prefix_and_encode(int reg_enc, bool byteinst = false); int prefixq_and_encode(int reg_enc); - int prefix_and_encode(int dst_enc, int src_enc, bool byteinst = false); + int prefix_and_encode(int dst_enc, int src_enc) { + return prefix_and_encode(dst_enc, false, src_enc, false); + } + int prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte); int prefixq_and_encode(int dst_enc, int src_enc); void prefix(Register reg); + void prefix(Register dst, Register src, Prefix p); + void prefix(Register dst, Address adr, Prefix p); void prefix(Address adr); void prefixq(Address adr); @@ -1177,6 +1184,10 @@ private: // Identify processor type and features void cpuid(); + // CRC32C + void crc32(Register crc, Register v, int8_t sizeInBytes); + void crc32(Register crc, Address adr, int8_t sizeInBytes); + // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value void cvtsd2ss(XMMRegister dst, XMMRegister src); void cvtsd2ss(XMMRegister dst, Address src); @@ -1672,10 +1683,14 @@ private: // SSE 4.1 extract void pextrd(Register dst, XMMRegister src, int imm8); void pextrq(Register dst, XMMRegister src, int imm8); + // SSE 2 extract + void pextrw(Register dst, XMMRegister src, int imm8); // SSE 4.1 insert void pinsrd(XMMRegister dst, Register src, int imm8); void pinsrq(XMMRegister dst, Register src, int imm8); + // SSE 2 insert + void pinsrw(XMMRegister dst, Register src, int imm8); // SSE4.1 packed move void pmovzxbw(XMMRegister dst, XMMRegister src); @@ -1783,6 +1798,7 @@ private: void setb(Condition cc, Register dst); void shldl(Register dst, Register src); + void shldl(Register dst, Register src, int8_t imm8); void shll(Register dst, int imm8); void shll(Register dst); @@ -1925,6 +1941,7 @@ private: // Multiply Packed Floating-Point Values void mulpd(XMMRegister dst, XMMRegister src); + void mulpd(XMMRegister dst, Address src); void mulps(XMMRegister dst, XMMRegister src); void vmulpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vmulps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); @@ -1951,6 +1968,9 @@ private: void vandpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void vandps(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void unpckhpd(XMMRegister dst, XMMRegister src); + void unpcklpd(XMMRegister dst, XMMRegister src); + // Bitwise Logical XOR of Packed Floating-Point Values void xorpd(XMMRegister dst, XMMRegister src); void xorps(XMMRegister dst, XMMRegister src); @@ -2046,6 +2066,9 @@ private: void vpand(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpand(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + // Andn packed integers + void pandn(XMMRegister dst, XMMRegister src); + // Or packed integers void por(XMMRegister dst, XMMRegister src); void vpor(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.inline.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.inline.hpp index 7dbb0950712..7219943a969 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.inline.hpp @@ -33,10 +33,12 @@ inline int Assembler::prefix_and_encode(int reg_enc, bool byteinst) { return reg_enc; } inline int Assembler::prefixq_and_encode(int reg_enc) { return reg_enc; } -inline int Assembler::prefix_and_encode(int dst_enc, int src_enc, bool byteinst) { return dst_enc << 3 | src_enc; } +inline int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { return dst_enc << 3 | src_enc; } inline int Assembler::prefixq_and_encode(int dst_enc, int src_enc) { return dst_enc << 3 | src_enc; } inline void Assembler::prefix(Register reg) {} +inline void Assembler::prefix(Register dst, Register src, Prefix p) {} +inline void Assembler::prefix(Register dst, Address adr, Prefix p) {} inline void Assembler::prefix(Address adr) {} inline void Assembler::prefixq(Address adr) {} diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index ff07711acc0..9870ac1c802 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -2457,9 +2457,6 @@ void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr unused, L // Should consider not saving rbx, if not necessary __ trigfunc('t', op->as_Op2()->fpu_stack_size()); break; - case lir_exp : - __ exp_with_fallback(op->as_Op2()->fpu_stack_size()); - break; case lir_pow : __ pow_with_fallback(op->as_Op2()->fpu_stack_size()); break; @@ -2684,7 +2681,7 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, #endif // _LP64 } } else { - fatal(err_msg("unexpected type: %s", basictype_to_str(c->type()))); + fatal("unexpected type: %s", basictype_to_str(c->type())); } // cpu register - address } else if (opr2->is_address()) { diff --git a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp index 1ee690ea442..f51fa24b07d 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp @@ -808,6 +808,12 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { assert(x->number_of_arguments() == 1 || (x->number_of_arguments() == 2 && x->id() == vmIntrinsics::_dpow), "wrong type"); + + if (x->id() == vmIntrinsics::_dexp) { + do_ExpIntrinsic(x); + return; + } + LIRItem value(x->argument_at(0), this); bool use_fpu = false; @@ -818,7 +824,6 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { case vmIntrinsics::_dtan: case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: - case vmIntrinsics::_dexp: case vmIntrinsics::_dpow: use_fpu = true; } @@ -870,7 +875,6 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { case vmIntrinsics::_dtan: __ tan (calc_input, calc_result, tmp1, tmp2); break; case vmIntrinsics::_dlog: __ log (calc_input, calc_result, tmp1); break; case vmIntrinsics::_dlog10: __ log10(calc_input, calc_result, tmp1); break; - case vmIntrinsics::_dexp: __ exp (calc_input, calc_result, tmp1, tmp2, FrameMap::rax_opr, FrameMap::rcx_opr, FrameMap::rdx_opr); break; case vmIntrinsics::_dpow: __ pow (calc_input, calc_input2, calc_result, tmp1, tmp2, FrameMap::rax_opr, FrameMap::rcx_opr, FrameMap::rdx_opr); break; default: ShouldNotReachHere(); } @@ -880,6 +884,32 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { } } +void LIRGenerator::do_ExpIntrinsic(Intrinsic* x) { + LIRItem value(x->argument_at(0), this); + value.set_destroys_register(); + + LIR_Opr calc_result = rlock_result(x); + LIR_Opr result_reg = result_register_for(x->type()); + + BasicTypeList signature(1); + signature.append(T_DOUBLE); + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + + value.load_item_force(cc->at(0)); + +#ifndef _LP64 + LIR_Opr tmp = FrameMap::fpu0_double_opr; + result_reg = tmp; + if (VM_Version::supports_sse2()) { + __ call_runtime_leaf(StubRoutines::dexp(), getThreadTemp(), result_reg, cc->args()); + } else { + __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dexp), getThreadTemp(), result_reg, cc->args()); + } +#else + __ call_runtime_leaf(StubRoutines::dexp(), getThreadTemp(), result_reg, cc->args()); +#endif + __ move(result_reg, calc_result); +} void LIRGenerator::do_ArrayCopy(Intrinsic* x) { assert(x->number_of_arguments() == 5, "wrong type"); diff --git a/hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp index ba5dc48623d..4f79619d564 100644 --- a/hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp @@ -814,8 +814,7 @@ void FpuStackAllocator::handle_op2(LIR_Op2* op2) { case lir_tan: case lir_sin: - case lir_cos: - case lir_exp: { + case lir_cos: { // sin, cos and exp need two temporary fpu stack slots, so there are two temporary // registers (stored in right and temp of the operation). // the stack allocator must guarantee that the stack slots are really free, diff --git a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp index a32e0a0bae6..db3692f8ccc 100644 --- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp @@ -48,11 +48,11 @@ define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, OnStackReplacePercentage, 140); define_pd_global(intx, ConditionalMoveLimit, 3); -define_pd_global(intx, FLOATPRESSURE, 6); define_pd_global(intx, FreqInlineSize, 325); define_pd_global(intx, MinJumpTableSize, 10); #ifdef AMD64 define_pd_global(intx, INTPRESSURE, 13); +define_pd_global(intx, FLOATPRESSURE, 14); define_pd_global(intx, InteriorEntryAlignment, 16); define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, LoopUnrollLimit, 60); @@ -64,6 +64,7 @@ define_pd_global(intx, CodeCacheExpansionSize, 64*K); define_pd_global(uint64_t, MaxRAM, 128ULL*G); #else define_pd_global(intx, INTPRESSURE, 6); +define_pd_global(intx, FLOATPRESSURE, 6); define_pd_global(intx, InteriorEntryAlignment, 4); define_pd_global(size_t, NewSizeThreadIncrease, 4*K); define_pd_global(intx, LoopUnrollLimit, 50); // Design center runs on 1.3.1 @@ -82,6 +83,7 @@ define_pd_global(bool, OptoPeephole, true); define_pd_global(bool, UseCISCSpill, true); define_pd_global(bool, OptoScheduling, false); define_pd_global(bool, OptoBundling, false); +define_pd_global(bool, OptoRegScheduling, true); define_pd_global(intx, ReservedCodeCacheSize, 48*M); define_pd_global(intx, NonProfiledCodeHeapSize, 21*M); diff --git a/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp index 29eba2fb99d..865e149331c 100644 --- a/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp +++ b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp @@ -50,13 +50,15 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from // calling compiled code to calling interpreted code. // movq rbx, 0 // jmp -5 # to self - address mark = cbuf.insts_mark(); // Get mark within main instrs section. + if (mark == NULL) { + mark = cbuf.insts_mark(); // Get mark within main instrs section. + } // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a stub. @@ -73,6 +75,8 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { // This is recognized as unresolved by relocs/nativeinst/ic code. __ jump(RuntimeAddress(__ pc())); + assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size"); + // Update current stubs pointer and restore insts_end. __ end_a_stub(); return base; @@ -104,10 +108,15 @@ void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); - assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(), +#ifdef ASSERT + // read the value once + intptr_t data = method_holder->data(); + address destination = jump->jump_destination(); + assert(data == 0 || data == (intptr_t)callee(), "a) MT-unsafe modification of inline cache"); - assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry, + assert(destination == (address)-1 || destination == entry, "b) MT-unsafe modification of inline cache"); +#endif // Update stub. method_holder->set_data((intptr_t)callee()); @@ -124,11 +133,12 @@ void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) assert(stub != NULL, "stub not found"); // Creation also verifies the object. NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); - NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); method_holder->set_data(0); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); jump->set_jump_destination((address)-1); } + //----------------------------------------------------------------------------- // Non-product mode code #ifndef PRODUCT @@ -150,5 +160,4 @@ void CompiledStaticCall::verify() { // Verify state. assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); } - #endif // !PRODUCT diff --git a/hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp b/hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp index 9f81215b396..bf47c3430ef 100644 --- a/hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp +++ b/hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp @@ -29,6 +29,7 @@ void generate_more_monitors(); void generate_deopt_handling(); + void lock_method(void); address generate_interpreter_frame_manager(bool synchronized); // C++ interpreter only void generate_compute_interpreter_state(const Register state, const Register prev_state, diff --git a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp index 27f1b309727..b3ed77e68c6 100644 --- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp +++ b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp @@ -741,7 +741,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) { // Find preallocated monitor and lock method (C++ interpreter) // rbx - Method* // -void InterpreterGenerator::lock_method(void) { +void CppInterpreterGenerator::lock_method() { // assumes state == rsi/r13 == pointer to current interpreterState // minimally destroys rax, rdx|c_rarg1, rdi // @@ -807,7 +807,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_jump_to_normal_entry(); + return NULL; } // diff --git a/hotspot/src/cpu/x86/vm/crc32c.h b/hotspot/src/cpu/x86/vm/crc32c.h new file mode 100644 index 00000000000..83746b42947 --- /dev/null +++ b/hotspot/src/cpu/x86/vm/crc32c.h @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +* +*/ + +enum { + // S. Gueron / Information Processing Letters 112 (2012) 184 + // shows than anything above 6K and below 32K is a good choice + // 32K does not deliver any further performance gains + // 6K=8*256 (*3 as we compute 3 blocks together) + // + // Thus selecting the smallest value so it could apply to the largest number + // of buffer sizes. + CRC32C_HIGH = 8 * 256, + + // empirical + // based on ubench study using methodology described in + // V. Gopal et al. / Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction April 2011 8 + // + // arbitrary value between 27 and 256 + CRC32C_MIDDLE = 8 * 86, + + // V. Gopal et al. / Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction April 2011 9 + // shows that 240 and 1024 are equally good choices as the 216==8*27 + // + // Selecting the smallest value which resulted in a significant performance improvement over + // sequential version + CRC32C_LOW = 8 * 27, + + CRC32C_NUM_ChunkSizeInBytes = 3, + + // We need to compute powers of 64N and 128N for each "chunk" size + CRC32C_NUM_PRECOMPUTED_CONSTANTS = ( 2 * CRC32C_NUM_ChunkSizeInBytes ) +}; +// Notes: +// 1. Why we need to choose a "chunk" approach? +// Overhead of computing a powers and powers of for an arbitrary buffer of size N is significant +// (implementation approaches a library perf.) +// 2. Why only 3 "chunks"? +// Performance experiments results showed that a HIGH+LOW was not delivering a stable speedup +// curve. +// +// Disclaimer: +// If you ever decide to increase/decrease number of "chunks" be sure to modify +// a) constants table generation (hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp) +// b) constant fetch from that table (macroAssembler_x86.cpp) +// c) unrolled for loop (macroAssembler_x86.cpp) diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp index f831342b9d7..695902087f4 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp @@ -48,8 +48,6 @@ void RegisterMap::check_location_valid() { } #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { @@ -280,7 +278,7 @@ void frame::patch_pc(Thread* thread, address pc) { address* pc_addr = &(((address*) sp())[-1]); if (TracePcPatching) { tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]", - pc_addr, *pc_addr, pc); + p2i(pc_addr), p2i(*pc_addr), p2i(pc)); } // Either the return address is the original one or we are going to // patch in the same address that's already there. @@ -458,11 +456,11 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { // This is the sp before any possible extension (adapter/locals). intptr_t* unextended_sp = interpreter_frame_sender_sp(); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (map->update_map()) { update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset)); } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI return frame(sender_sp, unextended_sp, link(), sender_pc()); } @@ -683,10 +681,19 @@ void frame::describe_pd(FrameValues& values, int frame_no) { DESCRIBE_FP_OFFSET(interpreter_frame_locals); DESCRIBE_FP_OFFSET(interpreter_frame_bcp); DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp); -#endif +#ifdef AMD64 + } else if (is_entry_frame()) { + // This could be more descriptive if we use the enum in + // stubGenerator to map to real names but it's most important to + // claim these frame slots so the error checking works. + for (int i = 0; i < entry_frame_after_call_words; i++) { + values.describe(frame_no, fp() - i, err_msg("call_stub word fp - %d", i)); + } +#endif // AMD64 } -} #endif +} +#endif // !PRODUCT intptr_t *frame::initial_deoptimization_info() { // used to reset the saved FP diff --git a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp index 7f6a99ad2d6..3b5cd411ea3 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp @@ -78,7 +78,11 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address assert(((nmethod*)_cb)->insts_contains(_pc), "original PC must be in nmethod"); _deopt_state = is_deoptimized; } else { - _deopt_state = not_deoptimized; + if (_cb->is_deoptimization_stub()) { + _deopt_state = is_deoptimized; + } else { + _deopt_state = not_deoptimized; + } } } diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp index 1777d54af7e..fe81aac91f4 100644 --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp @@ -46,7 +46,7 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs // the the vep is aligned at CodeEntryAlignment whereas c2 only aligns // the uep and the vep doesn't get real alignment but just slops on by // only assured that the entry instruction meets the 5 byte size requirement. -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI define_pd_global(intx, CodeEntryAlignment, 32); #else define_pd_global(intx, CodeEntryAlignment, 16); @@ -55,16 +55,28 @@ define_pd_global(intx, OptoLoopAlignment, 16); define_pd_global(intx, InlineFrequencyCount, 100); define_pd_global(intx, InlineSmallCode, 1000); -define_pd_global(intx, StackYellowPages, NOT_WINDOWS(2) WINDOWS_ONLY(3)); -define_pd_global(intx, StackRedPages, 1); +#define DEFAULT_STACK_YELLOW_PAGES (NOT_WINDOWS(2) WINDOWS_ONLY(3)) +#define DEFAULT_STACK_RED_PAGES (1) + +#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES +#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES + #ifdef AMD64 // Very large C++ stack frames using solaris-amd64 optimized builds // due to lack of optimization caused by C++ compiler bugs -define_pd_global(intx, StackShadowPages, NOT_WIN64(20) WIN64_ONLY(6) DEBUG_ONLY(+2)); +#define DEFAULT_STACK_SHADOW_PAGES (NOT_WIN64(20) WIN64_ONLY(6) DEBUG_ONLY(+2)) +// For those clients that do not use write socket, we allow +// the min range value to be below that of the default +#define MIN_STACK_SHADOW_PAGES (NOT_WIN64(10) WIN64_ONLY(6) DEBUG_ONLY(+2)) #else -define_pd_global(intx, StackShadowPages, 4 DEBUG_ONLY(+5)); +#define DEFAULT_STACK_SHADOW_PAGES (4 DEBUG_ONLY(+5)) +#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES #endif // AMD64 +define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); +define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); +define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); + define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); @@ -91,6 +103,7 @@ define_pd_global(bool, PreserveFramePointer, false); \ product(intx, UseAVX, 99, \ "Highest supported AVX instructions set on x86/x64") \ + range(0, 99) \ \ product(bool, UseCLMUL, false, \ "Control whether CLMUL instructions can be used on x86/x64") \ @@ -134,6 +147,7 @@ define_pd_global(bool, PreserveFramePointer, false); \ product(uintx, RTMRetryCount, 5, \ "Number of RTM retries on lock abort or busy") \ + range(0, max_uintx) \ \ experimental(intx, RTMSpinLoopCount, 100, \ "Spin count for lock to become free before RTM retry") \ diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp index 5501b91530c..ea4c18d11c6 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp @@ -40,6 +40,11 @@ // Implementation of InterpreterMacroAssembler +void InterpreterMacroAssembler::jump_to_entry(address entry) { + assert(entry, "Entry must have been generated by now"); + jump(RuntimeAddress(entry)); +} + #ifndef CC_INTERP void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { Label update, next, none; @@ -1497,13 +1502,39 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. +#if INCLUDE_JVMCI + if (MethodProfileWidth == 0) { + update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); + } +#else // INCLUDE_JVMCI update_mdp_by_constant(mdp, in_bytes(VirtualCallData:: virtual_call_data_size())); +#endif // INCLUDE_JVMCI bind(profile_continue); } } +#if INCLUDE_JVMCI +void InterpreterMacroAssembler::profile_called_method(Register method, Register mdp, Register reg2) { + assert_different_registers(method, mdp, reg2); + if (ProfileInterpreter && MethodProfileWidth > 0) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + Label done; + record_item_in_profile_helper(method, mdp, reg2, 0, done, MethodProfileWidth, + &VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset())); + bind(done); + + update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); + bind(profile_continue); + } +} +#endif // INCLUDE_JVMCI + // This routine creates a state machine for updating the multi-row // type profile at a virtual call site (or other type-sensitive bytecode). // The machine visits each row (of receiver/count) until the receiver type @@ -1523,14 +1554,36 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( if (is_virtual_call) { increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); } - return; - } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + increment_mdp_data_at(mdp, in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset())); + } +#endif // INCLUDE_JVMCI + } else { + int non_profiled_offset = -1; + if (is_virtual_call) { + non_profiled_offset = in_bytes(CounterData::count_offset()); + } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()); + } +#endif // INCLUDE_JVMCI - int last_row = VirtualCallData::row_limit() - 1; + record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth, + &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); + } +} + +void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp, + Register reg2, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset) { + int last_row = total_rows - 1; assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the receiver and for null. + // Test this row for both the item and for null. // Take any of three different outcomes: - // 1. found receiver => increment count and goto done + // 1. found item => increment count and goto done // 2. found null => keep looking for case 1, maybe allocate this cell // 3. found something else => keep looking for cases 1 and 2 // Case 3 is handled by a recursive call. @@ -1538,30 +1591,30 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( Label next_test; bool test_for_null_also = (row == start_row); - // See if the receiver is receiver[n]. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); - test_mdp_data_at(mdp, recvr_offset, receiver, + // See if the item is item[n]. + int item_offset = in_bytes(item_offset_fn(row)); + test_mdp_data_at(mdp, item_offset, item, (test_for_null_also ? reg2 : noreg), next_test); - // (Reg2 now contains the receiver from the CallData.) + // (Reg2 now contains the item from the CallData.) - // The receiver is receiver[n]. Increment count[n]. - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); + // The item is item[n]. Increment count[n]. + int count_offset = in_bytes(item_count_offset_fn(row)); increment_mdp_data_at(mdp, count_offset); jmp(done); bind(next_test); if (test_for_null_also) { Label found_null; - // Failed the equality check on receiver[n]... Test for null. + // Failed the equality check on item[n]... Test for null. testptr(reg2, reg2); if (start_row == last_row) { // The only thing left to do is handle the null case. - if (is_virtual_call) { + if (non_profiled_offset >= 0) { jccb(Assembler::zero, found_null); - // Receiver did not match any saved receiver and there is no empty row for it. + // Item did not match any saved item and there is no empty row for it. // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + increment_mdp_data_at(mdp, non_profiled_offset); jmp(done); bind(found_null); } else { @@ -1573,21 +1626,22 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( jcc(Assembler::zero, found_null); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); + record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows, + item_offset_fn, item_count_offset_fn, non_profiled_offset); - // Found a null. Keep searching for a matching receiver, + // Found a null. Keep searching for a matching item, // but remember that this is an empty (unused) slot. bind(found_null); } } - // In the fall-through case, we found no matching receiver, but we - // observed the receiver[start_row] is NULL. + // In the fall-through case, we found no matching item, but we + // observed the item[start_row] is NULL. - // Fill in the receiver field and increment the count. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); - set_mdp_data_at(mdp, recvr_offset, receiver); - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); + // Fill in the item field and increment the count. + int item_offset = in_bytes(item_offset_fn(start_row)); + set_mdp_data_at(mdp, item_offset, item); + int count_offset = in_bytes(item_count_offset_fn(start_row)); movl(reg2, DataLayout::counter_increment); set_mdp_data_at(mdp, count_offset, reg2); if (start_row > 0) { diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp index 35d1ad35686..08a293f99a2 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp @@ -32,6 +32,7 @@ // This file specializes the assember with interpreter-specific macros +typedef ByteSize (*OffsetFunction)(uint); class InterpreterMacroAssembler: public MacroAssembler { @@ -60,6 +61,8 @@ class InterpreterMacroAssembler: public MacroAssembler { _locals_register(LP64_ONLY(r14) NOT_LP64(rdi)), _bcp_register(LP64_ONLY(r13) NOT_LP64(rsi)) {} + void jump_to_entry(address entry); + void load_earlyret_value(TosState state); #ifdef CC_INTERP @@ -249,6 +252,10 @@ class InterpreterMacroAssembler: public MacroAssembler { void record_klass_in_profile_helper(Register receiver, Register mdp, Register reg2, int start_row, Label& done, bool is_virtual_call); + void record_item_in_profile_helper(Register item, Register mdp, + Register reg2, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset); void update_mdp_by_offset(Register mdp_in, int offset_of_offset); void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); @@ -262,6 +269,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_virtual_call(Register receiver, Register mdp, Register scratch2, bool receiver_can_be_null = false); + void profile_called_method(Register method, Register mdp, Register reg2) NOT_JVMCI_RETURN; void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); void profile_typecheck(Register mdp, Register klass, Register scratch); diff --git a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp index 229803a80ff..e22e3d366a0 100644 --- a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp @@ -31,17 +31,6 @@ #define __ _masm-> -// Jump into normal path for accessor and empty entry to jump to normal entry -// The "fast" optimization don't update compilation count therefore can disable inlining -// for these functions that should be inlined. -address InterpreterGenerator::generate_jump_to_normal_entry(void) { - address entry_point = __ pc(); - - assert(Interpreter::entry_for_kind(Interpreter::zerolocals) != NULL, "should already be generated"); - __ jump(RuntimeAddress(Interpreter::entry_for_kind(Interpreter::zerolocals))); - return entry_point; -} - // Abstract method entry // Attempt to execute abstract method. Throw exception address InterpreterGenerator::generate_abstract_entry(void) { diff --git a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp index 70e38d9a245..ad9ca0fba3d 100644 --- a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp +++ b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp @@ -36,19 +36,18 @@ address generate_native_entry(bool synchronized); address generate_abstract_entry(void); address generate_math_entry(AbstractInterpreter::MethodKind kind); - address generate_jump_to_normal_entry(void); - address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } - address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } + address generate_accessor_entry(void) { return NULL; } + address generate_empty_entry(void) { return NULL; } address generate_Reference_get_entry(); address generate_CRC32_update_entry(); address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind); #ifndef _LP64 address generate_Float_intBitsToFloat_entry(); address generate_Float_floatToRawIntBits_entry(); address generate_Double_longBitsToDouble_entry(); address generate_Double_doubleToRawLongBits_entry(); #endif - void lock_method(void); void generate_stack_overflow_check(void); void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp index 4a2903b3736..2e641aa2522 100644 --- a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp @@ -151,11 +151,15 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin __ pop_fTOS(); break; case Interpreter::java_lang_math_exp: - __ exp_with_fallback(0); - // Store to stack to convert 80bit precision back to 64bits - __ push_fTOS(); - __ pop_fTOS(); - break; + __ subptr(rsp, 2*wordSize); + __ fstp_d(Address(rsp, 0)); + if (VM_Version::supports_sse2()) { + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dexp()))); + } else { + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dexp))); + } + __ addptr(rsp, 2*wordSize); + break; default : ShouldNotReachHere(); } diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp index af4f7fac388..682addd3c77 100644 --- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp @@ -52,8 +52,6 @@ #define __ _masm-> -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef _WIN64 address AbstractInterpreterGenerator::generate_slow_signature_handler() { address entry = __ pc(); @@ -252,6 +250,9 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin if (kind == Interpreter::java_lang_math_sqrt) { __ sqrtsd(xmm0, Address(rsp, wordSize)); + } else if (kind == Interpreter::java_lang_math_exp) { + __ movdbl(xmm0, Address(rsp, wordSize)); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dexp()))); } else { __ fld_d(Address(rsp, wordSize)); switch (kind) { @@ -278,9 +279,6 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin // empty stack slot) __ pow_with_fallback(0); break; - case Interpreter::java_lang_math_exp: - __ exp_with_fallback(0); - break; default : ShouldNotReachHere(); } diff --git a/hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp b/hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp new file mode 100644 index 00000000000..6b467b1110b --- /dev/null +++ b/hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "compiler/disassembler.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/sharedRuntime.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "asm/register.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/vmreg.hpp" +#include "vmreg_x86.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + if (inst->is_call() || inst->is_jump()) { + assert(NativeCall::instruction_size == (int)NativeJump::instruction_size, "unexpected size"); + return (pc_offset + NativeCall::instruction_size); + } else if (inst->is_mov_literal64()) { + // mov+call instruction pair + jint offset = pc_offset + NativeMovConstReg::instruction_size; + u_char* call = (u_char*) (_instructions->start() + offset); + if (call[0] == Assembler::REX_B) { + offset += 1; /* prefix byte for extended register R8-R15 */ + call++; + } + assert(call[0] == 0xFF, "expected call"); + offset += 2; /* opcode byte + modrm byte */ + return (offset); + } else if (inst->is_call_reg()) { + // the inlined vtable stub contains a "call register" instruction + assert(method != NULL, "only valid for virtual calls"); + return (pc_offset + ((NativeCallReg *) inst)->next_instruction_offset()); + } else if (inst->is_cond_jump()) { + address pc = (address) (inst); + return pc_offset + (jint) (Assembler::locate_next_instruction(pc) - pc); + } else { + fatal("unsupported type of instruction for call site"); + return 0; + } +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + address pc = _instructions->start() + pc_offset; + Handle obj = HotSpotObjectConstantImpl::object(constant); + jobject value = JNIHandles::make_local(obj()); + if (HotSpotObjectConstantImpl::compressed(constant)) { +#ifdef _LP64 + address operand = Assembler::locate_operand(pc, Assembler::narrow_oop_operand); + int oop_index = _oop_recorder->find_index(value); + _instructions->relocate(pc, oop_Relocation::spec(oop_index), Assembler::narrow_oop_operand); + TRACE_jvmci_3("relocating (narrow oop constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); +#else + fatal("compressed oop on 32bit"); +#endif + } else { + address operand = Assembler::locate_operand(pc, Assembler::imm_operand); + *((jobject*) operand) = value; + _instructions->relocate(pc, oop_Relocation::spec_for_immediate(), Assembler::imm_operand); + TRACE_jvmci_3("relocating (oop constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); + } +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + address pc = _instructions->start() + pc_offset; + + address operand = Assembler::locate_operand(pc, Assembler::disp32_operand); + address next_instruction = Assembler::locate_next_instruction(pc); + address dest = _constants->start() + data_offset; + + long disp = dest - next_instruction; + assert(disp == (jint) disp, "disp doesn't fit in 32 bits"); + *((jint*) operand) = (jint) disp; + + _instructions->relocate(pc, section_word_Relocation::spec((address) dest, CodeBuffer::SECT_CONSTS), Assembler::disp32_operand); + TRACE_jvmci_3("relocating at " PTR_FORMAT "/" PTR_FORMAT " with destination at " PTR_FORMAT " (%d)", p2i(pc), p2i(operand), p2i(dest), data_offset); +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point()); + } else { + nativeJump_at((address)inst)->set_jump_destination(cb->code_begin()); + } + _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + address pc = (address) inst; + if (inst->is_call()) { + // NOTE: for call without a mov, the offset must fit a 32-bit immediate + // see also CompilerToVM.getMaxCallTargetOffset() + NativeCall* call = nativeCall_at(pc); + call->set_destination((address) foreign_call_destination); + _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + } else if (inst->is_mov_literal64()) { + NativeMovConstReg* mov = nativeMovConstReg_at(pc); + mov->set_data((intptr_t) foreign_call_destination); + _instructions->relocate(mov->instruction_address(), runtime_call_Relocation::spec(), Assembler::imm_operand); + } else if (inst->is_jump()) { + NativeJump* jump = nativeJump_at(pc); + jump->set_jump_destination((address) foreign_call_destination); + _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + } else if (inst->is_cond_jump()) { + address old_dest = nativeGeneralJump_at(pc)->jump_destination(); + address disp = Assembler::locate_operand(pc, Assembler::call32_operand); + *(jint*) disp += ((address) foreign_call_destination) - old_dest; + _instructions->relocate(pc, runtime_call_Relocation::spec(), Assembler::call32_operand); + } else { + fatal("unsupported relocation for foreign call"); + } + + TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst)); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { +#ifdef ASSERT + Method* method = NULL; + // we need to check, this might also be an unresolved method + if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { + method = getMethodFromHotSpotMethod(hotspot_method); + } +#endif + switch (_next_call_type) { + case INLINE_INVOKE: + break; + case INVOKEVIRTUAL: + case INVOKEINTERFACE: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface"); + + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), + virtual_call_Relocation::spec(_invoke_mark_pc), + Assembler::call32_operand); + break; + } + case INVOKESTATIC: { + assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic"); + + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_static_call_stub()); + _instructions->relocate(call->instruction_address(), + relocInfo::static_call_type, Assembler::call32_operand); + break; + } + case INVOKESPECIAL: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), + relocInfo::opt_virtual_call_type, Assembler::call32_operand); + break; + } + default: + break; + } +} + +static void relocate_poll_near(address pc) { + NativeInstruction* ni = nativeInstruction_at(pc); + int32_t* disp = (int32_t*) Assembler::locate_operand(pc, Assembler::disp32_operand); + int32_t offset = *disp; // The Java code installed the polling page offset into the disp32 operand + intptr_t new_disp = (intptr_t) (os::get_polling_page() + offset) - (intptr_t) ni; + *disp = (int32_t)new_disp; +} + + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + switch (mark) { + case POLL_NEAR: { + relocate_poll_near(pc); + _instructions->relocate(pc, relocInfo::poll_type, Assembler::disp32_operand); + break; + } + case POLL_FAR: + // This is a load from a register so there is no relocatable operand. + // We just have to ensure that the format is not disp32_operand + // so that poll_Relocation::fix_relocation_after_move does the right + // thing (i.e. ignores this relocation record) + _instructions->relocate(pc, relocInfo::poll_type, Assembler::imm_operand); + break; + case POLL_RETURN_NEAR: { + relocate_poll_near(pc); + _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::disp32_operand); + break; + } + case POLL_RETURN_FAR: + // see comment above for POLL_FAR + _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::imm_operand); + break; + default: + fatal("invalid mark value"); + break; + } +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + if (jvmci_reg < RegisterImpl::number_of_registers) { + return as_Register(jvmci_reg)->as_VMReg(); + } else { + jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers; + if (floatRegisterNumber < XMMRegisterImpl::number_of_registers) { + return as_XMMRegister(floatRegisterNumber)->as_VMReg(); + } + ShouldNotReachHere(); + return NULL; + } +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return !(hotspotRegister->is_FloatRegister() || hotspotRegister->is_XMMRegister()); +} diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index eb6e422a854..eef3cd90afe 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -45,6 +45,7 @@ #include "gc/g1/g1SATBCardTableModRefBS.hpp" #include "gc/g1/heapRegion.hpp" #endif // INCLUDE_ALL_GCS +#include "crc32c.h" #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -56,8 +57,6 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef ASSERT bool AbstractAssembler::pd_check_instruction_mark() { return true; } #endif @@ -417,7 +416,7 @@ void MacroAssembler::debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rd ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg); } // Don't assert holding the ttyLock - assert(false, err_msg("DEBUG MESSAGE: %s", msg)); + assert(false, "DEBUG MESSAGE: %s", msg); ThreadStateTransition::transition(thread, _thread_in_vm, saved_state); } @@ -883,7 +882,7 @@ void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[]) { ttyLocker ttyl; ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg); - assert(false, err_msg("DEBUG MESSAGE: %s", msg)); + assert(false, "DEBUG MESSAGE: %s", msg); } } @@ -2888,7 +2887,7 @@ void MacroAssembler::divss(XMMRegister dst, AddressLiteral src) { } // !defined(COMPILER2) is because of stupid core builds -#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) +#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) || INCLUDE_JVMCI void MacroAssembler::empty_FPU_stack() { if (VM_Version::supports_mmx()) { emms(); @@ -2896,7 +2895,7 @@ void MacroAssembler::empty_FPU_stack() { for (int i = 8; i-- > 0; ) ffree(i); } } -#endif // !LP64 || C1 || !C2 +#endif // !LP64 || C1 || !C2 || INCLUDE_JVMCI // Defines obj, preserves var_size_in_bytes @@ -3032,6 +3031,15 @@ void MacroAssembler::fldcw(AddressLiteral src) { Assembler::fldcw(as_Address(src)); } +void MacroAssembler::mulpd(XMMRegister dst, AddressLiteral src) { + if (reachable(src)) { + Assembler::mulpd(dst, as_Address(src)); + } else { + lea(rscratch1, src); + Assembler::mulpd(dst, Address(rscratch1, 0)); + } +} + void MacroAssembler::pow_exp_core_encoding() { // kills rax, rcx, rdx subptr(rsp,sizeof(jdouble)); @@ -3104,19 +3112,7 @@ void MacroAssembler::fast_pow() { BLOCK_COMMENT("} fast_pow"); } -void MacroAssembler::fast_exp() { - // computes exp(X) = 2^(X * log2(e)) - // if fast computation is not possible, result is NaN. Requires - // fallback from user of this macro. - // increase precision for intermediate steps of the computation - increase_precision(); - fldl2e(); // Stack: log2(e) X ... - fmulp(1); // Stack: (X*log2(e)) ... - pow_exp_core_encoding(); // Stack: exp(X) ... - restore_precision(); -} - -void MacroAssembler::pow_or_exp(bool is_exp, int num_fpu_regs_in_use) { +void MacroAssembler::pow_or_exp(int num_fpu_regs_in_use) { // kills rax, rcx, rdx // pow and exp needs 2 extra registers on the fpu stack. Label slow_case, done; @@ -3128,182 +3124,164 @@ void MacroAssembler::pow_or_exp(bool is_exp, int num_fpu_regs_in_use) { Register tmp2 = rax; Register tmp3 = rcx; - if (is_exp) { - // Stack: X - fld_s(0); // duplicate argument for runtime call. Stack: X X - fast_exp(); // Stack: exp(X) X - fcmp(tmp, 0, false, false); // Stack: exp(X) X - // exp(X) not equal to itself: exp(X) is NaN go to slow case. - jcc(Assembler::parity, slow_case); - // get rid of duplicate argument. Stack: exp(X) - if (num_fpu_regs_in_use > 0) { - fxch(); - fpop(); - } else { - ffree(1); - } - jmp(done); + // Stack: X Y + Label x_negative, y_not_2; + + static double two = 2.0; + ExternalAddress two_addr((address)&two); + + // constant maybe too far on 64 bit + lea(tmp2, two_addr); + fld_d(Address(tmp2, 0)); // Stack: 2 X Y + fcmp(tmp, 2, true, false); // Stack: X Y + jcc(Assembler::parity, y_not_2); + jcc(Assembler::notEqual, y_not_2); + + fxch(); fpop(); // Stack: X + fmul(0); // Stack: X*X + + jmp(done); + + bind(y_not_2); + + fldz(); // Stack: 0 X Y + fcmp(tmp, 1, true, false); // Stack: X Y + jcc(Assembler::above, x_negative); + + // X >= 0 + + fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y + fld_s(1); // Stack: X Y X Y + fast_pow(); // Stack: X^Y X Y + fcmp(tmp, 0, false, false); // Stack: X^Y X Y + // X^Y not equal to itself: X^Y is NaN go to slow case. + jcc(Assembler::parity, slow_case); + // get rid of duplicate arguments. Stack: X^Y + if (num_fpu_regs_in_use > 0) { + fxch(); fpop(); + fxch(); fpop(); } else { - // Stack: X Y - Label x_negative, y_not_2; + ffree(2); + ffree(1); + } + jmp(done); - static double two = 2.0; - ExternalAddress two_addr((address)&two); + // X <= 0 + bind(x_negative); - // constant maybe too far on 64 bit - lea(tmp2, two_addr); - fld_d(Address(tmp2, 0)); // Stack: 2 X Y - fcmp(tmp, 2, true, false); // Stack: X Y - jcc(Assembler::parity, y_not_2); - jcc(Assembler::notEqual, y_not_2); + fld_s(1); // Stack: Y X Y + frndint(); // Stack: int(Y) X Y + fcmp(tmp, 2, false, false); // Stack: int(Y) X Y + jcc(Assembler::notEqual, slow_case); - fxch(); fpop(); // Stack: X - fmul(0); // Stack: X*X + subptr(rsp, 8); - jmp(done); - - bind(y_not_2); - - fldz(); // Stack: 0 X Y - fcmp(tmp, 1, true, false); // Stack: X Y - jcc(Assembler::above, x_negative); - - // X >= 0 - - fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y - fld_s(1); // Stack: X Y X Y - fast_pow(); // Stack: X^Y X Y - fcmp(tmp, 0, false, false); // Stack: X^Y X Y - // X^Y not equal to itself: X^Y is NaN go to slow case. - jcc(Assembler::parity, slow_case); - // get rid of duplicate arguments. Stack: X^Y - if (num_fpu_regs_in_use > 0) { - fxch(); fpop(); - fxch(); fpop(); - } else { - ffree(2); - ffree(1); - } - jmp(done); - - // X <= 0 - bind(x_negative); - - fld_s(1); // Stack: Y X Y - frndint(); // Stack: int(Y) X Y - fcmp(tmp, 2, false, false); // Stack: int(Y) X Y - jcc(Assembler::notEqual, slow_case); - - subptr(rsp, 8); - - // For X^Y, when X < 0, Y has to be an integer and the final - // result depends on whether it's odd or even. We just checked - // that int(Y) == Y. We move int(Y) to gp registers as a 64 bit - // integer to test its parity. If int(Y) is huge and doesn't fit - // in the 64 bit integer range, the integer indefinite value will - // end up in the gp registers. Huge numbers are all even, the - // integer indefinite number is even so it's fine. + // For X^Y, when X < 0, Y has to be an integer and the final + // result depends on whether it's odd or even. We just checked + // that int(Y) == Y. We move int(Y) to gp registers as a 64 bit + // integer to test its parity. If int(Y) is huge and doesn't fit + // in the 64 bit integer range, the integer indefinite value will + // end up in the gp registers. Huge numbers are all even, the + // integer indefinite number is even so it's fine. #ifdef ASSERT - // Let's check we don't end up with an integer indefinite number - // when not expected. First test for huge numbers: check whether - // int(Y)+1 == int(Y) which is true for very large numbers and - // those are all even. A 64 bit integer is guaranteed to not - // overflow for numbers where y+1 != y (when precision is set to - // double precision). - Label y_not_huge; + // Let's check we don't end up with an integer indefinite number + // when not expected. First test for huge numbers: check whether + // int(Y)+1 == int(Y) which is true for very large numbers and + // those are all even. A 64 bit integer is guaranteed to not + // overflow for numbers where y+1 != y (when precision is set to + // double precision). + Label y_not_huge; - fld1(); // Stack: 1 int(Y) X Y - fadd(1); // Stack: 1+int(Y) int(Y) X Y + fld1(); // Stack: 1 int(Y) X Y + fadd(1); // Stack: 1+int(Y) int(Y) X Y #ifdef _LP64 - // trip to memory to force the precision down from double extended - // precision - fstp_d(Address(rsp, 0)); - fld_d(Address(rsp, 0)); + // trip to memory to force the precision down from double extended + // precision + fstp_d(Address(rsp, 0)); + fld_d(Address(rsp, 0)); #endif - fcmp(tmp, 1, true, false); // Stack: int(Y) X Y + fcmp(tmp, 1, true, false); // Stack: int(Y) X Y #endif - // move int(Y) as 64 bit integer to thread's stack - fistp_d(Address(rsp,0)); // Stack: X Y + // move int(Y) as 64 bit integer to thread's stack + fistp_d(Address(rsp,0)); // Stack: X Y #ifdef ASSERT - jcc(Assembler::notEqual, y_not_huge); + jcc(Assembler::notEqual, y_not_huge); - // Y is huge so we know it's even. It may not fit in a 64 bit - // integer and we don't want the debug code below to see the - // integer indefinite value so overwrite int(Y) on the thread's - // stack with 0. - movl(Address(rsp, 0), 0); - movl(Address(rsp, 4), 0); + // Y is huge so we know it's even. It may not fit in a 64 bit + // integer and we don't want the debug code below to see the + // integer indefinite value so overwrite int(Y) on the thread's + // stack with 0. + movl(Address(rsp, 0), 0); + movl(Address(rsp, 4), 0); - bind(y_not_huge); + bind(y_not_huge); #endif - fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y - fld_s(1); // Stack: X Y X Y - fabs(); // Stack: abs(X) Y X Y - fast_pow(); // Stack: abs(X)^Y X Y - fcmp(tmp, 0, false, false); // Stack: abs(X)^Y X Y - // abs(X)^Y not equal to itself: abs(X)^Y is NaN go to slow case. + fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y + fld_s(1); // Stack: X Y X Y + fabs(); // Stack: abs(X) Y X Y + fast_pow(); // Stack: abs(X)^Y X Y + fcmp(tmp, 0, false, false); // Stack: abs(X)^Y X Y + // abs(X)^Y not equal to itself: abs(X)^Y is NaN go to slow case. - pop(tmp2); - NOT_LP64(pop(tmp3)); - jcc(Assembler::parity, slow_case); + pop(tmp2); + NOT_LP64(pop(tmp3)); + jcc(Assembler::parity, slow_case); #ifdef ASSERT - // Check that int(Y) is not integer indefinite value (int - // overflow). Shouldn't happen because for values that would - // overflow, 1+int(Y)==Y which was tested earlier. + // Check that int(Y) is not integer indefinite value (int + // overflow). Shouldn't happen because for values that would + // overflow, 1+int(Y)==Y which was tested earlier. #ifndef _LP64 - { - Label integer; - testl(tmp2, tmp2); - jcc(Assembler::notZero, integer); - cmpl(tmp3, 0x80000000); - jcc(Assembler::notZero, integer); - STOP("integer indefinite value shouldn't be seen here"); - bind(integer); - } -#else - { - Label integer; - mov(tmp3, tmp2); // preserve tmp2 for parity check below - shlq(tmp3, 1); - jcc(Assembler::carryClear, integer); - jcc(Assembler::notZero, integer); - STOP("integer indefinite value shouldn't be seen here"); - bind(integer); - } -#endif -#endif - - // get rid of duplicate arguments. Stack: X^Y - if (num_fpu_regs_in_use > 0) { - fxch(); fpop(); - fxch(); fpop(); - } else { - ffree(2); - ffree(1); - } - - testl(tmp2, 1); - jcc(Assembler::zero, done); // X <= 0, Y even: X^Y = abs(X)^Y - // X <= 0, Y even: X^Y = -abs(X)^Y - - fchs(); // Stack: -abs(X)^Y Y - jmp(done); + { + Label integer; + testl(tmp2, tmp2); + jcc(Assembler::notZero, integer); + cmpl(tmp3, 0x80000000); + jcc(Assembler::notZero, integer); + STOP("integer indefinite value shouldn't be seen here"); + bind(integer); } +#else + { + Label integer; + mov(tmp3, tmp2); // preserve tmp2 for parity check below + shlq(tmp3, 1); + jcc(Assembler::carryClear, integer); + jcc(Assembler::notZero, integer); + STOP("integer indefinite value shouldn't be seen here"); + bind(integer); + } +#endif +#endif + + // get rid of duplicate arguments. Stack: X^Y + if (num_fpu_regs_in_use > 0) { + fxch(); fpop(); + fxch(); fpop(); + } else { + ffree(2); + ffree(1); + } + + testl(tmp2, 1); + jcc(Assembler::zero, done); // X <= 0, Y even: X^Y = abs(X)^Y + // X <= 0, Y even: X^Y = -abs(X)^Y + + fchs(); // Stack: -abs(X)^Y Y + jmp(done); // slow case: runtime call bind(slow_case); fpop(); // pop incorrect result or int(Y) - fp_runtime_fallback(is_exp ? CAST_FROM_FN_PTR(address, SharedRuntime::dexp) : CAST_FROM_FN_PTR(address, SharedRuntime::dpow), - is_exp ? 1 : 2, num_fpu_regs_in_use); + fp_runtime_fallback(CAST_FROM_FN_PTR(address, SharedRuntime::dpow), 2, num_fpu_regs_in_use); // Come here with result in F-TOS bind(done); @@ -6267,7 +6245,9 @@ void MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool fp_ // Save caller's stack pointer into RBP if the frame pointer is preserved. if (PreserveFramePointer) { movptr(rbp, rsp); - addptr(rbp, framesize + wordSize); + if (framesize > 0) { + addptr(rbp, framesize); + } } } @@ -8636,6 +8616,471 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Regi notl(crc); // ~c } +#ifdef _LP64 +// S. Gueron / Information Processing Letters 112 (2012) 184 +// Algorithm 4: Computing carry-less multiplication using a precomputed lookup table. +// Input: A 32 bit value B = [byte3, byte2, byte1, byte0]. +// Output: the 64-bit carry-less product of B * CONST +void MacroAssembler::crc32c_ipl_alg4(Register in, uint32_t n, + Register tmp1, Register tmp2, Register tmp3) { + lea(tmp3, ExternalAddress(StubRoutines::crc32c_table_addr())); + if (n > 0) { + addq(tmp3, n * 256 * 8); + } + // Q1 = TABLEExt[n][B & 0xFF]; + movl(tmp1, in); + andl(tmp1, 0x000000FF); + shll(tmp1, 3); + addq(tmp1, tmp3); + movq(tmp1, Address(tmp1, 0)); + + // Q2 = TABLEExt[n][B >> 8 & 0xFF]; + movl(tmp2, in); + shrl(tmp2, 8); + andl(tmp2, 0x000000FF); + shll(tmp2, 3); + addq(tmp2, tmp3); + movq(tmp2, Address(tmp2, 0)); + + shlq(tmp2, 8); + xorq(tmp1, tmp2); + + // Q3 = TABLEExt[n][B >> 16 & 0xFF]; + movl(tmp2, in); + shrl(tmp2, 16); + andl(tmp2, 0x000000FF); + shll(tmp2, 3); + addq(tmp2, tmp3); + movq(tmp2, Address(tmp2, 0)); + + shlq(tmp2, 16); + xorq(tmp1, tmp2); + + // Q4 = TABLEExt[n][B >> 24 & 0xFF]; + shrl(in, 24); + andl(in, 0x000000FF); + shll(in, 3); + addq(in, tmp3); + movq(in, Address(in, 0)); + + shlq(in, 24); + xorq(in, tmp1); + // return Q1 ^ Q2 << 8 ^ Q3 << 16 ^ Q4 << 24; +} + +void MacroAssembler::crc32c_pclmulqdq(XMMRegister w_xtmp1, + Register in_out, + uint32_t const_or_pre_comp_const_index, bool is_pclmulqdq_supported, + XMMRegister w_xtmp2, + Register tmp1, + Register n_tmp2, Register n_tmp3) { + if (is_pclmulqdq_supported) { + movdl(w_xtmp1, in_out); // modified blindly + + movl(tmp1, const_or_pre_comp_const_index); + movdl(w_xtmp2, tmp1); + pclmulqdq(w_xtmp1, w_xtmp2, 0); + + movdq(in_out, w_xtmp1); + } else { + crc32c_ipl_alg4(in_out, const_or_pre_comp_const_index, tmp1, n_tmp2, n_tmp3); + } +} + +// Recombination Alternative 2: No bit-reflections +// T1 = (CRC_A * U1) << 1 +// T2 = (CRC_B * U2) << 1 +// C1 = T1 >> 32 +// C2 = T2 >> 32 +// T1 = T1 & 0xFFFFFFFF +// T2 = T2 & 0xFFFFFFFF +// T1 = CRC32(0, T1) +// T2 = CRC32(0, T2) +// C1 = C1 ^ T1 +// C2 = C2 ^ T2 +// CRC = C1 ^ C2 ^ CRC_C +void MacroAssembler::crc32c_rec_alt2(uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, Register in_out, Register in1, Register in2, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp1, Register tmp2, + Register n_tmp3) { + crc32c_pclmulqdq(w_xtmp1, in_out, const_or_pre_comp_const_index_u1, is_pclmulqdq_supported, w_xtmp3, tmp1, tmp2, n_tmp3); + crc32c_pclmulqdq(w_xtmp2, in1, const_or_pre_comp_const_index_u2, is_pclmulqdq_supported, w_xtmp3, tmp1, tmp2, n_tmp3); + shlq(in_out, 1); + movl(tmp1, in_out); + shrq(in_out, 32); + xorl(tmp2, tmp2); + crc32(tmp2, tmp1, 4); + xorl(in_out, tmp2); // we don't care about upper 32 bit contents here + shlq(in1, 1); + movl(tmp1, in1); + shrq(in1, 32); + xorl(tmp2, tmp2); + crc32(tmp2, tmp1, 4); + xorl(in1, tmp2); + xorl(in_out, in1); + xorl(in_out, in2); +} + +// Set N to predefined value +// Subtract from a lenght of a buffer +// execute in a loop: +// CRC_A = 0xFFFFFFFF, CRC_B = 0, CRC_C = 0 +// for i = 1 to N do +// CRC_A = CRC32(CRC_A, A[i]) +// CRC_B = CRC32(CRC_B, B[i]) +// CRC_C = CRC32(CRC_C, C[i]) +// end for +// Recombine +void MacroAssembler::crc32c_proc_chunk(uint32_t size, uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, + Register in_out1, Register in_out2, Register in_out3, + Register tmp1, Register tmp2, Register tmp3, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp4, Register tmp5, + Register n_tmp6) { + Label L_processPartitions; + Label L_processPartition; + Label L_exit; + + bind(L_processPartitions); + cmpl(in_out1, 3 * size); + jcc(Assembler::less, L_exit); + xorl(tmp1, tmp1); + xorl(tmp2, tmp2); + movq(tmp3, in_out2); + addq(tmp3, size); + + bind(L_processPartition); + crc32(in_out3, Address(in_out2, 0), 8); + crc32(tmp1, Address(in_out2, size), 8); + crc32(tmp2, Address(in_out2, size * 2), 8); + addq(in_out2, 8); + cmpq(in_out2, tmp3); + jcc(Assembler::less, L_processPartition); + crc32c_rec_alt2(const_or_pre_comp_const_index_u1, const_or_pre_comp_const_index_u2, is_pclmulqdq_supported, in_out3, tmp1, tmp2, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + n_tmp6); + addq(in_out2, 2 * size); + subl(in_out1, 3 * size); + jmp(L_processPartitions); + + bind(L_exit); +} +#else +void MacroAssembler::crc32c_ipl_alg4(Register in_out, uint32_t n, + Register tmp1, Register tmp2, Register tmp3, + XMMRegister xtmp1, XMMRegister xtmp2) { + lea(tmp3, ExternalAddress(StubRoutines::crc32c_table_addr())); + if (n > 0) { + addl(tmp3, n * 256 * 8); + } + // Q1 = TABLEExt[n][B & 0xFF]; + movl(tmp1, in_out); + andl(tmp1, 0x000000FF); + shll(tmp1, 3); + addl(tmp1, tmp3); + movq(xtmp1, Address(tmp1, 0)); + + // Q2 = TABLEExt[n][B >> 8 & 0xFF]; + movl(tmp2, in_out); + shrl(tmp2, 8); + andl(tmp2, 0x000000FF); + shll(tmp2, 3); + addl(tmp2, tmp3); + movq(xtmp2, Address(tmp2, 0)); + + psllq(xtmp2, 8); + pxor(xtmp1, xtmp2); + + // Q3 = TABLEExt[n][B >> 16 & 0xFF]; + movl(tmp2, in_out); + shrl(tmp2, 16); + andl(tmp2, 0x000000FF); + shll(tmp2, 3); + addl(tmp2, tmp3); + movq(xtmp2, Address(tmp2, 0)); + + psllq(xtmp2, 16); + pxor(xtmp1, xtmp2); + + // Q4 = TABLEExt[n][B >> 24 & 0xFF]; + shrl(in_out, 24); + andl(in_out, 0x000000FF); + shll(in_out, 3); + addl(in_out, tmp3); + movq(xtmp2, Address(in_out, 0)); + + psllq(xtmp2, 24); + pxor(xtmp1, xtmp2); // Result in CXMM + // return Q1 ^ Q2 << 8 ^ Q3 << 16 ^ Q4 << 24; +} + +void MacroAssembler::crc32c_pclmulqdq(XMMRegister w_xtmp1, + Register in_out, + uint32_t const_or_pre_comp_const_index, bool is_pclmulqdq_supported, + XMMRegister w_xtmp2, + Register tmp1, + Register n_tmp2, Register n_tmp3) { + if (is_pclmulqdq_supported) { + movdl(w_xtmp1, in_out); + + movl(tmp1, const_or_pre_comp_const_index); + movdl(w_xtmp2, tmp1); + pclmulqdq(w_xtmp1, w_xtmp2, 0); + // Keep result in XMM since GPR is 32 bit in length + } else { + crc32c_ipl_alg4(in_out, const_or_pre_comp_const_index, tmp1, n_tmp2, n_tmp3, w_xtmp1, w_xtmp2); + } +} + +void MacroAssembler::crc32c_rec_alt2(uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, Register in_out, Register in1, Register in2, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp1, Register tmp2, + Register n_tmp3) { + crc32c_pclmulqdq(w_xtmp1, in_out, const_or_pre_comp_const_index_u1, is_pclmulqdq_supported, w_xtmp3, tmp1, tmp2, n_tmp3); + crc32c_pclmulqdq(w_xtmp2, in1, const_or_pre_comp_const_index_u2, is_pclmulqdq_supported, w_xtmp3, tmp1, tmp2, n_tmp3); + + psllq(w_xtmp1, 1); + movdl(tmp1, w_xtmp1); + psrlq(w_xtmp1, 32); + movdl(in_out, w_xtmp1); + + xorl(tmp2, tmp2); + crc32(tmp2, tmp1, 4); + xorl(in_out, tmp2); + + psllq(w_xtmp2, 1); + movdl(tmp1, w_xtmp2); + psrlq(w_xtmp2, 32); + movdl(in1, w_xtmp2); + + xorl(tmp2, tmp2); + crc32(tmp2, tmp1, 4); + xorl(in1, tmp2); + xorl(in_out, in1); + xorl(in_out, in2); +} + +void MacroAssembler::crc32c_proc_chunk(uint32_t size, uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, + Register in_out1, Register in_out2, Register in_out3, + Register tmp1, Register tmp2, Register tmp3, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp4, Register tmp5, + Register n_tmp6) { + Label L_processPartitions; + Label L_processPartition; + Label L_exit; + + bind(L_processPartitions); + cmpl(in_out1, 3 * size); + jcc(Assembler::less, L_exit); + xorl(tmp1, tmp1); + xorl(tmp2, tmp2); + movl(tmp3, in_out2); + addl(tmp3, size); + + bind(L_processPartition); + crc32(in_out3, Address(in_out2, 0), 4); + crc32(tmp1, Address(in_out2, size), 4); + crc32(tmp2, Address(in_out2, size*2), 4); + crc32(in_out3, Address(in_out2, 0+4), 4); + crc32(tmp1, Address(in_out2, size+4), 4); + crc32(tmp2, Address(in_out2, size*2+4), 4); + addl(in_out2, 8); + cmpl(in_out2, tmp3); + jcc(Assembler::less, L_processPartition); + + push(tmp3); + push(in_out1); + push(in_out2); + tmp4 = tmp3; + tmp5 = in_out1; + n_tmp6 = in_out2; + + crc32c_rec_alt2(const_or_pre_comp_const_index_u1, const_or_pre_comp_const_index_u2, is_pclmulqdq_supported, in_out3, tmp1, tmp2, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + n_tmp6); + + pop(in_out2); + pop(in_out1); + pop(tmp3); + + addl(in_out2, 2 * size); + subl(in_out1, 3 * size); + jmp(L_processPartitions); + + bind(L_exit); +} +#endif //LP64 + +#ifdef _LP64 +// Algorithm 2: Pipelined usage of the CRC32 instruction. +// Input: A buffer I of L bytes. +// Output: the CRC32C value of the buffer. +// Notations: +// Write L = 24N + r, with N = floor (L/24). +// r = L mod 24 (0 <= r < 24). +// Consider I as the concatenation of A|B|C|R, where A, B, C, each, +// N quadwords, and R consists of r bytes. +// A[j] = I [8j+7:8j], j= 0, 1, ..., N-1 +// B[j] = I [N + 8j+7:N + 8j], j= 0, 1, ..., N-1 +// C[j] = I [2N + 8j+7:2N + 8j], j= 0, 1, ..., N-1 +// if r > 0 R[j] = I [3N +j], j= 0, 1, ...,r-1 +void MacroAssembler::crc32c_ipl_alg2_alt2(Register in_out, Register in1, Register in2, + Register tmp1, Register tmp2, Register tmp3, + Register tmp4, Register tmp5, Register tmp6, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + bool is_pclmulqdq_supported) { + uint32_t const_or_pre_comp_const_index[CRC32C_NUM_PRECOMPUTED_CONSTANTS]; + Label L_wordByWord; + Label L_byteByByteProlog; + Label L_byteByByte; + Label L_exit; + + if (is_pclmulqdq_supported ) { + const_or_pre_comp_const_index[1] = *(uint32_t *)StubRoutines::_crc32c_table_addr; + const_or_pre_comp_const_index[0] = *((uint32_t *)StubRoutines::_crc32c_table_addr+1); + + const_or_pre_comp_const_index[3] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 2); + const_or_pre_comp_const_index[2] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 3); + + const_or_pre_comp_const_index[5] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 4); + const_or_pre_comp_const_index[4] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 5); + assert((CRC32C_NUM_PRECOMPUTED_CONSTANTS - 1 ) == 5, "Checking whether you declared all of the constants based on the number of \"chunks\""); + } else { + const_or_pre_comp_const_index[0] = 1; + const_or_pre_comp_const_index[1] = 0; + + const_or_pre_comp_const_index[2] = 3; + const_or_pre_comp_const_index[3] = 2; + + const_or_pre_comp_const_index[4] = 5; + const_or_pre_comp_const_index[5] = 4; + } + crc32c_proc_chunk(CRC32C_HIGH, const_or_pre_comp_const_index[0], const_or_pre_comp_const_index[1], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + crc32c_proc_chunk(CRC32C_MIDDLE, const_or_pre_comp_const_index[2], const_or_pre_comp_const_index[3], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + crc32c_proc_chunk(CRC32C_LOW, const_or_pre_comp_const_index[4], const_or_pre_comp_const_index[5], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + movl(tmp1, in2); + andl(tmp1, 0x00000007); + negl(tmp1); + addl(tmp1, in2); + addq(tmp1, in1); + + BIND(L_wordByWord); + cmpq(in1, tmp1); + jcc(Assembler::greaterEqual, L_byteByByteProlog); + crc32(in_out, Address(in1, 0), 4); + addq(in1, 4); + jmp(L_wordByWord); + + BIND(L_byteByByteProlog); + andl(in2, 0x00000007); + movl(tmp2, 1); + + BIND(L_byteByByte); + cmpl(tmp2, in2); + jccb(Assembler::greater, L_exit); + crc32(in_out, Address(in1, 0), 1); + incq(in1); + incl(tmp2); + jmp(L_byteByByte); + + BIND(L_exit); +} +#else +void MacroAssembler::crc32c_ipl_alg2_alt2(Register in_out, Register in1, Register in2, + Register tmp1, Register tmp2, Register tmp3, + Register tmp4, Register tmp5, Register tmp6, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + bool is_pclmulqdq_supported) { + uint32_t const_or_pre_comp_const_index[CRC32C_NUM_PRECOMPUTED_CONSTANTS]; + Label L_wordByWord; + Label L_byteByByteProlog; + Label L_byteByByte; + Label L_exit; + + if (is_pclmulqdq_supported) { + const_or_pre_comp_const_index[1] = *(uint32_t *)StubRoutines::_crc32c_table_addr; + const_or_pre_comp_const_index[0] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 1); + + const_or_pre_comp_const_index[3] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 2); + const_or_pre_comp_const_index[2] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 3); + + const_or_pre_comp_const_index[5] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 4); + const_or_pre_comp_const_index[4] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 5); + } else { + const_or_pre_comp_const_index[0] = 1; + const_or_pre_comp_const_index[1] = 0; + + const_or_pre_comp_const_index[2] = 3; + const_or_pre_comp_const_index[3] = 2; + + const_or_pre_comp_const_index[4] = 5; + const_or_pre_comp_const_index[5] = 4; + } + crc32c_proc_chunk(CRC32C_HIGH, const_or_pre_comp_const_index[0], const_or_pre_comp_const_index[1], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + crc32c_proc_chunk(CRC32C_MIDDLE, const_or_pre_comp_const_index[2], const_or_pre_comp_const_index[3], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + crc32c_proc_chunk(CRC32C_LOW, const_or_pre_comp_const_index[4], const_or_pre_comp_const_index[5], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + movl(tmp1, in2); + andl(tmp1, 0x00000007); + negl(tmp1); + addl(tmp1, in2); + addl(tmp1, in1); + + BIND(L_wordByWord); + cmpl(in1, tmp1); + jcc(Assembler::greaterEqual, L_byteByByteProlog); + crc32(in_out, Address(in1,0), 4); + addl(in1, 4); + jmp(L_wordByWord); + + BIND(L_byteByByteProlog); + andl(in2, 0x00000007); + movl(tmp2, 1); + + BIND(L_byteByByte); + cmpl(tmp2, in2); + jccb(Assembler::greater, L_exit); + movb(tmp1, Address(in1, 0)); + crc32(in_out, tmp1, 1); + incl(in1); + incl(tmp2); + jmp(L_byteByByte); + + BIND(L_exit); +} +#endif // LP64 #undef BIND #undef BLOCK_COMMENT diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 1a2fa3c163a..0b178ed8eeb 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -907,14 +907,14 @@ class MacroAssembler: public Assembler { // all corner cases and may result in NaN and require fallback to a // runtime call. void fast_pow(); - void fast_exp(); + void fast_exp(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, + XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, + Register rax, Register rcx, Register rdx, Register tmp); void increase_precision(); void restore_precision(); - // computes exp(x). Fallback to runtime call included. - void exp_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(true, num_fpu_regs_in_use); } // computes pow(x,y). Fallback to runtime call included. - void pow_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(false, num_fpu_regs_in_use); } + void pow_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(num_fpu_regs_in_use); } private: @@ -925,7 +925,7 @@ private: void pow_exp_core_encoding(); // computes pow(x,y) or exp(x). Fallback to runtime call included. - void pow_or_exp(bool is_exp, int num_fpu_regs_in_use); + void pow_or_exp(int num_fpu_regs_in_use); // these are private because users should be doing movflt/movdbl @@ -971,6 +971,10 @@ public: void movsd(XMMRegister dst, Address src) { Assembler::movsd(dst, src); } void movsd(XMMRegister dst, AddressLiteral src); + void mulpd(XMMRegister dst, XMMRegister src) { Assembler::mulpd(dst, src); } + void mulpd(XMMRegister dst, Address src) { Assembler::mulpd(dst, src); } + void mulpd(XMMRegister dst, AddressLiteral src); + void mulsd(XMMRegister dst, XMMRegister src) { Assembler::mulsd(dst, src); } void mulsd(XMMRegister dst, Address src) { Assembler::mulsd(dst, src); } void mulsd(XMMRegister dst, AddressLiteral src); @@ -1278,9 +1282,42 @@ public: Register raxReg); #endif - // CRC32 code for java.util.zip.CRC32::updateBytes() instrinsic. + // CRC32 code for java.util.zip.CRC32::updateBytes() intrinsic. void update_byte_crc32(Register crc, Register val, Register table); void kernel_crc32(Register crc, Register buf, Register len, Register table, Register tmp); + // CRC32C code for java.util.zip.CRC32C::updateBytes() intrinsic + // Note on a naming convention: + // Prefix w = register only used on a Westmere+ architecture + // Prefix n = register only used on a Nehalem architecture +#ifdef _LP64 + void crc32c_ipl_alg4(Register in_out, uint32_t n, + Register tmp1, Register tmp2, Register tmp3); +#else + void crc32c_ipl_alg4(Register in_out, uint32_t n, + Register tmp1, Register tmp2, Register tmp3, + XMMRegister xtmp1, XMMRegister xtmp2); +#endif + void crc32c_pclmulqdq(XMMRegister w_xtmp1, + Register in_out, + uint32_t const_or_pre_comp_const_index, bool is_pclmulqdq_supported, + XMMRegister w_xtmp2, + Register tmp1, + Register n_tmp2, Register n_tmp3); + void crc32c_rec_alt2(uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, Register in_out, Register in1, Register in2, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp1, Register tmp2, + Register n_tmp3); + void crc32c_proc_chunk(uint32_t size, uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, + Register in_out1, Register in_out2, Register in_out3, + Register tmp1, Register tmp2, Register tmp3, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp4, Register tmp5, + Register n_tmp6); + void crc32c_ipl_alg2_alt2(Register in_out, Register in1, Register in2, + Register tmp1, Register tmp2, Register tmp3, + Register tmp4, Register tmp5, Register tmp6, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + bool is_pclmulqdq_supported); // Fold 128-bit data chunk void fold_128bit_crc32(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf, int offset); void fold_128bit_crc32(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, XMMRegister xbuf); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86_libm.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86_libm.cpp new file mode 100644 index 00000000000..b5b66b7f10a --- /dev/null +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86_libm.cpp @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2015, Intel Corporation. + * Intel Math Library (LIBM) Source Code + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/******************************************************************************/ +// ALGORITHM DESCRIPTION +// --------------------- +// +// Description: +// Let K = 64 (table size). +// x x/log(2) n +// e = 2 = 2 * T[j] * (1 + P(y)) +// where +// x = m*log(2)/K + y, y in [-log(2)/K..log(2)/K] +// m = n*K + j, m,n,j - signed integer, j in [-K/2..K/2] +// j/K +// values of 2 are tabulated as T[j] = T_hi[j] ( 1 + T_lo[j]). +// +// P(y) is a minimax polynomial approximation of exp(x)-1 +// on small interval [-log(2)/K..log(2)/K] (were calculated by Maple V). +// +// To avoid problems with arithmetic overflow and underflow, +// n n1 n2 +// value of 2 is safely computed as 2 * 2 where n1 in [-BIAS/2..BIAS/2] +// where BIAS is a value of exponent bias. +// +// Special cases: +// exp(NaN) = NaN +// exp(+INF) = +INF +// exp(-INF) = 0 +// exp(x) = 1 for subnormals +// for finite argument, only exp(0)=1 is exact +// For IEEE double +// if x > 709.782712893383973096 then exp(x) overflow +// if x < -745.133219101941108420 then exp(x) underflow +// +/******************************************************************************/ + + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "macroAssembler_x86.hpp" + +#ifdef _MSC_VER +#define ALIGNED_(x) __declspec(align(x)) +#else +#define ALIGNED_(x) __attribute__ ((aligned(x))) +#endif + +#ifdef _LP64 + +ALIGNED_(16) juint _cv[] = +{ + 0x652b82feUL, 0x40571547UL, 0x652b82feUL, 0x40571547UL, 0xfefa0000UL, + 0x3f862e42UL, 0xfefa0000UL, 0x3f862e42UL, 0xbc9e3b3aUL, 0x3d1cf79aUL, + 0xbc9e3b3aUL, 0x3d1cf79aUL, 0xfffffffeUL, 0x3fdfffffUL, 0xfffffffeUL, + 0x3fdfffffUL, 0xe3289860UL, 0x3f56c15cUL, 0x555b9e25UL, 0x3fa55555UL, + 0xc090cf0fUL, 0x3f811115UL, 0x55548ba1UL, 0x3fc55555UL +}; + +ALIGNED_(16) juint _shifter[] = +{ + 0x00000000UL, 0x43380000UL, 0x00000000UL, 0x43380000UL +}; + +ALIGNED_(16) juint _mmask[] = +{ + 0xffffffc0UL, 0x00000000UL, 0xffffffc0UL, 0x00000000UL +}; + +ALIGNED_(16) juint _bias[] = +{ + 0x0000ffc0UL, 0x00000000UL, 0x0000ffc0UL, 0x00000000UL +}; + +ALIGNED_(16) juint _Tbl_addr[] = +{ + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0e03754dUL, + 0x3cad7bbfUL, 0x3e778060UL, 0x00002c9aUL, 0x3567f613UL, 0x3c8cd252UL, + 0xd3158574UL, 0x000059b0UL, 0x61e6c861UL, 0x3c60f74eUL, 0x18759bc8UL, + 0x00008745UL, 0x5d837b6cUL, 0x3c979aa6UL, 0x6cf9890fUL, 0x0000b558UL, + 0x702f9cd1UL, 0x3c3ebe3dUL, 0x32d3d1a2UL, 0x0000e3ecUL, 0x1e63bcd8UL, + 0x3ca3516eUL, 0xd0125b50UL, 0x00011301UL, 0x26f0387bUL, 0x3ca4c554UL, + 0xaea92ddfUL, 0x0001429aUL, 0x62523fb6UL, 0x3ca95153UL, 0x3c7d517aUL, + 0x000172b8UL, 0x3f1353bfUL, 0x3c8b898cUL, 0xeb6fcb75UL, 0x0001a35bUL, + 0x3e3a2f5fUL, 0x3c9aecf7UL, 0x3168b9aaUL, 0x0001d487UL, 0x44a6c38dUL, + 0x3c8a6f41UL, 0x88628cd6UL, 0x0002063bUL, 0xe3a8a894UL, 0x3c968efdUL, + 0x6e756238UL, 0x0002387aUL, 0x981fe7f2UL, 0x3c80472bUL, 0x65e27cddUL, + 0x00026b45UL, 0x6d09ab31UL, 0x3c82f7e1UL, 0xf51fdee1UL, 0x00029e9dUL, + 0x720c0ab3UL, 0x3c8b3782UL, 0xa6e4030bUL, 0x0002d285UL, 0x4db0abb6UL, + 0x3c834d75UL, 0x0a31b715UL, 0x000306feUL, 0x5dd3f84aUL, 0x3c8fdd39UL, + 0xb26416ffUL, 0x00033c08UL, 0xcc187d29UL, 0x3ca12f8cUL, 0x373aa9caUL, + 0x000371a7UL, 0x738b5e8bUL, 0x3ca7d229UL, 0x34e59ff6UL, 0x0003a7dbUL, + 0xa72a4c6dUL, 0x3c859f48UL, 0x4c123422UL, 0x0003dea6UL, 0x259d9205UL, + 0x3ca8b846UL, 0x21f72e29UL, 0x0004160aUL, 0x60c2ac12UL, 0x3c4363edUL, + 0x6061892dUL, 0x00044e08UL, 0xdaa10379UL, 0x3c6ecce1UL, 0xb5c13cd0UL, + 0x000486a2UL, 0xbb7aafb0UL, 0x3c7690ceUL, 0xd5362a27UL, 0x0004bfdaUL, + 0x9b282a09UL, 0x3ca083ccUL, 0x769d2ca6UL, 0x0004f9b2UL, 0xc1aae707UL, + 0x3ca509b0UL, 0x569d4f81UL, 0x0005342bUL, 0x18fdd78eUL, 0x3c933505UL, + 0x36b527daUL, 0x00056f47UL, 0xe21c5409UL, 0x3c9063e1UL, 0xdd485429UL, + 0x0005ab07UL, 0x2b64c035UL, 0x3c9432e6UL, 0x15ad2148UL, 0x0005e76fUL, + 0x99f08c0aUL, 0x3ca01284UL, 0xb03a5584UL, 0x0006247eUL, 0x0073dc06UL, + 0x3c99f087UL, 0x82552224UL, 0x00066238UL, 0x0da05571UL, 0x3c998d4dUL, + 0x667f3bccUL, 0x0006a09eUL, 0x86ce4786UL, 0x3ca52bb9UL, 0x3c651a2eUL, + 0x0006dfb2UL, 0x206f0dabUL, 0x3ca32092UL, 0xe8ec5f73UL, 0x00071f75UL, + 0x8e17a7a6UL, 0x3ca06122UL, 0x564267c8UL, 0x00075febUL, 0x461e9f86UL, + 0x3ca244acUL, 0x73eb0186UL, 0x0007a114UL, 0xabd66c55UL, 0x3c65ebe1UL, + 0x36cf4e62UL, 0x0007e2f3UL, 0xbbff67d0UL, 0x3c96fe9fUL, 0x994cce12UL, + 0x00082589UL, 0x14c801dfUL, 0x3c951f14UL, 0x9b4492ecUL, 0x000868d9UL, + 0xc1f0eab4UL, 0x3c8db72fUL, 0x422aa0dbUL, 0x0008ace5UL, 0x59f35f44UL, + 0x3c7bf683UL, 0x99157736UL, 0x0008f1aeUL, 0x9c06283cUL, 0x3ca360baUL, + 0xb0cdc5e4UL, 0x00093737UL, 0x20f962aaUL, 0x3c95e8d1UL, 0x9fde4e4fUL, + 0x00097d82UL, 0x2b91ce27UL, 0x3c71affcUL, 0x82a3f090UL, 0x0009c491UL, + 0x589a2ebdUL, 0x3c9b6d34UL, 0x7b5de564UL, 0x000a0c66UL, 0x9ab89880UL, + 0x3c95277cUL, 0xb23e255cUL, 0x000a5503UL, 0x6e735ab3UL, 0x3c846984UL, + 0x5579fdbfUL, 0x000a9e6bUL, 0x92cb3387UL, 0x3c8c1a77UL, 0x995ad3adUL, + 0x000ae89fUL, 0xdc2d1d96UL, 0x3ca22466UL, 0xb84f15faUL, 0x000b33a2UL, + 0xb19505aeUL, 0x3ca1112eUL, 0xf2fb5e46UL, 0x000b7f76UL, 0x0a5fddcdUL, + 0x3c74ffd7UL, 0x904bc1d2UL, 0x000bcc1eUL, 0x30af0cb3UL, 0x3c736eaeUL, + 0xdd85529cUL, 0x000c199bUL, 0xd10959acUL, 0x3c84e08fUL, 0x2e57d14bUL, + 0x000c67f1UL, 0x6c921968UL, 0x3c676b2cUL, 0xdcef9069UL, 0x000cb720UL, + 0x36df99b3UL, 0x3c937009UL, 0x4a07897bUL, 0x000d072dUL, 0xa63d07a7UL, + 0x3c74a385UL, 0xdcfba487UL, 0x000d5818UL, 0xd5c192acUL, 0x3c8e5a50UL, + 0x03db3285UL, 0x000da9e6UL, 0x1c4a9792UL, 0x3c98bb73UL, 0x337b9b5eUL, + 0x000dfc97UL, 0x603a88d3UL, 0x3c74b604UL, 0xe78b3ff6UL, 0x000e502eUL, + 0x92094926UL, 0x3c916f27UL, 0xa2a490d9UL, 0x000ea4afUL, 0x41aa2008UL, + 0x3c8ec3bcUL, 0xee615a27UL, 0x000efa1bUL, 0x31d185eeUL, 0x3c8a64a9UL, + 0x5b6e4540UL, 0x000f5076UL, 0x4d91cd9dUL, 0x3c77893bUL, 0x819e90d8UL, + 0x000fa7c1UL +}; + +ALIGNED_(16) juint _ALLONES[] = +{ + 0xffffffffUL, 0xffffffffUL, 0xffffffffUL, 0xffffffffUL +}; + +ALIGNED_(16) juint _ebias[] = +{ + 0x00000000UL, 0x3ff00000UL, 0x00000000UL, 0x3ff00000UL +}; + +ALIGNED_(4) juint _XMAX[] = +{ + 0xffffffffUL, 0x7fefffffUL +}; + +ALIGNED_(4) juint _XMIN[] = +{ + 0x00000000UL, 0x00100000UL +}; + +ALIGNED_(4) juint _INF[] = +{ + 0x00000000UL, 0x7ff00000UL +}; + +ALIGNED_(4) juint _ZERO[] = +{ + 0x00000000UL, 0x00000000UL +}; + +ALIGNED_(4) juint _ONE_val[] = +{ + 0x00000000UL, 0x3ff00000UL +}; + + +// Registers: +// input: xmm0 +// scratch: xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 +// rax, rdx, rcx, tmp - r11 + +// Code generated by Intel C compiler for LIBM library + +void MacroAssembler::fast_exp(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register eax, Register ecx, Register edx, Register tmp) { + Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_2_0_2, L_2TAG_PACKET_3_0_2; + Label L_2TAG_PACKET_4_0_2, L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2, L_2TAG_PACKET_7_0_2; + Label L_2TAG_PACKET_8_0_2, L_2TAG_PACKET_9_0_2, L_2TAG_PACKET_10_0_2, L_2TAG_PACKET_11_0_2; + Label L_2TAG_PACKET_12_0_2, B1_3, B1_5, start; + + assert_different_registers(tmp, eax, ecx, edx); + jmp(start); + address cv = (address)_cv; + address Shifter = (address)_shifter; + address mmask = (address)_mmask; + address bias = (address)_bias; + address Tbl_addr = (address)_Tbl_addr; + address ALLONES = (address)_ALLONES; + address ebias = (address)_ebias; + address XMAX = (address)_XMAX; + address XMIN = (address)_XMIN; + address INF = (address)_INF; + address ZERO = (address)_ZERO; + address ONE_val = (address)_ONE_val; + + bind(start); + subq(rsp, 24); + movsd(Address(rsp, 8), xmm0); + unpcklpd(xmm0, xmm0); + movdqu(xmm1, ExternalAddress(cv)); // 0x652b82feUL, 0x40571547UL, 0x652b82feUL, 0x40571547UL + movdqu(xmm6, ExternalAddress(Shifter)); // 0x00000000UL, 0x43380000UL, 0x00000000UL, 0x43380000UL + movdqu(xmm2, ExternalAddress(16+cv)); // 0xfefa0000UL, 0x3f862e42UL, 0xfefa0000UL, 0x3f862e42UL + movdqu(xmm3, ExternalAddress(32+cv)); // 0xbc9e3b3aUL, 0x3d1cf79aUL, 0xbc9e3b3aUL, 0x3d1cf79aUL + pextrw(eax, xmm0, 3); + andl(eax, 32767); + movl(edx, 16527); + subl(edx, eax); + subl(eax, 15504); + orl(edx, eax); + cmpl(edx, INT_MIN); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_0_0_2); + mulpd(xmm1, xmm0); + addpd(xmm1, xmm6); + movapd(xmm7, xmm1); + subpd(xmm1, xmm6); + mulpd(xmm2, xmm1); + movdqu(xmm4, ExternalAddress(64+cv)); // 0xe3289860UL, 0x3f56c15cUL, 0x555b9e25UL, 0x3fa55555UL + mulpd(xmm3, xmm1); + movdqu(xmm5, ExternalAddress(80+cv)); // 0xc090cf0fUL, 0x3f811115UL, 0x55548ba1UL, 0x3fc55555UL + subpd(xmm0, xmm2); + movdl(eax, xmm7); + movl(ecx, eax); + andl(ecx, 63); + shll(ecx, 4); + sarl(eax, 6); + movl(edx, eax); + movdqu(xmm6, ExternalAddress(mmask)); // 0xffffffc0UL, 0x00000000UL, 0xffffffc0UL, 0x00000000UL + pand(xmm7, xmm6); + movdqu(xmm6, ExternalAddress(bias)); // 0x0000ffc0UL, 0x00000000UL, 0x0000ffc0UL, 0x00000000UL + paddq(xmm7, xmm6); + psllq(xmm7, 46); + subpd(xmm0, xmm3); + lea(tmp, ExternalAddress(Tbl_addr)); + movdqu(xmm2, Address(ecx,tmp)); + mulpd(xmm4, xmm0); + movapd(xmm6, xmm0); + movapd(xmm1, xmm0); + mulpd(xmm6, xmm6); + mulpd(xmm0, xmm6); + addpd(xmm5, xmm4); + mulsd(xmm0, xmm6); + mulpd(xmm6, ExternalAddress(48+cv)); // 0xfffffffeUL, 0x3fdfffffUL, 0xfffffffeUL, 0x3fdfffffUL + addsd(xmm1, xmm2); + unpckhpd(xmm2, xmm2); + mulpd(xmm0, xmm5); + addsd(xmm1, xmm0); + por(xmm2, xmm7); + unpckhpd(xmm0, xmm0); + addsd(xmm0, xmm1); + addsd(xmm0, xmm6); + addl(edx, 894); + cmpl(edx, 1916); + jcc (Assembler::above, L_2TAG_PACKET_1_0_2); + mulsd(xmm0, xmm2); + addsd(xmm0, xmm2); + jmp (B1_5); + + bind(L_2TAG_PACKET_1_0_2); + xorpd(xmm3, xmm3); + movdqu(xmm4, ExternalAddress(ALLONES)); // 0xffffffffUL, 0xffffffffUL, 0xffffffffUL, 0xffffffffUL + movl(edx, -1022); + subl(edx, eax); + movdl(xmm5, edx); + psllq(xmm4, xmm5); + movl(ecx, eax); + sarl(eax, 1); + pinsrw(xmm3, eax, 3); + movdqu(xmm6, ExternalAddress(ebias)); // 0x00000000UL, 0x3ff00000UL, 0x00000000UL, 0x3ff00000UL + psllq(xmm3, 4); + psubd(xmm2, xmm3); + mulsd(xmm0, xmm2); + cmpl(edx, 52); + jcc(Assembler::greater, L_2TAG_PACKET_2_0_2); + pand(xmm4, xmm2); + paddd(xmm3, xmm6); + subsd(xmm2, xmm4); + addsd(xmm0, xmm2); + cmpl(ecx, 1023); + jcc(Assembler::greaterEqual, L_2TAG_PACKET_3_0_2); + pextrw(ecx, xmm0, 3); + andl(ecx, 32768); + orl(edx, ecx); + cmpl(edx, 0); + jcc(Assembler::equal, L_2TAG_PACKET_4_0_2); + movapd(xmm6, xmm0); + addsd(xmm0, xmm4); + mulsd(xmm0, xmm3); + pextrw(ecx, xmm0, 3); + andl(ecx, 32752); + cmpl(ecx, 0); + jcc(Assembler::equal, L_2TAG_PACKET_5_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_5_0_2); + mulsd(xmm6, xmm3); + mulsd(xmm4, xmm3); + movdqu(xmm0, xmm6); + pxor(xmm6, xmm4); + psrad(xmm6, 31); + pshufd(xmm6, xmm6, 85); + psllq(xmm0, 1); + psrlq(xmm0, 1); + pxor(xmm0, xmm6); + psrlq(xmm6, 63); + paddq(xmm0, xmm6); + paddq(xmm0, xmm4); + movl(Address(rsp,0), 15); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_4_0_2); + addsd(xmm0, xmm4); + mulsd(xmm0, xmm3); + jmp(B1_5); + + bind(L_2TAG_PACKET_3_0_2); + addsd(xmm0, xmm4); + mulsd(xmm0, xmm3); + pextrw(ecx, xmm0, 3); + andl(ecx, 32752); + cmpl(ecx, 32752); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_7_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_2_0_2); + paddd(xmm3, xmm6); + addpd(xmm0, xmm2); + mulsd(xmm0, xmm3); + movl(Address(rsp,0), 15); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_8_0_2); + cmpl(eax, 2146435072); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_9_0_2); + movl(eax, Address(rsp,12)); + cmpl(eax, INT_MIN); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_10_0_2); + movsd(xmm0, ExternalAddress(XMAX)); // 0xffffffffUL, 0x7fefffffUL + mulsd(xmm0, xmm0); + + bind(L_2TAG_PACKET_7_0_2); + movl(Address(rsp,0), 14); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_10_0_2); + movsd(xmm0, ExternalAddress(XMIN)); // 0x00000000UL, 0x00100000UL + mulsd(xmm0, xmm0); + movl(Address(rsp,0), 15); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_9_0_2); + movl(edx, Address(rsp,8)); + cmpl(eax, 2146435072); + jcc(Assembler::above, L_2TAG_PACKET_11_0_2); + cmpl(edx, 0); + jcc(Assembler::notEqual, L_2TAG_PACKET_11_0_2); + movl(eax, Address(rsp,12)); + cmpl(eax, 2146435072); + jcc(Assembler::notEqual, L_2TAG_PACKET_12_0_2); + movsd(xmm0, ExternalAddress(INF)); // 0x00000000UL, 0x7ff00000UL + jmp(B1_5); + + bind(L_2TAG_PACKET_12_0_2); + movsd(xmm0, ExternalAddress(ZERO)); // 0x00000000UL, 0x00000000UL + jmp(B1_5); + + bind(L_2TAG_PACKET_11_0_2); + movsd(xmm0, Address(rsp, 8)); + addsd(xmm0, xmm0); + jmp(B1_5); + + bind(L_2TAG_PACKET_0_0_2); + movl(eax, Address(rsp, 12)); + andl(eax, 2147483647); + cmpl(eax, 1083179008); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_8_0_2); + movsd(Address(rsp, 8), xmm0); + addsd(xmm0, ExternalAddress(ONE_val)); // 0x00000000UL, 0x3ff00000UL + jmp(B1_5); + + bind(L_2TAG_PACKET_6_0_2); + movq(Address(rsp, 16), xmm0); + + bind(B1_3); + movq(xmm0, Address(rsp, 16)); + + bind(B1_5); + addq(rsp, 24); +} +#endif + +#ifndef _LP64 + +ALIGNED_(16) juint _static_const_table[] = +{ + 0x00000000UL, 0xfff00000UL, 0x00000000UL, 0xfff00000UL, 0xffffffc0UL, + 0x00000000UL, 0xffffffc0UL, 0x00000000UL, 0x0000ffc0UL, 0x00000000UL, + 0x0000ffc0UL, 0x00000000UL, 0x00000000UL, 0x43380000UL, 0x00000000UL, + 0x43380000UL, 0x652b82feUL, 0x40571547UL, 0x652b82feUL, 0x40571547UL, + 0xfefa0000UL, 0x3f862e42UL, 0xfefa0000UL, 0x3f862e42UL, 0xbc9e3b3aUL, + 0x3d1cf79aUL, 0xbc9e3b3aUL, 0x3d1cf79aUL, 0xfffffffeUL, 0x3fdfffffUL, + 0xfffffffeUL, 0x3fdfffffUL, 0xe3289860UL, 0x3f56c15cUL, 0x555b9e25UL, + 0x3fa55555UL, 0xc090cf0fUL, 0x3f811115UL, 0x55548ba1UL, 0x3fc55555UL, + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0e03754dUL, + 0x3cad7bbfUL, 0x3e778060UL, 0x00002c9aUL, 0x3567f613UL, 0x3c8cd252UL, + 0xd3158574UL, 0x000059b0UL, 0x61e6c861UL, 0x3c60f74eUL, 0x18759bc8UL, + 0x00008745UL, 0x5d837b6cUL, 0x3c979aa6UL, 0x6cf9890fUL, 0x0000b558UL, + 0x702f9cd1UL, 0x3c3ebe3dUL, 0x32d3d1a2UL, 0x0000e3ecUL, 0x1e63bcd8UL, + 0x3ca3516eUL, 0xd0125b50UL, 0x00011301UL, 0x26f0387bUL, 0x3ca4c554UL, + 0xaea92ddfUL, 0x0001429aUL, 0x62523fb6UL, 0x3ca95153UL, 0x3c7d517aUL, + 0x000172b8UL, 0x3f1353bfUL, 0x3c8b898cUL, 0xeb6fcb75UL, 0x0001a35bUL, + 0x3e3a2f5fUL, 0x3c9aecf7UL, 0x3168b9aaUL, 0x0001d487UL, 0x44a6c38dUL, + 0x3c8a6f41UL, 0x88628cd6UL, 0x0002063bUL, 0xe3a8a894UL, 0x3c968efdUL, + 0x6e756238UL, 0x0002387aUL, 0x981fe7f2UL, 0x3c80472bUL, 0x65e27cddUL, + 0x00026b45UL, 0x6d09ab31UL, 0x3c82f7e1UL, 0xf51fdee1UL, 0x00029e9dUL, + 0x720c0ab3UL, 0x3c8b3782UL, 0xa6e4030bUL, 0x0002d285UL, 0x4db0abb6UL, + 0x3c834d75UL, 0x0a31b715UL, 0x000306feUL, 0x5dd3f84aUL, 0x3c8fdd39UL, + 0xb26416ffUL, 0x00033c08UL, 0xcc187d29UL, 0x3ca12f8cUL, 0x373aa9caUL, + 0x000371a7UL, 0x738b5e8bUL, 0x3ca7d229UL, 0x34e59ff6UL, 0x0003a7dbUL, + 0xa72a4c6dUL, 0x3c859f48UL, 0x4c123422UL, 0x0003dea6UL, 0x259d9205UL, + 0x3ca8b846UL, 0x21f72e29UL, 0x0004160aUL, 0x60c2ac12UL, 0x3c4363edUL, + 0x6061892dUL, 0x00044e08UL, 0xdaa10379UL, 0x3c6ecce1UL, 0xb5c13cd0UL, + 0x000486a2UL, 0xbb7aafb0UL, 0x3c7690ceUL, 0xd5362a27UL, 0x0004bfdaUL, + 0x9b282a09UL, 0x3ca083ccUL, 0x769d2ca6UL, 0x0004f9b2UL, 0xc1aae707UL, + 0x3ca509b0UL, 0x569d4f81UL, 0x0005342bUL, 0x18fdd78eUL, 0x3c933505UL, + 0x36b527daUL, 0x00056f47UL, 0xe21c5409UL, 0x3c9063e1UL, 0xdd485429UL, + 0x0005ab07UL, 0x2b64c035UL, 0x3c9432e6UL, 0x15ad2148UL, 0x0005e76fUL, + 0x99f08c0aUL, 0x3ca01284UL, 0xb03a5584UL, 0x0006247eUL, 0x0073dc06UL, + 0x3c99f087UL, 0x82552224UL, 0x00066238UL, 0x0da05571UL, 0x3c998d4dUL, + 0x667f3bccUL, 0x0006a09eUL, 0x86ce4786UL, 0x3ca52bb9UL, 0x3c651a2eUL, + 0x0006dfb2UL, 0x206f0dabUL, 0x3ca32092UL, 0xe8ec5f73UL, 0x00071f75UL, + 0x8e17a7a6UL, 0x3ca06122UL, 0x564267c8UL, 0x00075febUL, 0x461e9f86UL, + 0x3ca244acUL, 0x73eb0186UL, 0x0007a114UL, 0xabd66c55UL, 0x3c65ebe1UL, + 0x36cf4e62UL, 0x0007e2f3UL, 0xbbff67d0UL, 0x3c96fe9fUL, 0x994cce12UL, + 0x00082589UL, 0x14c801dfUL, 0x3c951f14UL, 0x9b4492ecUL, 0x000868d9UL, + 0xc1f0eab4UL, 0x3c8db72fUL, 0x422aa0dbUL, 0x0008ace5UL, 0x59f35f44UL, + 0x3c7bf683UL, 0x99157736UL, 0x0008f1aeUL, 0x9c06283cUL, 0x3ca360baUL, + 0xb0cdc5e4UL, 0x00093737UL, 0x20f962aaUL, 0x3c95e8d1UL, 0x9fde4e4fUL, + 0x00097d82UL, 0x2b91ce27UL, 0x3c71affcUL, 0x82a3f090UL, 0x0009c491UL, + 0x589a2ebdUL, 0x3c9b6d34UL, 0x7b5de564UL, 0x000a0c66UL, 0x9ab89880UL, + 0x3c95277cUL, 0xb23e255cUL, 0x000a5503UL, 0x6e735ab3UL, 0x3c846984UL, + 0x5579fdbfUL, 0x000a9e6bUL, 0x92cb3387UL, 0x3c8c1a77UL, 0x995ad3adUL, + 0x000ae89fUL, 0xdc2d1d96UL, 0x3ca22466UL, 0xb84f15faUL, 0x000b33a2UL, + 0xb19505aeUL, 0x3ca1112eUL, 0xf2fb5e46UL, 0x000b7f76UL, 0x0a5fddcdUL, + 0x3c74ffd7UL, 0x904bc1d2UL, 0x000bcc1eUL, 0x30af0cb3UL, 0x3c736eaeUL, + 0xdd85529cUL, 0x000c199bUL, 0xd10959acUL, 0x3c84e08fUL, 0x2e57d14bUL, + 0x000c67f1UL, 0x6c921968UL, 0x3c676b2cUL, 0xdcef9069UL, 0x000cb720UL, + 0x36df99b3UL, 0x3c937009UL, 0x4a07897bUL, 0x000d072dUL, 0xa63d07a7UL, + 0x3c74a385UL, 0xdcfba487UL, 0x000d5818UL, 0xd5c192acUL, 0x3c8e5a50UL, + 0x03db3285UL, 0x000da9e6UL, 0x1c4a9792UL, 0x3c98bb73UL, 0x337b9b5eUL, + 0x000dfc97UL, 0x603a88d3UL, 0x3c74b604UL, 0xe78b3ff6UL, 0x000e502eUL, + 0x92094926UL, 0x3c916f27UL, 0xa2a490d9UL, 0x000ea4afUL, 0x41aa2008UL, + 0x3c8ec3bcUL, 0xee615a27UL, 0x000efa1bUL, 0x31d185eeUL, 0x3c8a64a9UL, + 0x5b6e4540UL, 0x000f5076UL, 0x4d91cd9dUL, 0x3c77893bUL, 0x819e90d8UL, + 0x000fa7c1UL, 0x00000000UL, 0x3ff00000UL, 0x00000000UL, 0x7ff00000UL, + 0x00000000UL, 0x00000000UL, 0xffffffffUL, 0x7fefffffUL, 0x00000000UL, + 0x00100000UL +}; + +//registers, +// input: (rbp + 8) +// scratch: xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 +// rax, rdx, rcx, rbx (tmp) + +// Code generated by Intel C compiler for LIBM library + +void MacroAssembler::fast_exp(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register eax, Register ecx, Register edx, Register tmp) { + Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_2_0_2, L_2TAG_PACKET_3_0_2; + Label L_2TAG_PACKET_4_0_2, L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2, L_2TAG_PACKET_7_0_2; + Label L_2TAG_PACKET_8_0_2, L_2TAG_PACKET_9_0_2, L_2TAG_PACKET_10_0_2, L_2TAG_PACKET_11_0_2; + Label L_2TAG_PACKET_12_0_2, L_2TAG_PACKET_13_0_2, B1_3, B1_5, start; + + assert_different_registers(tmp, eax, ecx, edx); + jmp(start); + address static_const_table = (address)_static_const_table; + + bind(start); + subl(rsp, 120); + movl(Address(rsp, 64), tmp); + lea(tmp, ExternalAddress(static_const_table)); + movdqu(xmm0, Address(rsp, 128)); + unpcklpd(xmm0, xmm0); + movdqu(xmm1, Address(tmp, 64)); // 0x652b82feUL, 0x40571547UL, 0x652b82feUL, 0x40571547UL + movdqu(xmm6, Address(tmp, 48)); // 0x00000000UL, 0x43380000UL, 0x00000000UL, 0x43380000UL + movdqu(xmm2, Address(tmp, 80)); // 0xfefa0000UL, 0x3f862e42UL, 0xfefa0000UL, 0x3f862e42UL + movdqu(xmm3, Address(tmp, 96)); // 0xbc9e3b3aUL, 0x3d1cf79aUL, 0xbc9e3b3aUL, 0x3d1cf79aUL + pextrw(eax, xmm0, 3); + andl(eax, 32767); + movl(edx, 16527); + subl(edx, eax); + subl(eax, 15504); + orl(edx, eax); + cmpl(edx, INT_MIN); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_0_0_2); + mulpd(xmm1, xmm0); + addpd(xmm1, xmm6); + movapd(xmm7, xmm1); + subpd(xmm1, xmm6); + mulpd(xmm2, xmm1); + movdqu(xmm4, Address(tmp, 128)); // 0xe3289860UL, 0x3f56c15cUL, 0x555b9e25UL, 0x3fa55555UL + mulpd(xmm3, xmm1); + movdqu(xmm5, Address(tmp, 144)); // 0xc090cf0fUL, 0x3f811115UL, 0x55548ba1UL, 0x3fc55555UL + subpd(xmm0, xmm2); + movdl(eax, xmm7); + movl(ecx, eax); + andl(ecx, 63); + shll(ecx, 4); + sarl(eax, 6); + movl(edx, eax); + movdqu(xmm6, Address(tmp, 16)); // 0xffffffc0UL, 0x00000000UL, 0xffffffc0UL, 0x00000000UL + pand(xmm7, xmm6); + movdqu(xmm6, Address(tmp, 32)); // 0x0000ffc0UL, 0x00000000UL, 0x0000ffc0UL, 0x00000000UL + paddq(xmm7, xmm6); + psllq(xmm7, 46); + subpd(xmm0, xmm3); + movdqu(xmm2, Address(tmp, ecx, Address::times_1, 160)); + mulpd(xmm4, xmm0); + movapd(xmm6, xmm0); + movapd(xmm1, xmm0); + mulpd(xmm6, xmm6); + mulpd(xmm0, xmm6); + addpd(xmm5, xmm4); + mulsd(xmm0, xmm6); + mulpd(xmm6, Address(tmp, 112)); // 0xfffffffeUL, 0x3fdfffffUL, 0xfffffffeUL, 0x3fdfffffUL + addsd(xmm1, xmm2); + unpckhpd(xmm2, xmm2); + mulpd(xmm0, xmm5); + addsd(xmm1, xmm0); + por(xmm2, xmm7); + unpckhpd(xmm0, xmm0); + addsd(xmm0, xmm1); + addsd(xmm0, xmm6); + addl(edx, 894); + cmpl(edx, 1916); + jcc (Assembler::above, L_2TAG_PACKET_1_0_2); + mulsd(xmm0, xmm2); + addsd(xmm0, xmm2); + jmp(L_2TAG_PACKET_2_0_2); + + bind(L_2TAG_PACKET_1_0_2); + fnstcw(Address(rsp, 24)); + movzwl(edx, Address(rsp, 24)); + orl(edx, 768); + movw(Address(rsp, 28), edx); + fldcw(Address(rsp, 28)); + movl(edx, eax); + sarl(eax, 1); + subl(edx, eax); + movdqu(xmm6, Address(tmp, 0)); // 0x00000000UL, 0xfff00000UL, 0x00000000UL, 0xfff00000UL + pandn(xmm6, xmm2); + addl(eax, 1023); + movdl(xmm3, eax); + psllq(xmm3, 52); + por(xmm6, xmm3); + addl(edx, 1023); + movdl(xmm4, edx); + psllq(xmm4, 52); + movsd(Address(rsp, 8), xmm0); + fld_d(Address(rsp, 8)); + movsd(Address(rsp, 16), xmm6); + fld_d(Address(rsp, 16)); + fmula(1); + faddp(1); + movsd(Address(rsp, 8), xmm4); + fld_d(Address(rsp, 8)); + fmulp(1); + fstp_d(Address(rsp, 8)); + movsd(xmm0,Address(rsp, 8)); + fldcw(Address(rsp, 24)); + pextrw(ecx, xmm0, 3); + andl(ecx, 32752); + cmpl(ecx, 32752); + jcc(Assembler::greaterEqual, L_2TAG_PACKET_3_0_2); + cmpl(ecx, 0); + jcc(Assembler::equal, L_2TAG_PACKET_4_0_2); + jmp(L_2TAG_PACKET_2_0_2); + cmpl(ecx, INT_MIN); + jcc(Assembler::less, L_2TAG_PACKET_3_0_2); + cmpl(ecx, -1064950997); + jcc(Assembler::less, L_2TAG_PACKET_2_0_2); + jcc(Assembler::greater, L_2TAG_PACKET_4_0_2); + movl(edx, Address(rsp, 128)); + cmpl(edx ,-17155601); + jcc(Assembler::less, L_2TAG_PACKET_2_0_2); + jmp(L_2TAG_PACKET_4_0_2); + + bind(L_2TAG_PACKET_3_0_2); + movl(edx, 14); + jmp(L_2TAG_PACKET_5_0_2); + + bind(L_2TAG_PACKET_4_0_2); + movl(edx, 15); + + bind(L_2TAG_PACKET_5_0_2); + movsd(Address(rsp, 0), xmm0); + movsd(xmm0, Address(rsp, 128)); + fld_d(Address(rsp, 0)); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_7_0_2); + cmpl(eax, 2146435072); + jcc(Assembler::greaterEqual, L_2TAG_PACKET_8_0_2); + movl(eax, Address(rsp, 132)); + cmpl(eax, INT_MIN); + jcc(Assembler::greaterEqual, L_2TAG_PACKET_9_0_2); + movsd(xmm0, Address(tmp, 1208)); // 0xffffffffUL, 0x7fefffffUL + mulsd(xmm0, xmm0); + movl(edx, 14); + jmp(L_2TAG_PACKET_5_0_2); + + bind(L_2TAG_PACKET_9_0_2); + movsd(xmm0, Address(tmp, 1216)); + mulsd(xmm0, xmm0); + movl(edx, 15); + jmp(L_2TAG_PACKET_5_0_2); + + bind(L_2TAG_PACKET_8_0_2); + movl(edx, Address(rsp, 128)); + cmpl(eax, 2146435072); + jcc(Assembler::above, L_2TAG_PACKET_10_0_2); + cmpl(edx, 0); + jcc(Assembler::notEqual, L_2TAG_PACKET_10_0_2); + movl(eax, Address(rsp, 132)); + cmpl(eax, 2146435072); + jcc(Assembler::notEqual, L_2TAG_PACKET_11_0_2); + movsd(xmm0, Address(tmp, 1192)); // 0x00000000UL, 0x7ff00000UL + jmp(L_2TAG_PACKET_2_0_2); + + bind(L_2TAG_PACKET_11_0_2); + movsd(xmm0, Address(tmp, 1200)); // 0x00000000UL, 0x00000000UL + jmp(L_2TAG_PACKET_2_0_2); + + bind(L_2TAG_PACKET_10_0_2); + movsd(xmm0, Address(rsp, 128)); + addsd(xmm0, xmm0); + jmp(L_2TAG_PACKET_2_0_2); + + bind(L_2TAG_PACKET_0_0_2); + movl(eax, Address(rsp, 132)); + andl(eax, 2147483647); + cmpl(eax, 1083179008); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_7_0_2); + movsd(xmm0, Address(rsp, 128)); + addsd(xmm0, Address(tmp, 1184)); // 0x00000000UL, 0x3ff00000UL + jmp(L_2TAG_PACKET_2_0_2); + + bind(L_2TAG_PACKET_2_0_2); + movsd(Address(rsp, 48), xmm0); + fld_d(Address(rsp, 48)); + + bind(L_2TAG_PACKET_6_0_2); + movl(tmp, Address(rsp, 64)); +} + +#endif diff --git a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp index 1a476e80c75..be97c30acf1 100644 --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp @@ -30,8 +30,6 @@ #include "memory/allocation.inline.hpp" #include "prims/methodHandles.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #define __ _masm-> #ifdef PRODUCT @@ -53,7 +51,7 @@ void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_ #ifdef ASSERT static int check_nonzero(const char* xname, int x) { - assert(x != 0, err_msg("%s should be nonzero", xname)); + assert(x != 0, "%s should be nonzero", xname); return x; } #define NONZERO(x) check_nonzero(#x, x) @@ -456,7 +454,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, } default: - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } @@ -488,7 +486,7 @@ void trace_method_handle_stub(const char* adaptername, const char* mh_reg_name = has_mh ? "rcx_mh" : "rcx"; tty->print_cr("MH %s %s=" PTR_FORMAT " sp=" PTR_FORMAT, adaptername, mh_reg_name, - (void *)mh, entry_sp); + p2i(mh), p2i(entry_sp)); if (Verbose) { tty->print_cr("Registers:"); diff --git a/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp b/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp index c38455f1fca..26c6f3392ad 100644 --- a/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp +++ b/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp @@ -35,18 +35,15 @@ #include "c1/c1_Runtime1.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void NativeInstruction::wrote(int offset) { ICache::invalidate_word(addr_at(offset)); } - void NativeCall::verify() { // Make sure code pattern is actually a call imm32 instruction. int inst = ubyte_at(0); if (inst != instruction_code) { - tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", instruction_address(), + tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()), inst); fatal("not a call disp32"); } @@ -63,7 +60,7 @@ address NativeCall::destination() const { void NativeCall::print() { tty->print_cr(PTR_FORMAT ": call " PTR_FORMAT, - instruction_address(), destination()); + p2i(instruction_address()), p2i(destination())); } // Inserts a native call instruction at a given pc @@ -230,7 +227,7 @@ void NativeMovConstReg::verify() { void NativeMovConstReg::print() { tty->print_cr(PTR_FORMAT ": mov reg, " INTPTR_FORMAT, - instruction_address(), data()); + p2i(instruction_address()), data()); } //------------------------------------------------------------------- @@ -396,7 +393,7 @@ void NativeMovRegMem::verify() { void NativeMovRegMem::print() { - tty->print_cr("0x%x: mov reg, [reg + %x]", instruction_address(), offset()); + tty->print_cr(PTR_FORMAT ": mov reg, [reg + %x]", p2i(instruction_address()), offset()); } //------------------------------------------------------------------- @@ -418,7 +415,7 @@ void NativeLoadAddress::verify() { void NativeLoadAddress::print() { - tty->print_cr("0x%x: lea [reg + %x], reg", instruction_address(), offset()); + tty->print_cr(PTR_FORMAT ": lea [reg + %x], reg", p2i(instruction_address()), offset()); } //-------------------------------------------------------------------------------- @@ -474,6 +471,7 @@ void NativeJump::check_verified_entry_alignment(address entry, address verified_ // // In C2 the 5+ byte sized instruction is enforced by code in MachPrologNode::emit. // In C1 the restriction is enforced by CodeEmitter::method_entry +// In JVMCI, the restriction is enforced by HotSpotFrameContext.enter(...) // void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { // complete jump instruction (to be inserted) is in code_buffer; diff --git a/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp b/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp index 529512731cf..6c527d49991 100644 --- a/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp +++ b/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp @@ -60,6 +60,7 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { bool is_nop() { return ubyte_at(0) == nop_instruction_code; } inline bool is_call(); + inline bool is_call_reg(); inline bool is_illegal(); inline bool is_return(); inline bool is_jump(); @@ -180,6 +181,24 @@ inline NativeCall* nativeCall_before(address return_address) { return call; } +class NativeCallReg: public NativeInstruction { + public: + enum Intel_specific_constants { + instruction_code = 0xFF, + instruction_offset = 0, + return_address_offset_norex = 2, + return_address_offset_rex = 3 + }; + + int next_instruction_offset() const { + if (ubyte_at(0) == NativeCallReg::instruction_code) { + return return_address_offset_norex; + } else { + return return_address_offset_rex; + } + } +}; + // An interface for accessing/manipulating native mov reg, imm32 instructions. // (used to manipulate inlined 32bit data dll calls, etc.) class NativeMovConstReg: public NativeInstruction { @@ -519,6 +538,9 @@ class NativeTstRegMem: public NativeInstruction { inline bool NativeInstruction::is_illegal() { return (short)int_at(0) == (short)NativeIllegalInstruction::instruction_code; } inline bool NativeInstruction::is_call() { return ubyte_at(0) == NativeCall::instruction_code; } +inline bool NativeInstruction::is_call_reg() { return ubyte_at(0) == NativeCallReg::instruction_code || + (ubyte_at(1) == NativeCallReg::instruction_code && + (ubyte_at(0) == Assembler::REX || ubyte_at(0) == Assembler::REX_B)); } inline bool NativeInstruction::is_return() { return ubyte_at(0) == NativeReturn::instruction_code || ubyte_at(0) == NativeReturnX::instruction_code; } inline bool NativeInstruction::is_jump() { return ubyte_at(0) == NativeJump::instruction_code || @@ -527,26 +549,24 @@ inline bool NativeInstruction::is_cond_jump() { return (int_at(0) & 0xF0FF) = (ubyte_at(0) & 0xF0) == 0x70; /* short jump */ } inline bool NativeInstruction::is_safepoint_poll() { #ifdef AMD64 - if (Assembler::is_polling_page_far()) { - // two cases, depending on the choice of the base register in the address. - if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix && - ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl && - (ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) || - ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && - (ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) { - return true; - } else { - return false; - } - } else { - if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && - ubyte_at(1) == 0x05) { // 00 rax 101 - address fault = addr_at(6) + int_at(2); - return os::is_poll_address(fault); - } else { - return false; - } + // Try decoding a near safepoint first: + if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && + ubyte_at(1) == 0x05) { // 00 rax 101 + address fault = addr_at(6) + int_at(2); + NOT_JVMCI(assert(!Assembler::is_polling_page_far(), "unexpected poll encoding");) + return os::is_poll_address(fault); } + // Now try decoding a far safepoint: + // two cases, depending on the choice of the base register in the address. + if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix && + ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl && + (ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) || + ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && + (ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) { + NOT_JVMCI(assert(Assembler::is_polling_page_far(), "unexpected poll encoding");) + return true; + } + return false; #else return ( ubyte_at(0) == NativeMovRegMem::instruction_code_mem2reg || ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl ) && diff --git a/hotspot/src/cpu/x86/vm/registerMap_x86.cpp b/hotspot/src/cpu/x86/vm/registerMap_x86.cpp new file mode 100644 index 00000000000..32e71c7e263 --- /dev/null +++ b/hotspot/src/cpu/x86/vm/registerMap_x86.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "runtime/registerMap.hpp" +#include "vmreg_x86.inline.hpp" + +address RegisterMap::pd_location(VMReg reg) const { + if (reg->is_XMMRegister()) { + int regBase = reg->value() - ConcreteRegisterImpl::max_fpr; + if (regBase % 4 == 0) { + // Reads of the low and high 16 byte parts should be handled by location itself + // because they have separate callee saved entries. + // See RegisterSaver::save_live_registers(). + return NULL; + } + VMReg baseReg = as_XMMRegister(regBase / XMMRegisterImpl::max_slots_per_register)->as_VMReg(); + intptr_t offset = (reg->value() - baseReg->value()) * VMRegImpl::stack_slot_size; // offset in bytes + if (offset >= 16) { + // The high part of YMM registers are saved in a their own area in the frame + baseReg = baseReg->next()->next()->next()->next(); + offset -= 16; + } + address baseLocation = location(baseReg); + if (baseLocation != NULL) { + return baseLocation + offset; + } + } + return NULL; +} diff --git a/hotspot/src/cpu/x86/vm/registerMap_x86.hpp b/hotspot/src/cpu/x86/vm/registerMap_x86.hpp index 5d91b1ba755..0cbf0646831 100644 --- a/hotspot/src/cpu/x86/vm/registerMap_x86.hpp +++ b/hotspot/src/cpu/x86/vm/registerMap_x86.hpp @@ -31,11 +31,7 @@ private: // This is the hook for finding a register in an "well-known" location, // such as a register block of a predetermined format. - // Since there is none, we just return NULL. - // See registerMap_sparc.hpp for an example of grabbing registers - // from register save areas of a standard layout. - address pd_location(VMReg reg) const {return NULL;} - + address pd_location(VMReg reg) const; // no PD state to clear or copy: void pd_clear() {} void pd_initialize() {} diff --git a/hotspot/src/cpu/x86/vm/register_x86.cpp b/hotspot/src/cpu/x86/vm/register_x86.cpp index 00cba4c9461..2a07a9eb19c 100644 --- a/hotspot/src/cpu/x86/vm/register_x86.cpp +++ b/hotspot/src/cpu/x86/vm/register_x86.cpp @@ -69,6 +69,31 @@ const char* XMMRegisterImpl::name() const { return is_valid() ? names[encoding()] : "xnoreg"; } +const char* XMMRegisterImpl::sub_word_name(int i) const { + const char* names[number_of_registers * 8] = { + "xmm0:0", "xmm0:1", "xmm0:2", "xmm0:3", "xmm0:4", "xmm0:5", "xmm0:6", "xmm0:7", + "xmm1:0", "xmm1:1", "xmm1:2", "xmm1:3", "xmm1:4", "xmm1:5", "xmm1:6", "xmm1:7", + "xmm2:0", "xmm2:1", "xmm2:2", "xmm2:3", "xmm2:4", "xmm2:5", "xmm2:6", "xmm2:7", + "xmm3:0", "xmm3:1", "xmm3:2", "xmm3:3", "xmm3:4", "xmm3:5", "xmm3:6", "xmm3:7", + "xmm4:0", "xmm4:1", "xmm4:2", "xmm4:3", "xmm4:4", "xmm4:5", "xmm4:6", "xmm4:7", + "xmm5:0", "xmm5:1", "xmm5:2", "xmm5:3", "xmm5:4", "xmm5:5", "xmm5:6", "xmm5:7", + "xmm6:0", "xmm6:1", "xmm6:2", "xmm6:3", "xmm6:4", "xmm6:5", "xmm6:6", "xmm6:7", + "xmm7:0", "xmm7:1", "xmm7:2", "xmm7:3", "xmm7:4", "xmm7:5", "xmm7:6", "xmm7:7", +#ifdef AMD64 + "xmm8:0", "xmm8:1", "xmm8:2", "xmm8:3", "xmm8:4", "xmm8:5", "xmm8:6", "xmm8:7", + "xmm9:0", "xmm9:1", "xmm9:2", "xmm9:3", "xmm9:4", "xmm9:5", "xmm9:6", "xmm9:7", + "xmm10:0", "xmm10:1", "xmm10:2", "xmm10:3", "xmm10:4", "xmm10:5", "xmm10:6", "xmm10:7", + "xmm11:0", "xmm11:1", "xmm11:2", "xmm11:3", "xmm11:4", "xmm11:5", "xmm11:6", "xmm11:7", + "xmm12:0", "xmm12:1", "xmm12:2", "xmm12:3", "xmm12:4", "xmm12:5", "xmm12:6", "xmm12:7", + "xmm13:0", "xmm13:1", "xmm13:2", "xmm13:3", "xmm13:4", "xmm13:5", "xmm13:6", "xmm13:7", + "xmm14:0", "xmm14:1", "xmm14:2", "xmm14:3", "xmm14:4", "xmm14:5", "xmm14:6", "xmm14:7", + "xmm15:0", "xmm15:1", "xmm15:2", "xmm15:3", "xmm15:4", "xmm15:5", "xmm15:6", "xmm15:7", +#endif // AMD64 + }; + assert(i >= 0 && i < 8, "offset too large"); + return is_valid() ? names[encoding() * 8 + i] : "xnoreg"; +} + const char* KRegisterImpl::name() const { const char* names[number_of_registers] = { "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7" diff --git a/hotspot/src/cpu/x86/vm/register_x86.hpp b/hotspot/src/cpu/x86/vm/register_x86.hpp index ccce3850261..1d1c6eef627 100644 --- a/hotspot/src/cpu/x86/vm/register_x86.hpp +++ b/hotspot/src/cpu/x86/vm/register_x86.hpp @@ -162,9 +162,10 @@ class XMMRegisterImpl: public AbstractRegisterImpl { XMMRegister successor() const { return as_XMMRegister(encoding() + 1); } // accessors - int encoding() const { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this )); return (intptr_t)this; } + int encoding() const { assert(is_valid(), "invalid register (%d)", (int)(intptr_t)this ); return (intptr_t)this; } bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } const char* name() const; + const char* sub_word_name(int offset) const; }; @@ -245,7 +246,7 @@ public: KRegister successor() const { return as_KRegister(encoding() + 1); } // accessors - int encoding() const { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this)); return (intptr_t)this; } + int encoding() const { assert(is_valid(), "invalid register (%d)", (int)(intptr_t)this); return (intptr_t)this; } bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } const char* name() const; }; diff --git a/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp b/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp index 32b2d073cce..4c558b7c3cd 100644 --- a/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp +++ b/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp @@ -180,39 +180,17 @@ address Relocation::pd_get_address_from_code() { void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { #ifdef _LP64 - if (!Assembler::is_polling_page_far()) { - typedef Assembler::WhichOperand WhichOperand; - WhichOperand which = (WhichOperand) format(); - // This format is imm but it is really disp32 - which = Assembler::disp32_operand; + typedef Assembler::WhichOperand WhichOperand; + WhichOperand which = (WhichOperand) format(); +#if !INCLUDE_JVMCI + assert((which == Assembler::disp32_operand) == !Assembler::is_polling_page_far(), "format not set correctly"); +#endif + if (which == Assembler::disp32_operand) { address orig_addr = old_addr_for(addr(), src, dest); NativeInstruction* oni = nativeInstruction_at(orig_addr); int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); // This poll_addr is incorrect by the size of the instruction it is irrelevant intptr_t poll_addr = (intptr_t)oni + *orig_disp; - - NativeInstruction* ni = nativeInstruction_at(addr()); - intptr_t new_disp = poll_addr - (intptr_t) ni; - - int32_t* disp = (int32_t*) Assembler::locate_operand(addr(), which); - * disp = (int32_t)new_disp; - } -#endif // _LP64 -} - -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { -#ifdef _LP64 - if (!Assembler::is_polling_page_far()) { - typedef Assembler::WhichOperand WhichOperand; - WhichOperand which = (WhichOperand) format(); - // This format is imm but it is really disp32 - which = Assembler::disp32_operand; - address orig_addr = old_addr_for(addr(), src, dest); - NativeInstruction* oni = nativeInstruction_at(orig_addr); - int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); - // This poll_addr is incorrect by the size of the instruction it is irrelevant - intptr_t poll_addr = (intptr_t)oni + *orig_disp; - NativeInstruction* ni = nativeInstruction_at(addr()); intptr_t new_disp = poll_addr - (intptr_t) ni; diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index 80f2873c04f..e2047549877 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -699,12 +699,11 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg __ bind(L_fail); } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { - +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Note: rsi contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled // code goes non-entrant while we get args ready. @@ -1434,7 +1433,7 @@ static void gen_special_dispatch(MacroAssembler* masm, } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg_res("unexpected intrinsic id %d", iid)); + fatal("unexpected intrinsic id %d", iid); } if (member_reg != noreg) { diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 46874844473..0b17c56095c 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -43,6 +43,9 @@ #ifdef COMPILER2 #include "opto/runtime.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif #define __ masm-> @@ -158,23 +161,25 @@ class RegisterSaver { OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) { int vect_words = 0; + int ymmhi_offset = -1; int off = 0; int num_xmm_regs = XMMRegisterImpl::number_of_registers; if (UseAVX < 3) { num_xmm_regs = num_xmm_regs/2; } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (save_vectors) { assert(UseAVX > 0, "512bit vectors are supported only with EVEX"); assert(MaxVectorSize == 64, "only 512bit vectors are supported now"); // Save upper half of YMM registers vect_words = 16 * num_xmm_regs / wordSize; if (UseAVX < 3) { + ymmhi_offset = additional_frame_words; additional_frame_words += vect_words; } } #else - assert(!save_vectors, "vectors are generated only by C2"); + assert(!save_vectors, "vectors are generated only by C2 and JVMCI"); #endif // Always make the frame size 16-byte aligned @@ -220,6 +225,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ OopMap* map = new OopMap(frame_size_in_slots, 0); #define STACK_OFFSET(x) VMRegImpl::stack2reg((x) + additional_frame_slots) +#define YMMHI_STACK_OFFSET(x) VMRegImpl::stack2reg((x / VMRegImpl::stack_slot_size) + ymmhi_offset) map->set_callee_saved(STACK_OFFSET( rax_off ), rax->as_VMReg()); map->set_callee_saved(STACK_OFFSET( rcx_off ), rcx->as_VMReg()); @@ -257,6 +263,28 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ } } +#if defined(COMPILER2) || INCLUDE_JVMCI + if (save_vectors) { + assert(ymmhi_offset != -1, "save area must exist"); + map->set_callee_saved(YMMHI_STACK_OFFSET( 0), xmm0->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 16), xmm1->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 32), xmm2->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 48), xmm3->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 64), xmm4->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 80), xmm5->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 96), xmm6->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(112), xmm7->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(128), xmm8->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(144), xmm9->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(160), xmm10->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(176), xmm11->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(192), xmm12->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(208), xmm13->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(224), xmm14->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(240), xmm15->as_VMReg()->next(4)); + } +#endif // COMPILER2 || INCLUDE_JVMCI + // %%% These should all be a waste but we'll keep things as they were for now if (true) { map->set_callee_saved(STACK_OFFSET( raxH_off ), rax->as_VMReg()->next()); @@ -307,7 +335,7 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_ve // Pop arg register save area __ addptr(rsp, frame::arg_reg_save_area_bytes); } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // On EVEX enabled targets everything is handled in pop fpu state if ((restore_vectors) && (UseAVX < 3)) { assert(UseAVX > 0, "256/512-bit vectors are supported only with AVX"); @@ -320,7 +348,7 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_ve __ addptr(rsp, num_xmm_regs*16); } #else - assert(!restore_vectors, "vectors are generated only by C2"); + assert(!restore_vectors, "vectors are generated only by C2 and JVMCI"); #endif // Recover CPU state __ pop_CPU_state(); @@ -655,11 +683,11 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg __ bind(L_fail); } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Note: r13 contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled @@ -752,6 +780,18 @@ static void gen_i2c_adapter(MacroAssembler *masm, // Pre-load the register-jump target early, to schedule it better. __ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_offset()))); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // check if this call should be routed towards a specific entry point + __ cmpptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0); + Label no_alternative_target; + __ jcc(Assembler::equal, no_alternative_target); + __ movptr(r11, Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); + __ movptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0); + __ bind(no_alternative_target); + } +#endif // INCLUDE_JVMCI + // Now generate the shuffle code. Pick up all register args and move the // rest through the floating point stack top. for (int i = 0; i < total_args_passed; i++) { @@ -1695,7 +1735,7 @@ static void gen_special_dispatch(MacroAssembler* masm, } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg_res("unexpected intrinsic id %d", iid)); + fatal("unexpected intrinsic id %d", iid); } if (member_reg != noreg) { @@ -2685,7 +2725,13 @@ void SharedRuntime::generate_deopt_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("deopt_blob", 2048, 1024); + int pad = 0; +#if INCLUDE_JVMCI + if (EnableJVMCI) { + pad += 512; // Increase the buffer size when compiling for JVMCI + } +#endif + CodeBuffer buffer("deopt_blob", 2048+pad, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; OopMap* map = NULL; @@ -2734,6 +2780,12 @@ void SharedRuntime::generate_deopt_blob() { __ jmp(cont); int reexecute_offset = __ pc() - start; +#if INCLUDE_JVMCI && !defined(COMPILER1) + if (EnableJVMCI && UseJVMCICompiler) { + // JVMCI does not use this kind of deoptimization + __ should_not_reach_here(); + } +#endif // Reexecute case // return address is the pc describes what bci to do re-execute at @@ -2744,6 +2796,38 @@ void SharedRuntime::generate_deopt_blob() { __ movl(r14, Deoptimization::Unpack_reexecute); // callee-saved __ jmp(cont); +#if INCLUDE_JVMCI + Label after_fetch_unroll_info_call; + int implicit_exception_uncommon_trap_offset = 0; + int uncommon_trap_offset = 0; + + if (EnableJVMCI) { + implicit_exception_uncommon_trap_offset = __ pc() - start; + + __ pushptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); + __ movptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())), (int32_t)NULL_WORD); + + uncommon_trap_offset = __ pc() - start; + + // Save everything in sight. + RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); + // fetch_unroll_info needs to call last_java_frame() + __ set_last_Java_frame(noreg, noreg, NULL); + + __ movl(c_rarg1, Address(r15_thread, in_bytes(JavaThread::pending_deoptimization_offset()))); + __ movl(Address(r15_thread, in_bytes(JavaThread::pending_deoptimization_offset())), -1); + + __ movl(r14, (int32_t)Deoptimization::Unpack_reexecute); + __ mov(c_rarg0, r15_thread); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); + oop_maps->add_gc_map( __ pc()-start, map->deep_copy()); + + __ reset_last_Java_frame(false, false); + + __ jmp(after_fetch_unroll_info_call); + } // EnableJVMCI +#endif // INCLUDE_JVMCI + int exception_offset = __ pc() - start; // Prolog for exception case @@ -2829,6 +2913,12 @@ void SharedRuntime::generate_deopt_blob() { __ reset_last_Java_frame(false, false); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + __ bind(after_fetch_unroll_info_call); + } +#endif + // Load UnrollBlock* into rdi __ mov(rdi, rax); @@ -3003,6 +3093,12 @@ void SharedRuntime::generate_deopt_blob() { _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset); + _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); + } +#endif } #ifdef COMPILER2 diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp index 35c8d0940b6..ba7cb9950bf 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp @@ -2134,14 +2134,6 @@ class StubGenerator: public StubCodeGenerator { __ trigfunc('t'); __ ret(0); } - { - StubCodeMark mark(this, "StubRoutines", "exp"); - StubRoutines::_intrinsic_exp = (double (*)(double)) __ pc(); - - __ fld_d(Address(rsp, 4)); - __ exp_with_fallback(0); - __ ret(0); - } { StubCodeMark mark(this, "StubRoutines", "pow"); StubRoutines::_intrinsic_pow = (double (*)(double,double)) __ pc(); @@ -2991,6 +2983,89 @@ class StubGenerator: public StubCodeGenerator { return start; } + /** + * Arguments: + * + * Inputs: + * rsp(4) - int crc + * rsp(8) - byte* buf + * rsp(12) - int length + * rsp(16) - table_start - optional (present only when doing a library_calll, + * not used by x86 algorithm) + * + * Ouput: + * rax - int crc result + */ + address generate_updateBytesCRC32C(bool is_pclmulqdq_supported) { + assert(UseCRC32CIntrinsics, "need SSE4_2"); + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32C"); + address start = __ pc(); + const Register crc = rax; // crc + const Register buf = rcx; // source java byte array address + const Register len = rdx; // length + const Register d = rbx; + const Register g = rsi; + const Register h = rdi; + const Register empty = 0; // will never be used, in order not + // to change a signature for crc32c_IPL_Alg2_Alt2 + // between 64/32 I'm just keeping it here + assert_different_registers(crc, buf, len, d, g, h); + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + Address crc_arg(rsp, 4 + 4 + 0); // ESP+4 + + // we need to add additional 4 because __ enter + // have just pushed ebp on a stack + Address buf_arg(rsp, 4 + 4 + 4); + Address len_arg(rsp, 4 + 4 + 8); + // Load up: + __ movl(crc, crc_arg); + __ movl(buf, buf_arg); + __ movl(len, len_arg); + __ push(d); + __ push(g); + __ push(h); + __ crc32c_ipl_alg2_alt2(crc, buf, len, + d, g, h, + empty, empty, empty, + xmm0, xmm1, xmm2, + is_pclmulqdq_supported); + __ pop(h); + __ pop(g); + __ pop(d); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + } + + address generate_libmExp() { + address start = __ pc(); + + const XMMRegister x0 = xmm0; + const XMMRegister x1 = xmm1; + const XMMRegister x2 = xmm2; + const XMMRegister x3 = xmm3; + + const XMMRegister x4 = xmm4; + const XMMRegister x5 = xmm5; + const XMMRegister x6 = xmm6; + const XMMRegister x7 = xmm7; + + const Register tmp = rbx; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + __ fast_exp(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + + } + + // Safefetch stubs. void generate_safefetch(const char* name, int size, address* entry, address* fault_pc, address* continuation_pc) { @@ -3204,6 +3279,16 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table; StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32(); } + + if (UseCRC32CIntrinsics) { + bool supports_clmul = VM_Version::supports_clmul(); + StubRoutines::x86::generate_CRC32C_table(supports_clmul); + StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table; + StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul); + } + if (VM_Version::supports_sse2()) { + StubRoutines::_dexp = generate_libmExp(); + } } diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 36049bae44b..c37e02ecd39 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -3038,19 +3038,6 @@ class StubGenerator: public StubCodeGenerator { __ addq(rsp, 8); __ ret(0); } - { - StubCodeMark mark(this, "StubRoutines", "exp"); - StubRoutines::_intrinsic_exp = (double (*)(double)) __ pc(); - - __ subq(rsp, 8); - __ movdbl(Address(rsp, 0), xmm0); - __ fld_d(Address(rsp, 0)); - __ exp_with_fallback(0); - __ fstp_d(Address(rsp, 0)); - __ movdbl(xmm0, Address(rsp, 0)); - __ addq(rsp, 8); - __ ret(0); - } { StubCodeMark mark(this, "StubRoutines", "pow"); StubRoutines::_intrinsic_pow = (double (*)(double,double)) __ pc(); @@ -3958,6 +3945,64 @@ class StubGenerator: public StubCodeGenerator { return start; } + /** + * Arguments: + * + * Inputs: + * c_rarg0 - int crc + * c_rarg1 - byte* buf + * c_rarg2 - long length + * c_rarg3 - table_start - optional (present only when doing a library_calll, + * not used by x86 algorithm) + * + * Ouput: + * rax - int crc result + */ + address generate_updateBytesCRC32C(bool is_pclmulqdq_supported) { + assert(UseCRC32CIntrinsics, "need SSE4_2"); + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32C"); + address start = __ pc(); + //reg.arg int#0 int#1 int#2 int#3 int#4 int#5 float regs + //Windows RCX RDX R8 R9 none none XMM0..XMM3 + //Lin / Sol RDI RSI RDX RCX R8 R9 XMM0..XMM7 + const Register crc = c_rarg0; // crc + const Register buf = c_rarg1; // source java byte array address + const Register len = c_rarg2; // length + const Register a = rax; + const Register j = r9; + const Register k = r10; + const Register l = r11; +#ifdef _WIN64 + const Register y = rdi; + const Register z = rsi; +#else + const Register y = rcx; + const Register z = r8; +#endif + assert_different_registers(crc, buf, len, a, j, k, l, y, z); + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame +#ifdef _WIN64 + __ push(y); + __ push(z); +#endif + __ crc32c_ipl_alg2_alt2(crc, buf, len, + a, j, k, + l, y, z, + c_farg0, c_farg1, c_farg2, + is_pclmulqdq_supported); + __ movl(rax, crc); +#ifdef _WIN64 + __ pop(z); + __ pop(y); +#endif + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + } /** * Arguments: @@ -4122,6 +4167,44 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_libmExp() { + address start = __ pc(); + + const XMMRegister x0 = xmm0; + const XMMRegister x1 = xmm1; + const XMMRegister x2 = xmm2; + const XMMRegister x3 = xmm3; + + const XMMRegister x4 = xmm4; + const XMMRegister x5 = xmm5; + const XMMRegister x6 = xmm6; + const XMMRegister x7 = xmm7; + + const Register tmp = r11; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + +#ifdef _WIN64 + // save the xmm registers which must be preserved 6-7 + __ movdqu(xmm_save(6), as_XMMRegister(6)); + __ movdqu(xmm_save(7), as_XMMRegister(7)); +#endif + __ fast_exp(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp); + +#ifdef _WIN64 + // restore xmm regs belonging to calling function + __ movdqu(as_XMMRegister(6), xmm_save(6)); + __ movdqu(as_XMMRegister(7), xmm_save(7)); +#endif + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + + } + #undef __ #define __ masm-> @@ -4302,6 +4385,14 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table; StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32(); } + + if (UseCRC32CIntrinsics) { + bool supports_clmul = VM_Version::supports_clmul(); + StubRoutines::x86::generate_CRC32C_table(supports_clmul); + StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table; + StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul); + } + StubRoutines::_dexp = generate_libmExp(); } void generate_all() { diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp index 9b0d8fc756f..cd5681a44d6 100644 --- a/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp +++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp @@ -27,6 +27,7 @@ #include "runtime/frame.inline.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" +#include "crc32c.h" // Implementation of the platform-specific part of StubRoutines - for // a description of how to extend it, see the stubRoutines.hpp file. @@ -130,3 +131,107 @@ juint StubRoutines::x86::_crc_table[] = 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL }; + +#define D 32 +#define P 0x82F63B78 // Reflection of Castagnoli (0x11EDC6F41) + +#define TILL_CYCLE 31 +uint32_t _crc32c_pow_2k_table[TILL_CYCLE]; // because _crc32c_pow_2k_table[TILL_CYCLE == 31] == _crc32c_pow_2k_table[0] + +// A. Kadatch and B. Jenkins / Everything we know about CRC but afraid to forget September 3, 2010 8 +// Listing 1: Multiplication of normalized polynomials +// "a" and "b" occupy D least significant bits. +uint32_t crc32c_multiply(uint32_t a, uint32_t b) { + uint32_t product = 0; + uint32_t b_pow_x_table[D + 1]; // b_pow_x_table[k] = (b * x**k) mod P + b_pow_x_table[0] = b; + for (int k = 0; k < D; ++k) { + // If "a" has non-zero coefficient at x**k,/ add ((b * x**k) mod P) to the result. + if ((a & (uint64_t)(1 << (D - 1 - k))) != 0) product ^= b_pow_x_table[k]; + + // Compute b_pow_x_table[k+1] = (b ** x**(k+1)) mod P. + if (b_pow_x_table[k] & 1) { + // If degree of (b_pow_x_table[k] * x) is D, then + // degree of (b_pow_x_table[k] * x - P) is less than D. + b_pow_x_table[k + 1] = (b_pow_x_table[k] >> 1) ^ P; + } + else { + b_pow_x_table[k + 1] = b_pow_x_table[k] >> 1; + } + } + return product; +} +#undef D +#undef P + +// A. Kadatch and B. Jenkins / Everything we know about CRC but afraid to forget September 3, 2010 9 +void crc32c_init_pow_2k(void) { + // _crc32c_pow_2k_table(0) = + // x^(2^k) mod P(x) = x mod P(x) = x + // Since we are operating on a reflected values + // x = 10b, reflect(x) = 0x40000000 + _crc32c_pow_2k_table[0] = 0x40000000; + + for (int k = 1; k < TILL_CYCLE; k++) { + // _crc32c_pow_2k_table(k+1) = _crc32c_pow_2k_table(k-1)^2 mod P(x) + uint32_t tmp = _crc32c_pow_2k_table[k - 1]; + _crc32c_pow_2k_table[k] = crc32c_multiply(tmp, tmp); + } +} + +// x^N mod P(x) +uint32_t crc32c_f_pow_n(uint32_t n) { + // result = 1 (polynomial) + uint32_t one, result = 0x80000000, i = 0; + + while (one = (n & 1), (n == 1 || n - one > 0)) { + if (one) { + result = crc32c_multiply(result, _crc32c_pow_2k_table[i]); + } + n >>= 1; + i++; + } + + return result; +} + +juint *StubRoutines::x86::_crc32c_table; + +void StubRoutines::x86::generate_CRC32C_table(bool is_pclmulqdq_table_supported) { + + static juint pow_n[CRC32C_NUM_PRECOMPUTED_CONSTANTS]; + + crc32c_init_pow_2k(); + + pow_n[0] = crc32c_f_pow_n(CRC32C_HIGH * 8); // 8N * 8 = 64N + pow_n[1] = crc32c_f_pow_n(CRC32C_HIGH * 8 * 2); // 128N + + pow_n[2] = crc32c_f_pow_n(CRC32C_MIDDLE * 8); + pow_n[3] = crc32c_f_pow_n(CRC32C_MIDDLE * 8 * 2); + + pow_n[4] = crc32c_f_pow_n(CRC32C_LOW * 8); + pow_n[CRC32C_NUM_PRECOMPUTED_CONSTANTS - 1] = + crc32c_f_pow_n(CRC32C_LOW * 8 * 2); + + if (is_pclmulqdq_table_supported) { + _crc32c_table = pow_n; + } else { + static julong pclmulqdq_table[CRC32C_NUM_PRECOMPUTED_CONSTANTS * 256]; + + for (int j = 0; j < CRC32C_NUM_PRECOMPUTED_CONSTANTS; j++) { + static juint X_CONST = pow_n[j]; + for (int64_t i = 0; i < 256; i++) { // to force 64 bit wide computations + // S. Gueron / Information Processing Letters 112 (2012) 184 + // Algorithm 3: Generating a carry-less multiplication lookup table. + // Input: A 32-bit constant, X_CONST. + // Output: A table of 256 entries, each one is a 64-bit quadword, + // that can be used for computing "byte" * X_CONST, for a given byte. + pclmulqdq_table[j * 256 + i] = + ((i & 1) * X_CONST) ^ ((i & 2) * X_CONST) ^ ((i & 4) * X_CONST) ^ + ((i & 8) * X_CONST) ^ ((i & 16) * X_CONST) ^ ((i & 32) * X_CONST) ^ + ((i & 64) * X_CONST) ^ ((i & 128) * X_CONST); + } + } + _crc32c_table = (juint*)pclmulqdq_table; + } +} diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp index bb160486cd1..7e236967fb8 100644 --- a/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp +++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp @@ -36,6 +36,8 @@ // masks and table for CRC32 static uint64_t _crc_by128_masks[]; static juint _crc_table[]; + // table for CRC32C + static juint* _crc32c_table; // swap mask for ghash static address _ghash_long_swap_mask_addr; static address _ghash_byte_swap_mask_addr; @@ -46,5 +48,6 @@ static address crc_by128_masks_addr() { return (address)_crc_by128_masks; } static address ghash_long_swap_mask_addr() { return _ghash_long_swap_mask_addr; } static address ghash_byte_swap_mask_addr() { return _ghash_byte_swap_mask_addr; } + static void generate_CRC32C_table(bool is_pclmulqdq_supported); #endif // CPU_X86_VM_STUBROUTINES_X86_32_HPP diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index eab2e64a618..6e27d776142 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -538,7 +538,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) { // Allocate monitor and lock method (asm interpreter) // rbx, - Method* // -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { // synchronize method const Address access_flags (rbx, Method::access_flags_offset()); const Address monitor_block_top (rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); @@ -697,15 +697,14 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { __ jmp(rdi); __ bind(slow_path); - (void) generate_normal_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); return entry; } #endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_jump_to_normal_entry(); + return NULL; } /** @@ -753,12 +752,10 @@ address InterpreterGenerator::generate_CRC32_update_entry() { // generate a vanilla native entry as the slow path __ bind(slow_path); - - (void) generate_native_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); return entry; } - return generate_native_entry(false); + return NULL; } /** @@ -790,18 +787,25 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret const Register buf = rdx; // source java byte array address const Register len = rdi; // length + // value x86_32 + // interp. arg ptr ESP + 4 + // int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len) + // 3 2 1 0 + // int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len) + // 4 2,3 1 0 + // Arguments are reversed on java expression stack - __ movl(len, Address(rsp, wordSize)); // Length + __ movl(len, Address(rsp, 4 + 0)); // Length // Calculate address of start element if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) { - __ movptr(buf, Address(rsp, 3*wordSize)); // long buf - __ addptr(buf, Address(rsp, 2*wordSize)); // + offset - __ movl(crc, Address(rsp, 5*wordSize)); // Initial CRC + __ movptr(buf, Address(rsp, 4 + 2 * wordSize)); // long buf + __ addptr(buf, Address(rsp, 4 + 1 * wordSize)); // + offset + __ movl(crc, Address(rsp, 4 + 4 * wordSize)); // Initial CRC } else { - __ movptr(buf, Address(rsp, 3*wordSize)); // byte[] array + __ movptr(buf, Address(rsp, 4 + 2 * wordSize)); // byte[] array __ addptr(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // + header size - __ addptr(buf, Address(rsp, 2*wordSize)); // + offset - __ movl(crc, Address(rsp, 4*wordSize)); // Initial CRC + __ addptr(buf, Address(rsp, 4 + 1 * wordSize)); // + offset + __ movl(crc, Address(rsp, 4 + 3 * wordSize)); // Initial CRC } __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32()), crc, buf, len); @@ -814,12 +818,57 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret // generate a vanilla native entry as the slow path __ bind(slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); + return entry; + } + return NULL; +} - (void) generate_native_entry(false); +/** +* Method entry for static native methods: +* int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int end) +* int java.util.zip.CRC32C.updateByteBuffer(int crc, long address, int off, int end) +*/ +address InterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { + if (UseCRC32CIntrinsics) { + address entry = __ pc(); + // Load parameters + const Register crc = rax; // crc + const Register buf = rcx; // source java byte array address + const Register len = rdx; // length + const Register end = len; + + // value x86_32 + // interp. arg ptr ESP + 4 + // int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int end) + // 3 2 1 0 + // int java.util.zip.CRC32.updateByteBuffer(int crc, long address, int off, int end) + // 4 2,3 1 0 + + // Arguments are reversed on java expression stack + __ movl(end, Address(rsp, 4 + 0)); // end + __ subl(len, Address(rsp, 4 + 1 * wordSize)); // end - offset == length + // Calculate address of start element + if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) { + __ movptr(buf, Address(rsp, 4 + 2 * wordSize)); // long address + __ addptr(buf, Address(rsp, 4 + 1 * wordSize)); // + offset + __ movl(crc, Address(rsp, 4 + 4 * wordSize)); // Initial CRC + } else { + __ movptr(buf, Address(rsp, 4 + 2 * wordSize)); // byte[] array + __ addptr(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // + header size + __ addptr(buf, Address(rsp, 4 + 1 * wordSize)); // + offset + __ movl(crc, Address(rsp, 4 + 3 * wordSize)); // Initial CRC + } + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32C()), crc, buf, len); + // result in rax + // _areturn + __ pop(rdi); // get return address + __ mov(rsp, rsi); // set sp to sender sp + __ jmp(rdi); return entry; } - return generate_native_entry(false); + return NULL; } /** @@ -827,10 +876,8 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret * java.lang.Float.intBitsToFloat(int bits) */ address InterpreterGenerator::generate_Float_intBitsToFloat_entry() { - address entry; - if (UseSSE >= 1) { - entry = __ pc(); + address entry = __ pc(); // rsi: the sender's SP @@ -844,11 +891,10 @@ address InterpreterGenerator::generate_Float_intBitsToFloat_entry() { __ pop(rdi); // get return address __ mov(rsp, rsi); // set rsp to the sender's SP __ jmp(rdi); - } else { - entry = generate_native_entry(false); + return entry; } - return entry; + return NULL; } /** @@ -856,10 +902,8 @@ address InterpreterGenerator::generate_Float_intBitsToFloat_entry() { * java.lang.Float.floatToRawIntBits(float value) */ address InterpreterGenerator::generate_Float_floatToRawIntBits_entry() { - address entry; - if (UseSSE >= 1) { - entry = __ pc(); + address entry = __ pc(); // rsi: the sender's SP @@ -873,11 +917,10 @@ address InterpreterGenerator::generate_Float_floatToRawIntBits_entry() { __ pop(rdi); // get return address __ mov(rsp, rsi); // set rsp to the sender's SP __ jmp(rdi); - } else { - entry = generate_native_entry(false); + return entry; } - return entry; + return NULL; } @@ -886,10 +929,8 @@ address InterpreterGenerator::generate_Float_floatToRawIntBits_entry() { * java.lang.Double.longBitsToDouble(long bits) */ address InterpreterGenerator::generate_Double_longBitsToDouble_entry() { - address entry; - if (UseSSE >= 2) { - entry = __ pc(); + address entry = __ pc(); // rsi: the sender's SP @@ -903,11 +944,10 @@ address InterpreterGenerator::generate_Double_longBitsToDouble_entry() { __ pop(rdi); // get return address __ mov(rsp, rsi); // set rsp to the sender's SP __ jmp(rdi); - } else { - entry = generate_native_entry(false); + return entry; } - return entry; + return NULL; } /** @@ -915,10 +955,8 @@ address InterpreterGenerator::generate_Double_longBitsToDouble_entry() { * java.lang.Double.doubleToRawLongBits(double value) */ address InterpreterGenerator::generate_Double_doubleToRawLongBits_entry() { - address entry; - if (UseSSE >= 2) { - entry = __ pc(); + address entry = __ pc(); // rsi: the sender's SP @@ -933,11 +971,10 @@ address InterpreterGenerator::generate_Double_doubleToRawLongBits_entry() { __ pop(rdi); // get return address __ mov(rsp, rsi); // set rsp to the sender's SP __ jmp(rdi); - } else { - entry = generate_native_entry(false); + return entry; } - return entry; + return NULL; } // diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 5a8466f60e8..cea18ba83a7 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -198,13 +198,27 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, } -address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, - int step) { +address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) { address entry = __ pc(); // NULL last_sp until next java call __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); __ restore_bcp(); __ restore_locals(); +#if INCLUDE_JVMCI + // Check if we need to take lock at entry of synchronized method. + if (UseJVMCICompiler) { + Label L; + __ cmpb(Address(r15_thread, JavaThread::pending_monitorenter_offset()), 0); + __ jcc(Assembler::zero, L); + // Clear flag. + __ movb(Address(r15_thread, JavaThread::pending_monitorenter_offset()), 0); + // Satisfy calling convention for lock_method(). + __ get_method(rbx); + // Take lock. + lock_method(); + __ bind(L); + } +#endif // handle exceptions { Label L; @@ -500,7 +514,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) { // rax // c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs) // rscratch1, rscratch2 (scratch regs) -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { // synchronize method const Address access_flags(rbx, Method::access_flags_offset()); const Address monitor_block_top( @@ -677,15 +691,14 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // generate a vanilla interpreter entry as the slow path __ bind(slow_path); - (void) generate_normal_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); return entry; } #endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_jump_to_normal_entry(); + return NULL; } /** @@ -733,12 +746,10 @@ address InterpreterGenerator::generate_CRC32_update_entry() { // generate a vanilla native entry as the slow path __ bind(slow_path); - - (void) generate_native_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); return entry; } - return generate_native_entry(false); + return NULL; } /** @@ -796,12 +807,61 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret // generate a vanilla native entry as the slow path __ bind(slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); + return entry; + } + return NULL; +} - (void) generate_native_entry(false); +/** +* Method entry for static native methods: +* int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int end) +* int java.util.zip.CRC32C.updateByteBuffer(int crc, long address, int off, int end) +*/ +address InterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { + if (UseCRC32CIntrinsics) { + address entry = __ pc(); + // Load parameters + const Register crc = c_rarg0; // crc + const Register buf = c_rarg1; // source java byte array address + const Register len = c_rarg2; + const Register off = c_rarg3; // offset + const Register end = len; + + // Arguments are reversed on java expression stack + // Calculate address of start element + if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) { + __ movptr(buf, Address(rsp, 3 * wordSize)); // long buf + __ movl2ptr(off, Address(rsp, 2 * wordSize)); // offset + __ addq(buf, off); // + offset + __ movl(crc, Address(rsp, 5 * wordSize)); // Initial CRC + // Note on 5 * wordSize vs. 4 * wordSize: + // * int java.util.zip.CRC32C.updateByteBuffer(int crc, long address, int off, int end) + // 4 2,3 1 0 + // end starts at SP + 8 + // The Java(R) Virtual Machine Specification Java SE 7 Edition + // 4.10.2.3. Values of Types long and double + // "When calculating operand stack length, values of type long and double have length two." + } else { + __ movptr(buf, Address(rsp, 3 * wordSize)); // byte[] array + __ addptr(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // + header size + __ movl2ptr(off, Address(rsp, 2 * wordSize)); // offset + __ addq(buf, off); // + offset + __ movl(crc, Address(rsp, 4 * wordSize)); // Initial CRC + } + __ movl(end, Address(rsp, wordSize)); // end + __ subl(end, off); // end - off + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32C()), crc, buf, len); + // result in rax + // _areturn + __ pop(rdi); // get return address + __ mov(rsp, r13); // set sp to sender sp + __ jmp(rdi); return entry; } - return generate_native_entry(false); + + return NULL; } // Interpreter stub for calling a native method. (asm interpreter) diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp index 2a992389170..82e355f797e 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp @@ -3595,6 +3595,8 @@ void TemplateTable::invokevirtual_helper(Register index, __ profile_virtual_call(rax, rlocals, rdx); // get target Method* & entry point __ lookup_virtual_method(rax, index, method); + __ profile_called_method(method, rdx, rbcp); + __ profile_arguments_type(rdx, method, rbcp, true); __ jump_from_interpreted(method, rdx); } @@ -3694,6 +3696,7 @@ void TemplateTable::invokeinterface(int byte_no) { __ testptr(rbx, rbx); __ jcc(Assembler::zero, no_such_method); + __ profile_called_method(rbx, rbcp, rdx); __ profile_arguments_type(rdx, rbx, rbcp, true); // do the call diff --git a/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp b/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp index 89cbc3b15a5..121ec0a02ac 100644 --- a/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp @@ -37,13 +37,50 @@ /******************************/ \ /* JavaFrameAnchor */ \ /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \ + static_field(VM_Version, _cpuFeatures, uint64_t) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + declare_toplevel_type(VM_Version) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ + LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \ + declare_constant(frame::interpreter_frame_sender_sp_offset) \ + declare_constant(frame::interpreter_frame_last_sp_offset) \ + declare_constant(VM_Version::CPU_CX8) \ + declare_constant(VM_Version::CPU_CMOV) \ + declare_constant(VM_Version::CPU_FXSR) \ + declare_constant(VM_Version::CPU_HT) \ + declare_constant(VM_Version::CPU_MMX) \ + declare_constant(VM_Version::CPU_3DNOW_PREFETCH) \ + declare_constant(VM_Version::CPU_SSE) \ + declare_constant(VM_Version::CPU_SSE2) \ + declare_constant(VM_Version::CPU_SSE3) \ + declare_constant(VM_Version::CPU_SSSE3) \ + declare_constant(VM_Version::CPU_SSE4A) \ + declare_constant(VM_Version::CPU_SSE4_1) \ + declare_constant(VM_Version::CPU_SSE4_2) \ + declare_constant(VM_Version::CPU_POPCNT) \ + declare_constant(VM_Version::CPU_LZCNT) \ + declare_constant(VM_Version::CPU_TSC) \ + declare_constant(VM_Version::CPU_TSCINV) \ + declare_constant(VM_Version::CPU_AVX) \ + declare_constant(VM_Version::CPU_AVX2) \ + declare_constant(VM_Version::CPU_AES) \ + declare_constant(VM_Version::CPU_ERMS) \ + declare_constant(VM_Version::CPU_CLMUL) \ + declare_constant(VM_Version::CPU_BMI1) \ + declare_constant(VM_Version::CPU_BMI2) \ + declare_constant(VM_Version::CPU_RTM) \ + declare_constant(VM_Version::CPU_ADX) \ + declare_constant(VM_Version::CPU_AVX512F) \ + declare_constant(VM_Version::CPU_AVX512DQ) \ + declare_constant(VM_Version::CPU_AVX512PF) \ + declare_constant(VM_Version::CPU_AVX512ER) \ + declare_constant(VM_Version::CPU_AVX512CD) \ + declare_constant(VM_Version::CPU_AVX512BW) #define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index f29b51469ff..4e2e1942cef 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -661,6 +661,18 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } + if (supports_sse4_2()) { + if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { + UseCRC32CIntrinsics = true; + } + } + else if (UseCRC32CIntrinsics) { + if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { + warning("CRC32C intrinsics are not available on this CPU"); + } + FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); + } + // The AES intrinsic stubs require AES instruction support (of course) // but also require sse3 mode for instructions it use. if (UseAES && (UseSSE > 2)) { @@ -704,12 +716,6 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } - if (UseCRC32CIntrinsics) { - if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) - warning("CRC32C intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); - } - if (UseAdler32Intrinsics) { warning("Adler32Intrinsics not available on this CPU."); FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); @@ -781,6 +787,8 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseFPUForSpilling, false); } } +#endif +#if defined(COMPILER2) || INCLUDE_JVMCI if (MaxVectorSize > 0) { if (!is_power_of_2(MaxVectorSize)) { warning("MaxVectorSize must be a power of 2"); @@ -797,7 +805,7 @@ void VM_Version::get_processor_features() { // Vectors (in XMM) are only supported with SSE2+ FLAG_SET_DEFAULT(MaxVectorSize, 0); } -#ifdef ASSERT +#if defined(COMPILER2) && defined(ASSERT) if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) { tty->print_cr("State of YMM registers after signal handle:"); int nreg = 2 LP64_ONLY(+2); @@ -810,9 +818,11 @@ void VM_Version::get_processor_features() { tty->cr(); } } -#endif +#endif // COMPILER2 && ASSERT } +#endif // COMPILER2 || INCLUDE_JVMCI +#ifdef COMPILER2 #ifdef _LP64 if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { UseMultiplyToLenIntrinsic = true; @@ -1082,11 +1092,6 @@ void VM_Version::get_processor_features() { } #endif // COMPILER2 - assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value"); - - // set valid Prefetch instruction - if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0; - if( AllocatePrefetchInstr > 3 ) AllocatePrefetchInstr = 3; if( AllocatePrefetchInstr == 3 && !supports_3dnow_prefetch() ) AllocatePrefetchInstr=0; if( !supports_sse() && supports_3dnow_prefetch() ) AllocatePrefetchInstr = 3; @@ -1125,7 +1130,6 @@ void VM_Version::get_processor_features() { } #endif } - assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value"); #ifdef _LP64 // Prefetch settings diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index 45abb210ffe..d97c681cfc0 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -29,6 +29,7 @@ #include "runtime/vm_version.hpp" class VM_Version : public Abstract_VM_Version { + friend class VMStructs; public: // cpuid result register layouts. These are all unions of a uint32_t // (in case anyone wants access to the register as a whole) and a bitfield. diff --git a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp index 2487fc87455..13f595884eb 100644 --- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp @@ -35,8 +35,6 @@ #include "opto/runtime.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // machine-dependent part of VtableStubs: create VtableStub of correct size and // initialize its code @@ -113,7 +111,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d", - vtable_index, s->entry_point(), + vtable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } @@ -206,7 +204,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d", - itable_index, s->entry_point(), + itable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } diff --git a/hotspot/src/cpu/x86/vm/x86.ad b/hotspot/src/cpu/x86/vm/x86.ad index 120be4f0bd1..00a017bfc8f 100644 --- a/hotspot/src/cpu/x86/vm/x86.ad +++ b/hotspot/src/cpu/x86/vm/x86.ad @@ -1712,6 +1712,18 @@ const bool Matcher::match_rule_supported(int opcode) { return ret_value; // Per default match rules are supported. } +const int Matcher::float_pressure(int default_pressure_threshold) { + int float_pressure_threshold = default_pressure_threshold; +#ifdef _LP64 + if (UseAVX > 2) { + // Increase pressure threshold on machines with AVX3 which have + // 2x more XMM registers. + float_pressure_threshold = default_pressure_threshold * 2; + } +#endif + return float_pressure_threshold; +} + // Max vector size in bytes. 0 if not supported. const int Matcher::vector_width_in_bytes(BasicType bt) { assert(is_java_primitive(bt), "only primitive type vectors"); diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 79b55056cba..009a3acacb0 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -580,7 +580,11 @@ void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const { st->print("MOV [ESP + #%d], EBP\t# Save EBP",framesize); if (PreserveFramePointer) { st->print("\n\t"); - st->print("MOV EBP, [ESP + #%d]\t# Save the caller's SP into EBP", (framesize + wordSize)); + st->print("MOV EBP, ESP\t# Save the caller's SP into EBP"); + if (framesize > 0) { + st->print("\n\t"); + st->print("ADD EBP, #%d", framesize); + } } } @@ -9911,35 +9915,6 @@ instruct powD_reg(regD dst, regD src0, regD src1, eAXRegI rax, eDXRegI rdx, eCXR ins_pipe( pipe_slow ); %} - -instruct expDPR_reg(regDPR1 dpr1, eAXRegI rax, eDXRegI rdx, eCXRegI rcx, eFlagsReg cr) %{ - predicate (UseSSE<=1); - match(Set dpr1 (ExpD dpr1)); - effect(KILL rax, KILL rcx, KILL rdx, KILL cr); - format %{ "fast_exp $dpr1 -> $dpr1 // KILL $rax, $rcx, $rdx" %} - ins_encode %{ - __ fast_exp(); - %} - ins_pipe( pipe_slow ); -%} - -instruct expD_reg(regD dst, regD src, eAXRegI rax, eDXRegI rdx, eCXRegI rcx, eFlagsReg cr) %{ - predicate (UseSSE>=2); - match(Set dst (ExpD src)); - effect(KILL rax, KILL rcx, KILL rdx, KILL cr); - format %{ "fast_exp $dst -> $src // KILL $rax, $rcx, $rdx" %} - ins_encode %{ - __ subptr(rsp, 8); - __ movdbl(Address(rsp, 0), $src$$XMMRegister); - __ fld_d(Address(rsp, 0)); - __ fast_exp(); - __ fstp_d(Address(rsp, 0)); - __ movdbl($dst$$XMMRegister, Address(rsp, 0)); - __ addptr(rsp, 8); - %} - ins_pipe( pipe_slow ); -%} - instruct log10DPR_reg(regDPR1 dst, regDPR1 src) %{ predicate (UseSSE<=1); // The source Double operand on FPU stack diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 9fcc7033c8a..b49f60592a7 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -867,7 +867,11 @@ void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const { st->print("movq [rsp + #%d], rbp\t# Save rbp",framesize); if (PreserveFramePointer) { st->print("\n\t"); - st->print("movq rbp, [rsp + #%d]\t# Save the caller's SP into rbp", (framesize + wordSize)); + st->print("movq rbp, rsp\t# Save the caller's SP into rbp"); + if (framesize > 0) { + st->print("\n\t"); + st->print("addq rbp, #%d", framesize); + } } } @@ -2136,12 +2140,13 @@ encode %{ RELOC_DISP32); } if (_method) { - // Emit stub for static call. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); + // Emit stubs for static call. + address mark = cbuf.insts_mark(); + address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, mark); if (stub == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; - } + } } %} @@ -3767,6 +3772,22 @@ operand indIndexScale(any_RegP reg, rRegL lreg, immI2 scale) %} %} +operand indPosIndexScale(any_RegP reg, rRegI idx, immI2 scale) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(n->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP reg (LShiftL (ConvI2L idx) scale)); + + op_cost(10); + format %{"[$reg + pos $idx << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale($scale); + disp(0x0); + %} +%} + // Indirect Memory Times Scale Plus Index Register Plus Offset Operand operand indIndexScaleOffset(any_RegP reg, immL32 off, rRegL lreg, immI2 scale) %{ @@ -4159,7 +4180,7 @@ operand cmpOpUCF2() %{ // case of this is memory operands. opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, - indIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset, + indIndexScale, indPosIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset, indCompressedOopOffset, indirectNarrow, indOffset8Narrow, indOffset32Narrow, indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, @@ -5186,6 +5207,17 @@ instruct leaPIdxScale(rRegP dst, indIndexScale mem) ins_pipe(ialu_reg_reg_fat); %} +instruct leaPPosIdxScale(rRegP dst, indPosIndexScale mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscale" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + instruct leaPIdxScaleOff(rRegP dst, indIndexScaleOffset mem) %{ match(Set dst mem); @@ -9871,22 +9903,6 @@ instruct powD_reg(regD dst, regD src0, regD src1, rax_RegI rax, rdx_RegI rdx, rc ins_pipe( pipe_slow ); %} -instruct expD_reg(regD dst, regD src, rax_RegI rax, rdx_RegI rdx, rcx_RegI rcx, rFlagsReg cr) %{ - match(Set dst (ExpD src)); - effect(KILL rax, KILL rcx, KILL rdx, KILL cr); - format %{ "fast_exp $dst -> $src // KILL $rax, $rcx, $rdx" %} - ins_encode %{ - __ subptr(rsp, 8); - __ movdbl(Address(rsp, 0), $src$$XMMRegister); - __ fld_d(Address(rsp, 0)); - __ fast_exp(); - __ fstp_d(Address(rsp, 0)); - __ movdbl($dst$$XMMRegister, Address(rsp, 0)); - __ addptr(rsp, 8); - %} - ins_pipe( pipe_slow ); -%} - //----------Arithmetic Conversion Instructions--------------------------------- instruct roundFloat_nop(regF dst) diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index 4875e109538..78dad699f97 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -816,7 +816,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // If G1 is not enabled then attempt to go through the normal entry point // Reference.get could be instrumented by jvmti - return generate_normal_entry(false); + return NULL; } address InterpreterGenerator::generate_native_entry(bool synchronized) { diff --git a/hotspot/src/cpu/zero/vm/globals_zero.hpp b/hotspot/src/cpu/zero/vm/globals_zero.hpp index 511554d1cf3..cc46781cd0a 100644 --- a/hotspot/src/cpu/zero/vm/globals_zero.hpp +++ b/hotspot/src/cpu/zero/vm/globals_zero.hpp @@ -45,9 +45,17 @@ define_pd_global(intx, OptoLoopAlignment, 16); define_pd_global(intx, InlineFrequencyCount, 100); define_pd_global(intx, InlineSmallCode, 1000 ); -define_pd_global(intx, StackYellowPages, 2); -define_pd_global(intx, StackRedPages, 1); -define_pd_global(intx, StackShadowPages, 5 LP64_ONLY(+1) DEBUG_ONLY(+3)); +#define DEFAULT_STACK_YELLOW_PAGES (2) +#define DEFAULT_STACK_RED_PAGES (1) +#define DEFAULT_STACK_SHADOW_PAGES (5 LP64_ONLY(+1) DEBUG_ONLY(+3)) + +#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES +#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES +#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES + +define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); +define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); +define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); diff --git a/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp b/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp index 68516b4daf9..8f54ae265a9 100644 --- a/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp +++ b/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp @@ -42,4 +42,5 @@ // Not supported address generate_CRC32_update_entry() { return NULL; } address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } #endif // CPU_ZERO_VM_INTERPRETERGENERATOR_ZERO_HPP diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java new file mode 100644 index 00000000000..591b3c0eee6 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.amd64; + +import static jdk.vm.ci.code.MemoryBarriers.*; +import static jdk.vm.ci.code.Register.*; + +import java.nio.*; +import java.util.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.meta.*; + +/** + * Represents the AMD64 architecture. + */ +public class AMD64 extends Architecture { + + public static final RegisterCategory CPU = new RegisterCategory("CPU"); + + // @formatter:off + + // General purpose CPU registers + public static final Register rax = new Register(0, 0, "rax", CPU); + public static final Register rcx = new Register(1, 1, "rcx", CPU); + public static final Register rdx = new Register(2, 2, "rdx", CPU); + public static final Register rbx = new Register(3, 3, "rbx", CPU); + public static final Register rsp = new Register(4, 4, "rsp", CPU); + public static final Register rbp = new Register(5, 5, "rbp", CPU); + public static final Register rsi = new Register(6, 6, "rsi", CPU); + public static final Register rdi = new Register(7, 7, "rdi", CPU); + + public static final Register r8 = new Register(8, 8, "r8", CPU); + public static final Register r9 = new Register(9, 9, "r9", CPU); + public static final Register r10 = new Register(10, 10, "r10", CPU); + public static final Register r11 = new Register(11, 11, "r11", CPU); + public static final Register r12 = new Register(12, 12, "r12", CPU); + public static final Register r13 = new Register(13, 13, "r13", CPU); + public static final Register r14 = new Register(14, 14, "r14", CPU); + public static final Register r15 = new Register(15, 15, "r15", CPU); + + public static final Register[] cpuRegisters = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15 + }; + + private static final int XMM_REFERENCE_MAP_SHIFT = 2; + + public static final RegisterCategory XMM = new RegisterCategory("XMM", cpuRegisters.length, XMM_REFERENCE_MAP_SHIFT); + + // XMM registers + public static final Register xmm0 = new Register(16, 0, "xmm0", XMM); + public static final Register xmm1 = new Register(17, 1, "xmm1", XMM); + public static final Register xmm2 = new Register(18, 2, "xmm2", XMM); + public static final Register xmm3 = new Register(19, 3, "xmm3", XMM); + public static final Register xmm4 = new Register(20, 4, "xmm4", XMM); + public static final Register xmm5 = new Register(21, 5, "xmm5", XMM); + public static final Register xmm6 = new Register(22, 6, "xmm6", XMM); + public static final Register xmm7 = new Register(23, 7, "xmm7", XMM); + + public static final Register xmm8 = new Register(24, 8, "xmm8", XMM); + public static final Register xmm9 = new Register(25, 9, "xmm9", XMM); + public static final Register xmm10 = new Register(26, 10, "xmm10", XMM); + public static final Register xmm11 = new Register(27, 11, "xmm11", XMM); + public static final Register xmm12 = new Register(28, 12, "xmm12", XMM); + public static final Register xmm13 = new Register(29, 13, "xmm13", XMM); + public static final Register xmm14 = new Register(30, 14, "xmm14", XMM); + public static final Register xmm15 = new Register(31, 15, "xmm15", XMM); + + public static final Register[] xmmRegisters = { + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + + public static final Register[] cpuxmmRegisters = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + + /** + * Register used to construct an instruction-relative address. + */ + public static final Register rip = new Register(32, -1, "rip", SPECIAL); + + public static final Register[] allRegisters = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, + rip + }; + + // @formatter:on + + /** + * Basic set of CPU features mirroring what is returned from the cpuid instruction. See: + * {@code VM_Version::cpuFeatureFlags}. + */ + public static enum CPUFeature { + CX8, + CMOV, + FXSR, + HT, + MMX, + AMD_3DNOW_PREFETCH, + SSE, + SSE2, + SSE3, + SSSE3, + SSE4A, + SSE4_1, + SSE4_2, + POPCNT, + LZCNT, + TSC, + TSCINV, + AVX, + AVX2, + AES, + ERMS, + CLMUL, + BMI1, + BMI2, + RTM, + ADX, + AVX512F, + AVX512DQ, + AVX512PF, + AVX512ER, + AVX512CD, + AVX512BW + } + + private final EnumSet features; + + /** + * Set of flags to control code emission. + */ + public static enum Flag { + UseCountLeadingZerosInstruction, + UseCountTrailingZerosInstruction + } + + private final EnumSet flags; + + public AMD64(EnumSet features, EnumSet flags) { + super("AMD64", JavaKind.Long, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, cpuRegisters.length + (xmmRegisters.length << XMM_REFERENCE_MAP_SHIFT), 8); + this.features = features; + this.flags = flags; + assert features.contains(CPUFeature.SSE2) : "minimum config for x64"; + } + + public EnumSet getFeatures() { + return features; + } + + public EnumSet getFlags() { + return flags; + } + + @Override + public PlatformKind getPlatformKind(JavaKind javaKind) { + if (javaKind.isObject()) { + return getWordKind(); + } else { + return javaKind; + } + } + + @Override + public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) { + if (!(platformKind instanceof JavaKind)) { + return false; + } + + JavaKind kind = (JavaKind) platformKind; + if (category.equals(CPU)) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + return true; + } + } else if (category.equals(XMM)) { + switch (kind) { + case Float: + case Double: + return true; + } + } + + return false; + } + + @Override + public PlatformKind getLargestStorableKind(RegisterCategory category) { + if (category.equals(CPU)) { + return JavaKind.Long; + } else if (category.equals(XMM)) { + return JavaKind.Double; + } else { + return JavaKind.Illegal; + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/overview.html b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/overview.html new file mode 100644 index 00000000000..6f12f4bc25a --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/overview.html @@ -0,0 +1,37 @@ + + + + + + + + +The jdk.vm.ci.code project provides an API to the runtime's native code cache. +It allows installation and execution of native code. + + + diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/AbstractAddress.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/AbstractAddress.java new file mode 100644 index 00000000000..5b14cfc8c52 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/AbstractAddress.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * Abstract base class that represents a platform specific address. + */ +public abstract class AbstractAddress { +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java new file mode 100644 index 00000000000..148d2ac5ec6 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.nio.*; +import java.util.*; + +import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.meta.*; + +/** + * Represents a CPU architecture, including information such as its endianness, CPU registers, word + * width, etc. + */ +public abstract class Architecture { + + /** + * The number of entries required in a {@link ReferenceMap} covering all the registers that may + * store references. The index of a register in the reference map is given by + * {@link Register#getReferenceMapIndex()}. + */ + private final int registerReferenceMapSize; + + /** + * The architecture specific type of a native word. + */ + private final PlatformKind wordKind; + + /** + * The name of this architecture (e.g. "AMD64", "SPARCv9"). + */ + private final String name; + + /** + * Array of all available registers on this architecture. The index of each register in this + * array is equal to its {@linkplain Register#number number}. + */ + private final Register[] registers; + + /** + * The byte ordering can be either little or big endian. + */ + private final ByteOrder byteOrder; + + /** + * Whether the architecture supports unaligned memory accesses. + */ + private final boolean unalignedMemoryAccess; + + /** + * Mask of the barrier constants denoting the barriers that are not required to be explicitly + * inserted under this architecture. + */ + private final int implicitMemoryBarriers; + + /** + * Offset in bytes from the beginning of a call instruction to the displacement. + */ + private final int machineCodeCallDisplacementOffset; + + /** + * The size of the return address pushed to the stack by a call instruction. A value of 0 + * denotes that call linkage uses registers instead (e.g. SPARC). + */ + private final int returnAddressSize; + + protected Architecture(String name, PlatformKind wordKind, ByteOrder byteOrder, boolean unalignedMemoryAccess, Register[] registers, int implicitMemoryBarriers, int nativeCallDisplacementOffset, + int registerReferenceMapSize, int returnAddressSize) { + this.name = name; + this.registers = registers; + this.wordKind = wordKind; + this.byteOrder = byteOrder; + this.unalignedMemoryAccess = unalignedMemoryAccess; + this.implicitMemoryBarriers = implicitMemoryBarriers; + this.machineCodeCallDisplacementOffset = nativeCallDisplacementOffset; + this.registerReferenceMapSize = registerReferenceMapSize; + this.returnAddressSize = returnAddressSize; + } + + /** + * Converts this architecture to a string. + * + * @return the string representation of this architecture + */ + @Override + public final String toString() { + return getName().toLowerCase(); + } + + public int getRegisterReferenceMapSize() { + return registerReferenceMapSize; + } + + /** + * Gets the natural size of words (typically registers and pointers) of this architecture, in + * bytes. + */ + public int getWordSize() { + return wordKind.getSizeInBytes(); + } + + public PlatformKind getWordKind() { + return wordKind; + } + + /** + * Gets the name of this architecture. + */ + public String getName() { + return name; + } + + /** + * Gets an array of all available registers on this architecture. The index of each register in + * this array is equal to its {@linkplain Register#number number}. + */ + public Register[] getRegisters() { + return registers.clone(); + } + + public ByteOrder getByteOrder() { + return byteOrder; + } + + /** + * @return true if the architecture supports unaligned memory accesses. + */ + public boolean supportsUnalignedMemoryAccess() { + return unalignedMemoryAccess; + } + + /** + * Gets the size of the return address pushed to the stack by a call instruction. A value of 0 + * denotes that call linkage uses registers instead. + */ + public int getReturnAddressSize() { + return returnAddressSize; + } + + /** + * Gets the offset in bytes from the beginning of a call instruction to the displacement. + */ + public int getMachineCodeCallDisplacementOffset() { + return machineCodeCallDisplacementOffset; + } + + /** + * Determines the barriers in a given barrier mask that are explicitly required on this + * architecture. + * + * @param barriers a mask of the barrier constants + * @return the value of {@code barriers} minus the barriers unnecessary on this architecture + */ + public final int requiredBarriers(int barriers) { + return barriers & ~implicitMemoryBarriers; + } + + /** + * Determine whether a kind can be stored in a register of a given category. + * + * @param category the category of the register + * @param kind the kind that should be stored in the register + */ + public abstract boolean canStoreValue(RegisterCategory category, PlatformKind kind); + + /** + * Return the largest kind that can be stored in a register of a given category. + * + * @param category the category of the register + * @return the largest kind that can be stored in a register {@code category} + */ + public abstract PlatformKind getLargestStorableKind(RegisterCategory category); + + /** + * Return the {@link PlatformKind} that is used to store values of a given {@link JavaKind}. + */ + public abstract PlatformKind getPlatformKind(JavaKind javaKind); + + @Override + public final boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Architecture) { + Architecture that = (Architecture) obj; + if (this.name.equals(that.name)) { + assert this.byteOrder.equals(that.byteOrder); + assert this.implicitMemoryBarriers == that.implicitMemoryBarriers; + assert this.machineCodeCallDisplacementOffset == that.machineCodeCallDisplacementOffset; + assert this.registerReferenceMapSize == that.registerReferenceMapSize; + assert Arrays.equals(this.registers, that.registers); + assert this.returnAddressSize == that.returnAddressSize; + assert this.unalignedMemoryAccess == that.unalignedMemoryAccess; + assert this.wordKind == that.wordKind; + return true; + } + } + return false; + } + + @Override + public final int hashCode() { + return name.hashCode(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BailoutException.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BailoutException.java new file mode 100644 index 00000000000..ad26925cc35 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BailoutException.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +/** + * Exception thrown when the compiler refuses to compile a method because of problems with the + * method. e.g. bytecode wouldn't verify, too big, JSR/ret too complicated, etc. This exception is + * not meant to indicate problems with the compiler itself. + */ +public class BailoutException extends RuntimeException { + + public static final long serialVersionUID = 8974598793458772L; + private final boolean permanent; + + /** + * Creates a new {@link BailoutException}. + * + * + * @param args parameters to the formatter + */ + public BailoutException(String format, Object... args) { + super(String.format(Locale.ENGLISH, format, args)); + this.permanent = true; + } + + /** + * Creates a new {@link BailoutException}. + * + * + * @param args parameters to the formatter + */ + public BailoutException(Throwable cause, String format, Object... args) { + super(String.format(Locale.ENGLISH, format, args), cause); + this.permanent = true; + } + + /** + * Creates a new {@link BailoutException}. + * + * @param permanent specifies whether this exception will occur again if compilation is retried + * @param args parameters to the formatter + */ + public BailoutException(boolean permanent, String format, Object... args) { + super(String.format(Locale.ENGLISH, format, args)); + this.permanent = permanent; + } + + /** + * @return whether this exception will occur again if compilation is retried + */ + public boolean isPermanent() { + return permanent; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodeFrame.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodeFrame.java new file mode 100644 index 00000000000..e51f83ee18c --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodeFrame.java @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Represents the Java bytecode frame state(s) at a given position including {@link Value locations} + * where to find the local variables, operand stack values and locked objects of the bytecode + * frame(s). + */ +public class BytecodeFrame extends BytecodePosition { + + /** + * An array of values representing how to reconstruct the state of the Java frame. This is array + * is partitioned as follows: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Start index (inclusive)End index (exclusive)Description
0numLocalsLocal variables
numLocalsnumLocals + numStackOperand stack
numLocals + numStackvalues.lengthLocked objects
+ *

+ * Note that the number of locals and the number of stack slots may be smaller than the maximum + * number of locals and stack slots as specified in the compiled method. + */ + public final JavaValue[] values; + + /** + * An array describing the Java kind of the {@link #values}. It records a kind for the locals + * and the operand stack. + */ + public final JavaKind[] slotKinds; + + /** + * The number of locals in the values array. + */ + public final int numLocals; + + /** + * The number of stack slots in the values array. + */ + public final int numStack; + + /** + * The number of locks in the values array. + */ + public final int numLocks; + + /** + * True if this is a position inside an exception handler before the exception object has been + * consumed. In this case, {@link #numStack} {@code == 1} and {@link #getStackValue(int) + * getStackValue(0)} is the location of the exception object. If deoptimization happens at this + * position, the interpreter will rethrow the exception instead of executing the bytecode + * instruction at this position. + */ + public final boolean rethrowException; + + public final boolean duringCall; + + /** + * This BCI should be used for frame states that are built for code with no meaningful BCI. + */ + public static final int UNKNOWN_BCI = -5; + + /** + * The BCI for exception unwind. This is synthetic code and has no representation in bytecode. + * In contrast with {@link #AFTER_EXCEPTION_BCI}, at this point, if the method is synchronized, + * the monitor is still held. + */ + public static final int UNWIND_BCI = -1; + + /** + * The BCI for the state before starting to execute a method. Note that if the method is + * synchronized, the monitor is not yet held. + */ + public static final int BEFORE_BCI = -2; + + /** + * The BCI for the state after finishing the execution of a method and returning normally. Note + * that if the method was synchronized the monitor is already released. + */ + public static final int AFTER_BCI = -3; + + /** + * The BCI for exception unwind. This is synthetic code and has no representation in bytecode. + * In contrast with {@link #UNWIND_BCI}, at this point, if the method is synchronized, the + * monitor is already released. + */ + public static final int AFTER_EXCEPTION_BCI = -4; + + /** + * This BCI should be used for states that cannot be the target of a deoptimization, like + * snippet frame states. + */ + public static final int INVALID_FRAMESTATE_BCI = -6; + + /** + * Determines if a given BCI matches one of the placeholder BCI constants defined in this class. + */ + public static boolean isPlaceholderBci(int bci) { + return bci < 0; + } + + /** + * Gets the name of a given placeholder BCI. + */ + public static String getPlaceholderBciName(int bci) { + assert isPlaceholderBci(bci); + if (bci == BytecodeFrame.AFTER_BCI) { + return "AFTER_BCI"; + } else if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { + return "AFTER_EXCEPTION_BCI"; + } else if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { + return "INVALID_FRAMESTATE_BCI"; + } else if (bci == BytecodeFrame.BEFORE_BCI) { + return "BEFORE_BCI"; + } else if (bci == BytecodeFrame.UNKNOWN_BCI) { + return "UNKNOWN_BCI"; + } else { + assert bci == BytecodeFrame.UNWIND_BCI; + return "UNWIND_BCI"; + } + } + + /** + * Creates a new frame object. + * + * @param caller the caller frame (which may be {@code null}) + * @param method the method + * @param bci a BCI within the method + * @param rethrowException specifies if the VM should re-throw the pending exception when + * deopt'ing using this frame + * @param values the frame state {@link #values} + * @param numLocals the number of local variables + * @param numStack the depth of the stack + * @param numLocks the number of locked objects + */ + public BytecodeFrame(BytecodeFrame caller, ResolvedJavaMethod method, int bci, boolean rethrowException, boolean duringCall, JavaValue[] values, JavaKind[] slotKinds, int numLocals, int numStack, + int numLocks) { + super(caller, method, bci); + assert values != null; + this.rethrowException = rethrowException; + this.duringCall = duringCall; + this.values = values; + this.slotKinds = slotKinds; + this.numLocals = numLocals; + this.numStack = numStack; + this.numLocks = numLocks; + assert !rethrowException || numStack == 1 : "must have exception on top of the stack"; + } + + /** + * Ensure that the frame state is formatted as expected by the JVM, with null or Illegal in the + * slot following a double word item. This should really be checked in FrameState itself but + * because of Word type rewriting and alternative backends that can't be done. + */ + public boolean validateFormat() { + if (caller() != null) { + caller().validateFormat(); + } + for (int i = 0; i < numLocals + numStack; i++) { + if (values[i] != null) { + JavaKind kind = slotKinds[i]; + if (kind.needsTwoSlots()) { + assert slotKinds.length > i + 1 : String.format("missing second word %s", this); + assert slotKinds[i + 1] == JavaKind.Illegal : this; + } + } + } + return true; + } + + /** + * Gets the value representing the specified local variable. + * + * @param i the local variable index + * @return the value that can be used to reconstruct the local's current value + */ + public JavaValue getLocalValue(int i) { + return values[i]; + } + + /** + * Gets the value representing the specified stack slot. + * + * @param i the stack index + * @return the value that can be used to reconstruct the stack slot's current value + */ + public JavaValue getStackValue(int i) { + return values[i + numLocals]; + } + + /** + * Gets the value representing the specified lock. + * + * @param i the lock index + * @return the value that can be used to reconstruct the lock's current value + */ + public JavaValue getLockValue(int i) { + return values[i + numLocals + numStack]; + } + + /** + * Gets the caller of this frame. + * + * @return {@code null} if this frame has no caller + */ + public BytecodeFrame caller() { + return (BytecodeFrame) getCaller(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof BytecodeFrame && super.equals(obj)) { + BytecodeFrame that = (BytecodeFrame) obj; + // @formatter:off + if (this.duringCall == that.duringCall && + this.rethrowException == that.rethrowException && + this.numLocals == that.numLocals && + this.numLocks == that.numLocks && + this.numStack == that.numStack && + Arrays.equals(this.values, that.values)) { + return true; + } + // @formatter:off + return true; + } + return false; + } + + @Override + public String toString() { + return CodeUtil.append(new StringBuilder(100), this).toString(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java new file mode 100644 index 00000000000..a17b427c5bb --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Represents a code position, that is, a chain of inlined methods with bytecode locations, that is + * communicated from the compiler to the runtime system. A code position can be used by the runtime + * system to reconstruct a source-level stack trace for exceptions and to create + * {@linkplain BytecodeFrame frames} for deoptimization. + */ +public class BytecodePosition { + + private final BytecodePosition caller; + private final ResolvedJavaMethod method; + private final int bci; + + /** + * Constructs a new object representing a given parent/caller, a given method, and a given BCI. + * + * @param caller the parent position + * @param method the method + * @param bci a BCI within the method + */ + public BytecodePosition(BytecodePosition caller, ResolvedJavaMethod method, int bci) { + assert method != null; + this.caller = caller; + this.method = method; + this.bci = bci; + } + + /** + * Converts this code position to a string representation. + * + * @return a string representation of this code position + */ + @Override + public String toString() { + return CodeUtil.append(new StringBuilder(100), this).toString(); + } + + /** + * Deep equality test. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && getClass() == obj.getClass()) { + BytecodePosition that = (BytecodePosition) obj; + if (this.bci == that.bci && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.caller, that.caller)) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return getBCI(); + } + + /** + * @return The location within the method, as a bytecode index. The constant {@code -1} may be + * used to indicate the location is unknown, for example within code synthesized by the + * compiler. + */ + public int getBCI() { + return bci; + } + + /** + * @return The runtime interface method for this position. + */ + public ResolvedJavaMethod getMethod() { + return method; + } + + /** + * The position where this position has been called, {@code null} if none. + */ + public BytecodePosition getCaller() { + return caller; + } + + /** + * Adds a caller to the current position returning the new position. + */ + public BytecodePosition addCaller(BytecodePosition link) { + if (getCaller() == null) { + return new BytecodePosition(link, getMethod(), getBCI()); + } else { + return new BytecodePosition(getCaller().addCaller(link), getMethod(), getBCI()); + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CallingConvention.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CallingConvention.java new file mode 100644 index 00000000000..c299c8400de --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CallingConvention.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2009, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import static jdk.vm.ci.code.ValueUtil.*; + +import jdk.vm.ci.meta.*; + +/** + * A calling convention describes the locations in which the arguments for a call are placed and the + * location in which the return value is placed if the call is not void. + */ +public class CallingConvention { + + /** + * Constants denoting the type of a call for which a calling convention is requested. + */ + public enum Type { + /** + * A request for the outgoing argument locations at a call site to Java code. + */ + JavaCall(true), + + /** + * A request for the incoming argument locations. + */ + JavaCallee(false), + + /** + * A request for the outgoing argument locations at a call site to external native code that + * complies with the platform ABI. + */ + NativeCall(true); + + /** + * Determines if this is a request for the outgoing argument locations at a call site. + */ + public final boolean out; + + public static final Type[] VALUES = values(); + + private Type(boolean out) { + this.out = out; + } + } + + /** + * The amount of stack space (in bytes) required for the stack-based arguments of the call. + */ + private final int stackSize; + + private final AllocatableValue returnLocation; + + /** + * The ordered locations in which the arguments are placed. + */ + private final AllocatableValue[] argumentLocations; + + /** + * Creates a description of the registers and stack locations used by a call. + * + * @param stackSize amount of stack space (in bytes) required for the stack-based arguments of + * the call + * @param returnLocation the location for the return value or {@link Value#ILLEGAL} if a void + * call + * @param argumentLocations the ordered locations in which the arguments are placed + */ + public CallingConvention(int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) { + assert argumentLocations != null; + assert returnLocation != null; + this.argumentLocations = argumentLocations; + this.stackSize = stackSize; + this.returnLocation = returnLocation; + assert verify(); + } + + /** + * Gets the location for the return value or {@link Value#ILLEGAL} if a void call. + */ + public AllocatableValue getReturn() { + return returnLocation; + } + + /** + * Gets the location for the {@code index}'th argument. + */ + public AllocatableValue getArgument(int index) { + return argumentLocations[index]; + } + + /** + * Gets the amount of stack space (in bytes) required for the stack-based arguments of the call. + */ + public int getStackSize() { + return stackSize; + } + + /** + * Gets the number of locations required for the arguments. + */ + public int getArgumentCount() { + return argumentLocations.length; + } + + /** + * Gets the locations required for the arguments. + */ + public AllocatableValue[] getArguments() { + if (argumentLocations.length == 0) { + return argumentLocations; + } + return argumentLocations.clone(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("CallingConvention["); + String sep = ""; + for (Value op : argumentLocations) { + sb.append(sep).append(op); + sep = ", "; + } + if (!returnLocation.equals(Value.ILLEGAL)) { + sb.append(" -> ").append(returnLocation); + } + sb.append("]"); + return sb.toString(); + } + + private boolean verify() { + for (int i = 0; i < argumentLocations.length; i++) { + Value location = argumentLocations[i]; + assert isStackSlot(location) || isAllocatableValue(location); + } + return true; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeCacheProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeCacheProvider.java new file mode 100644 index 00000000000..d0007ac08b4 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeCacheProvider.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import jdk.vm.ci.code.CompilationResult.*; +import jdk.vm.ci.code.DataSection.*; +import jdk.vm.ci.meta.*; + +/** + * Access to code cache related details and requirements. + */ +public interface CodeCacheProvider { + + /** + * Adds the given compilation result as an implementation of the given method without making it + * the default implementation. + * + * @param method a method to which the executable code is begin added + * @param compResult the compilation result to be added + * @param speculationLog the speculation log to be used + * @return a reference to the compiled and ready-to-run code or throws a + * {@link BailoutException} if the code installation failed + */ + InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode); + + /** + * Sets the given compilation result as the default implementation of the given method. + * + * @param method a method to which the executable code is begin added + * @param compResult the compilation result to be added + * @return a reference to the compiled and ready-to-run code or null if the code installation + * failed + */ + InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult); + + /** + * Gets a name for a {@link Mark} mark. + */ + default String getMarkName(Mark mark) { + return String.valueOf(mark.id); + } + + /** + * Gets a name for the {@linkplain Call#target target} of a {@link Call}. + */ + default String getTargetName(Call call) { + return String.valueOf(call.target); + } + + /** + * Gets the register configuration to use when compiling a given method. + */ + RegisterConfig getRegisterConfig(); + + /** + * Minimum size of the stack area reserved for outgoing parameters. This area is reserved in all + * cases, even when the compiled method has no regular call instructions. + * + * @return the minimum size of the outgoing parameter area in bytes + */ + int getMinimumOutgoingSize(); + + /** + * Determines if a {@link DataPatch} should be created for a given primitive constant that is + * part of a {@link CompilationResult}. A data patch is always created for an object constant. + */ + boolean needsDataPatch(JavaConstant constant); + + /** + * Create a {@link Data} item for one or more {@link Constant Constants}, that can be used in a + * {@link DataPatch}. If more than one {@link Constant} is given, then they are tightly packed + * into a single {@link Data} item. + */ + Data createDataItem(Constant... constants); + + /** + * Gets a description of the target architecture. + */ + TargetDescription getTarget(); + + /** + * Create a new speculation log for the target runtime. + */ + SpeculationLog createSpeculationLog(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeUtil.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeUtil.java new file mode 100644 index 00000000000..bae5a53b8e7 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeUtil.java @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Miscellaneous collection of utility methods used by {@code jdk.vm.ci.code} and its clients. + */ +public class CodeUtil { + + public static final String NEW_LINE = String.format("%n"); + + public static final int K = 1024; + public static final int M = 1024 * 1024; + + public static boolean isOdd(int n) { + return (n & 1) == 1; + } + + public static boolean isEven(int n) { + return (n & 1) == 0; + } + + /** + * Checks whether the specified integer is a power of two. + * + * @param val the value to check + * @return {@code true} if the value is a power of two; {@code false} otherwise + */ + public static boolean isPowerOf2(int val) { + return val > 0 && (val & val - 1) == 0; + } + + /** + * Checks whether the specified long is a power of two. + * + * @param val the value to check + * @return {@code true} if the value is a power of two; {@code false} otherwise + */ + public static boolean isPowerOf2(long val) { + return val > 0 && (val & val - 1) == 0; + } + + /** + * Computes the log (base 2) of the specified integer, rounding down. (E.g {@code log2(8) = 3}, + * {@code log2(21) = 4} ) + * + * @param val the value + * @return the log base 2 of the value + */ + public static int log2(int val) { + assert val > 0; + return (Integer.SIZE - 1) - Integer.numberOfLeadingZeros(val); + } + + /** + * Computes the log (base 2) of the specified long, rounding down. (E.g {@code log2(8) = 3}, + * {@code log2(21) = 4}) + * + * @param val the value + * @return the log base 2 of the value + */ + public static int log2(long val) { + assert val > 0; + return (Long.SIZE - 1) - Long.numberOfLeadingZeros(val); + } + + /** + * Narrow an integer value to a given bit width, and return the result as a signed long. + * + * @param value the value + * @param resultBits the result bit width + * @return {@code value} interpreted as {@code resultBits} bit number, encoded as signed long + */ + public static long narrow(long value, int resultBits) { + long ret = value & mask(resultBits); + return signExtend(ret, resultBits); + } + + /** + * Sign extend an integer. + * + * @param value the input value + * @param inputBits the bit width of the input value + * @return a signed long with the same value as the signed {@code inputBits}-bit number + * {@code value} + */ + public static long signExtend(long value, int inputBits) { + if (inputBits < 64) { + if ((value >>> (inputBits - 1) & 1) == 1) { + return value | (-1L << inputBits); + } else { + return value & ~(-1L << inputBits); + } + } else { + return value; + } + } + + /** + * Zero extend an integer. + * + * @param value the input value + * @param inputBits the bit width of the input value + * @return an unsigned long with the same value as the unsigned {@code inputBits}-bit number + * {@code value} + */ + public static long zeroExtend(long value, int inputBits) { + if (inputBits < 64) { + return value & ~(-1L << inputBits); + } else { + return value; + } + } + + /** + * Convert an integer to long. + * + * @param value the input value + * @param inputBits the bit width of the input value + * @param unsigned whether the values should be interpreted as signed or unsigned + * @return a long with the same value as the {@code inputBits}-bit number {@code value} + */ + public static long convert(long value, int inputBits, boolean unsigned) { + if (unsigned) { + return zeroExtend(value, inputBits); + } else { + return signExtend(value, inputBits); + } + } + + /** + * Get a bitmask with the low {@code bits} bit set and the high {@code 64 - bits} bit clear. + */ + public static long mask(int bits) { + assert 0 <= bits && bits <= 64; + if (bits == 64) { + return 0xffffffffffffffffL; + } else { + return (1L << bits) - 1; + } + } + + /** + * Get the minimum value representable in a {@code bits} bit signed integer. + */ + public static long minValue(int bits) { + assert 0 < bits && bits <= 64; + return -1L << (bits - 1); + } + + /** + * Get the maximum value representable in a {@code bits} bit signed integer. + */ + public static long maxValue(int bits) { + assert 0 < bits && bits <= 64; + return mask(bits - 1); + } + + /** + * Formats the values in a frame as a tabulated string. + * + * @param frame + * @return the values in {@code frame} as a tabulated string + */ + public static String tabulateValues(BytecodeFrame frame) { + int cols = Math.max(frame.numLocals, Math.max(frame.numStack, frame.numLocks)); + assert cols > 0; + ArrayList cells = new ArrayList<>(); + cells.add(""); + for (int i = 0; i < cols; i++) { + cells.add(i); + } + cols++; + if (frame.numLocals != 0) { + cells.add("locals:"); + cells.addAll(Arrays.asList(frame.values).subList(0, frame.numLocals)); + cells.addAll(Collections.nCopies(cols - frame.numLocals - 1, "")); + } + if (frame.numStack != 0) { + cells.add("stack:"); + cells.addAll(Arrays.asList(frame.values).subList(frame.numLocals, frame.numLocals + frame.numStack)); + cells.addAll(Collections.nCopies(cols - frame.numStack - 1, "")); + } + if (frame.numLocks != 0) { + cells.add("locks:"); + cells.addAll(Arrays.asList(frame.values).subList(frame.numLocals + frame.numStack, frame.values.length)); + cells.addAll(Collections.nCopies(cols - frame.numLocks - 1, "")); + } + Object[] cellArray = cells.toArray(); + for (int i = 0; i < cellArray.length; i++) { + if ((i % cols) != 0) { + cellArray[i] = "|" + cellArray[i]; + } + } + return CodeUtil.tabulate(cellArray, cols, 1, 1); + } + + /** + * Formats a given table as a string. The value of each cell is produced by + * {@link String#valueOf(Object)}. + * + * @param cells the cells of the table in row-major order + * @param cols the number of columns per row + * @param lpad the number of space padding inserted before each formatted cell value + * @param rpad the number of space padding inserted after each formatted cell value + * @return a string with one line per row and each column left-aligned + */ + public static String tabulate(Object[] cells, int cols, int lpad, int rpad) { + int rows = (cells.length + (cols - 1)) / cols; + int[] colWidths = new int[cols]; + for (int col = 0; col < cols; col++) { + for (int row = 0; row < rows; row++) { + int index = col + (row * cols); + if (index < cells.length) { + Object cell = cells[index]; + colWidths[col] = Math.max(colWidths[col], String.valueOf(cell).length()); + } + } + } + StringBuilder sb = new StringBuilder(); + String nl = NEW_LINE; + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + int index = col + (row * cols); + if (index < cells.length) { + for (int i = 0; i < lpad; i++) { + sb.append(' '); + } + Object cell = cells[index]; + String s = String.valueOf(cell); + int w = s.length(); + sb.append(s); + while (w < colWidths[col]) { + sb.append(' '); + w++; + } + for (int i = 0; i < rpad; i++) { + sb.append(' '); + } + } + } + sb.append(nl); + } + return sb.toString(); + } + + /** + * Appends a formatted code position to a {@link StringBuilder}. + * + * @param sb the {@link StringBuilder} to append to + * @param pos the code position to format and append to {@code sb} + * @return the value of {@code sb} + */ + public static StringBuilder append(StringBuilder sb, BytecodePosition pos) { + MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI()); + if (pos.getCaller() != null) { + sb.append(NEW_LINE); + append(sb, pos.getCaller()); + } + return sb; + } + + /** + * Appends a formatted frame to a {@link StringBuilder}. + * + * @param sb the {@link StringBuilder} to append to + * @param frame the frame to format and append to {@code sb} + * @return the value of {@code sb} + */ + public static StringBuilder append(StringBuilder sb, BytecodeFrame frame) { + MetaUtil.appendLocation(sb.append("at "), frame.getMethod(), frame.getBCI()); + assert sb.charAt(sb.length() - 1) == ']'; + sb.deleteCharAt(sb.length() - 1); + sb.append(", duringCall: ").append(frame.duringCall).append(", rethrow: ").append(frame.rethrowException).append(']'); + if (frame.values != null && frame.values.length > 0) { + sb.append(NEW_LINE); + String table = tabulateValues(frame); + String[] rows = table.split(NEW_LINE); + for (int i = 0; i < rows.length; i++) { + String row = rows[i]; + if (!row.trim().isEmpty()) { + sb.append(" ").append(row); + if (i != rows.length - 1) { + sb.append(NEW_LINE); + } + } + } + } + if (frame.caller() != null) { + sb.append(NEW_LINE); + append(sb, frame.caller()); + } else if (frame.getCaller() != null) { + sb.append(NEW_LINE); + append(sb, frame.getCaller()); + } + return sb; + } + + public interface RefMapFormatter { + + String formatStackSlot(int frameRefMapIndex); + + String formatRegister(int regRefMapIndex); + } + + /** + * Formats a location in a register reference map. + */ + public static class DefaultRegFormatter implements RefMapFormatter { + + private final Register[] registers; + + public DefaultRegFormatter(Architecture arch) { + registers = new Register[arch.getRegisterReferenceMapSize()]; + for (Register r : arch.getRegisters()) { + if (r.getReferenceMapIndex() >= 0) { + registers[r.getReferenceMapIndex()] = r; + } + } + } + + public String formatStackSlot(int frameRefMapIndex) { + return null; + } + + public String formatRegister(int regRefMapIndex) { + int i = regRefMapIndex; + int idx = 0; + while (registers[i] == null) { + i--; + idx++; + } + if (idx == 0) { + return registers[i].toString(); + } else { + return String.format("%s+%d", registers[i].toString(), idx); + } + } + } + + /** + * Formats a location present in a register or frame reference map. + */ + public static class DefaultRefMapFormatter extends DefaultRegFormatter { + + /** + * The size of a stack slot. + */ + public final int slotSize; + + /** + * The register used as the frame pointer. + */ + public final Register fp; + + /** + * The offset (in bytes) from the slot pointed to by {@link #fp} to the slot corresponding + * to bit 0 in the frame reference map. + */ + public final int refMapToFPOffset; + + public DefaultRefMapFormatter(Architecture arch, int slotSize, Register fp, int refMapToFPOffset) { + super(arch); + this.slotSize = slotSize; + this.fp = fp; + this.refMapToFPOffset = refMapToFPOffset; + } + + @Override + public String formatStackSlot(int frameRefMapIndex) { + int refMapOffset = frameRefMapIndex * slotSize; + int fpOffset = refMapOffset + refMapToFPOffset; + if (fpOffset >= 0) { + return fp + "+" + fpOffset; + } + return fp.name + fpOffset; + } + } + + public static class NumberedRefMapFormatter implements RefMapFormatter { + + public String formatStackSlot(int frameRefMapIndex) { + return "s" + frameRefMapIndex; + } + + public String formatRegister(int regRefMapIndex) { + return "r" + regRefMapIndex; + } + } + + /** + * Appends a formatted debug info to a {@link StringBuilder}. + * + * @param sb the {@link StringBuilder} to append to + * @param info the debug info to format and append to {@code sb} + * @return the value of {@code sb} + */ + public static StringBuilder append(StringBuilder sb, DebugInfo info, RefMapFormatter formatterArg) { + RefMapFormatter formatter = formatterArg; + if (formatter == null) { + formatter = new NumberedRefMapFormatter(); + } + String nl = NEW_LINE; + ReferenceMap refMap = info.getReferenceMap(); + if (refMap != null) { + sb.append(refMap.toString()); + } + RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); + if (calleeSaveInfo != null) { + sb.append("callee-save-info:").append(nl); + Map map = calleeSaveInfo.slotsToRegisters(true); + for (Map.Entry e : map.entrySet()) { + sb.append(" ").append(e.getValue()).append(" -> ").append(formatter.formatStackSlot(e.getKey())).append(nl); + } + } + BytecodeFrame frame = info.frame(); + if (frame != null) { + append(sb, frame); + } else if (info.getBytecodePosition() != null) { + append(sb, info.getBytecodePosition()); + } + return sb; + } + + /** + * Create a calling convention from a {@link ResolvedJavaMethod}. + */ + public static CallingConvention getCallingConvention(CodeCacheProvider codeCache, CallingConvention.Type type, ResolvedJavaMethod method, boolean stackOnly) { + Signature sig = method.getSignature(); + JavaType retType = sig.getReturnType(null); + int sigCount = sig.getParameterCount(false); + JavaType[] argTypes; + int argIndex = 0; + if (!method.isStatic()) { + argTypes = new JavaType[sigCount + 1]; + argTypes[argIndex++] = method.getDeclaringClass(); + } else { + argTypes = new JavaType[sigCount]; + } + for (int i = 0; i < sigCount; i++) { + argTypes[argIndex++] = sig.getParameterType(i, null); + } + + RegisterConfig registerConfig = codeCache.getRegisterConfig(); + return registerConfig.getCallingConvention(type, retType, argTypes, codeCache.getTarget(), stackOnly); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationResult.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationResult.java new file mode 100644 index 00000000000..5cd3636eaad --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationResult.java @@ -0,0 +1,1054 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import static java.util.Collections.*; +import static jdk.vm.ci.meta.MetaUtil.*; + +import java.util.*; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.*; + +/** + * Represents the output from compiling a method, including the compiled machine code, associated + * data and references, relocation information, deoptimization information, etc. + */ +public class CompilationResult { + + /** + * Represents a code position with associated additional information. + */ + public abstract static class Site { + + /** + * The position (or offset) of this site with respect to the start of the target method. + */ + public final int pcOffset; + + public Site(int pos) { + this.pcOffset = pos; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public abstract boolean equals(Object obj); + } + + /** + * Represents an infopoint with associated debug info. Note that safepoints are also infopoints. + */ + public static class Infopoint extends Site implements Comparable { + + public final DebugInfo debugInfo; + + public final InfopointReason reason; + + public Infopoint(int pcOffset, DebugInfo debugInfo, InfopointReason reason) { + super(pcOffset); + this.debugInfo = debugInfo; + this.reason = reason; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(pcOffset); + sb.append("[]"); + appendDebugInfo(sb, debugInfo); + return sb.toString(); + } + + @Override + public int compareTo(Infopoint o) { + if (pcOffset < o.pcOffset) { + return -1; + } else if (pcOffset > o.pcOffset) { + return 1; + } + return this.reason.compareTo(o.reason); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj != null && obj.getClass() == getClass()) { + Infopoint that = (Infopoint) obj; + if (this.pcOffset == that.pcOffset && Objects.equals(this.debugInfo, that.debugInfo) && Objects.equals(this.reason, that.reason)) { + return true; + } + } + return false; + } + } + + public enum MetaSpaceAccessType { + Move, + Store, // store only works for compressed oops (memory <- 32bit value). Compressed oops is + // not supported using AOT. TODO: Look at HotSpotStoreConstantOp + Compare; // HotSpotCompareMemoryConstantOp, HotSpotCompareConstantOp + + private MetaSpaceAccessType() { + } + } + + /** + * Represents a meta space pointer access in the code. + */ + public static final class MetaSpaceAccess extends Infopoint { + + private static final long serialVersionUID = 1701958512608684706L; + + /** + * Metaspace reference. + */ + public final Object reference; // Object here is a HotSpotResolvedObjectType or a + // HotSpotMetaSpaceConstant + + public final MetaSpaceAccessType type; + + /** + * Instruction size. + */ + public final int instructionSize; + + public MetaSpaceAccess(Object reference, int instructionSize, MetaSpaceAccessType type, int pcOffset, DebugInfo debugInfo) { + super(pcOffset, debugInfo, InfopointReason.METASPACE_ACCESS); + this.type = type; + this.reference = reference; + this.instructionSize = instructionSize; + } + } + + /** + * Represents a call in the code. + */ + public static final class Call extends Infopoint { + + /** + * The target of the call. + */ + public final InvokeTarget target; + + /** + * The size of the call instruction. + */ + public final int size; + + /** + * Specifies if this call is direct or indirect. A direct call has an immediate operand + * encoding the absolute or relative (to the call itself) address of the target. An indirect + * call has a register or memory operand specifying the target address of the call. + */ + public final boolean direct; + + public Call(InvokeTarget target, int pcOffset, int size, boolean direct, DebugInfo debugInfo) { + super(pcOffset, debugInfo, InfopointReason.CALL); + this.size = size; + this.target = target; + this.direct = direct; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Call && super.equals(obj)) { + Call that = (Call) obj; + if (this.size == that.size && this.direct == that.direct && Objects.equals(this.target, that.target)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(pcOffset); + sb.append('['); + sb.append(target); + sb.append(']'); + + if (debugInfo != null) { + appendDebugInfo(sb, debugInfo); + } + + return sb.toString(); + } + } + + /** + * Represents some external data that is referenced by the code. + */ + public abstract static class Reference { + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(Object obj); + } + + public static final class ConstantReference extends Reference { + + private final VMConstant constant; + + public ConstantReference(VMConstant constant) { + this.constant = constant; + } + + public VMConstant getConstant() { + return constant; + } + + @Override + public String toString() { + return constant.toString(); + } + + @Override + public int hashCode() { + return constant.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ConstantReference) { + ConstantReference that = (ConstantReference) obj; + return Objects.equals(this.constant, that.constant); + } + return false; + } + } + + public static final class DataSectionReference extends Reference { + + private boolean initialized; + private int offset; + + public DataSectionReference() { + // will be set after the data section layout is fixed + offset = 0xDEADDEAD; + } + + public int getOffset() { + assert initialized; + + return offset; + } + + public void setOffset(int offset) { + assert !initialized; + initialized = true; + + this.offset = offset; + } + + @Override + public int hashCode() { + return offset; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DataSectionReference) { + DataSectionReference that = (DataSectionReference) obj; + return this.offset == that.offset; + } + return false; + } + } + + /** + * Represents a code site that references some data. The associated data can be either a + * {@link DataSectionReference reference} to the data section, or it may be an inlined + * {@link JavaConstant} that needs to be patched. + */ + public static final class DataPatch extends Site { + + public Reference reference; + public Object note; + + public DataPatch(int pcOffset, Reference reference) { + super(pcOffset); + this.reference = reference; + this.note = null; + } + + public DataPatch(int pcOffset, Reference reference, Object note) { + super(pcOffset); + this.reference = reference; + this.note = note; + } + + @Override + public String toString() { + if (note != null) { + return String.format("%d[, note: %s]", pcOffset, reference.toString(), note.toString()); + } else { + return String.format("%d[]", pcOffset, reference.toString()); + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DataPatch) { + DataPatch that = (DataPatch) obj; + if (this.pcOffset == that.pcOffset && Objects.equals(this.reference, that.reference) && Objects.equals(this.note, that.note)) { + return true; + } + } + return false; + } + } + + /** + * Provides extra information about instructions or data at specific positions in + * {@link CompilationResult#getTargetCode()}. This is optional information that can be used to + * enhance a disassembly of the code. + */ + public abstract static class CodeAnnotation { + + public final int position; + + public CodeAnnotation(int position) { + this.position = position; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public abstract boolean equals(Object obj); + } + + /** + * A string comment about one or more instructions at a specific position in the code. + */ + public static final class CodeComment extends CodeAnnotation { + + public final String value; + + public CodeComment(int position, String comment) { + super(position); + this.value = comment; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof CodeComment) { + CodeComment that = (CodeComment) obj; + if (this.position == that.position && this.value.equals(that.value)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "@" + position + ": " + value; + } + } + + /** + * Describes a table of signed offsets embedded in the code. The offsets are relative to the + * starting address of the table. This type of table maybe generated when translating a + * multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch} + * JVM instruction). + * + * The table is indexed by the contiguous range of integers from {@link #low} to {@link #high} + * inclusive. + */ + public static final class JumpTable extends CodeAnnotation { + + /** + * The low value in the key range (inclusive). + */ + public final int low; + + /** + * The high value in the key range (inclusive). + */ + public final int high; + + /** + * The size (in bytes) of each table entry. + */ + public final int entrySize; + + public JumpTable(int position, int low, int high, int entrySize) { + super(position); + this.low = low; + this.high = high; + this.entrySize = entrySize; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof JumpTable) { + JumpTable that = (JumpTable) obj; + if (this.position == that.position && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "@" + position + ": [" + low + " .. " + high + "]"; + } + } + + /** + * Represents exception handler information for a specific code position. It includes the catch + * code position as well as the caught exception type. + */ + public static final class ExceptionHandler extends Site { + + public final int handlerPos; + + ExceptionHandler(int pcOffset, int handlerPos) { + super(pcOffset); + this.handlerPos = handlerPos; + } + + @Override + public String toString() { + return String.format("%d[]", pcOffset, handlerPos); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ExceptionHandler) { + ExceptionHandler that = (ExceptionHandler) obj; + if (this.pcOffset == that.pcOffset && this.handlerPos == that.handlerPos) { + return true; + } + } + return false; + } + } + + /** + * Represents a mark in the machine code that can be used by the runtime for its own purposes. A + * mark can reference other marks. + */ + public static final class Mark extends Site { + + public final Object id; + + public Mark(int pcOffset, Object id) { + super(pcOffset); + this.id = id; + } + + @Override + public String toString() { + if (id == null) { + return String.format("%d[]", pcOffset); + } else if (id instanceof Integer) { + return String.format("%d[]", pcOffset, Integer.toHexString((Integer) id)); + } else { + return String.format("%d[]", pcOffset, id.toString()); + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Mark) { + Mark that = (Mark) obj; + if (this.pcOffset == that.pcOffset && Objects.equals(this.id, that.id)) { + return true; + } + } + return false; + } + } + + private int id = -1; + + /** + * Specifies whether this compilation is a {@code +ImmutableCode} {@code +GeneratePIC} + * compilation. + */ + private final boolean isImmutablePIC; + + private int entryBCI = -1; + + private final DataSection dataSection = new DataSection(); + + private final List infopoints = new ArrayList<>(); + private final List dataPatches = new ArrayList<>(); + private final List exceptionHandlers = new ArrayList<>(); + private final List marks = new ArrayList<>(); + + private int totalFrameSize = -1; + private int customStackAreaOffset = -1; + + private final String name; + + /** + * The buffer containing the emitted machine code. + */ + private byte[] targetCode; + + /** + * The leading number of bytes in {@link #targetCode} containing the emitted machine code. + */ + private int targetCodeSize; + + private ArrayList annotations; + + private Assumption[] assumptions; + + /** + * The list of the methods whose bytecodes were used as input to the compilation. If + * {@code null}, then the compilation did not record method dependencies. Otherwise, the first + * element of this array is the root method of the compilation. + */ + private ResolvedJavaMethod[] methods; + + private int bytecodeSize; + + private boolean hasUnsafeAccess; + + public CompilationResult() { + this(null); + } + + public CompilationResult(String name) { + this.name = name; + this.isImmutablePIC = false; + } + + public CompilationResult(boolean isImmutablePIC) { + this.name = null; + this.isImmutablePIC = isImmutablePIC; + } + + @Override + public int hashCode() { + // CompilationResult instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + if (methods != null) { + return getClass().getName() + "[" + methods[0].format("%H.%n(%p)%r") + "]"; + } + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj != null && obj.getClass() == getClass()) { + CompilationResult that = (CompilationResult) obj; + // @formatter:off + if (this.entryBCI == that.entryBCI && + this.id == that.id && + this.customStackAreaOffset == that.customStackAreaOffset && + this.totalFrameSize == that.totalFrameSize && + this.targetCodeSize == that.targetCodeSize && + Objects.equals(this.name, that.name) && + Objects.equals(this.annotations, that.annotations) && + Objects.equals(this.dataSection, that.dataSection) && + Objects.equals(this.exceptionHandlers, that.exceptionHandlers) && + Objects.equals(this.dataPatches, that.dataPatches) && + Objects.equals(this.infopoints, that.infopoints) && + Objects.equals(this.marks, that.marks) && + Arrays.equals(this.assumptions, that.assumptions) && + Arrays.equals(targetCode, that.targetCode)) { + return true; + } + // @formatter:on + } + return false; + } + + /** + * @return the compile id + */ + public int getId() { + return id; + } + + /** + * @param id the compile id to set + */ + public void setId(int id) { + this.id = id; + } + + /** + * @return true is this is a {@code +ImmutableCode} {@code +GeneratePIC} compilation, false + * otherwise. + */ + public boolean isImmutablePIC() { + return isImmutablePIC; + } + + /** + * @return the entryBCI + */ + public int getEntryBCI() { + return entryBCI; + } + + /** + * @param entryBCI the entryBCI to set + */ + public void setEntryBCI(int entryBCI) { + this.entryBCI = entryBCI; + } + + /** + * Sets the assumptions made during compilation. + */ + public void setAssumptions(Assumption[] assumptions) { + this.assumptions = assumptions; + } + + /** + * Gets the assumptions made during compilation. + */ + public Assumption[] getAssumptions() { + return assumptions; + } + + /** + * Sets the methods whose bytecodes were used as input to the compilation. + * + * @param rootMethod the root method of the compilation + * @param inlinedMethods the methods inlined during compilation + */ + public void setMethods(ResolvedJavaMethod rootMethod, Collection inlinedMethods) { + assert rootMethod != null; + assert inlinedMethods != null; + if (inlinedMethods.contains(rootMethod)) { + methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]); + for (int i = 0; i < methods.length; i++) { + if (methods[i].equals(rootMethod)) { + if (i != 0) { + ResolvedJavaMethod tmp = methods[0]; + methods[0] = methods[i]; + methods[i] = tmp; + } + break; + } + } + } else { + methods = new ResolvedJavaMethod[1 + inlinedMethods.size()]; + methods[0] = rootMethod; + int i = 1; + for (ResolvedJavaMethod m : inlinedMethods) { + methods[i++] = m; + } + } + } + + /** + * Gets the methods whose bytecodes were used as input to the compilation. + * + * @return {@code null} if the compilation did not record method dependencies otherwise the + * methods whose bytecodes were used as input to the compilation with the first element + * being the root method of the compilation + */ + public ResolvedJavaMethod[] getMethods() { + return methods; + } + + public void setBytecodeSize(int bytecodeSize) { + this.bytecodeSize = bytecodeSize; + } + + public int getBytecodeSize() { + return bytecodeSize; + } + + public DataSection getDataSection() { + return dataSection; + } + + /** + * The total frame size of the method in bytes. This includes the return address pushed onto the + * stack, if any. + * + * @return the frame size + */ + public int getTotalFrameSize() { + assert totalFrameSize != -1 : "frame size not yet initialized!"; + return totalFrameSize; + } + + /** + * Sets the total frame size in bytes. This includes the return address pushed onto the stack, + * if any. + * + * @param size the size of the frame in bytes + */ + public void setTotalFrameSize(int size) { + totalFrameSize = size; + } + + /** + * Sets the machine that has been generated by the compiler. + * + * @param code the machine code generated + * @param size the size of the machine code + */ + public void setTargetCode(byte[] code, int size) { + targetCode = code; + targetCodeSize = size; + } + + /** + * Records a data patch in the code section. The data patch can refer to something in the + * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined + * constant}. + * + * @param codePos The position in the code that needs to be patched. + * @param ref The reference that should be inserted in the code. + */ + public void recordDataPatch(int codePos, Reference ref) { + assert codePos >= 0 && ref != null; + dataPatches.add(new DataPatch(codePos, ref)); + } + + /** + * Records a data patch in the code section. The data patch can refer to something in the + * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined + * constant}. + * + * @param codePos The position in the code that needs to be patched. + * @param ref The reference that should be inserted in the code. + * @param note The note attached to data patch for use by post-processing tools + */ + public void recordDataPatchWithNote(int codePos, Reference ref, Object note) { + assert codePos >= 0 && ref != null; + dataPatches.add(new DataPatch(codePos, ref, note)); + } + + /** + * Records metaspace access. + */ + public void recordMetaspaceAccess(Object reference, int instructionSize, MetaSpaceAccessType type, int codePos, DebugInfo debugInfo) { + final MetaSpaceAccess metaspace = new MetaSpaceAccess(reference, instructionSize, type, codePos, debugInfo); + addInfopoint(metaspace); + } + + /** + * Records a call in the code array. + * + * @param codePos the position of the call in the code array + * @param size the size of the call instruction + * @param target the being called + * @param debugInfo the debug info for the call + * @param direct specifies if this is a {@linkplain Call#direct direct} call + */ + public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) { + final Call call = new Call(target, codePos, size, direct, debugInfo); + addInfopoint(call); + } + + /** + * Records an exception handler for this method. + * + * @param codePos the position in the code that is covered by the handler + * @param handlerPos the position of the handler + */ + public void recordExceptionHandler(int codePos, int handlerPos) { + assert validateExceptionHandlerAdd(codePos, handlerPos) : String.format("Duplicate exception handler for pc 0x%x handlerPos 0x%x", codePos, handlerPos); + exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos)); + } + + /** + * Validate if the exception handler for codePos already exists and handlerPos is different. + * + * @param codePos + * @param handlerPos + * @return true if the validation is successful + */ + private boolean validateExceptionHandlerAdd(int codePos, int handlerPos) { + ExceptionHandler exHandler = getExceptionHandlerForCodePos(codePos); + return exHandler == null || exHandler.handlerPos == handlerPos; + } + + /** + * Returns the first ExceptionHandler which matches codePos. + * + * @param codePos position to search for + * @return first matching ExceptionHandler + */ + private ExceptionHandler getExceptionHandlerForCodePos(int codePos) { + for (ExceptionHandler h : exceptionHandlers) { + if (h.pcOffset == codePos) { + return h; + } + } + return null; + } + + /** + * Records an infopoint in the code array. + * + * @param codePos the position of the infopoint in the code array + * @param debugInfo the debug info for the infopoint + */ + public void recordInfopoint(int codePos, DebugInfo debugInfo, InfopointReason reason) { + addInfopoint(new Infopoint(codePos, debugInfo, reason)); + } + + /** + * Records a custom infopoint in the code section. + * + * Compiler implementations can use this method to record non-standard infopoints, which are not + * handled by the dedicated methods like {@link #recordCall}. + * + * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint} + */ + public void addInfopoint(Infopoint infopoint) { + // The infopoints list must always be sorted + if (!infopoints.isEmpty()) { + Infopoint previousInfopoint = infopoints.get(infopoints.size() - 1); + if (previousInfopoint.pcOffset > infopoint.pcOffset) { + // This re-sorting should be very rare + Collections.sort(infopoints); + previousInfopoint = infopoints.get(infopoints.size() - 1); + } + if (previousInfopoint.pcOffset == infopoint.pcOffset) { + if (infopoint.reason.canBeOmitted()) { + return; + } + if (previousInfopoint.reason.canBeOmitted()) { + Infopoint removed = infopoints.remove(infopoints.size() - 1); + assert removed == previousInfopoint; + } else { + throw new RuntimeException("Infopoints that can not be omited should have distinct PCs"); + } + } + } + infopoints.add(infopoint); + } + + /** + * Records an instruction mark within this method. + * + * @param codePos the position in the code that is covered by the handler + * @param markId the identifier for this mark + */ + public Mark recordMark(int codePos, Object markId) { + Mark mark = new Mark(codePos, markId); + marks.add(mark); + return mark; + } + + /** + * Offset in bytes for the custom stack area (relative to sp). + * + * @return the offset in bytes + */ + public int getCustomStackAreaOffset() { + return customStackAreaOffset; + } + + /** + * @see #getCustomStackAreaOffset() + * @param offset + */ + public void setCustomStackAreaOffset(int offset) { + customStackAreaOffset = offset; + } + + /** + * @return the machine code generated for this method + */ + public byte[] getTargetCode() { + return targetCode; + } + + /** + * @return the size of the machine code generated for this method + */ + public int getTargetCodeSize() { + return targetCodeSize; + } + + /** + * @return the code annotations or {@code null} if there are none + */ + public List getAnnotations() { + if (annotations == null) { + return Collections.emptyList(); + } + return annotations; + } + + public void addAnnotation(CodeAnnotation annotation) { + assert annotation != null; + if (annotations == null) { + annotations = new ArrayList<>(); + } + annotations.add(annotation); + } + + private static void appendDebugInfo(StringBuilder sb, DebugInfo info) { + if (info != null) { + ReferenceMap refMap = info.getReferenceMap(); + if (refMap != null) { + sb.append(refMap.toString()); + sb.append(']'); + } + RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); + if (calleeSaveInfo != null) { + sb.append(" callee-save-info["); + String sep = ""; + for (Map.Entry e : calleeSaveInfo.registersToSlots(true).entrySet()) { + sb.append(sep).append(e.getKey()).append("->").append(e.getValue()); + sep = ", "; + } + sb.append(']'); + } + BytecodePosition codePos = info.getBytecodePosition(); + if (codePos != null) { + MetaUtil.appendLocation(sb.append(" "), codePos.getMethod(), codePos.getBCI()); + if (info.hasFrame()) { + sb.append(" #locals=").append(info.frame().numLocals).append(" #expr=").append(info.frame().numStack); + if (info.frame().numLocks > 0) { + sb.append(" #locks=").append(info.frame().numLocks); + } + } + } + } + } + + /** + * @return the list of infopoints, sorted by {@link Site#pcOffset} + */ + public List getInfopoints() { + if (infopoints.isEmpty()) { + return emptyList(); + } + return unmodifiableList(infopoints); + } + + /** + * @return the list of data references + */ + public List getDataPatches() { + if (dataPatches.isEmpty()) { + return emptyList(); + } + return unmodifiableList(dataPatches); + } + + /** + * @return the list of exception handlers + */ + public List getExceptionHandlers() { + if (exceptionHandlers.isEmpty()) { + return emptyList(); + } + return unmodifiableList(exceptionHandlers); + } + + /** + * @return the list of marks + */ + public List getMarks() { + if (marks.isEmpty()) { + return emptyList(); + } + return unmodifiableList(marks); + } + + public String getName() { + return name; + } + + public void setHasUnsafeAccess(boolean hasUnsafeAccess) { + this.hasUnsafeAccess = hasUnsafeAccess; + } + + public boolean hasUnsafeAccess() { + return hasUnsafeAccess; + } + + public void reset() { + hasUnsafeAccess = false; + infopoints.clear(); + dataPatches.clear(); + exceptionHandlers.clear(); + marks.clear(); + dataSection.clear(); + if (annotations != null) { + annotations.clear(); + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DataSection.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DataSection.java new file mode 100644 index 00000000000..d4d28810261 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DataSection.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import static jdk.vm.ci.meta.MetaUtil.*; + +import java.nio.*; +import java.util.*; +import java.util.function.*; + +import jdk.vm.ci.code.CompilationResult.*; +import jdk.vm.ci.code.DataSection.*; +import jdk.vm.ci.meta.*; + +public final class DataSection implements Iterable { + + @FunctionalInterface + public interface DataBuilder { + + void emit(ByteBuffer buffer, Consumer patch); + + static DataBuilder raw(byte[] data) { + return (buffer, patch) -> buffer.put(data); + } + + static DataBuilder serializable(SerializableConstant c) { + return (buffer, patch) -> c.serialize(buffer); + } + + static DataBuilder zero(int size) { + switch (size) { + case 1: + return (buffer, patch) -> buffer.put((byte) 0); + case 2: + return (buffer, patch) -> buffer.putShort((short) 0); + case 4: + return (buffer, patch) -> buffer.putInt(0); + case 8: + return (buffer, patch) -> buffer.putLong(0L); + default: + return (buffer, patch) -> { + int rest = size; + while (rest > 8) { + buffer.putLong(0L); + rest -= 8; + } + while (rest > 0) { + buffer.put((byte) 0); + rest--; + } + }; + } + } + } + + public static final class Data { + + private int alignment; + private final int size; + private final DataBuilder builder; + + private DataSectionReference ref; + + public Data(int alignment, int size, DataBuilder builder) { + this.alignment = alignment; + this.size = size; + this.builder = builder; + + // initialized in DataSection.insertData(Data) + ref = null; + } + + public void updateAlignment(int newAlignment) { + if (newAlignment == alignment) { + return; + } + alignment = lcm(alignment, newAlignment); + } + + public int getAlignment() { + return alignment; + } + + public int getSize() { + return size; + } + + public DataBuilder getBuilder() { + return builder; + } + + @Override + public int hashCode() { + // Data instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + assert ref != null; + if (obj == this) { + return true; + } + if (obj instanceof Data) { + Data that = (Data) obj; + if (this.alignment == that.alignment && this.size == that.size && this.ref.equals(that.ref)) { + return true; + } + } + return false; + } + } + + private final ArrayList dataItems = new ArrayList<>(); + + private boolean finalLayout; + private int sectionAlignment; + private int sectionSize; + + @Override + public int hashCode() { + // DataSection instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DataSection) { + DataSection that = (DataSection) obj; + if (this.finalLayout == that.finalLayout && this.sectionAlignment == that.sectionAlignment && this.sectionSize == that.sectionSize && Objects.equals(this.dataItems, that.dataItems)) { + return true; + } + } + return false; + } + + /** + * Insert a {@link Data} item into the data section. If the item is already in the data section, + * the same {@link DataSectionReference} is returned. + * + * @param data the {@link Data} item to be inserted + * @return a unique {@link DataSectionReference} identifying the {@link Data} item + */ + public DataSectionReference insertData(Data data) { + assert !finalLayout; + if (data.ref == null) { + data.ref = new DataSectionReference(); + dataItems.add(data); + } + return data.ref; + } + + /** + * Compute the layout of the data section. This can be called only once, and after it has been + * called, the data section can no longer be modified. + */ + public void finalizeLayout() { + assert !finalLayout; + finalLayout = true; + + // simple heuristic: put items with larger alignment requirement first + dataItems.sort((a, b) -> a.alignment - b.alignment); + + int position = 0; + for (Data d : dataItems) { + sectionAlignment = lcm(sectionAlignment, d.alignment); + position = align(position, d.alignment); + + d.ref.setOffset(position); + position += d.size; + } + + sectionSize = position; + } + + public boolean isFinalized() { + return finalLayout; + } + + /** + * Get the size of the data section. Can only be called after {@link #finalizeLayout}. + */ + public int getSectionSize() { + assert finalLayout; + return sectionSize; + } + + /** + * Get the minimum alignment requirement of the data section. Can only be called after + * {@link #finalizeLayout}. + */ + public int getSectionAlignment() { + assert finalLayout; + return sectionAlignment; + } + + /** + * Build the data section. Can only be called after {@link #finalizeLayout}. + * + * @param buffer The {@link ByteBuffer} where the data section should be built. The buffer must + * hold at least {@link #getSectionSize()} bytes. + * @param patch A {@link Consumer} to receive {@link DataPatch data patches} for relocations in + * the data section. + */ + public void buildDataSection(ByteBuffer buffer, Consumer patch) { + assert finalLayout; + for (Data d : dataItems) { + buffer.position(d.ref.getOffset()); + d.builder.emit(buffer, patch); + } + } + + public Data findData(DataSectionReference ref) { + for (Data d : dataItems) { + if (d.ref == ref) { + return d; + } + } + return null; + } + + public Iterator iterator() { + return dataItems.iterator(); + } + + public static int lcm(int x, int y) { + if (x == 0) { + return y; + } else if (y == 0) { + return x; + } + + int a = Math.max(x, y); + int b = Math.min(x, y); + while (b > 0) { + int tmp = a % b; + a = b; + b = tmp; + } + + int gcd = a; + return x * y / gcd; + } + + private static int align(int position, int alignment) { + return ((position + alignment - 1) / alignment) * alignment; + } + + public void clear() { + assert !finalLayout; + this.dataItems.clear(); + this.sectionAlignment = 0; + this.sectionSize = 0; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java new file mode 100644 index 00000000000..60e811f3761 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +/** + * Represents the debugging information for a particular point of execution. This information + * includes: + *
    + *
  • a {@linkplain #getBytecodePosition() bytecode position}
  • + *
  • a reference map for registers and stack slots in the current frame
  • + *
  • a map from bytecode locals and operand stack slots to their values or locations from which + * their values can be read
  • + *
  • a map from the registers (in the caller's frame) to the slots where they are saved in the + * current frame
  • + *
+ */ +public final class DebugInfo { + + private final BytecodePosition bytecodePosition; + private ReferenceMap referenceMap; + @SuppressWarnings("unused") private final VirtualObject[] virtualObjectMapping; + private RegisterSaveLayout calleeSaveInfo; + + /** + * Creates a new {@link DebugInfo} from the given values. + * + * @param codePos the {@linkplain BytecodePosition code position} or {@linkplain BytecodeFrame + * frame} info + * @param virtualObjectMapping the mapping of {@link VirtualObject}s to their real values + */ + public DebugInfo(BytecodePosition codePos, VirtualObject[] virtualObjectMapping) { + this.bytecodePosition = codePos; + this.virtualObjectMapping = virtualObjectMapping; + } + + public DebugInfo(BytecodePosition codePos) { + this(codePos, null); + } + + public void setReferenceMap(ReferenceMap referenceMap) { + this.referenceMap = referenceMap; + } + + /** + * @return {@code true} if this debug information has a frame + */ + public boolean hasFrame() { + return getBytecodePosition() instanceof BytecodeFrame; + } + + /** + * Gets the deoptimization information for each inlined frame (if available). + * + * @return {@code null} if no frame de-opt info is {@linkplain #hasFrame() available} + */ + public BytecodeFrame frame() { + if (hasFrame()) { + return (BytecodeFrame) getBytecodePosition(); + } + return null; + } + + @Override + public String toString() { + return CodeUtil.append(new StringBuilder(100), this, null).toString(); + } + + /** + * @return The code position (including all inlined methods) of this debug info. If this is a + * {@link BytecodeFrame} instance, then it is also the deoptimization information for + * each inlined frame. + */ + public BytecodePosition getBytecodePosition() { + return bytecodePosition; + } + + public ReferenceMap getReferenceMap() { + return referenceMap; + } + + /** + * Sets the map from the registers (in the caller's frame) to the slots where they are saved in + * the current frame. + */ + public void setCalleeSaveInfo(RegisterSaveLayout calleeSaveInfo) { + this.calleeSaveInfo = calleeSaveInfo; + } + + /** + * Gets the map from the registers (in the caller's frame) to the slots where they are saved in + * the current frame. If no such information is available, {@code null} is returned. + */ + public RegisterSaveLayout getCalleeSaveInfo() { + return calleeSaveInfo; + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DebugInfo) { + DebugInfo that = (DebugInfo) obj; + if (Objects.equals(this.bytecodePosition, that.bytecodePosition) && Objects.equals(this.calleeSaveInfo, that.calleeSaveInfo) && Objects.equals(this.referenceMap, that.referenceMap)) { + return true; + } + } + return false; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InfopointReason.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InfopointReason.java new file mode 100644 index 00000000000..026bb5bd412 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InfopointReason.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * A reason for infopoint insertion. + */ +public enum InfopointReason { + UNKNOWN(false), + SAFEPOINT(false), + CALL(false), + IMPLICIT_EXCEPTION(false), + METHOD_START(true), + METHOD_END(true), + LINE_NUMBER(true), + METASPACE_ACCESS(true); + + private InfopointReason(boolean canBeOmitted) { + this.canBeOmitted = canBeOmitted; + } + + private final boolean canBeOmitted; + + public boolean canBeOmitted() { + return canBeOmitted; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InstalledCode.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InstalledCode.java new file mode 100644 index 00000000000..fe0c84ad1dc --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InstalledCode.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * Represents a compiled instance of a method. It may have been invalidated or removed in the + * meantime. + */ +public class InstalledCode { + + /** + * Raw address of this code blob. + */ + private long address; + + /** + * Counts how often the address field was reassigned. + */ + private long version; + + protected final String name; + + public InstalledCode(String name) { + this.name = name; + } + + public final void setAddress(long address) { + this.address = address; + version++; + } + + /** + * @return the address of this code blob + */ + public final long getAddress() { + return address; + } + + /** + * @return the address of this code blob + */ + public final long getVersion() { + return version; + } + + /** + * Returns the name of this code blob. + */ + public String getName() { + return name; + } + + /** + * Returns the start address of this installed code if it is {@linkplain #isValid() valid}, 0 + * otherwise. + */ + public long getStart() { + return 0; + } + + /** + * Returns the number of instruction bytes for this code. + */ + public long getCodeSize() { + return 0; + } + + /** + * Returns a copy of this installed code if it is {@linkplain #isValid() valid}, null otherwise. + */ + public byte[] getCode() { + return null; + } + + /** + * @return true if the code represented by this object is still valid, false otherwise (may + * happen due to deopt, etc.) + */ + public boolean isValid() { + return address != 0; + } + + /** + * Invalidates this installed code such that any subsequent + * {@linkplain #executeVarargs(Object...) invocation} will throw an + * {@link InvalidInstalledCodeException}. + */ + public void invalidate() { + throw new UnsupportedOperationException(); + } + + /** + * Executes the installed code with a variable number of arguments. + * + * @param args the array of object arguments + * @return the value returned by the executed code + */ + @SuppressWarnings("unused") + public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { + throw new UnsupportedOperationException(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InvalidInstalledCodeException.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InvalidInstalledCodeException.java new file mode 100644 index 00000000000..459e45f13d3 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InvalidInstalledCodeException.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * Exception thrown by the runtime in case an invalidated machine code is called. + */ +public final class InvalidInstalledCodeException extends Exception { + + private static final long serialVersionUID = -3540232440794244844L; +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Location.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Location.java new file mode 100644 index 00000000000..c11cb4df3c9 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Location.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * Represents a location where a value can be stored. This can be either a {@link Register} or a + * stack slot. + */ +public final class Location { + + public final Register reg; + public final int offset; + + private Location(Register reg, int offset) { + this.reg = reg; + this.offset = offset; + } + + /** + * Create a {@link Location} for a register. + */ + public static Location register(Register reg) { + return new Location(reg, 0); + } + + /** + * Create a {@link Location} for a vector subregister. + * + * @param reg the {@link Register vector register} + * @param offset the offset in bytes into the vector register + */ + public static Location subregister(Register reg, int offset) { + return new Location(reg, offset); + } + + /** + * Create a {@link Location} for a stack slot. + */ + public static Location stack(int offset) { + return new Location(null, offset); + } + + public boolean isRegister() { + return reg != null; + } + + public boolean isStack() { + return reg == null; + } + + @Override + public String toString() { + String regName; + if (isRegister()) { + regName = reg.name + ":"; + } else { + regName = "stack:"; + } + return regName + offset; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java new file mode 100644 index 00000000000..6e708ca7a0f --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * Constants and intrinsic definition for memory barriers. + * + * The documentation for each constant is taken from Doug Lea's The JSR-133 Cookbook for Compiler + * Writers. + *

+ * The {@code JMM_*} constants capture the memory barriers necessary to implement the Java Memory + * Model with respect to volatile field accesses. Their values are explained by this comment from + * templateTable_i486.cpp in the HotSpot source code: + * + *

+ * Volatile variables demand their effects be made known to all CPU's in
+ * order.  Store buffers on most chips allow reads & writes to reorder; the
+ * JMM's ReadAfterWrite.java test fails in -Xint mode without some kind of
+ * memory barrier (i.e., it's not sufficient that the interpreter does not
+ * reorder volatile references, the hardware also must not reorder them).
+ *
+ * According to the new Java Memory Model (JMM):
+ * (1) All volatiles are serialized wrt to each other.
+ * ALSO reads & writes act as acquire & release, so:
+ * (2) A read cannot let unrelated NON-volatile memory refs that happen after
+ * the read float up to before the read.  It's OK for non-volatile memory refs
+ * that happen before the volatile read to float down below it.
+ * (3) Similarly, a volatile write cannot let unrelated NON-volatile memory refs
+ * that happen BEFORE the write float down to after the write.  It's OK for
+ * non-volatile memory refs that happen after the volatile write to float up
+ * before it.
+ *
+ * We only put in barriers around volatile refs (they are expensive), not
+ * _between_ memory refs (which would require us to track the flavor of the
+ * previous memory refs).  Requirements (2) and (3) require some barriers
+ * before volatile stores and after volatile loads.  These nearly cover
+ * requirement (1) but miss the volatile-store-volatile-load case.  This final
+ * case is placed after volatile-stores although it could just as well go
+ * before volatile-loads.
+ * 
+ */ +public class MemoryBarriers { + + /** + * The sequence {@code Load1; LoadLoad; Load2} ensures that {@code Load1}'s data are loaded + * before data accessed by {@code Load2} and all subsequent load instructions are loaded. In + * general, explicit {@code LoadLoad} barriers are needed on processors that perform speculative + * loads and/or out-of-order processing in which waiting load instructions can bypass waiting + * stores. On processors that guarantee to always preserve load ordering, these barriers amount + * to no-ops. + */ + public static final int LOAD_LOAD = 0x0001; + + /** + * The sequence {@code Load1; LoadStore; Store2} ensures that {@code Load1}'s data are loaded + * before all data associated with {@code Store2} and subsequent store instructions are flushed. + * {@code LoadStore} barriers are needed only on those out-of-order processors in which waiting + * store instructions can bypass loads. + */ + public static final int LOAD_STORE = 0x0002; + + /** + * The sequence {@code Store1; StoreLoad; Load2} ensures that {@code Store1}'s data are made + * visible to other processors (i.e., flushed to main memory) before data accessed by + * {@code Load2} and all subsequent load instructions are loaded. {@code StoreLoad} barriers + * protect against a subsequent load incorrectly using {@code Store1}'s data value rather than + * that from a more recent store to the same location performed by a different processor. + * Because of this, on the processors discussed below, a {@code StoreLoad} is strictly necessary + * only for separating stores from subsequent loads of the same location(s) as were stored + * before the barrier. {@code StoreLoad} barriers are needed on nearly all recent + * multiprocessors, and are usually the most expensive kind. Part of the reason they are + * expensive is that they must disable mechanisms that ordinarily bypass cache to satisfy loads + * from write-buffers. This might be implemented by letting the buffer fully flush, among other + * possible stalls. + */ + public static final int STORE_LOAD = 0x0004; + + /** + * The sequence {@code Store1; StoreStore; Store2} ensures that {@code Store1}'s data are + * visible to other processors (i.e., flushed to memory) before the data associated with + * {@code Store2} and all subsequent store instructions. In general, {@code StoreStore} barriers + * are needed on processors that do not otherwise guarantee strict ordering of flushes from + * write buffers and/or caches to other processors or main memory. + */ + public static final int STORE_STORE = 0x0008; + + public static final int JMM_PRE_VOLATILE_WRITE = LOAD_STORE | STORE_STORE; + public static final int JMM_POST_VOLATILE_WRITE = STORE_LOAD | STORE_STORE; + public static final int JMM_PRE_VOLATILE_READ = 0; + public static final int JMM_POST_VOLATILE_READ = LOAD_LOAD | LOAD_STORE; + + public static String barriersString(int barriers) { + StringBuilder sb = new StringBuilder(); + sb.append((barriers & LOAD_LOAD) != 0 ? "LOAD_LOAD " : ""); + sb.append((barriers & LOAD_STORE) != 0 ? "LOAD_STORE " : ""); + sb.append((barriers & STORE_LOAD) != 0 ? "STORE_LOAD " : ""); + sb.append((barriers & STORE_STORE) != 0 ? "STORE_STORE " : ""); + return sb.toString().trim(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ReferenceMap.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ReferenceMap.java new file mode 100644 index 00000000000..1d1491de252 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ReferenceMap.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +public abstract class ReferenceMap { +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Register.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Register.java new file mode 100644 index 00000000000..b6c7e894209 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Register.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import jdk.vm.ci.meta.*; + +/** + * Represents a target machine register. + */ +public final class Register implements Comparable { + + public static final RegisterCategory SPECIAL = new RegisterCategory("SPECIAL"); + + /** + * Invalid register. + */ + public static final Register None = new Register(-1, -1, "noreg", SPECIAL); + + /** + * Frame pointer of the current method. All spill slots and outgoing stack-based arguments are + * addressed relative to this register. + */ + public static final Register Frame = new Register(-2, -2, "framereg", SPECIAL); + + public static final Register CallerFrame = new Register(-3, -3, "callerframereg", SPECIAL); + + /** + * The identifier for this register that is unique across all the registers in a + * {@link Architecture}. A valid register has {@code number > 0}. + */ + public final int number; + + /** + * The mnemonic of this register. + */ + public final String name; + + /** + * The actual encoding in a target machine instruction for this register, which may or may not + * be the same as {@link #number}. + */ + public final int encoding; + + /** + * The assembler calls this method to get the register's encoding. + */ + public int encoding() { + return encoding; + } + + /** + * A platform specific register category that describes which values can be stored in a + * register. + */ + private final RegisterCategory registerCategory; + + /** + * A platform specific register type that describes which values can be stored in a register. + */ + public static class RegisterCategory { + + private final String name; + + private final int referenceMapOffset; + private final int referenceMapShift; + + public RegisterCategory(String name) { + this(name, 0, 0); + } + + public RegisterCategory(String name, int referenceMapOffset) { + this(name, referenceMapOffset, 0); + } + + public RegisterCategory(String name, int referenceMapOffset, int referenceMapShift) { + this.name = name; + this.referenceMapOffset = referenceMapOffset; + this.referenceMapShift = referenceMapShift; + } + + @Override + public String toString() { + return name; + } + + @Override + public int hashCode() { + return 23 + name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RegisterCategory) { + RegisterCategory that = (RegisterCategory) obj; + return this.referenceMapOffset == that.referenceMapOffset && this.referenceMapShift == that.referenceMapShift && this.name.equals(that.name); + } + return false; + } + } + + /** + * Creates a {@link Register} instance. + * + * @param number unique identifier for the register + * @param encoding the target machine encoding for the register + * @param name the mnemonic name for the register + * @param registerCategory the register category + */ + public Register(int number, int encoding, String name, RegisterCategory registerCategory) { + this.number = number; + this.name = name; + this.registerCategory = registerCategory; + this.encoding = encoding; + } + + public RegisterCategory getRegisterCategory() { + return registerCategory; + } + + /** + * Get the start index of this register in the {@link ReferenceMap}. + */ + public int getReferenceMapIndex() { + return (encoding << registerCategory.referenceMapShift) + registerCategory.referenceMapOffset; + } + + /** + * Gets this register as a {@linkplain RegisterValue value} with a specified kind. + * + * @param kind the specified kind + * @return the {@link RegisterValue} + */ + public RegisterValue asValue(LIRKind kind) { + return new RegisterValue(kind, this); + } + + /** + * Gets this register as a {@linkplain RegisterValue value} with no particular kind. + * + * @return a {@link RegisterValue} with {@link JavaKind#Illegal} kind. + */ + public RegisterValue asValue() { + return asValue(LIRKind.Illegal); + } + + /** + * Determines if this is a valid register. + * + * @return {@code true} iff this register is valid + */ + public boolean isValid() { + return number >= 0; + } + + /** + * Gets the maximum register {@linkplain #number number} in a given set of registers. + * + * @param registers the set of registers to process + * @return the maximum register number for any register in {@code registers} + */ + public static int maxRegisterNumber(Register[] registers) { + int max = Integer.MIN_VALUE; + for (Register r : registers) { + if (r.number > max) { + max = r.number; + } + } + return max; + } + + /** + * Gets the maximum register {@linkplain #encoding encoding} in a given set of registers. + * + * @param registers the set of registers to process + * @return the maximum register encoding for any register in {@code registers} + */ + public static int maxRegisterEncoding(Register[] registers) { + int max = Integer.MIN_VALUE; + for (Register r : registers) { + if (r.encoding > max) { + max = r.encoding; + } + } + return max; + } + + @Override + public String toString() { + return name; + } + + @Override + public int compareTo(Register o) { + if (number < o.number) { + return -1; + } + if (number > o.number) { + return 1; + } + return 0; + } + + @Override + public int hashCode() { + return 17 + name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Register) { + Register other = (Register) obj; + if (number == other.number) { + assert name.equals(other.name); + assert encoding == other.encoding; + assert registerCategory.equals(other.registerCategory); + return true; + } + } + return false; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterAttributes.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterAttributes.java new file mode 100644 index 00000000000..34f1100e553 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterAttributes.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +/** + * A collection of register attributes. The specific attribute values for a register may be local to + * a compilation context. For example, a {@link RegisterConfig} in use during a compilation will + * determine which registers are callee saved. + */ +public class RegisterAttributes { + + private final boolean callerSave; + private final boolean calleeSave; + private final boolean allocatable; + + public RegisterAttributes(boolean isCallerSave, boolean isCalleeSave, boolean isAllocatable) { + this.callerSave = isCallerSave; + this.calleeSave = isCalleeSave; + this.allocatable = isAllocatable; + } + + public static final RegisterAttributes NONE = new RegisterAttributes(false, false, false); + + /** + * Creates a map from register {@linkplain Register#number numbers} to register + * {@linkplain RegisterAttributes attributes} for a given register configuration and set of + * registers. + * + * @param registerConfig a register configuration + * @param registers a set of registers + * @return an array whose length is the max register number in {@code registers} plus 1. An + * element at index i holds the attributes of the register whose number is i. + */ + public static RegisterAttributes[] createMap(RegisterConfig registerConfig, Register[] registers) { + RegisterAttributes[] map = new RegisterAttributes[registers.length]; + for (Register reg : registers) { + if (reg != null) { + Register[] csr = registerConfig.getCalleeSaveRegisters(); + RegisterAttributes attr = new RegisterAttributes(Arrays.asList(registerConfig.getCallerSaveRegisters()).contains(reg), csr == null ? false : Arrays.asList(csr).contains(reg), + Arrays.asList(registerConfig.getAllocatableRegisters()).contains(reg)); + if (map.length <= reg.number) { + map = Arrays.copyOf(map, reg.number + 1); + } + map[reg.number] = attr; + } + } + for (int i = 0; i < map.length; i++) { + if (map[i] == null) { + map[i] = NONE; + } + } + return map; + } + + /** + * @return Denotes a register that is available for use by a register allocator. + */ + public boolean isAllocatable() { + return allocatable; + } + + /** + * @return Denotes a register whose value preservation (if required) across a call is the + * responsibility of the callee. + */ + public boolean isCalleeSave() { + return calleeSave; + } + + /** + * @return Denotes a register whose value preservation (if required) across a call is the + * responsibility of the caller. + */ + public boolean isCallerSave() { + return callerSave; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterConfig.java new file mode 100644 index 00000000000..57298738551 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterConfig.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import jdk.vm.ci.code.CallingConvention.*; +import jdk.vm.ci.meta.*; + +/** + * A register configuration binds roles and {@linkplain RegisterAttributes attributes} to physical + * registers. + */ +public interface RegisterConfig { + + /** + * Gets the register to be used for returning a value of a given kind. + */ + Register getReturnRegister(JavaKind kind); + + /** + * Gets the maximum allowed size of the frame. + */ + default int getMaximumFrameSize() { + return Integer.MAX_VALUE; + } + + /** + * Gets the register to which {@link Register#Frame} and {@link Register#CallerFrame} are bound. + */ + Register getFrameRegister(); + + /** + * Gets the calling convention describing how arguments are passed. + * + * @param type the type of calling convention being requested + * @param returnType the return type (can be null for methods returning {@code void}) + * @param parameterTypes the types of the arguments of the call + * @param target the target platform + * @param stackOnly ignore registers + */ + CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly); + + /** + * Gets the ordered set of registers that are can be used to pass parameters according to a + * given calling convention. + * + * @param type the type of calling convention + * @param kind specifies what kind of registers is being requested + * @return the ordered set of registers that may be used to pass parameters in a call conforming + * to {@code type} + */ + Register[] getCallingConventionRegisters(Type type, JavaKind kind); + + /** + * Gets the set of all registers that might be used by the register allocator. + * + * To get the set of registers the register allocator is allowed to use see + * {@link RegisterAllocationConfig#getAllocatableRegisters()} + */ + @SuppressWarnings("javadoc") + Register[] getAllocatableRegisters(); + + /** + * Filters a set of registers and returns only those that can be used by the register allocator + * for a value of a particular kind. + */ + Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers); + + /** + * Gets the registers whose values must be preserved by a method across any call it makes. + */ + Register[] getCallerSaveRegisters(); + + /** + * Gets the registers whose values must be preserved by the callee. + */ + Register[] getCalleeSaveRegisters(); + + /** + * Gets a map from register {@linkplain Register#number numbers} to register + * {@linkplain RegisterAttributes attributes} for this register configuration. + * + * @return an array where an element at index i holds the attributes of the register whose + * number is i + */ + RegisterAttributes[] getAttributesMap(); + + /** + * Gets the register corresponding to a runtime-defined role. + * + * @param id the identifier of a runtime-defined register role + * @return the register playing the role specified by {@code id} + */ + Register getRegisterForRole(int id); + + /** + * Determines if all {@link #getAllocatableRegisters() allocatable} registers are + * {@link #getCallerSaveRegisters() caller saved}. + */ + boolean areAllAllocatableRegistersCallerSaved(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterSaveLayout.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterSaveLayout.java new file mode 100644 index 00000000000..4fe15605776 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterSaveLayout.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +/** + * A map from registers to frame slots. This can be used to describe where callee saved registers + * are saved in a callee's frame. + */ +public final class RegisterSaveLayout { + + /** + * Keys. + */ + private final Register[] registers; + + /** + * Slot indexes relative to stack pointer. + */ + private final int[] slots; + + /** + * Creates a map from registers to frame slots. + * + * @param registers the keys in the map + * @param slots frame slot index for each register in {@code registers} + */ + public RegisterSaveLayout(Register[] registers, int[] slots) { + assert registers.length == slots.length; + this.registers = registers; + this.slots = slots; + assert registersToSlots(false).size() == registers.length : "non-unique registers"; + assert new HashSet<>(registersToSlots(false).values()).size() == slots.length : "non-unqiue slots"; + } + + /** + * Gets the frame slot index for a given register. + * + * @param register register to get the frame slot index for + * @return frame slot index + */ + public int registerToSlot(Register register) { + for (int i = 0; i < registers.length; i++) { + if (register.equals(registers[i])) { + return slots[i]; + } + } + throw new IllegalArgumentException(register + " not saved by this layout: " + this); + } + + /** + * Gets this layout information as a {@link Map} from registers to slots. + */ + public Map registersToSlots(boolean sorted) { + Map result; + if (sorted) { + result = new TreeMap<>(); + } else { + result = new HashMap<>(); + } + for (int i = 0; i < registers.length; i++) { + result.put(registers[i], slots[i]); + } + return result; + } + + /** + * Gets this layout information as a {@link Map} from slots to registers. + */ + public Map slotsToRegisters(boolean sorted) { + Map result; + if (sorted) { + result = new TreeMap<>(); + } else { + result = new HashMap<>(); + } + for (int i = 0; i < registers.length; i++) { + result.put(slots[i], registers[i]); + } + return result; + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof RegisterSaveLayout) { + RegisterSaveLayout that = (RegisterSaveLayout) obj; + if (Arrays.equals(registers, that.registers) && Arrays.equals(slots, that.slots)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return registersToSlots(true).toString(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterValue.java new file mode 100644 index 00000000000..b578228ee73 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterValue.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import jdk.vm.ci.meta.*; + +/** + * Denotes a register that stores a value of a fixed kind. There is exactly one (canonical) instance + * of {@link RegisterValue} for each ({@link Register}, {@link JavaKind}) pair. Use + * {@link Register#asValue(LIRKind)} to retrieve the canonical {@link RegisterValue} instance for a + * given (register,kind) pair. + */ +public final class RegisterValue extends AllocatableValue { + + private final Register reg; + + /** + * Should only be called from {@link Register#Register} to ensure canonicalization. + */ + protected RegisterValue(LIRKind kind, Register register) { + super(kind); + this.reg = register; + } + + @Override + public String toString() { + return getRegister().name + getKindSuffix(); + } + + /** + * @return the register that contains the value + */ + public Register getRegister() { + return reg; + } + + @Override + public int hashCode() { + return 29 * super.hashCode() + reg.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RegisterValue) { + RegisterValue other = (RegisterValue) obj; + return super.equals(obj) && reg.equals(other.reg); + } + return false; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/SourceStackTrace.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/SourceStackTrace.java new file mode 100644 index 00000000000..1fa157a7794 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/SourceStackTrace.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * Class representing a exception with a stack trace of the currently processed position in the + * compiled Java program instead of the stack trace of the compiler. The exception of the compiler + * is saved as the cause of this exception. + */ +public abstract class SourceStackTrace extends BailoutException { + private static final long serialVersionUID = 2144811793442316776L; + + public static SourceStackTrace create(Throwable cause, String format, StackTraceElement[] elements) { + return new SourceStackTrace(cause, format) { + + private static final long serialVersionUID = 6279381376051787907L; + + @Override + public final synchronized Throwable fillInStackTrace() { + assert elements != null; + setStackTrace(elements); + return this; + } + }; + } + + private SourceStackTrace(Throwable cause, String format) { + super(cause, format); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackLockValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackLockValue.java new file mode 100644 index 00000000000..725650ef152 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackLockValue.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import static jdk.vm.ci.code.ValueUtil.*; + +import jdk.vm.ci.meta.*; + +/** + * Represents lock information in the debug information. + */ +public final class StackLockValue implements JavaValue { + + private JavaValue owner; + private StackSlotValue slot; + private final boolean eliminated; + + public StackLockValue(JavaValue object, StackSlotValue slot, boolean eliminated) { + this.owner = object; + this.slot = slot; + this.eliminated = eliminated; + } + + public JavaValue getOwner() { + return owner; + } + + public void setOwner(JavaValue newOwner) { + this.owner = newOwner; + } + + public Value getSlot() { + return slot; + } + + public boolean isEliminated() { + return eliminated; + } + + @Override + public String toString() { + return "monitor[" + owner + (slot != null ? ", " + slot : "") + (eliminated ? ", eliminated" : "") + "]"; + } + + @Override + public int hashCode() { + final int prime = 43; + int result = super.hashCode(); + result = prime * result + (eliminated ? 1231 : 1237); + result = prime * result + owner.hashCode(); + result = prime * result + slot.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof StackLockValue) { + StackLockValue other = (StackLockValue) obj; + return super.equals(obj) && eliminated == other.eliminated && owner.equals(other.owner) && slot.equals(other.slot); + } + return false; + } + + public void setSlot(StackSlotValue stackSlot) { + assert slot == null || (isVirtualStackSlot(slot) && (slot.equals(stackSlot) || isStackSlot(stackSlot))) : String.format("Can not set slot for %s to %s", this, stackSlot); + slot = stackSlot; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlot.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlot.java new file mode 100644 index 00000000000..edf6f45a360 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlot.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import jdk.vm.ci.meta.*; + +/** + * Represents a compiler spill slot or an outgoing stack-based argument in a method's frame or an + * incoming stack-based argument in a method's {@linkplain #isInCallerFrame() caller's frame}. + */ +public final class StackSlot extends StackSlotValue { + + private final int offset; + private final boolean addFrameSize; + + /** + * Gets a {@link StackSlot} instance representing a stack slot at a given index holding a value + * of a given kind. + * + * @param kind The kind of the value stored in the stack slot. + * @param offset The offset of the stack slot (in bytes) + * @param addFrameSize Specifies if the offset is relative to the stack pointer, or the + * beginning of the frame (stack pointer + total frame size). + */ + public static StackSlot get(LIRKind kind, int offset, boolean addFrameSize) { + assert addFrameSize || offset >= 0; + return new StackSlot(kind, offset, addFrameSize); + } + + /** + * Private constructor to enforce use of {@link #get(LIRKind, int, boolean)} so that a cache can + * be used. + */ + private StackSlot(LIRKind kind, int offset, boolean addFrameSize) { + super(kind); + this.offset = offset; + this.addFrameSize = addFrameSize; + } + + /** + * Gets the offset of this stack slot, relative to the stack pointer. + * + * @return The offset of this slot (in bytes). + */ + public int getOffset(int totalFrameSize) { + assert totalFrameSize > 0 || !addFrameSize; + int result = offset + (addFrameSize ? totalFrameSize : 0); + assert result >= 0; + return result; + } + + public boolean isInCallerFrame() { + return addFrameSize && offset >= 0; + } + + public int getRawOffset() { + return offset; + } + + public boolean getRawAddFrameSize() { + return addFrameSize; + } + + @Override + public String toString() { + if (!addFrameSize) { + return "out:" + offset + getKindSuffix(); + } else if (offset >= 0) { + return "in:" + offset + getKindSuffix(); + } else { + return "stack:" + (-offset) + getKindSuffix(); + } + } + + /** + * Gets this stack slot used to pass an argument from the perspective of a caller. + */ + public StackSlot asOutArg() { + assert offset >= 0; + if (addFrameSize) { + return get(getLIRKind(), offset, false); + } + return this; + } + + /** + * Gets this stack slot used to pass an argument from the perspective of a callee. + */ + public StackSlot asInArg() { + assert offset >= 0; + if (!addFrameSize) { + return get(getLIRKind(), offset, true); + } + return this; + } + + @Override + public int hashCode() { + final int prime = 37; + int result = super.hashCode(); + result = prime * result + (addFrameSize ? 1231 : 1237); + result = prime * result + offset; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof StackSlot) { + StackSlot other = (StackSlot) obj; + return super.equals(obj) && addFrameSize == other.addFrameSize && offset == other.offset; + } + return false; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlotValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlotValue.java new file mode 100644 index 00000000000..eaa71c5f367 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlotValue.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import jdk.vm.ci.meta.*; + +/** + * Common base class for {@linkplain StackSlot real} and {@linkplain VirtualStackSlot virtual} stack + * slots. + */ +public abstract class StackSlotValue extends AllocatableValue { + + public StackSlotValue(LIRKind lirKind) { + super(lirKind); + } + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/TargetDescription.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/TargetDescription.java new file mode 100644 index 00000000000..d6da8b88514 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/TargetDescription.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import static jdk.vm.ci.meta.MetaUtil.*; + +import jdk.vm.ci.meta.*; + +/** + * Represents the target machine for a compiler, including the CPU architecture, the size of + * pointers and references, alignment of stacks, caches, etc. + */ +public class TargetDescription { + + public final Architecture arch; + + /** + * Specifies if this is a multi-processor system. + */ + public final boolean isMP; + + /** + * Specifies if this target supports encoding objects inline in the machine code. + */ + public final boolean inlineObjects; + + /** + * The machine word size on this target. + */ + public final int wordSize; + + /** + * The kind to be used for representing raw pointers and CPU registers. + */ + public final JavaKind wordKind; + + /** + * The stack alignment requirement of the platform. For example, from Appendix D of Intel 64 and IA-32 Architectures + * Optimization Reference Manual: + * + *
+     *     "It is important to ensure that the stack frame is aligned to a
+     *      16-byte boundary upon function entry to keep local __m128 data,
+     *      parameters, and XMM register spill locations aligned throughout
+     *      a function invocation."
+     * 
+ */ + public final int stackAlignment; + + /** + * Maximum constant displacement at which a memory access can no longer be an implicit null + * check. + */ + public final int implicitNullCheckLimit; + + public TargetDescription(Architecture arch, boolean isMP, int stackAlignment, int implicitNullCheckLimit, boolean inlineObjects) { + this.arch = arch; + this.isMP = isMP; + this.wordSize = arch.getWordSize(); + this.wordKind = JavaKind.fromWordSize(wordSize); + this.stackAlignment = stackAlignment; + this.implicitNullCheckLimit = implicitNullCheckLimit; + this.inlineObjects = inlineObjects; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public final boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof TargetDescription) { + TargetDescription that = (TargetDescription) obj; + // @formatter:off + if (this.implicitNullCheckLimit == that.implicitNullCheckLimit && + this.inlineObjects == that.inlineObjects && + this.isMP == that.isMP && + this.stackAlignment == that.stackAlignment && + this.wordKind.equals(that.wordKind) && + this.wordSize == that.wordSize && + this.arch.equals(that.arch)) { + return true; + } + // @formatter:on + } + return false; + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + public int getSizeInBytes(PlatformKind kind) { + return kind.getSizeInBytes(); + } + + public LIRKind getLIRKind(JavaKind javaKind) { + PlatformKind platformKind = arch.getPlatformKind(javaKind); + if (javaKind.isObject()) { + return LIRKind.reference(platformKind); + } else { + return LIRKind.value(platformKind); + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/UnsignedMath.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/UnsignedMath.java new file mode 100644 index 00000000000..3e688528288 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/UnsignedMath.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.math.*; + +//JaCoCo Exclude + +/** + * Utilities for unsigned comparisons. All methods have correct, but slow, standard Java + * implementations so that they can be used with compilers not supporting the intrinsics. + */ +public class UnsignedMath { + + private static final long MASK = 0xffffffffL; + + /** + * Unsigned comparison aboveThan for two numbers. + */ + public static boolean aboveThan(int a, int b) { + return (a & MASK) > (b & MASK); + } + + /** + * Unsigned comparison aboveOrEqual for two numbers. + */ + public static boolean aboveOrEqual(int a, int b) { + return (a & MASK) >= (b & MASK); + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + public static boolean belowThan(int a, int b) { + return (a & MASK) < (b & MASK); + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + public static boolean belowOrEqual(int a, int b) { + return (a & MASK) <= (b & MASK); + } + + /** + * Unsigned comparison aboveThan for two numbers. + */ + public static boolean aboveThan(long a, long b) { + return (a > b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned comparison aboveOrEqual for two numbers. + */ + public static boolean aboveOrEqual(long a, long b) { + return (a >= b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + public static boolean belowThan(long a, long b) { + return (a < b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + public static boolean belowOrEqual(long a, long b) { + return (a <= b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned division for two numbers. + */ + public static int divide(int a, int b) { + return (int) ((a & MASK) / (b & MASK)); + } + + /** + * Unsigned remainder for two numbers. + */ + public static int remainder(int a, int b) { + return (int) ((a & MASK) % (b & MASK)); + } + + /** + * Unsigned division for two numbers. + */ + public static long divide(long a, long b) { + return bi(a).divide(bi(b)).longValue(); + } + + /** + * Unsigned remainder for two numbers. + */ + public static long remainder(long a, long b) { + return bi(a).remainder(bi(b)).longValue(); + } + + private static BigInteger bi(long unsigned) { + return unsigned >= 0 ? BigInteger.valueOf(unsigned) : BigInteger.valueOf(unsigned & 0x7fffffffffffffffL).setBit(63); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ValueUtil.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ValueUtil.java new file mode 100644 index 00000000000..982617d46bb --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ValueUtil.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Utility class for working with the {@link Value} class and its subclasses. + */ +public final class ValueUtil { + + public static boolean isIllegal(Value value) { + assert value != null; + return Value.ILLEGAL.equals(value); + } + + public static boolean isIllegalJavaValue(JavaValue value) { + assert value != null; + return Value.ILLEGAL.equals(value); + } + + public static boolean isLegal(Value value) { + return !isIllegal(value); + } + + public static boolean isVirtualObject(JavaValue value) { + assert value != null; + return value instanceof VirtualObject; + } + + public static VirtualObject asVirtualObject(JavaValue value) { + assert value != null; + return (VirtualObject) value; + } + + public static boolean isConstantJavaValue(JavaValue value) { + assert value != null; + return value instanceof JavaConstant; + } + + public static boolean isAllocatableValue(Value value) { + assert value != null; + return value instanceof AllocatableValue; + } + + public static AllocatableValue asAllocatableValue(Value value) { + assert value != null; + return (AllocatableValue) value; + } + + public static boolean isStackSlot(Value value) { + assert value != null; + return value instanceof StackSlot; + } + + public static StackSlot asStackSlot(Value value) { + assert value != null; + return (StackSlot) value; + } + + public static boolean isStackSlotValue(Value value) { + assert value != null; + return value instanceof StackSlotValue; + } + + public static StackSlotValue asStackSlotValue(Value value) { + assert value != null; + return (StackSlotValue) value; + } + + public static boolean isVirtualStackSlot(Value value) { + assert value != null; + return value instanceof VirtualStackSlot; + } + + public static VirtualStackSlot asVirtualStackSlot(Value value) { + assert value != null; + return (VirtualStackSlot) value; + } + + public static boolean isRegister(Value value) { + assert value != null; + return value instanceof RegisterValue; + } + + public static Register asRegister(Value value) { + return asRegisterValue(value).getRegister(); + } + + public static RegisterValue asRegisterValue(Value value) { + assert value != null; + return (RegisterValue) value; + } + + public static Register asRegister(Value value, PlatformKind kind) { + if (value.getPlatformKind() != kind) { + throw new InternalError("needed: " + kind + " got: " + value.getPlatformKind()); + } else { + return asRegister(value); + } + } + + public static boolean sameRegister(Value v1, Value v2) { + return isRegister(v1) && isRegister(v2) && asRegister(v1).equals(asRegister(v2)); + } + + public static boolean sameRegister(Value v1, Value v2, Value v3) { + return sameRegister(v1, v2) && sameRegister(v1, v3); + } + + /** + * Checks if all the provided values are different physical registers. The parameters can be + * either {@link Register registers}, {@link Value values} or arrays of them. All values that + * are not {@link RegisterValue registers} are ignored. + */ + public static boolean differentRegisters(Object... values) { + List registers = collectRegisters(values, new ArrayList()); + for (int i = 1; i < registers.size(); i++) { + Register r1 = registers.get(i); + for (int j = 0; j < i; j++) { + Register r2 = registers.get(j); + if (r1.equals(r2)) { + return false; + } + } + } + return true; + } + + private static List collectRegisters(Object[] values, List registers) { + for (Object o : values) { + if (o instanceof Register) { + registers.add((Register) o); + } else if (o instanceof Value) { + if (isRegister((Value) o)) { + registers.add(asRegister((Value) o)); + } + } else if (o instanceof Object[]) { + collectRegisters((Object[]) o, registers); + } else { + throw new IllegalArgumentException("Not a Register or Value: " + o); + } + } + return registers; + } + + /** + * Subtract sets of registers (x - y). + * + * @param x a set of register to subtract from. + * @param y a set of registers to subtract. + * @return resulting set of registers (x - y). + */ + public static Value[] subtractRegisters(Value[] x, Value[] y) { + ArrayList result = new ArrayList<>(x.length); + for (Value i : x) { + boolean append = true; + for (Value j : y) { + if (ValueUtil.sameRegister(i, j)) { + append = false; + break; + } + } + if (append) { + result.add(i); + } + } + Value[] resultArray = new Value[result.size()]; + return result.toArray(resultArray); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java new file mode 100644 index 00000000000..047d84b3850 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * An instance of this class represents an object whose allocation was removed by escape analysis. + * The information stored in the {@link VirtualObject} is used during deoptimization to recreate the + * object. + */ +public final class VirtualObject implements JavaValue { + + private final ResolvedJavaType type; + private JavaValue[] values; + private JavaKind[] slotKinds; + private final int id; + + /** + * Creates a new {@link VirtualObject} for the given type, with the given fields. If + * {@code type} is an instance class then {@code values} provides the values for the fields + * returned by {@link ResolvedJavaType#getInstanceFields(boolean) getInstanceFields(true)}. If + * {@code type} is an array then the length of the values array determines the reallocated array + * length. + * + * @param type the type of the object whose allocation was removed during compilation. This can + * be either an instance of an array type. + * @param id a unique id that identifies the object within the debug information for one + * position in the compiled code. + * @return a new {@link VirtualObject} instance. + */ + public static VirtualObject get(ResolvedJavaType type, int id) { + return new VirtualObject(type, id); + } + + private VirtualObject(ResolvedJavaType type, int id) { + this.type = type; + this.id = id; + } + + private static StringBuilder appendValue(StringBuilder buf, JavaValue value, Set visited) { + if (value instanceof VirtualObject) { + VirtualObject vo = (VirtualObject) value; + buf.append("vobject:").append(vo.type.toJavaName(false)).append(':').append(vo.id); + if (!visited.contains(vo)) { + visited.add(vo); + buf.append('{'); + if (vo.values == null) { + buf.append(""); + } else { + if (vo.type.isArray()) { + for (int i = 0; i < vo.values.length; i++) { + if (i != 0) { + buf.append(','); + } + buf.append(i).append('='); + appendValue(buf, vo.values[i], visited); + } + } else { + ResolvedJavaField[] fields = vo.type.getInstanceFields(true); + assert fields.length == vo.values.length : vo.type + ", fields=" + Arrays.toString(fields) + ", values=" + Arrays.toString(vo.values); + for (int i = 0; i < vo.values.length; i++) { + if (i != 0) { + buf.append(','); + } + buf.append(fields[i].getName()).append('='); + appendValue(buf, vo.values[i], visited); + } + } + } + buf.append('}'); + } + } else { + buf.append(value); + } + return buf; + } + + @Override + public String toString() { + Set visited = Collections.newSetFromMap(new IdentityHashMap()); + return appendValue(new StringBuilder(), this, visited).toString(); + } + + /** + * Returns the type of the object whose allocation was removed during compilation. This can be + * either an instance of an array type. + */ + public ResolvedJavaType getType() { + return type; + } + + /** + * Returns an array containing all the values to be stored into the object when it is recreated. + */ + public JavaValue[] getValues() { + return values; + } + + /** + * Returns an array containing the Java kind of all values in the object. + */ + public JavaKind[] getSlotKinds() { + return slotKinds; + } + + /** + * Returns the unique id that identifies the object within the debug information for one + * position in the compiled code. + */ + public int getId() { + return id; + } + + private boolean checkValues() { + assert (values == null) == (slotKinds == null); + if (values != null) { + assert values.length == slotKinds.length; + if (!type.isArray()) { + ResolvedJavaField[] fields = type.getInstanceFields(true); + int fieldIndex = 0; + for (int i = 0; i < values.length; i++) { + ResolvedJavaField field = fields[fieldIndex++]; + JavaKind valKind = slotKinds[i].getStackKind(); + if (field.getJavaKind() == JavaKind.Object) { + assert valKind.isObject() : field + ": " + valKind + " != " + field.getJavaKind(); + } else { + if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && field.getJavaKind() == JavaKind.Int) { + assert fields[fieldIndex].getJavaKind() == JavaKind.Int; + fieldIndex++; + } else { + assert valKind == field.getJavaKind().getStackKind() : field + ": " + valKind + " != " + field.getJavaKind(); + } + } + } + assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values); + } else { + JavaKind componentKind = type.getComponentType().getJavaKind().getStackKind(); + if (componentKind == JavaKind.Object) { + for (int i = 0; i < values.length; i++) { + assert slotKinds[i].isObject() : slotKinds[i] + " != " + componentKind; + } + } else { + for (int i = 0; i < values.length; i++) { + assert slotKinds[i] == componentKind || componentKind.getBitCount() >= slotKinds[i].getBitCount() || + (componentKind == JavaKind.Int && slotKinds[i].getBitCount() >= JavaKind.Int.getBitCount()) : slotKinds[i] + " != " + componentKind; + } + } + } + } + return true; + } + + /** + * Overwrites the current set of values with a new one. + * + * @param values an array containing all the values to be stored into the object when it is + * recreated. + * @param slotKinds an array containing the Java kinds of the values. + */ + public void setValues(JavaValue[] values, JavaKind[] slotKinds) { + this.values = values; + this.slotKinds = slotKinds; + assert checkValues(); + } + + @Override + public int hashCode() { + return 42 + type.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof VirtualObject) { + VirtualObject l = (VirtualObject) o; + if (!l.type.equals(type) || l.values.length != values.length) { + return false; + } + for (int i = 0; i < values.length; i++) { + /* + * Virtual objects can form cycles. Calling equals() could therefore lead to + * infinite recursion. + */ + if (!same(values[i], l.values[i])) { + return false; + } + } + return true; + } + return false; + } + + private static boolean same(Object o1, Object o2) { + return o1 == o2; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualStackSlot.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualStackSlot.java new file mode 100644 index 00000000000..14d2659bfbc --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualStackSlot.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import jdk.vm.ci.meta.*; + +/** + * {@link VirtualStackSlot}s are stack slots that are not yet fixed to specific frame offset. They + * are replaced by real {@link StackSlot}s with a fixed position in the frame before code emission. + */ +public abstract class VirtualStackSlot extends StackSlotValue { + + private final int id; + + public VirtualStackSlot(int id, LIRKind lirKind) { + super(lirKind); + this.id = id; + } + + public int getId() { + return id; + } + + @Override + public String toString() { + return "vstack:" + id + getKindSuffix(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + id; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + VirtualStackSlot other = (VirtualStackSlot) obj; + if (id != other.id) { + return false; + } + return true; + } + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/package-info.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/package-info.java new file mode 100644 index 00000000000..1010108f3ee --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/package-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010, 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. + * + * 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 that defines the interface between a Java application that wants to install code and the + * runtime. The runtime provides in implementation of the {@link jdk.vm.ci.code.CodeCacheProvider} + * interface. The method + * {@link jdk.vm.ci.code.CodeCacheProvider#addMethod(jdk.vm.ci.meta.ResolvedJavaMethod, CompilationResult, jdk.vm.ci.meta.SpeculationLog, InstalledCode)} + * can be used to install code for a given method. + */ +package jdk.vm.ci.code; diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrame.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrame.java new file mode 100644 index 00000000000..318e133133e --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrame.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code.stack; + +import jdk.vm.ci.meta.*; + +public interface InspectedFrame { + + /** + * Returns the value of the local at the given index. Currently only works for object values. + * This value is a copy iff {@link #isVirtual(int)} is true. + */ + Object getLocal(int index); + + /** + * Returns whether the local at the given index is a virtual object, and therefore the object + * returned by {@link #getLocal(int)} is a copy. + */ + boolean isVirtual(int index); + + /** + * Returns true if the stack frame is a compiled stack frame and there are virtual objects + * anywhere in the current state of the compiled method. This can return true even if + * {@link #isVirtual(int)} return false for all locals. + */ + boolean hasVirtualObjects(); + + /** + * This method will materialize all virtual objects, deoptimize the stack frame and make sure + * that subsequent execution of the deoptimized frame uses the materialized values. + */ + void materializeVirtualObjects(boolean invalidateCode); + + /** + * @return the current bytecode index + */ + int getBytecodeIndex(); + + /** + * @return the current method + */ + ResolvedJavaMethod getMethod(); + + /** + * Checks if the current method is equal to the given method. This is semantically equivalent to + * {@code method.equals(getMethod())}, but can be implemented more efficiently. + */ + boolean isMethod(ResolvedJavaMethod method); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrameVisitor.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrameVisitor.java new file mode 100644 index 00000000000..e3177903ee8 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrameVisitor.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code.stack; + +/** + * Callback interface for {@link StackIntrospection#iterateFrames}. Implementations of + * {@link #visitFrame} return null to indicate that frame iteration should continue and the next + * caller frame should be visited; and return any non-null value to indicate that frame iteration + * should stop. + */ +public interface InspectedFrameVisitor { + + T visitFrame(InspectedFrame frame); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/StackIntrospection.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/StackIntrospection.java new file mode 100644 index 00000000000..99f7e4fe59d --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/StackIntrospection.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code.stack; + +import jdk.vm.ci.meta.*; + +public interface StackIntrospection { + + /** + * Accesses the current stack, providing {@link InspectedFrame}s to the visitor that can be used + * to inspect the stack frames' contents. Iteration continues as long as + * {@link InspectedFrameVisitor#visitFrame}, which is invoked for every {@link InspectedFrame}, + * returns null. Any non-null result of the visitor indicates that frame iteration should stop. + * + * @param initialMethods if this is non-{@code null}, then the stack trace will start at these + * methods + * @param matchingMethods if this is non-{@code null}, then only matching stack frames are + * returned + * @param initialSkip the number of matching methods to skip (including the initial method) + * @param visitor the visitor that is called for every matching method + * @return the last result returned by the visitor (which is non-null to indicate that iteration + * should stop), or null if the whole stack was iterated. + */ + T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor visitor); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/JVMCIError.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/JVMCIError.java new file mode 100644 index 00000000000..3c53a309a9f --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/JVMCIError.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.common; + +import java.util.*; + +/** + * Indicates a condition in JVMCI related code that should never occur during normal operation. + */ +public class JVMCIError extends Error { + + private static final long serialVersionUID = 531632331813456233L; + private final ArrayList context = new ArrayList<>(); + + public static RuntimeException unimplemented() { + throw new JVMCIError("unimplemented"); + } + + public static RuntimeException unimplemented(String msg) { + throw new JVMCIError("unimplemented: %s", msg); + } + + public static RuntimeException shouldNotReachHere() { + throw new JVMCIError("should not reach here"); + } + + public static RuntimeException shouldNotReachHere(String msg) { + throw new JVMCIError("should not reach here: %s", msg); + } + + public static RuntimeException shouldNotReachHere(Throwable cause) { + throw new JVMCIError(cause); + } + + /** + * Checks a given condition and throws a {@link JVMCIError} if it is false. Guarantees are + * stronger than assertions in that they are always checked. Error messages for guarantee + * violations should clearly indicate the nature of the problem as well as a suggested solution + * if possible. + * + * @param condition the condition to check + * @param msg the message that will be associated with the error, in + * {@link String#format(String, Object...)} syntax + * @param args arguments to the format string + */ + public static void guarantee(boolean condition, String msg, Object... args) { + if (!condition) { + throw new JVMCIError("failed guarantee: " + msg, args); + } + } + + /** + * This constructor creates a {@link JVMCIError} with a given message. + * + * @param msg the message that will be associated with the error + */ + public JVMCIError(String msg) { + super(msg); + } + + /** + * This constructor creates a {@link JVMCIError} with a message assembled via + * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to + * always generate the same output. + * + * @param msg the message that will be associated with the error, in String.format syntax + * @param args parameters to String.format - parameters that implement {@link Iterable} will be + * expanded into a [x, x, ...] representation. + */ + public JVMCIError(String msg, Object... args) { + super(format(msg, args)); + } + + /** + * This constructor creates a {@link JVMCIError} for a given causing Throwable instance. + * + * @param cause the original exception that contains additional information on this error + */ + public JVMCIError(Throwable cause) { + super(cause); + } + + /** + * This constructor creates a {@link JVMCIError} and adds all the + * {@linkplain #addContext(String) context} of another {@link JVMCIError}. + * + * @param e the original {@link JVMCIError} + */ + public JVMCIError(JVMCIError e) { + super(e); + context.addAll(e.context); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append(super.toString()); + for (String s : context) { + str.append("\n\tat ").append(s); + } + return str.toString(); + } + + private static String format(String msg, Object... args) { + if (args != null) { + // expand Iterable parameters into a list representation + for (int i = 0; i < args.length; i++) { + if (args[i] instanceof Iterable) { + ArrayList list = new ArrayList<>(); + for (Object o : (Iterable) args[i]) { + list.add(o); + } + args[i] = list.toString(); + } + } + } + return String.format(Locale.ENGLISH, msg, args); + } + + public JVMCIError addContext(String newContext) { + this.context.add(newContext); + return this; + } + + public JVMCIError addContext(String name, Object obj) { + return addContext(format("%s: %s", name, obj)); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/UnsafeUtil.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/UnsafeUtil.java new file mode 100644 index 00000000000..7668759da84 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/UnsafeUtil.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.common; + +import sun.misc.Unsafe; + +/** + * Utilities for operating on raw memory with {@link Unsafe}. + */ +public class UnsafeUtil { + + /** + * Copies the contents of a {@link String} to a native memory buffer as a {@code '\0'} + * terminated C string. The native memory buffer is allocated via + * {@link Unsafe#allocateMemory(long)}. The caller is responsible for releasing the buffer when + * it is no longer needed via {@link Unsafe#freeMemory(long)}. + * + * @return the native memory pointer of the C string created from {@code s} + */ + public static long createCString(Unsafe unsafe, String s) { + return writeCString(unsafe, s, unsafe.allocateMemory(s.length() + 1)); + } + + /** + * Reads a {@code '\0'} terminated C string from native memory and converts it to a + * {@link String}. + * + * @return a Java string + */ + public static String readCString(Unsafe unsafe, long address) { + if (address == 0) { + return null; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0;; i++) { + char c = (char) unsafe.getByte(address + i); + if (c == 0) { + break; + } + sb.append(c); + } + return sb.toString(); + } + + /** + * Writes the contents of a {@link String} to a native memory buffer as a {@code '\0'} + * terminated C string. The caller is responsible for ensuring the buffer is at least + * {@code s.length() + 1} bytes long. The caller is also responsible for releasing the buffer + * when it is no longer. + * + * @return the value of {@code buf} + */ + public static long writeCString(Unsafe unsafe, String s, long buf) { + int size = s.length(); + for (int i = 0; i < size; i++) { + unsafe.putByte(buf + i, (byte) s.charAt(i)); + } + unsafe.putByte(buf + size, (byte) '\0'); + return buf; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/Compiler.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/Compiler.java new file mode 100644 index 00000000000..8b07d6747ef --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/Compiler.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.compiler; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.options.*; + +public interface Compiler { + int INVOCATION_ENTRY_BCI = -1; + + @Option(help = "", type = OptionType.Debug) OptionValue PrintFilter = new OptionValue<>(null); + @Option(help = "", type = OptionType.Debug) OptionValue PrintCompilation = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue PrintAfterCompilation = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue PrintBailout = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue ExitVMOnBailout = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue ExitVMOnException = new OptionValue<>(true); + @Option(help = "", type = OptionType.Debug) OptionValue PrintStackTraceOnException = new OptionValue<>(false); + + /** + * Request the compilation of a method by this JVMCI compiler. The compiler should compile the + * method to machine code and install it in the code cache if the compilation is successful. + * + * @param method the method that should be compiled + * @param entryBCI the BCI at which to start compiling where -1 denotes a non-OSR compilation + * request and all other values denote an OSR compilation request + * @param jvmciEnv pointer to native {@code JVMCIEnv} object + * @param id a unique identifier for this compilation + */ + void compileMethod(ResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/CompilerFactory.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/CompilerFactory.java new file mode 100644 index 00000000000..98e08dc0e82 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/CompilerFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.compiler; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.runtime.*; + +/** + * Factory for a JVMCI compiler. + */ +public interface CompilerFactory { + + /** + * Get the name of this compiler. The compiler will be selected when the jvmci.compiler system + * property is equal to this name. + */ + String getCompilerName(); + + /** + * Initialize an {@link Architecture}. The compiler has the opportunity to extend the + * {@link Architecture} description with a custom subclass. + */ + Architecture initializeArchitecture(Architecture arch); + + /** + * Create a new instance of the {@link Compiler}. + */ + Compiler createCompiler(JVMCIRuntime runtime); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/StartupEventListener.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/StartupEventListener.java new file mode 100644 index 00000000000..a67e04c0750 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/StartupEventListener.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.compiler; + +public interface StartupEventListener { + + /** + * This method is called before any of the {@link CompilerFactory} methods. + */ + void beforeJVMCIStartup(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java new file mode 100644 index 00000000000..54138bb92e1 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot.amd64; + +import static jdk.vm.ci.inittimer.InitTimer.*; + +import java.util.*; + +import jdk.vm.ci.amd64.*; +import jdk.vm.ci.code.*; +import jdk.vm.ci.compiler.*; +import jdk.vm.ci.hotspot.*; +import jdk.vm.ci.inittimer.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; +import jdk.vm.ci.service.*; + +@ServiceProvider(HotSpotJVMCIBackendFactory.class) +public class AMD64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFactory { + + protected EnumSet computeFeatures(HotSpotVMConfig config) { + // Configure the feature set using the HotSpot flag settings. + EnumSet features = EnumSet.noneOf(AMD64.CPUFeature.class); + if ((config.x86CPUFeatures & config.cpu3DNOWPREFETCH) != 0) { + features.add(AMD64.CPUFeature.AMD_3DNOW_PREFETCH); + } + assert config.useSSE >= 2 : "minimum config for x64"; + features.add(AMD64.CPUFeature.SSE); + features.add(AMD64.CPUFeature.SSE2); + if ((config.x86CPUFeatures & config.cpuSSE3) != 0) { + features.add(AMD64.CPUFeature.SSE3); + } + if ((config.x86CPUFeatures & config.cpuSSSE3) != 0) { + features.add(AMD64.CPUFeature.SSSE3); + } + if ((config.x86CPUFeatures & config.cpuSSE4A) != 0) { + features.add(AMD64.CPUFeature.SSE4A); + } + if ((config.x86CPUFeatures & config.cpuSSE41) != 0) { + features.add(AMD64.CPUFeature.SSE4_1); + } + if ((config.x86CPUFeatures & config.cpuSSE42) != 0) { + features.add(AMD64.CPUFeature.SSE4_2); + } + if ((config.x86CPUFeatures & config.cpuPOPCNT) != 0) { + features.add(AMD64.CPUFeature.POPCNT); + } + if ((config.x86CPUFeatures & config.cpuLZCNT) != 0) { + features.add(AMD64.CPUFeature.LZCNT); + } + if ((config.x86CPUFeatures & config.cpuAVX) != 0) { + features.add(AMD64.CPUFeature.AVX); + } + if ((config.x86CPUFeatures & config.cpuAVX2) != 0) { + features.add(AMD64.CPUFeature.AVX2); + } + if ((config.x86CPUFeatures & config.cpuAES) != 0) { + features.add(AMD64.CPUFeature.AES); + } + if ((config.x86CPUFeatures & config.cpuERMS) != 0) { + features.add(AMD64.CPUFeature.ERMS); + } + if ((config.x86CPUFeatures & config.cpuBMI1) != 0) { + features.add(AMD64.CPUFeature.BMI1); + } + return features; + } + + protected EnumSet computeFlags(HotSpotVMConfig config) { + EnumSet flags = EnumSet.noneOf(AMD64.Flag.class); + if (config.useCountLeadingZerosInstruction) { + flags.add(AMD64.Flag.UseCountLeadingZerosInstruction); + } + if (config.useCountTrailingZerosInstruction) { + flags.add(AMD64.Flag.UseCountTrailingZerosInstruction); + } + return flags; + } + + protected TargetDescription createTarget(HotSpotVMConfig config, CompilerFactory compilerFactory) { + final int stackFrameAlignment = 16; + final int implicitNullCheckLimit = 4096; + final boolean inlineObjects = true; + Architecture arch = new AMD64(computeFeatures(config), computeFlags(config)); + return new TargetDescription(compilerFactory.initializeArchitecture(arch), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); + } + + protected HotSpotConstantReflectionProvider createConstantReflection(HotSpotJVMCIRuntimeProvider runtime) { + return new HotSpotConstantReflectionProvider(runtime); + } + + protected RegisterConfig createRegisterConfig(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target) { + return new AMD64HotSpotRegisterConfig(target.arch, runtime.getConfig()); + } + + protected HotSpotCodeCacheProvider createCodeCache(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { + return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig); + } + + protected HotSpotMetaAccessProvider createMetaAccess(HotSpotJVMCIRuntimeProvider runtime) { + return new HotSpotMetaAccessProvider(runtime); + } + + @Override + public String getArchitecture() { + return "AMD64"; + } + + @Override + public String toString() { + return "JVMCIBackend:" + getArchitecture(); + } + + @SuppressWarnings("try") + public JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntimeProvider runtime, CompilerFactory compilerFactory, JVMCIBackend host) { + + assert host == null; + TargetDescription target = createTarget(runtime.getConfig(), compilerFactory); + + RegisterConfig regConfig; + HotSpotCodeCacheProvider codeCache; + ConstantReflectionProvider constantReflection; + HotSpotMetaAccessProvider metaAccess; + try (InitTimer t = timer("create providers")) { + try (InitTimer rt = timer("create MetaAccess provider")) { + metaAccess = createMetaAccess(runtime); + } + try (InitTimer rt = timer("create RegisterConfig")) { + regConfig = createRegisterConfig(runtime, target); + } + try (InitTimer rt = timer("create CodeCache provider")) { + codeCache = createCodeCache(runtime, target, regConfig); + } + try (InitTimer rt = timer("create ConstantReflection provider")) { + constantReflection = createConstantReflection(runtime); + } + } + try (InitTimer rt = timer("instantiate backend")) { + return createBackend(metaAccess, codeCache, constantReflection); + } + } + + protected JVMCIBackend createBackend(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection) { + return new JVMCIBackend(metaAccess, codeCache, constantReflection); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java new file mode 100644 index 00000000000..6804a5eaa61 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot.amd64; + +import static jdk.vm.ci.amd64.AMD64.*; + +import java.util.*; + +import jdk.vm.ci.amd64.*; +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.CallingConvention.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.hotspot.*; +import jdk.vm.ci.meta.*; + +public class AMD64HotSpotRegisterConfig implements RegisterConfig { + + private final Architecture architecture; + + private final Register[] allocatable; + + private final int maxFrameSize; + + /** + * The caller saved registers always include all parameter registers. + */ + private final Register[] callerSaved; + + private final boolean allAllocatableAreCallerSaved; + + private final RegisterAttributes[] attributesMap; + + public int getMaximumFrameSize() { + return maxFrameSize; + } + + @Override + public Register[] getAllocatableRegisters() { + return allocatable.clone(); + } + + public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { + ArrayList list = new ArrayList<>(); + for (Register reg : registers) { + if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { + list.add(reg); + } + } + + Register[] ret = list.toArray(new Register[list.size()]); + return ret; + } + + @Override + public RegisterAttributes[] getAttributesMap() { + return attributesMap.clone(); + } + + private final Register[] javaGeneralParameterRegisters; + private final Register[] nativeGeneralParameterRegisters; + private final Register[] xmmParameterRegisters = {xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7}; + + /* + * Some ABIs (e.g. Windows) require a so-called "home space", that is a save area on the stack + * to store the argument registers + */ + private final boolean needsNativeStackHomeSpace; + + private static Register[] initAllocatable(boolean reserveForHeapBase) { + Register[] registers = null; + // @formatter:off + if (reserveForHeapBase) { + registers = new Register[] { + rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, /*r12,*/ r13, r14, /*r15, */ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + } else { + registers = new Register[] { + rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, /*r15, */ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + } + // @formatter:on + return registers; + } + + public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config) { + this(architecture, config, initAllocatable(config.useCompressedOops)); + assert callerSaved.length >= allocatable.length; + } + + public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, Register[] allocatable) { + this.architecture = architecture; + this.maxFrameSize = config.maxFrameSize; + + if (config.windowsOs) { + javaGeneralParameterRegisters = new Register[]{rdx, r8, r9, rdi, rsi, rcx}; + nativeGeneralParameterRegisters = new Register[]{rcx, rdx, r8, r9}; + this.needsNativeStackHomeSpace = true; + } else { + javaGeneralParameterRegisters = new Register[]{rsi, rdx, rcx, r8, r9, rdi}; + nativeGeneralParameterRegisters = new Register[]{rdi, rsi, rdx, rcx, r8, r9}; + this.needsNativeStackHomeSpace = false; + } + + this.allocatable = allocatable.clone(); + Set callerSaveSet = new HashSet<>(); + Collections.addAll(callerSaveSet, allocatable); + Collections.addAll(callerSaveSet, xmmParameterRegisters); + Collections.addAll(callerSaveSet, javaGeneralParameterRegisters); + Collections.addAll(callerSaveSet, nativeGeneralParameterRegisters); + callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]); + + allAllocatableAreCallerSaved = true; + attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters); + } + + @Override + public Register[] getCallerSaveRegisters() { + return callerSaved; + } + + public Register[] getCalleeSaveRegisters() { + return null; + } + + @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return allAllocatableAreCallerSaved; + } + + @Override + public Register getRegisterForRole(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) { + if (type == Type.NativeCall) { + return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + // On x64, parameter locations are the same whether viewed + // from the caller or callee perspective + return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + + public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { + switch (kind) { + case Boolean: + case Byte: + case Short: + case Char: + case Int: + case Long: + case Object: + return type == Type.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; + case Float: + case Double: + return xmmParameterRegisters; + default: + throw JVMCIError.shouldNotReachHere(); + } + } + + private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { + AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; + + int currentGeneral = 0; + int currentXMM = 0; + int currentStackOffset = type == Type.NativeCall && needsNativeStackHomeSpace ? generalParameterRegisters.length * target.wordSize : 0; + + for (int i = 0; i < parameterTypes.length; i++) { + final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); + + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Object: + if (!stackOnly && currentGeneral < generalParameterRegisters.length) { + Register register = generalParameterRegisters[currentGeneral++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + case Float: + case Double: + if (!stackOnly && currentXMM < xmmParameterRegisters.length) { + Register register = xmmParameterRegisters[currentXMM++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + default: + throw JVMCIError.shouldNotReachHere(); + } + + if (locations[i] == null) { + LIRKind lirKind = target.getLIRKind(kind); + locations[i] = StackSlot.get(lirKind, currentStackOffset, !type.out); + currentStackOffset += Math.max(target.getSizeInBytes(lirKind.getPlatformKind()), target.wordSize); + } + } + + JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); + AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(target.getLIRKind(returnKind.getStackKind())); + return new CallingConvention(currentStackOffset, returnLocation, locations); + } + + @Override + public Register getReturnRegister(JavaKind kind) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + return rax; + case Float: + case Double: + return xmm0; + case Void: + case Illegal: + return null; + default: + throw new UnsupportedOperationException("no return register for type " + kind); + } + } + + @Override + public Register getFrameRegister() { + return rsp; + } + + @Override + public String toString() { + return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java new file mode 100644 index 00000000000..0f26eb6ca22 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot.sparc; + +import static jdk.vm.ci.inittimer.InitTimer.*; + +import java.util.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.compiler.*; +import jdk.vm.ci.hotspot.*; +import jdk.vm.ci.inittimer.*; +import jdk.vm.ci.runtime.*; +import jdk.vm.ci.service.*; +import jdk.vm.ci.sparc.*; +import jdk.vm.ci.sparc.SPARC.CPUFeature; + +@ServiceProvider(HotSpotJVMCIBackendFactory.class) +public class SPARCHotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFactory { + + protected TargetDescription createTarget(HotSpotVMConfig config, CompilerFactory compilerFactory) { + final int stackFrameAlignment = 16; + final int implicitNullCheckLimit = 4096; + final boolean inlineObjects = false; + Architecture arch = new SPARC(computeFeatures(config)); + return new TargetDescription(compilerFactory.initializeArchitecture(arch), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); + } + + protected HotSpotCodeCacheProvider createCodeCache(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { + return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig); + } + + protected EnumSet computeFeatures(HotSpotVMConfig config) { + EnumSet features = EnumSet.noneOf(CPUFeature.class); + if ((config.sparcFeatures & config.vis1Instructions) != 0) { + features.add(CPUFeature.VIS1); + } + if ((config.sparcFeatures & config.vis2Instructions) != 0) { + features.add(CPUFeature.VIS2); + } + if ((config.sparcFeatures & config.vis3Instructions) != 0) { + features.add(CPUFeature.VIS3); + } + if ((config.sparcFeatures & config.cbcondInstructions) != 0) { + features.add(CPUFeature.CBCOND); + } + if (config.useBlockZeroing) { + features.add(CPUFeature.BLOCK_ZEROING); + } + return features; + } + + @Override + public String getArchitecture() { + return "SPARC"; + } + + @Override + public String toString() { + return "JVMCIBackend:" + getArchitecture(); + } + + @SuppressWarnings("try") + public JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntimeProvider runtime, CompilerFactory compilerFactory, JVMCIBackend host) { + assert host == null; + TargetDescription target = createTarget(runtime.getConfig(), compilerFactory); + + HotSpotMetaAccessProvider metaAccess = new HotSpotMetaAccessProvider(runtime); + RegisterConfig regConfig = new SPARCHotSpotRegisterConfig(target, runtime.getConfig()); + HotSpotCodeCacheProvider codeCache = createCodeCache(runtime, target, regConfig); + HotSpotConstantReflectionProvider constantReflection = new HotSpotConstantReflectionProvider(runtime); + try (InitTimer rt = timer("instantiate backend")) { + return createBackend(metaAccess, codeCache, constantReflection); + } + } + + protected JVMCIBackend createBackend(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, HotSpotConstantReflectionProvider constantReflection) { + return new JVMCIBackend(metaAccess, codeCache, constantReflection); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java new file mode 100644 index 00000000000..cb47b2ea564 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot.sparc; + +import static jdk.vm.ci.sparc.SPARC.*; + +import java.util.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.CallingConvention.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.hotspot.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.sparc.*; + +public class SPARCHotSpotRegisterConfig implements RegisterConfig { + + private final Architecture architecture; + + private final Register[] allocatable; + + private final RegisterAttributes[] attributesMap; + + @Override + public Register[] getAllocatableRegisters() { + return allocatable.clone(); + } + + public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { + ArrayList list = new ArrayList<>(); + for (Register reg : registers) { + if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { + // Special treatment for double precision + // TODO: This is wasteful it uses only half of the registers as float. + if (kind == JavaKind.Double) { + if (reg.getRegisterCategory().equals(FPUd)) { + list.add(reg); + } + } else if (kind == JavaKind.Float) { + if (reg.getRegisterCategory().equals(FPUs)) { + list.add(reg); + } + } else { + list.add(reg); + } + } + } + + Register[] ret = list.toArray(new Register[list.size()]); + return ret; + } + + @Override + public RegisterAttributes[] getAttributesMap() { + return attributesMap.clone(); + } + + private final Register[] cpuCallerParameterRegisters = {o0, o1, o2, o3, o4, o5}; + private final Register[] cpuCalleeParameterRegisters = {i0, i1, i2, i3, i4, i5}; + + private final Register[] fpuParameterRegisters = {f0, f1, f2, f3, f4, f5, f6, f7}; + private final Register[] fpuDoubleParameterRegisters = {d0, null, d2, null, d4, null, d6, null}; + // @formatter:off + private final Register[] callerSaveRegisters = + {g1, g2, g3, g4, g5, g6, g7, + o0, o1, o2, o3, o4, o5, o7, + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62}; + // @formatter:on + + /** + * Registers saved by the callee. This lists all L and I registers which are saved in the + * register window. + */ + private final Register[] calleeSaveRegisters = {l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, i6, i7}; + + private static Register[] initAllocatable(boolean reserveForHeapBase) { + Register[] registers = null; + if (reserveForHeapBase) { + // @formatter:off + registers = new Register[]{ + // TODO this is not complete + // o7 cannot be used as register because it is always overwritten on call + // and the current register handler would ignore this fact if the called + // method still does not modify registers, in fact o7 is modified by the Call instruction + // There would be some extra handlin necessary to be able to handle the o7 properly for local usage + g1, g4, g5, + o0, o1, o2, o3, o4, o5, /*o6,o7,*/ + l0, l1, l2, l3, l4, l5, l6, l7, + i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ + //f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + } else { + // @formatter:off + registers = new Register[]{ + // TODO this is not complete + g1, g4, g5, + o0, o1, o2, o3, o4, o5, /*o6, o7,*/ + l0, l1, l2, l3, l4, l5, l6, l7, + i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ +// f0, f1, f2, f3, f4, f5, f6, f7 + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + } + + return registers; + } + + public SPARCHotSpotRegisterConfig(TargetDescription target, HotSpotVMConfig config) { + this(target, initAllocatable(config.useCompressedOops)); + } + + public SPARCHotSpotRegisterConfig(TargetDescription target, Register[] allocatable) { + this.architecture = target.arch; + this.allocatable = allocatable.clone(); + attributesMap = RegisterAttributes.createMap(this, SPARC.allRegisters); + } + + @Override + public Register[] getCallerSaveRegisters() { + return callerSaveRegisters; + } + + public Register[] getCalleeSaveRegisters() { + return calleeSaveRegisters; + } + + @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return false; + } + + @Override + public Register getRegisterForRole(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) { + if (type == Type.JavaCall || type == Type.NativeCall) { + return callingConvention(cpuCallerParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + if (type == Type.JavaCallee) { + return callingConvention(cpuCalleeParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + throw JVMCIError.shouldNotReachHere(); + } + + public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { + if (architecture.canStoreValue(FPUs, kind) || architecture.canStoreValue(FPUd, kind)) { + return fpuParameterRegisters; + } + assert architecture.canStoreValue(CPU, kind); + return type == Type.JavaCallee ? cpuCalleeParameterRegisters : cpuCallerParameterRegisters; + } + + private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { + AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; + + int currentGeneral = 0; + int currentFloating = 0; + int currentStackOffset = 0; + + for (int i = 0; i < parameterTypes.length; i++) { + final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); + + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Object: + if (!stackOnly && currentGeneral < generalParameterRegisters.length) { + Register register = generalParameterRegisters[currentGeneral++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + case Double: + if (!stackOnly && currentFloating < fpuParameterRegisters.length) { + if (currentFloating % 2 != 0) { + // Make register number even to be a double reg + currentFloating++; + } + Register register = fpuDoubleParameterRegisters[currentFloating]; + currentFloating += 2; // Only every second is a double register + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + case Float: + if (!stackOnly && currentFloating < fpuParameterRegisters.length) { + Register register = fpuParameterRegisters[currentFloating++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + default: + throw JVMCIError.shouldNotReachHere(); + } + + if (locations[i] == null) { + // Stack slot is always aligned to its size in bytes but minimum wordsize + int typeSize = SPARC.spillSlotSize(target, kind); + currentStackOffset = roundUp(currentStackOffset, typeSize); + int slotOffset = currentStackOffset + SPARC.REGISTER_SAFE_AREA_SIZE; + locations[i] = StackSlot.get(target.getLIRKind(kind.getStackKind()), slotOffset, !type.out); + currentStackOffset += typeSize; + } + } + + JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); + AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind, type).asValue(target.getLIRKind(returnKind.getStackKind())); + // Space where callee may spill outgoing parameters o0...o5 + int lowerOutgoingSpace = Math.min(locations.length, 6) * target.wordSize; + return new CallingConvention(currentStackOffset + lowerOutgoingSpace, returnLocation, locations); + } + + private static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } + + @Override + public Register getReturnRegister(JavaKind kind) { + return getReturnRegister(kind, Type.JavaCallee); + } + + private static Register getReturnRegister(JavaKind kind, Type type) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + return type == Type.JavaCallee ? i0 : o0; + case Float: + return f0; + case Double: + return d0; + case Void: + case Illegal: + return null; + default: + throw new UnsupportedOperationException("no return register for type " + kind); + } + } + + @Override + public Register getFrameRegister() { + return sp; + } + + @Override + public String toString() { + return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java new file mode 100644 index 00000000000..1e96b96d7c1 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java @@ -0,0 +1,574 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.inittimer.InitTimer.timer; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspotvmconfig.HotSpotVMField; +import jdk.vm.ci.inittimer.InitTimer; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.SpeculationLog; +import sun.misc.Unsafe; + +/** + * Calls from Java into HotSpot. The behavior of all the methods in this class that take a native + * pointer as an argument (e.g., {@link #getSymbol(long)}) is undefined if the argument does not + * denote a valid native object. + */ +public final class CompilerToVM { + /** + * Initializes the native part of the JVMCI runtime. + */ + private static native void registerNatives(); + + static { + initialize(); + } + + @SuppressWarnings("try") + private static void initialize() { + try (InitTimer t = timer("CompilerToVM.registerNatives")) { + registerNatives(); + } + } + + /** + * Copies the original bytecode of {@code method} into a new byte array and returns it. + * + * @return a new byte array containing the original bytecode of {@code method} + */ + native byte[] getBytecode(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the number of entries in {@code method}'s exception handler table or 0 if it has not + * exception handler table. + */ + native int getExceptionTableLength(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the address of the first entry in {@code method}'s exception handler table. + * + * Each entry is a native object described by these fields: + * + *
    + *
  • {@link HotSpotVMConfig#exceptionTableElementSize}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementStartPcOffset}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementEndPcOffset}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementHandlerPcOffset}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementCatchTypeIndexOffset} + *
+ * + * @return 0 if {@code method} has no exception handlers (i.e. + * {@code getExceptionTableLength(method) == 0}) + */ + native long getExceptionTableStart(HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if {@code method} can be inlined. A method may not be inlinable for a number of + * reasons such as: + *
    + *
  • a CompileOracle directive may prevent inlining or compilation of methods
  • + *
  • the method may have a bytecode breakpoint set
  • + *
  • the method may have other bytecode features that require special handling by the VM
  • + *
+ */ + native boolean canInlineMethod(HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if {@code method} should be inlined at any cost. This could be because: + *
    + *
  • a CompileOracle directive may forces inlining of this methods
  • + *
  • an annotation forces inlining of this method
  • + *
+ */ + native boolean shouldInlineMethod(HotSpotResolvedJavaMethodImpl method); + + /** + * Used to implement {@link ResolvedJavaType#findUniqueConcreteMethod(ResolvedJavaMethod)}. + * + * @param method the method on which to base the search + * @param actualHolderType the best known type of receiver + * @return the method result or 0 is there is no unique concrete method for {@code method} + */ + native HotSpotResolvedJavaMethodImpl findUniqueConcreteMethod(HotSpotResolvedObjectTypeImpl actualHolderType, HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the implementor for the interface class {@code type}. + * + * @return the implementor if there is a single implementor, 0 if there is no implementor, or + * {@code type} itself if there is more than one implementor + */ + native HotSpotResolvedObjectTypeImpl getImplementor(HotSpotResolvedObjectTypeImpl type); + + /** + * Determines if {@code method} is ignored by security stack walks. + */ + native boolean methodIsIgnoredBySecurityStackWalk(HotSpotResolvedJavaMethodImpl method); + + /** + * Converts a name to a type. + * + * @param name a well formed Java type in {@linkplain JavaType#getName() internal} format + * @param accessingClass the context of resolution (must not be null) + * @param resolve force resolution to a {@link ResolvedJavaType}. If true, this method will + * either return a {@link ResolvedJavaType} or throw an exception + * @return the type for {@code name} or 0 if resolution failed and {@code resolve == false} + * @throws LinkageError if {@code resolve == true} and the resolution failed + */ + native HotSpotResolvedObjectTypeImpl lookupType(String name, Class accessingClass, boolean resolve); + + /** + * Resolves the entry at index {@code cpi} in {@code constantPool} to an object. + * + * The behavior of this method is undefined if {@code cpi} does not denote one of the following + * entry types: {@code JVM_CONSTANT_MethodHandle}, {@code JVM_CONSTANT_MethodHandleInError}, + * {@code JVM_CONSTANT_MethodType} and {@code JVM_CONSTANT_MethodTypeInError}. + */ + native Object resolveConstantInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Resolves the entry at index {@code cpi} in {@code constantPool} to an object, looking in the + * constant pool cache first. + * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_String} entry. + */ + native Object resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} index from the entry at index {@code cpi} in + * {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry containing a + * {@code JVM_CONSTANT_NameAndType} index. + */ + native int lookupNameAndTypeRefIndexInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the name of the {@code JVM_CONSTANT_NameAndType} entry referenced by another entry + * denoted by {@code which} in {@code constantPool}. + * + * The behavior of this method is undefined if {@code which} does not denote a entry that + * references a {@code JVM_CONSTANT_NameAndType} entry. + */ + native String lookupNameInPool(HotSpotConstantPool constantPool, int which); + + /** + * Gets the signature of the {@code JVM_CONSTANT_NameAndType} entry referenced by another entry + * denoted by {@code which} in {@code constantPool}. + * + * The behavior of this method is undefined if {@code which} does not denote a entry that + * references a {@code JVM_CONSTANT_NameAndType} entry. + */ + native String lookupSignatureInPool(HotSpotConstantPool constantPool, int which); + + /** + * Gets the {@code JVM_CONSTANT_Class} index from the entry at index {@code cpi} in + * {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry containing a + * {@code JVM_CONSTANT_Class} index. + */ + native int lookupKlassRefIndexInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Looks up a class denoted by the {@code JVM_CONSTANT_Class} entry at index {@code cpi} in + * {@code constantPool}. This method does not perform any resolution. + * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_Class} entry. + * + * @return the resolved class entry or a String otherwise + */ + native Object lookupKlassInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Looks up a method denoted by the entry at index {@code cpi} in {@code constantPool}. This + * method does not perform any resolution. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry representing + * a method. + * + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1}. If non-negative, then resolution checks specific to the bytecode it + * denotes are performed if the method is already resolved. Should any of these + * checks fail, 0 is returned. + * @return the resolved method entry, 0 otherwise + */ + native HotSpotResolvedJavaMethodImpl lookupMethodInPool(HotSpotConstantPool constantPool, int cpi, byte opcode); + + /** + * Ensures that the type referenced by the specified {@code JVM_CONSTANT_InvokeDynamic} entry at + * index {@code cpi} in {@code constantPool} is loaded and initialized. + * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_InvokeDynamic} entry. + */ + native void resolveInvokeDynamicInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Ensures that the type referenced by the entry for a signature + * polymorphic method at index {@code cpi} in {@code constantPool} is loaded and + * initialized. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry representing + * a signature polymorphic method. + */ + native void resolveInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the resolved type denoted by the entry at index {@code cpi} in {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry representing + * a class. + * + * @throws LinkageError if resolution failed + */ + native HotSpotResolvedObjectTypeImpl resolveTypeInPool(HotSpotConstantPool constantPool, int cpi) throws LinkageError; + + /** + * Looks up and attempts to resolve the {@code JVM_CONSTANT_Field} entry at index {@code cpi} in + * {@code constantPool}. The values returned in {@code info} are: + * + *
+     *     [(int) flags,   // only valid if field is resolved
+     *      (int) offset]  // only valid if field is resolved
+     * 
+ * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_Field} entry. + * + * @param info an array in which the details of the field are returned + * @return the type defining the field if resolution is successful, 0 otherwise + */ + native HotSpotResolvedObjectTypeImpl resolveFieldInPool(HotSpotConstantPool constantPool, int cpi, byte opcode, long[] info); + + /** + * Converts {@code cpci} from an index into the cache for {@code constantPool} to an index + * directly into {@code constantPool}. + * + * The behavior of this method is undefined if {@code ccpi} is an invalid constant pool cache + * index. + */ + native int constantPoolRemapInstructionOperandFromCache(HotSpotConstantPool constantPool, int cpci); + + /** + * Gets the appendix object (if any) associated with the entry at index {@code cpi} in + * {@code constantPool}. + */ + native Object lookupAppendixInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Installs the result of a compilation into the code cache. + * + * @param target the target where this code should be installed + * @param compiledCode the result of a compilation + * @param code the details of the installed CodeBlob are written to this object + * @return the outcome of the installation which will be one of + * {@link HotSpotVMConfig#codeInstallResultOk}, + * {@link HotSpotVMConfig#codeInstallResultCacheFull}, + * {@link HotSpotVMConfig#codeInstallResultCodeTooLarge}, + * {@link HotSpotVMConfig#codeInstallResultDependenciesFailed} or + * {@link HotSpotVMConfig#codeInstallResultDependenciesInvalid}. + */ + public native int installCode(TargetDescription target, HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog); + + public native int getMetadata(TargetDescription target, HotSpotCompiledCode compiledCode, HotSpotMetaData metaData); + + /** + * Notifies the VM of statistics for a completed compilation. + * + * @param id the identifier of the compilation + * @param method the method compiled + * @param osr specifies if the compilation was for on-stack-replacement + * @param processedBytecodes the number of bytecodes processed during the compilation, including + * the bytecodes of all inlined methods + * @param time the amount time spent compiling {@code method} + * @param timeUnitsPerSecond the granularity of the units for the {@code time} value + * @param installedCode the nmethod installed as a result of the compilation + */ + public synchronized native void notifyCompilationStatistics(int id, HotSpotResolvedJavaMethodImpl method, boolean osr, int processedBytecodes, long time, long timeUnitsPerSecond, + InstalledCode installedCode); + + /** + * Resets all compilation statistics. + */ + public native void resetCompilationStatistics(); + + /** + * Initializes the fields of {@code config}. + */ + native long initializeConfiguration(); + + /** + * Resolves the implementation of {@code method} for virtual dispatches on objects of dynamic + * type {@code exactReceiver}. This resolution process only searches "up" the class hierarchy of + * {@code exactReceiver}. + * + * @param caller the caller or context type used to perform access checks + * @return the link-time resolved method (might be abstract) or {@code 0} if it can not be + * linked + */ + native HotSpotResolvedJavaMethodImpl resolveMethod(HotSpotResolvedObjectTypeImpl exactReceiver, HotSpotResolvedJavaMethodImpl method, HotSpotResolvedObjectTypeImpl caller); + + /** + * Gets the static initializer of {@code type}. + * + * @return 0 if {@code type} has no static initializer + */ + native HotSpotResolvedJavaMethodImpl getClassInitializer(HotSpotResolvedObjectTypeImpl type); + + /** + * Determines if {@code type} or any of its currently loaded subclasses overrides + * {@code Object.finalize()}. + */ + native boolean hasFinalizableSubclass(HotSpotResolvedObjectTypeImpl type); + + /** + * Gets the method corresponding to {@code holder} and slot number {@code slot} (i.e. + * {@link Method#slot} or {@link Constructor#slot}). + */ + native HotSpotResolvedJavaMethodImpl getResolvedJavaMethodAtSlot(Class holder, int slot); + + /** + * Gets the maximum absolute offset of a PC relative call to {@code address} from any position + * in the code cache. + * + * @param address an address that may be called from any code in the code cache + * @return -1 if {@code address == 0} + */ + public native long getMaxCallTargetOffset(long address); + + /** + * Gets a textual disassembly of {@code codeBlob}. + * + * @return a non-zero length string containing a disassembly of {@code codeBlob} or null if + * {@code codeBlob} could not be disassembled for some reason + */ + // The HotSpot disassembler seems not to be thread safe so it's better to synchronize its usage + public synchronized native String disassembleCodeBlob(long codeBlob); + + /** + * Gets a stack trace element for {@code method} at bytecode index {@code bci}. + */ + native StackTraceElement getStackTraceElement(HotSpotResolvedJavaMethodImpl method, int bci); + + /** + * Executes some {@code installedCode} with arguments {@code args}. + * + * @return the result of executing {@code installedCode} + * @throws InvalidInstalledCodeException if {@code installedCode} has been invalidated + */ + native Object executeInstalledCode(Object[] args, InstalledCode installedCode) throws InvalidInstalledCodeException; + + /** + * Gets the line number table for {@code method}. The line number table is encoded as (bci, + * source line number) pairs. + * + * @return the line number table for {@code method} or null if it doesn't have one + */ + native long[] getLineNumberTable(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the number of entries in the local variable table for {@code method}. + * + * @return the number of entries in the local variable table for {@code method} + */ + native int getLocalVariableTableLength(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the address of the first entry in the local variable table for {@code method}. + * + * Each entry is a native object described by these fields: + * + *
    + *
  • {@link HotSpotVMConfig#localVariableTableElementSize}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementLengthOffset}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementNameCpIndexOffset}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementDescriptorCpIndexOffset}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementSignatureCpIndexOffset} + *
  • {@link HotSpotVMConfig#localVariableTableElementSlotOffset} + *
  • {@link HotSpotVMConfig#localVariableTableElementStartBciOffset} + *
+ * + * @return 0 if {@code method} does not have a local variable table + */ + native long getLocalVariableTableStart(HotSpotResolvedJavaMethodImpl method); + + /** + * Reads an object pointer within a VM data structure. That is, any {@link HotSpotVMField} whose + * {@link HotSpotVMField#type() type} is {@code "oop"} (e.g., + * {@code ArrayKlass::_component_mirror}, {@code Klass::_java_mirror}, + * {@code JavaThread::_threadObj}). + * + * Note that {@link Unsafe#getObject(Object, long)} cannot be used for this since it does a + * {@code narrowOop} read if the VM is using compressed oops whereas oops within VM data + * structures are (currently) always uncompressed. + * + * @param address address of an oop field within a VM data structure + */ + native Object readUncompressedOop(long address); + + /** + * Determines if {@code method} should not be inlined or compiled. + */ + native void doNotInlineOrCompile(HotSpotResolvedJavaMethodImpl method); + + /** + * Invalidates the profiling information for {@code method} and (re)initializes it such that + * profiling restarts upon its next invocation. + */ + native void reprofile(HotSpotResolvedJavaMethodImpl method); + + /** + * Invalidates {@code installedCode} such that {@link InvalidInstalledCodeException} will be + * raised the next time {@code installedCode} is executed. + */ + public native void invalidateInstalledCode(InstalledCode installedCode); + + /** + * Collects the current values of all JVMCI benchmark counters, summed up over all threads. + */ + public native long[] collectCounters(); + + /** + * Determines if {@code metaspaceMethodData} is mature. + */ + native boolean isMature(long metaspaceMethodData); + + /** + * Generate a unique id to identify the result of the compile. + */ + native int allocateCompileId(HotSpotResolvedJavaMethodImpl method, int entryBCI); + + /** + * Determines if {@code method} has OSR compiled code identified by {@code entryBCI} for + * compilation level {@code level}. + */ + native boolean hasCompiledCodeForOSR(HotSpotResolvedJavaMethodImpl method, int entryBCI, int level); + + /** + * Gets the value of {@code metaspaceSymbol} as a String. + */ + native String getSymbol(long metaspaceSymbol); + + /** + * Looks for the next Java stack frame matching an entry in {@code methods}. + * + * @param frame the starting point of the search, where {@code null} refers to the topmost frame + * @param methods the methods to look for, where {@code null} means that any frame is returned + * @return the frame, or {@code null} if the end of the stack was reached during the search + */ + public native HotSpotStackFrameReference getNextStackFrame(HotSpotStackFrameReference frame, HotSpotResolvedJavaMethodImpl[] methods, int initialSkip); + + /** + * Materializes all virtual objects within {@code stackFrame} updates its locals. + * + * @param invalidate if {@code true}, the compiled method for the stack frame will be + * invalidated. + */ + native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate); + + /** + * Gets the v-table index for interface method {@code method} in the receiver {@code type} or + * {@link HotSpotVMConfig#invalidVtableIndex} if {@code method} is not in {@code type}'s + * v-table. + * + * @throws InternalError if {@code type} is an interface or {@code method} is not held by an + * interface or class represented by {@code type} is not initialized + */ + native int getVtableIndexForInterfaceMethod(HotSpotResolvedObjectTypeImpl type, HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if debug info should also be emitted at non-safepoint locations. + */ + public native boolean shouldDebugNonSafepoints(); + + /** + * Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to the + * HotSpot's log stream. + * + * @exception NullPointerException if bytes is null. + * @exception IndexOutOfBoundsException if copying would cause access of data outside array + * bounds. + */ + public native void writeDebugOutput(byte[] bytes, int offset, int length); + + /** + * Flush HotSpot's log stream. + */ + public native void flushDebugOutput(); + + /** + * Read a value representing a metaspace Method* and return the + * {@link HotSpotResolvedJavaMethodImpl} wrapping it. This method does no checking that the + * location actually contains a valid Method*. If the {@code base} object is a + * {@link HotSpotResolvedJavaMethodImpl}, {@link HotSpotConstantPool} or + * {@link HotSpotResolvedObjectTypeImpl} then the metaspace pointer is fetched from that object + * and used as the base. Otherwise the object itself is used as the base. + * + * @param base an object to read from or null + * @param displacement + * @return null or the resolved method for this location + */ + native HotSpotResolvedJavaMethodImpl getResolvedJavaMethod(Object base, long displacement); + + /** + * Read a value representing a metaspace ConstantPool* and return the + * {@link HotSpotConstantPool} wrapping it. This method does no checking that the location + * actually contains a valid ConstantPool*. If the {@code base} object is a + * {@link HotSpotResolvedJavaMethodImpl}, {@link HotSpotConstantPool} or + * {@link HotSpotResolvedObjectTypeImpl} then the metaspace pointer is fetched from that object + * and used as the base. Otherwise the object itself is used as the base. + * + * @param base an object to read from or null + * @param displacement + * @return null or the resolved method for this location + */ + native HotSpotConstantPool getConstantPool(Object base, long displacement); + + /** + * Read a value representing a metaspace Klass* and return the + * {@link HotSpotResolvedObjectTypeImpl} wrapping it. The method does no checking that the + * location actually contains a valid Klass*. If the {@code base} object is a + * {@link HotSpotResolvedJavaMethodImpl}, {@link HotSpotConstantPool} or + * {@link HotSpotResolvedObjectTypeImpl} then the metaspace pointer is fetched from that object + * and used as the base. Otherwise the object itself is used as the base. + * + * @param base an object to read from or null + * @param displacement + * @param compressed true if the location contains a compressed Klass* + * @return null or the resolved method for this location + */ + native HotSpotResolvedObjectTypeImpl getResolvedJavaType(Object base, long displacement, boolean compressed); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java new file mode 100644 index 00000000000..b1ccd16d14d --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.*; + +import java.lang.reflect.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.CompilationResult.*; +import jdk.vm.ci.code.DataSection.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; + +/** + * HotSpot implementation of {@link CodeCacheProvider}. + */ +public class HotSpotCodeCacheProvider implements CodeCacheProvider { + + protected final HotSpotJVMCIRuntimeProvider runtime; + public final HotSpotVMConfig config; + protected final TargetDescription target; + protected final RegisterConfig regConfig; + + public HotSpotCodeCacheProvider(HotSpotJVMCIRuntimeProvider runtime, HotSpotVMConfig config, TargetDescription target, RegisterConfig regConfig) { + this.runtime = runtime; + this.config = config; + this.target = target; + this.regConfig = regConfig; + } + + @Override + public String getMarkName(Mark mark) { + int markId = (int) mark.id; + Field[] fields = runtime.getConfig().getClass().getDeclaredFields(); + for (Field f : fields) { + if (f.getName().startsWith("MARKID_")) { + f.setAccessible(true); + try { + if (f.getInt(runtime.getConfig()) == markId) { + return f.getName(); + } + } catch (Exception e) { + } + } + } + return CodeCacheProvider.super.getMarkName(mark); + } + + /** + * Decodes a call target to a mnemonic if possible. + */ + @Override + public String getTargetName(Call call) { + Field[] fields = runtime.getConfig().getClass().getDeclaredFields(); + for (Field f : fields) { + if (f.getName().endsWith("Stub")) { + f.setAccessible(true); + try { + Object address = f.get(runtime.getConfig()); + if (address.equals(call.target)) { + return f.getName() + ":0x" + Long.toHexString((Long) address); + } + } catch (Exception e) { + } + } + } + return CodeCacheProvider.super.getTargetName(call); + } + + @Override + public RegisterConfig getRegisterConfig() { + return regConfig; + } + + @Override + public int getMinimumOutgoingSize() { + return runtime.getConfig().runtimeCallStackSize; + } + + public InstalledCode logOrDump(InstalledCode installedCode, CompilationResult compResult) { + HotSpotJVMCIRuntime.runtime().notifyInstall(this, installedCode, compResult); + return installedCode; + } + + private InstalledCode installCode(CompilationResult compResult, HotSpotCompiledNmethod compiledCode, InstalledCode installedCode, SpeculationLog log) { + int result = runtime.getCompilerToVM().installCode(target, compiledCode, installedCode, log); + if (result != config.codeInstallResultOk) { + String msg = compiledCode.getInstallationFailureMessage(); + String resultDesc = config.getCodeInstallResultDescription(result); + if (msg != null) { + msg = String.format("Code installation failed: %s%n%s", resultDesc, msg); + } else { + msg = String.format("Code installation failed: %s", resultDesc); + } + if (result == config.codeInstallResultDependenciesInvalid) { + throw new AssertionError(resultDesc + " " + msg); + } + throw new BailoutException(result != config.codeInstallResultDependenciesFailed, msg); + } + return logOrDump(installedCode, compResult); + } + + public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long jvmciEnv, boolean isDefault) { + if (compResult.getId() == -1) { + compResult.setId(method.allocateCompileId(compResult.getEntryBCI())); + } + HotSpotInstalledCode installedCode = new HotSpotNmethod(method, compResult.getName(), isDefault); + HotSpotCompiledNmethod compiledCode = new HotSpotCompiledNmethod(method, compResult, jvmciEnv); + return installCode(compResult, compiledCode, installedCode, method.getSpeculationLog()); + } + + @Override + public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, SpeculationLog log, InstalledCode predefinedInstalledCode) { + HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; + if (compResult.getId() == -1) { + compResult.setId(hotspotMethod.allocateCompileId(compResult.getEntryBCI())); + } + InstalledCode installedCode = predefinedInstalledCode; + if (installedCode == null) { + HotSpotInstalledCode code = new HotSpotNmethod(hotspotMethod, compResult.getName(), false); + installedCode = code; + } + HotSpotCompiledNmethod compiledCode = new HotSpotCompiledNmethod(hotspotMethod, compResult); + return installCode(compResult, compiledCode, installedCode, log); + } + + @Override + public InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult) { + HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; + return installMethod(hotspotMethod, compResult, 0L, true); + } + + public HotSpotNmethod addExternalMethod(ResolvedJavaMethod method, CompilationResult compResult) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) method; + if (compResult.getId() == -1) { + compResult.setId(javaMethod.allocateCompileId(compResult.getEntryBCI())); + } + HotSpotNmethod code = new HotSpotNmethod(javaMethod, compResult.getName(), false, true); + HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(javaMethod, compResult); + CompilerToVM vm = runtime.getCompilerToVM(); + int result = vm.installCode(target, compiled, code, null); + if (result != runtime.getConfig().codeInstallResultOk) { + return null; + } + return code; + } + + public boolean needsDataPatch(JavaConstant constant) { + return constant instanceof HotSpotMetaspaceConstant; + } + + private Data createSingleDataItem(Constant constant) { + int size; + DataBuilder builder; + if (constant instanceof VMConstant) { + VMConstant vmConstant = (VMConstant) constant; + boolean compressed; + long raw; + if (constant instanceof HotSpotObjectConstant) { + HotSpotObjectConstant c = (HotSpotObjectConstant) vmConstant; + compressed = c.isCompressed(); + raw = 0xDEADDEADDEADDEADL; + } else if (constant instanceof HotSpotMetaspaceConstant) { + HotSpotMetaspaceConstant meta = (HotSpotMetaspaceConstant) constant; + compressed = meta.isCompressed(); + raw = meta.rawValue(); + } else { + throw new JVMCIError(String.valueOf(constant)); + } + + size = target.getSizeInBytes(compressed ? JavaKind.Int : target.wordKind); + if (size == 4) { + builder = (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant))); + buffer.putInt((int) raw); + }; + } else { + assert size == 8; + builder = (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant))); + buffer.putLong(raw); + }; + } + } else if (JavaConstant.isNull(constant)) { + boolean compressed = COMPRESSED_NULL.equals(constant); + size = target.getSizeInBytes(compressed ? JavaKind.Int : target.wordKind); + builder = DataBuilder.zero(size); + } else if (constant instanceof SerializableConstant) { + SerializableConstant s = (SerializableConstant) constant; + size = s.getSerializedSize(); + builder = DataBuilder.serializable(s); + } else { + throw new JVMCIError(String.valueOf(constant)); + } + + return new Data(size, size, builder); + } + + public Data createDataItem(Constant... constants) { + assert constants.length > 0; + if (constants.length == 1) { + return createSingleDataItem(constants[0]); + } else { + DataBuilder[] builders = new DataBuilder[constants.length]; + int size = 0; + int alignment = 1; + for (int i = 0; i < constants.length; i++) { + Data data = createSingleDataItem(constants[i]); + + assert size % data.getAlignment() == 0 : "invalid alignment in packed constants"; + alignment = DataSection.lcm(alignment, data.getAlignment()); + + builders[i] = data.getBuilder(); + size += data.getSize(); + } + DataBuilder ret = (buffer, patches) -> { + for (DataBuilder b : builders) { + b.emit(buffer, patches); + } + }; + return new Data(alignment, size, ret); + } + } + + @Override + public TargetDescription getTarget() { + return target; + } + + public String disassemble(InstalledCode code) { + if (code.isValid()) { + long codeBlob = code.getAddress(); + return runtime.getCompilerToVM().disassembleCodeBlob(codeBlob); + } + return null; + } + + public SpeculationLog createSpeculationLog() { + return new HotSpotSpeculationLog(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java new file mode 100644 index 00000000000..c70c46f2fbf --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.nio.*; +import java.util.*; +import java.util.stream.*; +import java.util.stream.Stream.Builder; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.CompilationResult.CodeAnnotation; +import jdk.vm.ci.code.CompilationResult.CodeComment; +import jdk.vm.ci.code.CompilationResult.DataPatch; +import jdk.vm.ci.code.CompilationResult.ExceptionHandler; +import jdk.vm.ci.code.CompilationResult.Infopoint; +import jdk.vm.ci.code.CompilationResult.JumpTable; +import jdk.vm.ci.code.CompilationResult.Mark; +import jdk.vm.ci.code.CompilationResult.Site; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.Assumption; + +/** + * A {@link CompilationResult} with additional HotSpot-specific information required for installing + * the code in HotSpot's code cache. + */ +public abstract class HotSpotCompiledCode { + + public final String name; + public final Site[] sites; + public final ExceptionHandler[] exceptionHandlers; + public final Comment[] comments; + public final Assumption[] assumptions; + + public final byte[] targetCode; + public final int targetCodeSize; + + public final byte[] dataSection; + public final int dataSectionAlignment; + public final DataPatch[] dataSectionPatches; + public final boolean isImmutablePIC; + + public final int totalFrameSize; + public final int customStackAreaOffset; + + /** + * The list of the methods whose bytecodes were used as input to the compilation. If + * {@code null}, then the compilation did not record method dependencies. Otherwise, the first + * element of this array is the root method of the compilation. + */ + public final ResolvedJavaMethod[] methods; + + public static class Comment { + + public final String text; + public final int pcOffset; + + public Comment(int pcOffset, String text) { + this.text = text; + this.pcOffset = pcOffset; + } + } + + public HotSpotCompiledCode(CompilationResult compResult) { + name = compResult.getName(); + sites = getSortedSites(compResult); + if (compResult.getExceptionHandlers().isEmpty()) { + exceptionHandlers = null; + } else { + exceptionHandlers = compResult.getExceptionHandlers().toArray(new ExceptionHandler[compResult.getExceptionHandlers().size()]); + } + List annotations = compResult.getAnnotations(); + comments = new Comment[annotations.size()]; + if (!annotations.isEmpty()) { + for (int i = 0; i < comments.length; i++) { + CodeAnnotation annotation = annotations.get(i); + String text; + if (annotation instanceof CodeComment) { + CodeComment codeComment = (CodeComment) annotation; + text = codeComment.value; + } else if (annotation instanceof JumpTable) { + JumpTable jumpTable = (JumpTable) annotation; + text = "JumpTable [" + jumpTable.low + " .. " + jumpTable.high + "]"; + } else { + text = annotation.toString(); + } + comments[i] = new Comment(annotation.position, text); + } + } + assumptions = compResult.getAssumptions(); + assert validateFrames(); + + targetCode = compResult.getTargetCode(); + targetCodeSize = compResult.getTargetCodeSize(); + + DataSection data = compResult.getDataSection(); + if (!data.isFinalized()) { + data.finalizeLayout(); + } + dataSection = new byte[data.getSectionSize()]; + + ByteBuffer buffer = ByteBuffer.wrap(dataSection).order(ByteOrder.nativeOrder()); + Builder patchBuilder = Stream.builder(); + data.buildDataSection(buffer, patchBuilder); + + dataSectionAlignment = data.getSectionAlignment(); + dataSectionPatches = patchBuilder.build().toArray(len -> new DataPatch[len]); + + isImmutablePIC = compResult.isImmutablePIC(); + + totalFrameSize = compResult.getTotalFrameSize(); + customStackAreaOffset = compResult.getCustomStackAreaOffset(); + + methods = compResult.getMethods(); + } + + /** + * Ensure that all the frames passed into HotSpot are properly formatted with an empty or + * illegal slot following double word slots. + */ + private boolean validateFrames() { + for (Site site : sites) { + if (site instanceof Infopoint) { + Infopoint info = (Infopoint) site; + if (info.debugInfo != null) { + BytecodeFrame frame = info.debugInfo.frame(); + assert frame == null || frame.validateFormat(); + } + } + } + return true; + } + + static class SiteComparator implements Comparator { + + public int compare(Site s1, Site s2) { + if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { + return s1 instanceof Mark ? -1 : 1; + } + return s1.pcOffset - s2.pcOffset; + } + } + + private static Site[] getSortedSites(CompilationResult target) { + List[] lists = new List[]{target.getInfopoints(), target.getDataPatches(), target.getMarks()}; + int count = 0; + for (List list : lists) { + count += list.size(); + } + Site[] result = new Site[count]; + int pos = 0; + for (List list : lists) { + for (Object elem : list) { + result[pos++] = (Site) elem; + } + } + Arrays.sort(result, new SiteComparator()); + return result; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java new file mode 100644 index 00000000000..b23aec07823 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.inittimer.*; + +/** + * {@link HotSpotCompiledCode} destined for installation as an nmethod. + */ +public final class HotSpotCompiledNmethod extends HotSpotCompiledCode { + + public final HotSpotResolvedJavaMethod method; + public final int entryBCI; + public final int id; + public final long jvmciEnv; + public final boolean hasUnsafeAccess; + + /** + * May be set by VM if code installation fails. It will describe in more detail why installation + * failed (e.g., exactly which dependency failed). + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "set by the VM") private String installationFailureMessage; + + public HotSpotCompiledNmethod(HotSpotResolvedJavaMethod method, CompilationResult compResult) { + this(method, compResult, 0L); + } + + public HotSpotCompiledNmethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long jvmciEnv) { + super(compResult); + this.method = method; + this.entryBCI = compResult.getEntryBCI(); + this.id = compResult.getId(); + this.jvmciEnv = jvmciEnv; + this.hasUnsafeAccess = compResult.hasUnsafeAccess(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + id + ":" + method.format("%H.%n(%p)%r@") + entryBCI + "]"; + } + + public String getInstallationFailureMessage() { + return installationFailureMessage; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java new file mode 100644 index 00000000000..228848c997f --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * The compressed representation of the {@link JavaConstant#NULL_POINTER null constant}. + */ +public final class HotSpotCompressedNullConstant implements JavaConstant, HotSpotConstant { + + public static final JavaConstant COMPRESSED_NULL = new HotSpotCompressedNullConstant(); + + private HotSpotCompressedNullConstant() { + } + + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public boolean isCompressed() { + return true; + } + + @Override + public boolean isDefaultForKind() { + return true; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public String toString() { + return JavaConstant.toString(this); + } + + @Override + public String toValueString() { + return "null"; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object o) { + return o instanceof HotSpotCompressedNullConstant; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstant.java new file mode 100644 index 00000000000..55544367808 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstant.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * Marker interface for hotspot specific constants. + */ +public interface HotSpotConstant extends Constant { + + boolean isCompressed(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java new file mode 100644 index 00000000000..cae64abaa8d --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java @@ -0,0 +1,716 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.invoke.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; + +/** + * Implementation of {@link ConstantPool} for HotSpot. + */ +public final class HotSpotConstantPool implements ConstantPool, HotSpotProxified, MetaspaceWrapperObject { + + /** + * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}. + */ + public static class Bytecodes { + public static final int LDC = 18; // 0x12 + public static final int LDC_W = 19; // 0x13 + public static final int LDC2_W = 20; // 0x14 + public static final int GETSTATIC = 178; // 0xB2 + public static final int PUTSTATIC = 179; // 0xB3 + public static final int GETFIELD = 180; // 0xB4 + public static final int PUTFIELD = 181; // 0xB5 + public static final int INVOKEVIRTUAL = 182; // 0xB6 + public static final int INVOKESPECIAL = 183; // 0xB7 + public static final int INVOKESTATIC = 184; // 0xB8 + public static final int INVOKEINTERFACE = 185; // 0xB9 + public static final int INVOKEDYNAMIC = 186; // 0xBA + public static final int NEW = 187; // 0xBB + public static final int NEWARRAY = 188; // 0xBC + public static final int ANEWARRAY = 189; // 0xBD + public static final int CHECKCAST = 192; // 0xC0 + public static final int INSTANCEOF = 193; // 0xC1 + public static final int MULTIANEWARRAY = 197; // 0xC5 + + static boolean isInvoke(int opcode) { + switch (opcode) { + case INVOKEVIRTUAL: + case INVOKESPECIAL: + case INVOKESTATIC: + case INVOKEINTERFACE: + case INVOKEDYNAMIC: + return true; + default: + return false; + } + } + + /** + * See: {@code Rewriter::maybe_rewrite_invokehandle}. + */ + static boolean isInvokeHandleAlias(int opcode) { + switch (opcode) { + case INVOKEVIRTUAL: + case INVOKESPECIAL: + return true; + default: + return false; + } + } + } + + /** + * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and + * internal ones. + */ + private enum JVM_CONSTANT { + // @formatter:off + Utf8(config().jvmConstantUtf8), + Integer(config().jvmConstantInteger), + Long(config().jvmConstantLong), + Float(config().jvmConstantFloat), + Double(config().jvmConstantDouble), + Class(config().jvmConstantClass), + UnresolvedClass(config().jvmConstantUnresolvedClass), + UnresolvedClassInError(config().jvmConstantUnresolvedClassInError), + String(config().jvmConstantString), + Fieldref(config().jvmConstantFieldref), + MethodRef(config().jvmConstantMethodref), + InterfaceMethodref(config().jvmConstantInterfaceMethodref), + NameAndType(config().jvmConstantNameAndType), + MethodHandle(config().jvmConstantMethodHandle), + MethodHandleInError(config().jvmConstantMethodHandleInError), + MethodType(config().jvmConstantMethodType), + MethodTypeInError(config().jvmConstantMethodTypeInError), + InvokeDynamic(config().jvmConstantInvokeDynamic); + // @formatter:on + + private final int tag; + + private static final int ExternalMax = config().jvmConstantExternalMax; + private static final int InternalMin = config().jvmConstantInternalMin; + private static final int InternalMax = config().jvmConstantInternalMax; + + private JVM_CONSTANT(int tag) { + this.tag = tag; + } + + private static HotSpotVMConfig config() { + return runtime().getConfig(); + } + + /** + * Maps JVM_CONSTANT tags to {@link JVM_CONSTANT} values. Using a separate class for lazy + * initialization. + */ + static class TagValueMap { + private static final JVM_CONSTANT[] table = new JVM_CONSTANT[ExternalMax + 1 + (InternalMax - InternalMin) + 1]; + + static { + assert InternalMin > ExternalMax; + for (JVM_CONSTANT e : values()) { + table[indexOf(e.tag)] = e; + } + } + + private static int indexOf(int tag) { + if (tag >= InternalMin) { + return tag - InternalMin + ExternalMax + 1; + } else { + assert tag <= ExternalMax; + } + return tag; + } + + static JVM_CONSTANT get(int tag) { + JVM_CONSTANT res = table[indexOf(tag)]; + if (res != null) { + return res; + } + throw new JVMCIError("Unknown JVM_CONSTANT tag %s", tag); + } + } + + public static JVM_CONSTANT getEnum(int tag) { + return TagValueMap.get(tag); + } + } + + private static class LookupTypeCacheElement { + int lastCpi = Integer.MIN_VALUE; + JavaType javaType; + + public LookupTypeCacheElement(int lastCpi, JavaType javaType) { + super(); + this.lastCpi = lastCpi; + this.javaType = javaType; + } + } + + /** + * Reference to the C++ ConstantPool object. + */ + private final long metaspaceConstantPool; + private volatile LookupTypeCacheElement lastLookupType; + + /** + * Gets the JVMCI mirror from a HotSpot constant pool.The VM is responsible for ensuring that + * the ConstantPool is kept alive for the duration of this call and the + * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. + * + * Called from the VM. + * + * @param metaspaceConstantPool a metaspace ConstantPool object + * @return the {@link HotSpotConstantPool} corresponding to {@code metaspaceConstantPool} + */ + @SuppressWarnings("unused") + private static HotSpotConstantPool fromMetaspace(long metaspaceConstantPool) { + return new HotSpotConstantPool(metaspaceConstantPool); + } + + private HotSpotConstantPool(long metaspaceConstantPool) { + this.metaspaceConstantPool = metaspaceConstantPool; + } + + /** + * Gets the holder for this constant pool as {@link HotSpotResolvedObjectTypeImpl}. + * + * @return holder for this constant pool + */ + private HotSpotResolvedObjectType getHolder() { + return runtime().getCompilerToVM().getResolvedJavaType(this, runtime().getConfig().constantPoolHolderOffset, false); + } + + /** + * Converts a raw index from the bytecodes to a constant pool index by adding a + * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}. + * + * @param rawIndex index from the bytecode + * @param opcode bytecode to convert the index for + * @return constant pool index + */ + private static int rawIndexToConstantPoolIndex(int rawIndex, int opcode) { + int index; + if (opcode == Bytecodes.INVOKEDYNAMIC) { + index = rawIndex; + // See: ConstantPool::is_invokedynamic_index + assert index < 0 : "not an invokedynamic constant pool index " + index; + } else { + assert opcode == Bytecodes.GETFIELD || opcode == Bytecodes.PUTFIELD || opcode == Bytecodes.GETSTATIC || opcode == Bytecodes.PUTSTATIC || opcode == Bytecodes.INVOKEINTERFACE || + opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL || opcode == Bytecodes.INVOKESTATIC : "unexpected invoke opcode " + opcode; + index = rawIndex + runtime().getConfig().constantPoolCpCacheIndexTag; + } + return index; + } + + /** + * Decode a constant pool cache index to a constant pool index. + * + * See {@code ConstantPool::decode_cpcache_index}. + * + * @param index constant pool cache index + * @return decoded index + */ + private static int decodeConstantPoolCacheIndex(int index) { + if (isInvokedynamicIndex(index)) { + return decodeInvokedynamicIndex(index); + } else { + return index - runtime().getConfig().constantPoolCpCacheIndexTag; + } + } + + /** + * See {@code ConstantPool::is_invokedynamic_index}. + */ + private static boolean isInvokedynamicIndex(int index) { + return index < 0; + } + + /** + * See {@code ConstantPool::decode_invokedynamic_index}. + */ + private static int decodeInvokedynamicIndex(int i) { + assert isInvokedynamicIndex(i) : i; + return ~i; + } + + public long getMetaspaceConstantPool() { + return metaspaceConstantPool; + } + + public long getMetaspacePointer() { + return getMetaspaceConstantPool(); + } + + /** + * Gets the constant pool tag at index {@code index}. + * + * @param index constant pool index + * @return constant pool tag + */ + private JVM_CONSTANT getTagAt(int index) { + assertBounds(index); + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceConstantPoolTags = UNSAFE.getAddress(getMetaspaceConstantPool() + config.constantPoolTagsOffset); + final int tag = UNSAFE.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index); + if (tag == 0) { + return null; + } + return JVM_CONSTANT.getEnum(tag); + } + + /** + * Gets the constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return constant pool entry + */ + private long getEntryAt(int index) { + assertBounds(index); + return UNSAFE.getAddress(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the integer constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return integer constant pool entry at index + */ + private int getIntAt(int index) { + assertTag(index, JVM_CONSTANT.Integer); + return UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the long constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return long constant pool entry + */ + private long getLongAt(int index) { + assertTag(index, JVM_CONSTANT.Long); + return UNSAFE.getLong(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the float constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return float constant pool entry + */ + private float getFloatAt(int index) { + assertTag(index, JVM_CONSTANT.Float); + return UNSAFE.getFloat(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the double constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return float constant pool entry + */ + private double getDoubleAt(int index) { + assertTag(index, JVM_CONSTANT.Double); + return UNSAFE.getDouble(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return {@code JVM_CONSTANT_NameAndType} constant pool entry + */ + private int getNameAndTypeAt(int index) { + assertTag(index, JVM_CONSTANT.NameAndType); + return UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} reference index constant pool entry at index + * {@code index}. + * + * @param index constant pool index + * @return {@code JVM_CONSTANT_NameAndType} reference constant pool entry + */ + private int getNameAndTypeRefIndexAt(int index) { + return runtime().getCompilerToVM().lookupNameAndTypeRefIndexInPool(this, index); + } + + /** + * Gets the name of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by another + * entry denoted by {@code which}. + * + * @param which constant pool index or constant pool cache index + * @return name as {@link String} + */ + private String getNameOf(int which) { + return runtime().getCompilerToVM().lookupNameInPool(this, which); + } + + /** + * Gets the name reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry at + * index {@code index}. + * + * @param index constant pool index + * @return name reference index + */ + private int getNameRefIndexAt(int index) { + final int refIndex = getNameAndTypeAt(index); + // name ref index is in the low 16-bits. + return refIndex & 0xFFFF; + } + + /** + * Gets the signature of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by + * another entry denoted by {@code which}. + * + * @param which constant pool index or constant pool cache index + * @return signature as {@link String} + */ + private String getSignatureOf(int which) { + return runtime().getCompilerToVM().lookupSignatureInPool(this, which); + } + + /** + * Gets the signature reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry + * at index {@code index}. + * + * @param index constant pool index + * @return signature reference index + */ + private int getSignatureRefIndexAt(int index) { + final int refIndex = getNameAndTypeAt(index); + // signature ref index is in the high 16-bits. + return refIndex >>> 16; + } + + /** + * Gets the klass reference index constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return klass reference index + */ + private int getKlassRefIndexAt(int index) { + return runtime().getCompilerToVM().lookupKlassRefIndexInPool(this, index); + } + + /** + * Gets the uncached klass reference index constant pool entry at index {@code index}. See: + * {@code ConstantPool::uncached_klass_ref_index_at}. + * + * @param index constant pool index + * @return klass reference index + */ + private int getUncachedKlassRefIndexAt(int index, JVM_CONSTANT tag) { + int resultIndex; + if (tag == JVM_CONSTANT.MethodRef || tag == JVM_CONSTANT.Fieldref || tag == JVM_CONSTANT.InterfaceMethodref) { + assertTagIsFieldOrMethod(index); + final int refIndex = UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + // klass ref index is in the low 16-bits. + resultIndex = refIndex & 0xFFFF; + } else { + resultIndex = index; + } + + // Read the tag only once because it could change between multiple reads. + final JVM_CONSTANT klassTag = getTagAt(resultIndex); + assert klassTag == JVM_CONSTANT.Class || klassTag == JVM_CONSTANT.UnresolvedClass || klassTag == JVM_CONSTANT.UnresolvedClassInError : klassTag; + + return resultIndex; + } + + /** + * Asserts that the constant pool index {@code index} is in the bounds of the constant pool. + * + * @param index constant pool index + */ + private void assertBounds(int index) { + assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length(); + } + + /** + * Asserts that the constant pool tag at index {@code index} is equal to {@code tag}. + * + * @param index constant pool index + * @param tag expected tag + */ + private void assertTag(int index, JVM_CONSTANT tag) { + final JVM_CONSTANT tagAt = getTagAt(index); + assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag; + } + + /** + * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref}, + * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}. + * + * @param index constant pool index + */ + private void assertTagIsFieldOrMethod(int index) { + final JVM_CONSTANT tagAt = getTagAt(index); + assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt; + } + + @Override + public int length() { + return UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolLengthOffset); + } + + @Override + public Object lookupConstant(int cpi) { + assert cpi != 0; + final JVM_CONSTANT tag = getTagAt(cpi); + switch (tag) { + case Integer: + return JavaConstant.forInt(getIntAt(cpi)); + case Long: + return JavaConstant.forLong(getLongAt(cpi)); + case Float: + return JavaConstant.forFloat(getFloatAt(cpi)); + case Double: + return JavaConstant.forDouble(getDoubleAt(cpi)); + case Class: + case UnresolvedClass: + case UnresolvedClassInError: + final int opcode = -1; // opcode is not used + return lookupType(cpi, opcode); + case String: + /* + * Normally, we would expect a String here, but anonymous classes can have + * "pseudo strings" (arbitrary live objects) patched into a String entry. Such + * entries do not have a symbol in the constant pool slot. + */ + Object string = runtime().getCompilerToVM().resolvePossiblyCachedConstantInPool(this, cpi); + return HotSpotObjectConstantImpl.forObject(string); + case MethodHandle: + case MethodHandleInError: + case MethodType: + case MethodTypeInError: + Object obj = runtime().getCompilerToVM().resolveConstantInPool(this, cpi); + return HotSpotObjectConstantImpl.forObject(obj); + default: + throw new JVMCIError("Unknown constant pool tag %s", tag); + } + } + + @Override + public String lookupUtf8(int cpi) { + assertTag(cpi, JVM_CONSTANT.Utf8); + return runtime().getCompilerToVM().getSymbol(getEntryAt(cpi)); + } + + @Override + public Signature lookupSignature(int cpi) { + return new HotSpotSignature(runtime(), lookupUtf8(cpi)); + } + + @Override + public JavaConstant lookupAppendix(int cpi, int opcode) { + assert Bytecodes.isInvoke(opcode); + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + Object appendix = runtime().getCompilerToVM().lookupAppendixInPool(this, index); + if (appendix == null) { + return null; + } else { + return HotSpotObjectConstantImpl.forObject(appendix); + } + } + + /** + * Gets a {@link JavaType} corresponding a given resolved or unresolved type. + * + * @param type either a ResolvedJavaType or a String naming a unresolved type. + */ + private static JavaType getJavaType(final Object type) { + if (type instanceof String) { + String name = (String) type; + return HotSpotUnresolvedJavaType.create(runtime(), "L" + name + ";"); + } else { + return (JavaType) type; + } + } + + @Override + public JavaMethod lookupMethod(int cpi, int opcode) { + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final HotSpotResolvedJavaMethod method = runtime().getCompilerToVM().lookupMethodInPool(this, index, (byte) opcode); + if (method != null) { + return method; + } else { + // Get the method's name and signature. + String name = getNameOf(index); + HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureOf(index)); + if (opcode == Bytecodes.INVOKEDYNAMIC) { + HotSpotResolvedObjectType holder = HotSpotResolvedObjectTypeImpl.fromObjectClass(MethodHandle.class); + return new HotSpotMethodUnresolved(name, signature, holder); + } else { + final int klassIndex = getKlassRefIndexAt(index); + final Object type = runtime().getCompilerToVM().lookupKlassInPool(this, klassIndex); + JavaType holder = getJavaType(type); + return new HotSpotMethodUnresolved(name, signature, holder); + } + } + } + + @Override + public JavaType lookupType(int cpi, int opcode) { + final LookupTypeCacheElement elem = this.lastLookupType; + if (elem != null && elem.lastCpi == cpi) { + return elem.javaType; + } else { + final Object type = runtime().getCompilerToVM().lookupKlassInPool(this, cpi); + JavaType result = getJavaType(type); + if (result instanceof ResolvedJavaType) { + this.lastLookupType = new LookupTypeCacheElement(cpi, result); + } + return result; + } + } + + @Override + public JavaField lookupField(int cpi, int opcode) { + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index); + final int nameIndex = getNameRefIndexAt(nameAndTypeIndex); + String name = lookupUtf8(nameIndex); + final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex); + String typeName = lookupUtf8(typeIndex); + JavaType type = runtime().lookupType(typeName, getHolder(), false); + + final int holderIndex = getKlassRefIndexAt(index); + JavaType holder = lookupType(holderIndex, opcode); + + if (holder instanceof HotSpotResolvedObjectTypeImpl) { + long[] info = new long[2]; + HotSpotResolvedObjectTypeImpl resolvedHolder; + try { + resolvedHolder = runtime().getCompilerToVM().resolveFieldInPool(this, index, (byte) opcode, info); + } catch (Throwable t) { + /* + * If there was an exception resolving the field we give up and return an unresolved + * field. + */ + return new HotSpotUnresolvedField(holder, name, type); + } + final int flags = (int) info[0]; + final long offset = info[1]; + HotSpotResolvedJavaField result = resolvedHolder.createField(name, type, offset, flags); + return result; + } else { + return new HotSpotUnresolvedField(holder, name, type); + } + } + + @Override + @SuppressWarnings("fallthrough") + public void loadReferencedType(int cpi, int opcode) { + int index; + switch (opcode) { + case Bytecodes.CHECKCAST: + case Bytecodes.INSTANCEOF: + case Bytecodes.NEW: + case Bytecodes.ANEWARRAY: + case Bytecodes.MULTIANEWARRAY: + case Bytecodes.LDC: + case Bytecodes.LDC_W: + case Bytecodes.LDC2_W: + index = cpi; + break; + case Bytecodes.INVOKEDYNAMIC: { + // invokedynamic instructions point to a constant pool cache entry. + index = decodeConstantPoolCacheIndex(cpi) + runtime().getConfig().constantPoolCpCacheIndexTag; + index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); + break; + } + case Bytecodes.GETSTATIC: + case Bytecodes.PUTSTATIC: + case Bytecodes.GETFIELD: + case Bytecodes.PUTFIELD: + case Bytecodes.INVOKEVIRTUAL: + case Bytecodes.INVOKESPECIAL: + case Bytecodes.INVOKESTATIC: + case Bytecodes.INVOKEINTERFACE: { + // invoke and field instructions point to a constant pool cache entry. + index = rawIndexToConstantPoolIndex(cpi, opcode); + index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); + break; + } + default: + throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode); + } + + final JVM_CONSTANT tag = getTagAt(index); + if (tag == null) { + assert getTagAt(index - 1) == JVM_CONSTANT.Double || getTagAt(index - 1) == JVM_CONSTANT.Long; + return; + } + switch (tag) { + case MethodRef: + case Fieldref: + case InterfaceMethodref: + case Class: + case UnresolvedClass: + case UnresolvedClassInError: + index = getUncachedKlassRefIndexAt(index, tag); + final HotSpotResolvedObjectTypeImpl type = runtime().getCompilerToVM().resolveTypeInPool(this, index); + Class klass = type.mirror(); + if (!klass.isPrimitive() && !klass.isArray()) { + UNSAFE.ensureClassInitialized(klass); + } + switch (tag) { + case MethodRef: + if (Bytecodes.isInvokeHandleAlias(opcode)) { + final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode); + if (isInvokeHandle(methodRefCacheIndex, type)) { + runtime().getCompilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex); + } + } + } + break; + case InvokeDynamic: + if (isInvokedynamicIndex(cpi)) { + runtime().getCompilerToVM().resolveInvokeDynamicInPool(this, cpi); + } + break; + default: + // nothing + break; + } + } + + private boolean isInvokeHandle(int methodRefCacheIndex, HotSpotResolvedObjectTypeImpl klass) { + assertTag(runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef); + return ResolvedJavaMethod.isSignaturePolymorphic(klass, getNameOf(methodRefCacheIndex), runtime().getHostJVMCIBackend().getMetaAccess()); + } + + @Override + public String toString() { + HotSpotResolvedObjectType holder = getHolder(); + return "HotSpotConstantPool<" + holder.toJavaName() + ">"; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java new file mode 100644 index 00000000000..843176bae3d --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider.Options.*; + +import java.lang.reflect.*; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.options.*; + +/** + * HotSpot implementation of {@link ConstantReflectionProvider}. + */ +public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified { + + static class Options { + //@formatter:off + @Option(help = "Constant fold final fields with default values.", type = OptionType.Debug) + public static final OptionValue TrustFinalDefaultFields = new OptionValue<>(true); + //@formatter:on + } + + protected final HotSpotJVMCIRuntimeProvider runtime; + protected final HotSpotMethodHandleAccessProvider methodHandleAccess; + protected final HotSpotMemoryAccessProviderImpl memoryAccess; + + public HotSpotConstantReflectionProvider(HotSpotJVMCIRuntimeProvider runtime) { + this.runtime = runtime; + this.methodHandleAccess = new HotSpotMethodHandleAccessProvider(this); + this.memoryAccess = new HotSpotMemoryAccessProviderImpl(runtime); + } + + public MethodHandleAccessProvider getMethodHandleAccess() { + return methodHandleAccess; + } + + @Override + public MemoryAccessProvider getMemoryAccessProvider() { + return memoryAccess; + } + + @Override + public boolean isEmbeddable(Constant constant) { + return true; + } + + @Override + public Boolean constantEquals(Constant x, Constant y) { + if (x == y) { + return true; + } else if (x instanceof HotSpotObjectConstantImpl) { + return y instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) x).object() == ((HotSpotObjectConstantImpl) y).object(); + } else { + return x.equals(y); + } + } + + @Override + public Integer readArrayLength(JavaConstant array) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return null; + } + + Object arrayObject = ((HotSpotObjectConstantImpl) array).object(); + if (!arrayObject.getClass().isArray()) { + return null; + } + return Array.getLength(arrayObject); + } + + public JavaConstant readConstantArrayElement(JavaConstant array, int index) { + if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) { + JavaConstant element = readArrayElement(array, index); + if (element != null && (((HotSpotObjectConstantImpl) array).isDefaultStable() || !element.isDefaultForKind())) { + return element; + } + } + return null; + } + + /** + * Try to convert {@code offset} into an an index into {@code array}. + * + * @return the computed index or -1 if the offset isn't within the array + */ + private int indexForOffset(JavaConstant array, long offset) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return -1; + } + Class componentType = ((HotSpotObjectConstantImpl) array).object().getClass().getComponentType(); + JavaKind kind = runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(componentType).getJavaKind(); + int arraybase = runtime.getArrayBaseOffset(kind); + int scale = runtime.getArrayIndexScale(kind); + if (offset < arraybase) { + return -1; + } + long index = offset - arraybase; + if (index % scale != 0) { + return -1; + } + long result = index / scale; + if (result >= Integer.MAX_VALUE) { + return -1; + } + return (int) result; + } + + public JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset) { + if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) { + return readConstantArrayElement(array, indexForOffset(array, offset)); + } + return null; + } + + @Override + public JavaConstant readArrayElement(JavaConstant array, int index) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return null; + } + Object a = ((HotSpotObjectConstantImpl) array).object(); + + if (index < 0 || index >= Array.getLength(a)) { + return null; + } + + if (a instanceof Object[]) { + Object element = ((Object[]) a)[index]; + if (((HotSpotObjectConstantImpl) array).getStableDimension() > 1) { + return HotSpotObjectConstantImpl.forStableArray(element, ((HotSpotObjectConstantImpl) array).getStableDimension() - 1, ((HotSpotObjectConstantImpl) array).isDefaultStable()); + } else { + return HotSpotObjectConstantImpl.forObject(element); + } + } else { + return JavaConstant.forBoxedPrimitive(Array.get(a, index)); + } + } + + /** + * Check if the constant is a boxed value that is guaranteed to be cached by the platform. + * Otherwise the generated code might be the only reference to the boxed value and since object + * references from nmethods are weak this can cause GC problems. + * + * @param source + * @return true if the box is cached + */ + private static boolean isBoxCached(JavaConstant source) { + switch (source.getJavaKind()) { + case Boolean: + return true; + case Char: + return source.asInt() <= 127; + case Byte: + case Short: + case Int: + return source.asInt() >= -128 && source.asInt() <= 127; + case Long: + return source.asLong() >= -128 && source.asLong() <= 127; + case Float: + case Double: + return false; + default: + throw new IllegalArgumentException("unexpected kind " + source.getJavaKind()); + } + } + + @Override + public JavaConstant boxPrimitive(JavaConstant source) { + if (!source.getJavaKind().isPrimitive() || !isBoxCached(source)) { + return null; + } + return HotSpotObjectConstantImpl.forObject(source.asBoxedPrimitive()); + } + + @Override + public JavaConstant unboxPrimitive(JavaConstant source) { + if (!source.getJavaKind().isObject()) { + return null; + } + if (source.isNull()) { + return null; + } + return JavaConstant.forBoxedPrimitive(((HotSpotObjectConstantImpl) source).object()); + } + + public JavaConstant forString(String value) { + return HotSpotObjectConstantImpl.forObject(value); + } + + @Override + public ResolvedJavaType asJavaType(Constant constant) { + if (constant instanceof HotSpotObjectConstant) { + Object obj = ((HotSpotObjectConstantImpl) constant).object(); + if (obj instanceof Class) { + return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType((Class) obj); + } + } + if (constant instanceof HotSpotMetaspaceConstant) { + Object obj = HotSpotMetaspaceConstantImpl.getMetaspaceObject(constant); + if (obj instanceof HotSpotResolvedObjectTypeImpl) { + return (ResolvedJavaType) obj; + } + } + return null; + } + + private static final String SystemClassName = "Ljava/lang/System;"; + + /** + * Determines if a static field is constant for the purpose of + * {@link #readConstantFieldValue(JavaField, JavaConstant)}. + */ + protected boolean isStaticFieldConstant(HotSpotResolvedJavaField staticField) { + if (staticField.isFinal() || staticField.isStable()) { + ResolvedJavaType holder = staticField.getDeclaringClass(); + if (holder.isInitialized() && !holder.getName().equals(SystemClassName)) { + return true; + } + } + return false; + } + + /** + * Determines if a value read from a {@code final} instance field is considered constant. The + * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is + * not the {@link JavaConstant#isDefaultForKind default value} for its kind or if + * {@link Options#TrustFinalDefaultFields} is true. + * + * @param value a value read from a {@code final} instance field + * @param receiverClass the {@link Object#getClass() class} of object from which the + * {@code value} was read + */ + protected boolean isFinalInstanceFieldValueConstant(JavaConstant value, Class receiverClass) { + return !value.isDefaultForKind() || TrustFinalDefaultFields.getValue(); + } + + /** + * Determines if a value read from a {@link Stable} instance field is considered constant. The + * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is + * not the {@link JavaConstant#isDefaultForKind default value} for its kind. + * + * @param value a value read from a {@link Stable} field + * @param receiverClass the {@link Object#getClass() class} of object from which the + * {@code value} was read + */ + protected boolean isStableInstanceFieldValueConstant(JavaConstant value, Class receiverClass) { + return !value.isDefaultForKind(); + } + + /** + * {@inheritDoc} + *

+ * The {@code value} field in {@link OptionValue} is considered constant if the type of + * {@code receiver} is (assignable to) {@link StableOptionValue}. + */ + public JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver) { + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + + if (hotspotField.isStatic()) { + if (isStaticFieldConstant(hotspotField)) { + JavaConstant value = readFieldValue(field, receiver); + if (hotspotField.isFinal() || !value.isDefaultForKind()) { + return value; + } + } + } else { + /* + * for non-static final fields, we must assume that they are only initialized if they + * have a non-default value. + */ + Object object = receiver.isNull() ? null : ((HotSpotObjectConstantImpl) receiver).object(); + + // Canonicalization may attempt to process an unsafe read before + // processing a guard (e.g. a null check or a type check) for this read + // so we need to check the object being read + if (object != null) { + if (hotspotField.isFinal()) { + if (hotspotField.isInObject(object)) { + JavaConstant value = readFieldValue(field, receiver); + if (isFinalInstanceFieldValueConstant(value, object.getClass())) { + return value; + } + } + } else if (hotspotField.isStable()) { + if (hotspotField.isInObject(object)) { + JavaConstant value = readFieldValue(field, receiver); + if (isStableInstanceFieldValueConstant(value, object.getClass())) { + return value; + } + } + } else { + Class clazz = object.getClass(); + if (StableOptionValue.class.isAssignableFrom(clazz)) { + if (hotspotField.isInObject(object) && hotspotField.getName().equals("value")) { + StableOptionValue option = (StableOptionValue) object; + return HotSpotObjectConstantImpl.forObject(option.getValue()); + } + } + } + } + } + return null; + } + + public JavaConstant readFieldValue(JavaField field, JavaConstant receiver) { + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + if (!hotspotField.isStable()) { + return readNonStableFieldValue(field, receiver); + } else { + return readStableFieldValue(field, receiver, false); + } + } + + private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) { + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + if (hotspotField.isStatic()) { + HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass(); + if (holder.isInitialized()) { + return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset()); + } + } else { + if (receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object())) { + return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), receiver, hotspotField.offset()); + } + } + return null; + } + + public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) { + JavaConstant fieldValue = readNonStableFieldValue(field, receiver); + if (fieldValue.isNonNull()) { + JavaType declaredType = field.getType(); + if (declaredType.getComponentType() != null) { + int stableDimension = getArrayDimension(declaredType); + return HotSpotObjectConstantImpl.forStableArray(((HotSpotObjectConstantImpl) fieldValue).object(), stableDimension, isDefaultStable); + } + } + return fieldValue; + } + + private static int getArrayDimension(JavaType type) { + int dimensions = 0; + JavaType componentType = type; + while ((componentType = componentType.getComponentType()) != null) { + dimensions++; + } + return dimensions; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java new file mode 100644 index 00000000000..b13958b6995 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +public class HotSpotForeignCallTarget { + + /** + * The entry point address of this call's target. + */ + protected long address; + + public HotSpotForeignCallTarget(long address) { + this.address = address; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotInstalledCode.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotInstalledCode.java new file mode 100644 index 00000000000..00277ecd3f4 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotInstalledCode.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.inittimer.SuppressFBWarnings; +import sun.misc.Unsafe; + +/** + * Implementation of {@link InstalledCode} for HotSpot. + */ +public abstract class HotSpotInstalledCode extends InstalledCode { + + /** + * Total size of the code blob. + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int size; + + /** + * Start address of the code. + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private long codeStart; + + /** + * Size of the code. + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int codeSize; + + public HotSpotInstalledCode(String name) { + super(name); + } + + /** + * @return the total size of this code blob + */ + public int getSize() { + return size; + } + + /** + * @return a copy of this code blob if it is {@linkplain #isValid() valid}, null otherwise. + */ + public byte[] getBlob() { + if (!isValid()) { + return null; + } + byte[] blob = new byte[size]; + UNSAFE.copyMemory(null, getAddress(), blob, Unsafe.ARRAY_BYTE_BASE_OFFSET, size); + return blob; + } + + @Override + public abstract String toString(); + + @Override + public long getStart() { + return codeStart; + } + + @Override + public long getCodeSize() { + return codeSize; + } + + @Override + public byte[] getCode() { + if (!isValid()) { + return null; + } + byte[] code = new byte[codeSize]; + UNSAFE.copyMemory(null, codeStart, code, Unsafe.ARRAY_BYTE_BASE_OFFSET, codeSize); + return code; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java new file mode 100644 index 00000000000..50c51da78e9 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.compiler.*; +import jdk.vm.ci.runtime.*; + +public interface HotSpotJVMCIBackendFactory { + + JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntimeProvider runtime, CompilerFactory compilerFactory, JVMCIBackend host); + + /** + * Gets the CPU architecture of this backend. + */ + String getArchitecture(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java new file mode 100644 index 00000000000..1a0e5423165 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.compiler.*; +import jdk.vm.ci.compiler.Compiler; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; +import jdk.vm.ci.service.*; + +final class HotSpotJVMCICompilerConfig { + + private static class DummyCompilerFactory implements CompilerFactory, Compiler { + + public void compileMethod(ResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) { + throw new JVMCIError("no JVMCI compiler selected"); + } + + public String getCompilerName() { + return ""; + } + + public Architecture initializeArchitecture(Architecture arch) { + return arch; + } + + public Compiler createCompiler(JVMCIRuntime runtime) { + return this; + } + } + + private static CompilerFactory compilerFactory; + + /** + * Selects the system compiler. + * + * Called from VM. This method has an object return type to allow it to be called with a VM + * utility function used to call other static initialization methods. + */ + static Boolean selectCompiler(String compilerName) { + assert compilerFactory == null; + for (CompilerFactory factory : Services.load(CompilerFactory.class)) { + if (factory.getCompilerName().equals(compilerName)) { + compilerFactory = factory; + return Boolean.TRUE; + } + } + + throw new JVMCIError("JVMCI compiler '%s' not found", compilerName); + } + + static CompilerFactory getCompilerFactory() { + if (compilerFactory == null) { + compilerFactory = new DummyCompilerFactory(); + } + return compilerFactory; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext.java new file mode 100644 index 00000000000..b3bad532f7f --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.lang.ref.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * This class manages the set of metadata roots that must be scanned during garbage collection. + * Because of class redefinition Method* and ConstantPool* can be freed if they don't appear to be + * in use so they must be tracked when there are live references to them from Java. + * + * The general theory of operation is that all {@link MetaspaceWrapperObject}s are created by + * calling into the VM which calls back out to actually create the wrapper instance. During the call + * the VM keeps the metadata reference alive through the use of metadata handles. Once the call + * completes the wrapper object is registered here and will be scanned during metadata scanning. The + * weakness of the reference to the wrapper object allows them to be reclaimed when they are no + * longer used. + * + */ +public class HotSpotJVMCIMetaAccessContext implements JVMCIMetaAccessContext { + + /** + * The set of currently live contexts used for tracking of live metadata. Examined from the VM + * during garbage collection. + */ + private static WeakReference[] allContexts = new WeakReference[0]; + + /** + * This is a chunked list of metadata roots. It can be read from VM native code so it's been + * marked volatile to ensure the order of updates are respected. + */ + private volatile Object[] metadataRoots; + + private ChunkedList> list = new ChunkedList<>(); + + /** + * The number of weak references freed since the last time the list was shrunk. + */ + private int freed; + + /** + * The {@link ReferenceQueue} tracking the weak references created by this context. + */ + private final ReferenceQueue queue = new ReferenceQueue<>(); + + static synchronized void add(HotSpotJVMCIMetaAccessContext context) { + for (int i = 0; i < allContexts.length; i++) { + if (allContexts[i] == null || allContexts[i].get() == null) { + allContexts[i] = new WeakReference<>(context); + return; + } + } + int index = allContexts.length; + allContexts = Arrays.copyOf(allContexts, index + 2); + allContexts[index] = new WeakReference<>(context); + } + + HotSpotJVMCIMetaAccessContext() { + add(this); + } + + /** + * Periodically trim the list of tracked metadata. A new list is created to replace the old to + * avoid concurrent scanning issues. + */ + private void clean() { + Reference ref = queue.poll(); + if (ref == null) { + return; + } + while (ref != null) { + freed++; + ref = queue.poll(); + } + if (freed > list.size() / 2) { + ChunkedList> newList = new ChunkedList<>(); + for (WeakReference element : list) { + /* + * The referent could become null anywhere in here but it doesn't matter. It will + * get cleaned up next time. + */ + if (element != null && element.get() != null) { + newList.add(element); + } + } + list = newList; + metadataRoots = list.getHead(); + freed = 0; + } + } + + /** + * Add a {@link MetaspaceWrapperObject} to tracked by the GC. It's assumed that the caller is + * responsible for keeping the reference alive for the duration of the call. Once registration + * is complete then the VM will ensure it's kept alive. + * + * @param metaspaceObject + */ + + public synchronized void add(MetaspaceWrapperObject metaspaceObject) { + clean(); + list.add(new WeakReference<>(metaspaceObject, queue)); + if (list.getHead() != metadataRoots) { + /* + * The list enlarged so update the head. + */ + metadataRoots = list.getHead(); + } + } + + protected ResolvedJavaType createClass(Class javaClass) { + if (javaClass.isPrimitive()) { + JavaKind kind = JavaKind.fromJavaClass(javaClass); + return new HotSpotResolvedPrimitiveType(kind); + } else { + return new HotSpotResolvedObjectTypeImpl(javaClass, this); + } + } + + private final Map, WeakReference> typeMap = new WeakHashMap<>(); + + @Override + public synchronized ResolvedJavaType fromClass(Class javaClass) { + WeakReference typeRef = typeMap.get(javaClass); + ResolvedJavaType type = typeRef != null ? typeRef.get() : null; + if (type == null) { + type = createClass(javaClass); + typeMap.put(javaClass, new WeakReference<>(type)); + } + return type; + } + + /** + * A very simple append only chunked list implementation. + */ + static class ChunkedList implements Iterable { + private static final int CHUNK_SIZE = 32; + + private static final int NEXT_CHUNK_INDEX = CHUNK_SIZE - 1; + + private Object[] head; + private int index; + private int size; + + ChunkedList() { + head = new Object[CHUNK_SIZE]; + index = 0; + } + + void add(T element) { + if (index == NEXT_CHUNK_INDEX) { + Object[] newHead = new Object[CHUNK_SIZE]; + newHead[index] = head; + head = newHead; + index = 0; + } + head[index++] = element; + size++; + } + + Object[] getHead() { + return head; + } + + public Iterator iterator() { + return new ChunkIterator<>(); + } + + int size() { + return size; + } + + class ChunkIterator implements Iterator { + + ChunkIterator() { + currentChunk = head; + currentIndex = -1; + findNext(); + } + + Object[] currentChunk; + int currentIndex; + V next; + + @SuppressWarnings("unchecked") + V findNext() { + V result; + do { + currentIndex++; + if (currentIndex == NEXT_CHUNK_INDEX) { + currentChunk = (Object[]) currentChunk[currentIndex]; + currentIndex = 0; + if (currentChunk == null) { + return null; + } + } + result = (V) currentChunk[currentIndex]; + } while (result == null); + return result; + } + + public boolean hasNext() { + return next != null; + } + + public V next() { + V result = next; + next = findNext(); + return result; + } + + } + + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java new file mode 100644 index 00000000000..6b5204f5161 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.inittimer.InitTimer.*; + +import java.util.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.compiler.*; +import jdk.vm.ci.compiler.Compiler; +import jdk.vm.ci.inittimer.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; +import jdk.vm.ci.service.*; + +//JaCoCo Exclude + +public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider, HotSpotProxified { + + /** + * The proper initialization of this class is complex because it's tangled up with the + * initialization of the JVMCI and really should only ever be triggered through + * {@link JVMCI#getRuntime}. However since {@link #runtime} can also be called directly it + * should also trigger proper initialization. To ensure proper ordering, the static initializer + * of this class initializes {@link JVMCI} and then access to {@link DelayedInit#instance} + * triggers the final initialization of the {@link HotSpotJVMCIRuntime}. + */ + static { + JVMCI.initialize(); + } + + @SuppressWarnings("try") + static class DelayedInit { + private static final HotSpotJVMCIRuntime instance; + + static { + try (InitTimer t0 = timer("HotSpotJVMCIRuntime.")) { + try (InitTimer t = timer("StartupEventListener.beforeJVMCIStartup")) { + for (StartupEventListener l : Services.load(StartupEventListener.class)) { + l.beforeJVMCIStartup(); + } + } + + try (InitTimer t = timer("HotSpotJVMCIRuntime.")) { + instance = new HotSpotJVMCIRuntime(); + } + + try (InitTimer t = timer("HotSpotJVMCIRuntime.completeInitialization")) { + instance.completeInitialization(); + } + } + } + } + + /** + * Gets the singleton {@link HotSpotJVMCIRuntime} object. + */ + public static HotSpotJVMCIRuntime runtime() { + assert DelayedInit.instance != null; + return DelayedInit.instance; + } + + /** + * Do deferred initialization. + */ + public void completeInitialization() { + compiler = HotSpotJVMCICompilerConfig.getCompilerFactory().createCompiler(this); + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + vmEventListener.completeInitialization(this); + } + } + + public static HotSpotJVMCIBackendFactory findFactory(String architecture) { + for (HotSpotJVMCIBackendFactory factory : Services.load(HotSpotJVMCIBackendFactory.class)) { + if (factory.getArchitecture().equalsIgnoreCase(architecture)) { + return factory; + } + } + + throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture); + } + + /** + * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend. + */ + public static JavaKind getHostWordKind() { + return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordKind; + } + + protected final CompilerToVM compilerToVm; + + protected final HotSpotVMConfig config; + private final JVMCIBackend hostBackend; + + private Compiler compiler; + protected final JVMCIMetaAccessContext metaAccessContext; + + private final Map, JVMCIBackend> backends = new HashMap<>(); + + private final Iterable vmEventListeners; + + @SuppressWarnings("try") + private HotSpotJVMCIRuntime() { + compilerToVm = new CompilerToVM(); + try (InitTimer t = timer("HotSpotVMConfig")) { + config = new HotSpotVMConfig(compilerToVm); + } + + String hostArchitecture = config.getHostArchitectureName(); + + HotSpotJVMCIBackendFactory factory; + try (InitTimer t = timer("find factory:", hostArchitecture)) { + factory = findFactory(hostArchitecture); + } + + CompilerFactory compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory(); + + try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) { + hostBackend = registerBackend(factory.createJVMCIBackend(this, compilerFactory, null)); + } + + vmEventListeners = Services.load(HotSpotVMEventListener.class); + + JVMCIMetaAccessContext context = null; + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + context = vmEventListener.createMetaAccessContext(this); + if (context != null) { + break; + } + } + if (context == null) { + context = new HotSpotJVMCIMetaAccessContext(); + } + metaAccessContext = context; + } + + private JVMCIBackend registerBackend(JVMCIBackend backend) { + Class arch = backend.getCodeCache().getTarget().arch.getClass(); + JVMCIBackend oldValue = backends.put(arch, backend); + assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); + return backend; + } + + public ResolvedJavaType fromClass(Class javaClass) { + return metaAccessContext.fromClass(javaClass); + } + + public HotSpotVMConfig getConfig() { + return config; + } + + public CompilerToVM getCompilerToVM() { + return compilerToVm; + } + + public JVMCIMetaAccessContext getMetaAccessContext() { + return metaAccessContext; + } + + public Compiler getCompiler() { + return compiler; + } + + public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { + Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); + // If the name represents a primitive type we can short-circuit the lookup. + if (name.length() == 1) { + JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); + return fromClass(kind.toJavaClass()); + } + + // Resolve non-primitive types in the VM. + HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; + final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve); + + if (klass == null) { + assert resolve == false; + return HotSpotUnresolvedJavaType.create(this, name); + } + return klass; + } + + public JVMCIBackend getHostJVMCIBackend() { + return hostBackend; + } + + public JVMCIBackend getJVMCIBackend(Class arch) { + assert arch != Architecture.class; + return backends.get(arch); + } + + public Map, JVMCIBackend> getBackends() { + return Collections.unmodifiableMap(backends); + } + + /** + * Called from the VM. + */ + @SuppressWarnings({"unused"}) + private void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) { + compiler.compileMethod(method, entryBCI, jvmciEnv, id); + } + + /** + * Shuts down the runtime. + * + * Called from the VM. + */ + @SuppressWarnings({"unused"}) + private void shutdown() throws Exception { + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + vmEventListener.notifyShutdown(); + } + } + + /** + * Notify on successful install into the CodeCache. + * + * @param hotSpotCodeCacheProvider + * @param installedCode + * @param compResult + */ + void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompilationResult compResult) { + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compResult); + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntimeProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntimeProvider.java new file mode 100644 index 00000000000..13665ac0f56 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntimeProvider.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.compiler.Compiler; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; +import sun.misc.*; + +//JaCoCo Exclude + +/** + * Configuration information for the HotSpot JVMCI runtime. + */ +public interface HotSpotJVMCIRuntimeProvider extends JVMCIRuntime { + + HotSpotVMConfig getConfig(); + + CompilerToVM getCompilerToVM(); + + Compiler getCompiler(); + + /** + * Converts a name to a Java type. This method attempts to resolve {@code name} to a + * {@link ResolvedJavaType}. + * + * @param name a well formed Java type in {@linkplain JavaType#getName() internal} format + * @param accessingType the context of resolution which must be non-null + * @param resolve specifies whether resolution failure results in an unresolved type being + * return or a {@link LinkageError} being thrown + * @return a Java type for {@code name} which is guaranteed to be of type + * {@link ResolvedJavaType} if {@code resolve == true} + * @throws LinkageError if {@code resolve == true} and the resolution failed + * @throws NullPointerException if {@code accessingClass} is {@code null} + */ + JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve); + + /** + * Gets the JVMCI mirror for a {@link Class} object. + * + * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} + */ + ResolvedJavaType fromClass(Class clazz); + + JVMCIMetaAccessContext getMetaAccessContext(); + + /** + * The offset from the origin of an array to the first element. + * + * @return the offset in bytes + */ + default int getArrayBaseOffset(JavaKind kind) { + switch (kind) { + case Boolean: + return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; + case Byte: + return Unsafe.ARRAY_BYTE_BASE_OFFSET; + case Char: + return Unsafe.ARRAY_CHAR_BASE_OFFSET; + case Short: + return Unsafe.ARRAY_SHORT_BASE_OFFSET; + case Int: + return Unsafe.ARRAY_INT_BASE_OFFSET; + case Long: + return Unsafe.ARRAY_LONG_BASE_OFFSET; + case Float: + return Unsafe.ARRAY_FLOAT_BASE_OFFSET; + case Double: + return Unsafe.ARRAY_DOUBLE_BASE_OFFSET; + case Object: + return Unsafe.ARRAY_OBJECT_BASE_OFFSET; + default: + throw new JVMCIError("%s", kind); + } + } + + /** + * The scale used for the index when accessing elements of an array of this kind. + * + * @return the scale in order to convert the index into a byte offset + */ + default int getArrayIndexScale(JavaKind kind) { + switch (kind) { + case Boolean: + return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; + case Byte: + return Unsafe.ARRAY_BYTE_INDEX_SCALE; + case Char: + return Unsafe.ARRAY_CHAR_INDEX_SCALE; + case Short: + return Unsafe.ARRAY_SHORT_INDEX_SCALE; + case Int: + return Unsafe.ARRAY_INT_INDEX_SCALE; + case Long: + return Unsafe.ARRAY_LONG_INDEX_SCALE; + case Float: + return Unsafe.ARRAY_FLOAT_INDEX_SCALE; + case Double: + return Unsafe.ARRAY_DOUBLE_INDEX_SCALE; + case Object: + return Unsafe.ARRAY_OBJECT_INDEX_SCALE; + default: + throw new JVMCIError("%s", kind); + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJavaType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJavaType.java new file mode 100644 index 00000000000..8c1a9808d7e --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJavaType.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * Common base class for all HotSpot {@link JavaType} implementations. + */ +public abstract class HotSpotJavaType implements JavaType { + + private final String name; + + public HotSpotJavaType(String name) { + this.name = name; + } + + @Override + public final String getName() { + return name; + } + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java new file mode 100644 index 00000000000..ed48d9b34f4 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.hotspot.HotSpotVMConfig.*; +import jdk.vm.ci.meta.*; + +/** + * HotSpot specific extension of {@link MemoryAccessProvider}. + */ +public interface HotSpotMemoryAccessProvider extends MemoryAccessProvider { + + JavaConstant readNarrowOopConstant(Constant base, long displacement, CompressEncoding encoding); + + Constant readKlassPointerConstant(Constant base, long displacement); + + Constant readNarrowKlassPointerConstant(Constant base, long displacement, CompressEncoding encoding); + + Constant readMethodPointerConstant(Constant base, long displacement); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java new file mode 100644 index 00000000000..40efe0319c5 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.hotspot.HotSpotVMConfig.CompressEncoding; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.PrimitiveConstant; + +/** + * HotSpot implementation of {@link MemoryAccessProvider}. + */ +public class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider, HotSpotProxified { + + protected final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotMemoryAccessProviderImpl(HotSpotJVMCIRuntimeProvider runtime) { + this.runtime = runtime; + } + + private static Object asObject(Constant base) { + if (base instanceof HotSpotObjectConstantImpl) { + return ((HotSpotObjectConstantImpl) base).object(); + } else { + return null; + } + } + + private boolean isValidObjectFieldDisplacement(Constant base, long displacement) { + if (base instanceof HotSpotMetaspaceConstant) { + Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { + if (displacement == runtime.getConfig().classMirrorOffset) { + // Klass::_java_mirror is valid for all Klass* values + return true; + } + } else { + throw new JVMCIError("%s", metaspaceObject); + } + } + return false; + } + + private static long asRawPointer(Constant base) { + if (base instanceof HotSpotMetaspaceConstant) { + return ((HotSpotMetaspaceConstant) base).rawValue(); + } else if (base instanceof PrimitiveConstant) { + PrimitiveConstant prim = (PrimitiveConstant) base; + if (prim.getJavaKind().isNumericInteger()) { + return prim.asLong(); + } + } + throw new JVMCIError("%s", base); + } + + private static long readRawValue(Constant baseConstant, long displacement, int bits) { + Object base = asObject(baseConstant); + if (base != null) { + switch (bits) { + case 8: + return UNSAFE.getByte(base, displacement); + case 16: + return UNSAFE.getShort(base, displacement); + case 32: + return UNSAFE.getInt(base, displacement); + case 64: + return UNSAFE.getLong(base, displacement); + default: + throw new JVMCIError("%d", bits); + } + } else { + long pointer = asRawPointer(baseConstant); + switch (bits) { + case 8: + return UNSAFE.getByte(pointer + displacement); + case 16: + return UNSAFE.getShort(pointer + displacement); + case 32: + return UNSAFE.getInt(pointer + displacement); + case 64: + return UNSAFE.getLong(pointer + displacement); + default: + throw new JVMCIError("%d", bits); + } + } + } + + private boolean verifyReadRawObject(Object expected, Constant base, long displacement, boolean compressed) { + if (compressed == runtime.getConfig().useCompressedOops) { + Object obj = asObject(base); + if (obj != null) { + assert expected == UNSAFE.getObject(obj, displacement) : "readUnsafeOop doesn't agree with unsafe.getObject"; + } + } + if (base instanceof HotSpotMetaspaceConstant) { + Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { + if (displacement == runtime.getConfig().classMirrorOffset) { + assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror(); + } + } + } + return true; + } + + private Object readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) { + long displacement = initialDisplacement; + + Object ret; + Object base = asObject(baseConstant); + if (base == null) { + assert !compressed; + displacement += asRawPointer(baseConstant); + ret = runtime.getCompilerToVM().readUncompressedOop(displacement); + } else { + assert runtime.getConfig().useCompressedOops == compressed; + ret = UNSAFE.getObject(base, displacement); + } + assert verifyReadRawObject(ret, baseConstant, initialDisplacement, compressed); + return ret; + } + + @Override + public JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant baseConstant, long displacement) { + if (kind == JavaKind.Object) { + Object o = readRawObject(baseConstant, displacement, runtime.getConfig().useCompressedOops); + return HotSpotObjectConstantImpl.forObject(o); + } else { + return readPrimitiveConstant(kind, baseConstant, displacement, kind.getByteCount() * 8); + } + } + + @Override + public JavaConstant readPrimitiveConstant(JavaKind kind, Constant baseConstant, long initialDisplacement, int bits) { + try { + long rawValue = readRawValue(baseConstant, initialDisplacement, bits); + switch (kind) { + case Boolean: + return JavaConstant.forBoolean(rawValue != 0); + case Byte: + return JavaConstant.forByte((byte) rawValue); + case Char: + return JavaConstant.forChar((char) rawValue); + case Short: + return JavaConstant.forShort((short) rawValue); + case Int: + return JavaConstant.forInt((int) rawValue); + case Long: + return JavaConstant.forLong(rawValue); + case Float: + return JavaConstant.forFloat(Float.intBitsToFloat((int) rawValue)); + case Double: + return JavaConstant.forDouble(Double.longBitsToDouble(rawValue)); + default: + throw new JVMCIError("Unsupported kind: %s", kind); + } + } catch (NullPointerException e) { + return null; + } + } + + @Override + public JavaConstant readObjectConstant(Constant base, long displacement) { + if (!isValidObjectFieldDisplacement(base, displacement)) { + return null; + } + return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, false)); + } + + @Override + public JavaConstant readNarrowOopConstant(Constant base, long displacement, CompressEncoding encoding) { + assert encoding.equals(runtime.getConfig().getOopEncoding()) : "unexpected oop encoding: " + encoding + " != " + runtime.getConfig().getOopEncoding(); + return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, true), true); + } + + private HotSpotResolvedObjectTypeImpl readKlass(Constant base, long displacement, boolean compressed) { + assert (base instanceof HotSpotMetaspaceConstantImpl) || (base instanceof HotSpotObjectConstantImpl) : base.getClass(); + Object baseObject = (base instanceof HotSpotMetaspaceConstantImpl) ? ((HotSpotMetaspaceConstantImpl) base).asResolvedJavaType() : ((HotSpotObjectConstantImpl) base).object(); + return runtime.getCompilerToVM().getResolvedJavaType(baseObject, displacement, compressed); + } + + @Override + public Constant readKlassPointerConstant(Constant base, long displacement) { + HotSpotResolvedObjectTypeImpl klass = readKlass(base, displacement, false); + if (klass == null) { + return JavaConstant.NULL_POINTER; + } + TargetDescription target = runtime.getHostJVMCIBackend().getCodeCache().getTarget(); + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(target.wordKind, klass.getMetaspaceKlass(), klass, false); + } + + @Override + public Constant readNarrowKlassPointerConstant(Constant base, long displacement, CompressEncoding encoding) { + HotSpotResolvedObjectTypeImpl klass = readKlass(base, displacement, true); + if (klass == null) { + return HotSpotCompressedNullConstant.COMPRESSED_NULL; + } + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(JavaKind.Int, encoding.compress(klass.getMetaspaceKlass()), klass, true); + } + + @Override + public Constant readMethodPointerConstant(Constant base, long displacement) { + TargetDescription target = runtime.getHostJVMCIBackend().getCodeCache().getTarget(); + assert (base instanceof HotSpotObjectConstantImpl); + Object baseObject = ((HotSpotObjectConstantImpl) base).object(); + HotSpotResolvedJavaMethodImpl method = runtime.getCompilerToVM().getResolvedJavaMethod(baseObject, displacement); + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(target.wordKind, method.getMetaspaceMethod(), method, false); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java new file mode 100644 index 00000000000..e3fb69d8b80 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.reflect.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; + +// JaCoCo Exclude + +/** + * HotSpot implementation of {@link MetaAccessProvider}. + */ +public class HotSpotMetaAccessProvider implements MetaAccessProvider, HotSpotProxified { + + protected final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotMetaAccessProvider(HotSpotJVMCIRuntimeProvider runtime) { + this.runtime = runtime; + } + + public ResolvedJavaType lookupJavaType(Class clazz) { + if (clazz == null) { + throw new IllegalArgumentException("Class parameter was null"); + } + return runtime.fromClass(clazz); + } + + public HotSpotResolvedObjectType lookupJavaType(JavaConstant constant) { + if (constant.isNull() || !(constant instanceof HotSpotObjectConstant)) { + return null; + } + return ((HotSpotObjectConstant) constant).getType(); + } + + public Signature parseMethodDescriptor(String signature) { + return new HotSpotSignature(runtime, signature); + } + + /** + * {@link Field} object of {@link Method#slot}. + */ + private Field reflectionMethodSlot = getReflectionSlotField(Method.class); + + /** + * {@link Field} object of {@link Constructor#slot}. + */ + private Field reflectionConstructorSlot = getReflectionSlotField(Constructor.class); + + private static Field getReflectionSlotField(Class reflectionClass) { + try { + Field field = reflectionClass.getDeclaredField("slot"); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException | SecurityException e) { + throw new JVMCIError(e); + } + } + + public ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod) { + try { + Class holder = reflectionMethod.getDeclaringClass(); + Field slotField = reflectionMethod instanceof Constructor ? reflectionConstructorSlot : reflectionMethodSlot; + final int slot = slotField.getInt(reflectionMethod); + return runtime.getCompilerToVM().getResolvedJavaMethodAtSlot(holder, slot); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new JVMCIError(e); + } + } + + public ResolvedJavaField lookupJavaField(Field reflectionField) { + String name = reflectionField.getName(); + Class fieldHolder = reflectionField.getDeclaringClass(); + Class fieldType = reflectionField.getType(); + // java.lang.reflect.Field's modifiers should be enough here since VM internal modifier bits + // are not used (yet). + final int modifiers = reflectionField.getModifiers(); + final long offset = Modifier.isStatic(modifiers) ? UNSAFE.staticFieldOffset(reflectionField) : UNSAFE.objectFieldOffset(reflectionField); + + HotSpotResolvedObjectType holder = fromObjectClass(fieldHolder); + JavaType type = runtime.fromClass(fieldType); + + if (offset != -1) { + HotSpotResolvedObjectType resolved = holder; + return resolved.createField(name, type, offset, modifiers); + } else { + throw new JVMCIError("unresolved field %s", reflectionField); + } + } + + private static int intMaskRight(int n) { + assert n <= 32; + return n == 32 ? -1 : (1 << n) - 1; + } + + @Override + public JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int debugId) { + HotSpotVMConfig config = runtime.getConfig(); + int actionValue = convertDeoptAction(action); + int reasonValue = convertDeoptReason(reason); + int debugValue = debugId & intMaskRight(config.deoptimizationDebugIdBits); + JavaConstant c = JavaConstant.forInt(~((debugValue << config.deoptimizationDebugIdShift) | (reasonValue << config.deoptimizationReasonShift) | (actionValue << config.deoptimizationActionShift))); + assert c.asInt() < 0; + return c; + } + + public DeoptimizationReason decodeDeoptReason(JavaConstant constant) { + HotSpotVMConfig config = runtime.getConfig(); + int reasonValue = ((~constant.asInt()) >> config.deoptimizationReasonShift) & intMaskRight(config.deoptimizationReasonBits); + DeoptimizationReason reason = convertDeoptReason(reasonValue); + return reason; + } + + public DeoptimizationAction decodeDeoptAction(JavaConstant constant) { + HotSpotVMConfig config = runtime.getConfig(); + int actionValue = ((~constant.asInt()) >> config.deoptimizationActionShift) & intMaskRight(config.deoptimizationActionBits); + DeoptimizationAction action = convertDeoptAction(actionValue); + return action; + } + + public int decodeDebugId(JavaConstant constant) { + HotSpotVMConfig config = runtime.getConfig(); + return ((~constant.asInt()) >> config.deoptimizationDebugIdShift) & intMaskRight(config.deoptimizationDebugIdBits); + } + + public int convertDeoptAction(DeoptimizationAction action) { + HotSpotVMConfig config = runtime.getConfig(); + switch (action) { + case None: + return config.deoptActionNone; + case RecompileIfTooManyDeopts: + return config.deoptActionMaybeRecompile; + case InvalidateReprofile: + return config.deoptActionReinterpret; + case InvalidateRecompile: + return config.deoptActionMakeNotEntrant; + case InvalidateStopCompiling: + return config.deoptActionMakeNotCompilable; + default: + throw new JVMCIError("%s", action); + } + } + + public DeoptimizationAction convertDeoptAction(int action) { + HotSpotVMConfig config = runtime.getConfig(); + if (action == config.deoptActionNone) { + return DeoptimizationAction.None; + } + if (action == config.deoptActionMaybeRecompile) { + return DeoptimizationAction.RecompileIfTooManyDeopts; + } + if (action == config.deoptActionReinterpret) { + return DeoptimizationAction.InvalidateReprofile; + } + if (action == config.deoptActionMakeNotEntrant) { + return DeoptimizationAction.InvalidateRecompile; + } + if (action == config.deoptActionMakeNotCompilable) { + return DeoptimizationAction.InvalidateStopCompiling; + } + throw new JVMCIError("%d", action); + } + + public int convertDeoptReason(DeoptimizationReason reason) { + HotSpotVMConfig config = runtime.getConfig(); + switch (reason) { + case None: + return config.deoptReasonNone; + case NullCheckException: + return config.deoptReasonNullCheck; + case BoundsCheckException: + return config.deoptReasonRangeCheck; + case ClassCastException: + return config.deoptReasonClassCheck; + case ArrayStoreException: + return config.deoptReasonArrayCheck; + case UnreachedCode: + return config.deoptReasonUnreached0; + case TypeCheckedInliningViolated: + return config.deoptReasonTypeCheckInlining; + case OptimizedTypeCheckViolated: + return config.deoptReasonOptimizedTypeCheck; + case NotCompiledExceptionHandler: + return config.deoptReasonNotCompiledExceptionHandler; + case Unresolved: + return config.deoptReasonUnresolved; + case JavaSubroutineMismatch: + return config.deoptReasonJsrMismatch; + case ArithmeticException: + return config.deoptReasonDiv0Check; + case RuntimeConstraint: + return config.deoptReasonConstraint; + case LoopLimitCheck: + return config.deoptReasonLoopLimitCheck; + case Aliasing: + return config.deoptReasonAliasing; + case TransferToInterpreter: + return config.deoptReasonTransferToInterpreter; + default: + throw new JVMCIError("%s", reason); + } + } + + public DeoptimizationReason convertDeoptReason(int reason) { + HotSpotVMConfig config = runtime.getConfig(); + if (reason == config.deoptReasonNone) { + return DeoptimizationReason.None; + } + if (reason == config.deoptReasonNullCheck) { + return DeoptimizationReason.NullCheckException; + } + if (reason == config.deoptReasonRangeCheck) { + return DeoptimizationReason.BoundsCheckException; + } + if (reason == config.deoptReasonClassCheck) { + return DeoptimizationReason.ClassCastException; + } + if (reason == config.deoptReasonArrayCheck) { + return DeoptimizationReason.ArrayStoreException; + } + if (reason == config.deoptReasonUnreached0) { + return DeoptimizationReason.UnreachedCode; + } + if (reason == config.deoptReasonTypeCheckInlining) { + return DeoptimizationReason.TypeCheckedInliningViolated; + } + if (reason == config.deoptReasonOptimizedTypeCheck) { + return DeoptimizationReason.OptimizedTypeCheckViolated; + } + if (reason == config.deoptReasonNotCompiledExceptionHandler) { + return DeoptimizationReason.NotCompiledExceptionHandler; + } + if (reason == config.deoptReasonUnresolved) { + return DeoptimizationReason.Unresolved; + } + if (reason == config.deoptReasonJsrMismatch) { + return DeoptimizationReason.JavaSubroutineMismatch; + } + if (reason == config.deoptReasonDiv0Check) { + return DeoptimizationReason.ArithmeticException; + } + if (reason == config.deoptReasonConstraint) { + return DeoptimizationReason.RuntimeConstraint; + } + if (reason == config.deoptReasonLoopLimitCheck) { + return DeoptimizationReason.LoopLimitCheck; + } + if (reason == config.deoptReasonAliasing) { + return DeoptimizationReason.Aliasing; + } + if (reason == config.deoptReasonTransferToInterpreter) { + return DeoptimizationReason.TransferToInterpreter; + } + throw new JVMCIError("%x", reason); + } + + @Override + public long getMemorySize(JavaConstant constant) { + if (constant.getJavaKind() == JavaKind.Object) { + HotSpotResolvedObjectType lookupJavaType = lookupJavaType(constant); + + if (lookupJavaType == null) { + return 0; + } else { + if (lookupJavaType.isArray()) { + // TODO(tw): Add compressed pointer support. + int length = Array.getLength(((HotSpotObjectConstantImpl) constant).object()); + ResolvedJavaType elementType = lookupJavaType.getComponentType(); + JavaKind elementKind = elementType.getJavaKind(); + final int headerSize = runtime.getArrayBaseOffset(elementKind); + TargetDescription target = runtime.getHostJVMCIBackend().getTarget(); + int sizeOfElement = target.getSizeInBytes(elementKind); + int alignment = target.wordSize; + int log2ElementSize = CodeUtil.log2(sizeOfElement); + return computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); + } + return lookupJavaType.instanceSize(); + } + } else { + return constant.getJavaKind().getByteCount(); + } + } + + /** + * Computes the size of the memory chunk allocated for an array. This size accounts for the + * array header size, body size and any padding after the last element to satisfy object + * alignment requirements. + * + * @param length the number of elements in the array + * @param alignment the object alignment requirement + * @param headerSize the size of the array header + * @param log2ElementSize log2 of the size of an element in the array + */ + public static int computeArrayAllocationSize(int length, int alignment, int headerSize, int log2ElementSize) { + int size = (length << log2ElementSize) + headerSize + (alignment - 1); + int mask = ~(alignment - 1); + return size & mask; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java new file mode 100644 index 00000000000..fd40b38a7e8 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +public class HotSpotMetaData { + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] pcDescBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] scopesDescBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] relocBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] exceptionBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] oopMaps; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private String[] metadata; + + public byte[] pcDescBytes() { + return pcDescBytes != null ? pcDescBytes : new byte[0]; + } + + public byte[] scopesDescBytes() { + return scopesDescBytes != null ? scopesDescBytes : new byte[0]; + } + + public byte[] relocBytes() { + return relocBytes != null ? relocBytes : new byte[0]; + } + + public byte[] exceptionBytes() { + return exceptionBytes != null ? exceptionBytes : new byte[0]; + } + + public byte[] oopMaps() { + return oopMaps != null ? oopMaps : new byte[0]; + } + + public String[] metadataEntries() { + return metadata != null ? metadata : new String[0]; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java new file mode 100644 index 00000000000..d37328eb269 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.hotspot.HotSpotVMConfig.*; +import jdk.vm.ci.meta.*; + +public interface HotSpotMetaspaceConstant extends HotSpotConstant, VMConstant { + + Constant compress(CompressEncoding encoding); + + Constant uncompress(CompressEncoding encoding); + + HotSpotResolvedObjectType asResolvedJavaType(); + + HotSpotResolvedJavaMethod asResolvedJavaMethod(); + + long rawValue(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java new file mode 100644 index 00000000000..35e4519c4c1 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.util.*; + +import jdk.vm.ci.hotspot.HotSpotVMConfig.*; +import jdk.vm.ci.meta.*; + +public final class HotSpotMetaspaceConstantImpl extends PrimitiveConstant implements HotSpotMetaspaceConstant, VMConstant, HotSpotProxified { + + static HotSpotMetaspaceConstantImpl forMetaspaceObject(JavaKind kind, long primitive, Object metaspaceObject, boolean compressed) { + return new HotSpotMetaspaceConstantImpl(kind, primitive, metaspaceObject, compressed); + } + + static Object getMetaspaceObject(Constant constant) { + return ((HotSpotMetaspaceConstantImpl) constant).metaspaceObject; + } + + private final Object metaspaceObject; + private final boolean compressed; + + private HotSpotMetaspaceConstantImpl(JavaKind kind, long primitive, Object metaspaceObject, boolean compressed) { + super(kind, primitive); + this.metaspaceObject = metaspaceObject; + this.compressed = compressed; + } + + @Override + public int hashCode() { + return super.hashCode() ^ System.identityHashCode(metaspaceObject); + } + + @Override + public boolean equals(Object o) { + return o == this || (o instanceof HotSpotMetaspaceConstantImpl && super.equals(o) && Objects.equals(metaspaceObject, ((HotSpotMetaspaceConstantImpl) o).metaspaceObject)); + } + + @Override + public String toString() { + return super.toString() + "{" + metaspaceObject + (compressed ? ";compressed}" : "}"); + } + + public boolean isCompressed() { + return compressed; + } + + public JavaConstant compress(CompressEncoding encoding) { + assert !isCompressed(); + HotSpotMetaspaceConstantImpl res = HotSpotMetaspaceConstantImpl.forMetaspaceObject(JavaKind.Int, encoding.compress(asLong()), metaspaceObject, true); + assert res.isCompressed(); + return res; + } + + public JavaConstant uncompress(CompressEncoding encoding) { + assert isCompressed(); + HotSpotMetaspaceConstantImpl res = HotSpotMetaspaceConstantImpl.forMetaspaceObject(JavaKind.Long, encoding.uncompress(asInt()), metaspaceObject, false); + assert !res.isCompressed(); + return res; + } + + public HotSpotResolvedObjectType asResolvedJavaType() { + if (metaspaceObject instanceof HotSpotResolvedObjectType) { + return (HotSpotResolvedObjectType) metaspaceObject; + } + return null; + } + + public HotSpotResolvedJavaMethod asResolvedJavaMethod() { + if (metaspaceObject instanceof HotSpotResolvedJavaMethod) { + return (HotSpotResolvedJavaMethod) metaspaceObject; + } + return null; + } + + public long rawValue() { + return asLong(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethod.java new file mode 100644 index 00000000000..c6e8e72869e --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethod.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static java.util.FormattableFlags.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +public abstract class HotSpotMethod implements JavaMethod, Formattable /* , JavaMethodContex */{ + + public static String applyFormattingFlagsAndWidth(String s, int flags, int width) { + if (flags == 0 && width < 0) { + return s; + } + StringBuilder sb = new StringBuilder(s); + + // apply width and justification + int len = sb.length(); + if (len < width) { + for (int i = 0; i < width - len; i++) { + if ((flags & LEFT_JUSTIFY) == LEFT_JUSTIFY) { + sb.append(' '); + } else { + sb.insert(0, ' '); + } + } + } + + String res = sb.toString(); + if ((flags & UPPERCASE) == UPPERCASE) { + res = res.toUpperCase(); + } + return res; + } + + protected String name; + + /** + * Controls whether {@link #toString()} includes the qualified or simple name of the class in + * which the method is declared. + */ + public static final boolean FULLY_QUALIFIED_METHOD_NAME = false; + + protected HotSpotMethod(String name) { + this.name = name; + } + + @Override + public final String getName() { + return name; + } + + @Override + public final String toString() { + char h = FULLY_QUALIFIED_METHOD_NAME ? 'H' : 'h'; + String suffix = this instanceof ResolvedJavaMethod ? "" : ", unresolved"; + String fmt = String.format("HotSpotMethod<%%%c.%%n(%%p)%s>", h, suffix); + return format(fmt); + } + + public void formatTo(Formatter formatter, int flags, int width, int precision) { + String base = (flags & ALTERNATE) == ALTERNATE ? getName() : toString(); + formatter.format(applyFormattingFlagsAndWidth(base, flags & ~ALTERNATE, width)); + } + + public JavaMethod asJavaMethod() { + return this; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java new file mode 100644 index 00000000000..8fed389a799 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java @@ -0,0 +1,864 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static java.lang.String.*; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.util.*; + +import jdk.vm.ci.hotspot.HotSpotMethodDataAccessor.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.JavaMethodProfile.*; +import jdk.vm.ci.meta.JavaTypeProfile.*; +import sun.misc.*; + +/** + * Access to a HotSpot MethodData structure (defined in methodData.hpp). + */ +public final class HotSpotMethodData { + + private static final HotSpotVMConfig config = runtime().getConfig(); + private static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(TriState.FALSE); + private static final HotSpotMethodDataAccessor NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR = new NoMethodData(TriState.UNKNOWN); + + // sorted by tag + // @formatter:off + private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = { + null, + new BitData(), + new CounterData(), + new JumpData(), + new TypeCheckData(), + new VirtualCallData(), + new RetData(), + new BranchData(), + new MultiBranchData(), + new ArgInfoData(), + null, // call_type_data_tag + null, // virtual_call_type_data_tag + null, // parameters_type_data_tag + null, // speculative_trap_data_tag + }; + // @formatter:on + + /** + * Reference to the C++ MethodData object. + */ + private final long metaspaceMethodData; + @SuppressWarnings("unused") private final HotSpotResolvedJavaMethodImpl method; + + public HotSpotMethodData(long metaspaceMethodData, HotSpotResolvedJavaMethodImpl method) { + this.metaspaceMethodData = metaspaceMethodData; + this.method = method; + } + + /** + * @return value of the MethodData::_data_size field + */ + private int normalDataSize() { + return UNSAFE.getInt(metaspaceMethodData + config.methodDataDataSize); + } + + /** + * Returns the size of the extra data records. This method does the same calculation as + * MethodData::extra_data_size(). + * + * @return size of extra data records + */ + private int extraDataSize() { + final int extraDataBase = config.methodDataOopDataOffset + normalDataSize(); + final int extraDataLimit = UNSAFE.getInt(metaspaceMethodData + config.methodDataSize); + return extraDataLimit - extraDataBase; + } + + public boolean hasNormalData() { + return normalDataSize() > 0; + } + + public boolean hasExtraData() { + return extraDataSize() > 0; + } + + public int getExtraDataBeginOffset() { + return normalDataSize(); + } + + public boolean isWithin(int position) { + return position >= 0 && position < normalDataSize() + extraDataSize(); + } + + public int getDeoptimizationCount(DeoptimizationReason reason) { + HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); + int reasonIndex = metaAccess.convertDeoptReason(reason); + return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF; + } + + public int getOSRDeoptimizationCount(DeoptimizationReason reason) { + HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); + int reasonIndex = metaAccess.convertDeoptReason(reason); + return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + config.deoptReasonOSROffset + reasonIndex) & 0xFF; + } + + public HotSpotMethodDataAccessor getNormalData(int position) { + if (position >= normalDataSize()) { + return null; + } + + HotSpotMethodDataAccessor result = getData(position); + assert result != null : "NO_DATA tag is not allowed"; + return result; + } + + public HotSpotMethodDataAccessor getExtraData(int position) { + if (position >= normalDataSize() + extraDataSize()) { + return null; + } + HotSpotMethodDataAccessor data = getData(position); + if (data != null) { + return data; + } + return data; + } + + public static HotSpotMethodDataAccessor getNoDataAccessor(boolean exceptionPossiblyNotRecorded) { + if (exceptionPossiblyNotRecorded) { + return NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR; + } else { + return NO_DATA_NO_EXCEPTION_ACCESSOR; + } + } + + private HotSpotMethodDataAccessor getData(int position) { + assert position >= 0 : "out of bounds"; + final Tag tag = AbstractMethodData.readTag(this, position); + HotSpotMethodDataAccessor accessor = PROFILE_DATA_ACCESSORS[tag.getValue()]; + assert accessor == null || accessor.getTag() == tag : "wrong data accessor " + accessor + " for tag " + tag; + return accessor; + } + + private int readUnsignedByte(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return UNSAFE.getByte(metaspaceMethodData + fullOffsetInBytes) & 0xFF; + } + + private int readUnsignedShort(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return UNSAFE.getShort(metaspaceMethodData + fullOffsetInBytes) & 0xFFFF; + } + + /** + * Since the values are stored in cells (platform words) this method uses + * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. + */ + private long readUnsignedInt(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes) & 0xFFFFFFFFL; + } + + private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) { + long value = readUnsignedInt(position, offsetInBytes); + return truncateLongToInt(value); + } + + /** + * Since the values are stored in cells (platform words) this method uses + * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. + */ + private int readInt(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return (int) UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes); + } + + private HotSpotResolvedJavaMethod readMethod(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return runtime().compilerToVm.getResolvedJavaMethod(null, metaspaceMethodData + fullOffsetInBytes); + } + + private HotSpotResolvedObjectTypeImpl readKlass(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return runtime().compilerToVm.getResolvedJavaType(null, metaspaceMethodData + fullOffsetInBytes, false); + } + + private static int truncateLongToInt(long value) { + return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value; + } + + private static int computeFullOffset(int position, int offsetInBytes) { + return config.methodDataOopDataOffset + position + offsetInBytes; + } + + private static int cellIndexToOffset(int cells) { + return config.dataLayoutHeaderSize + cellsToBytes(cells); + } + + private static int cellsToBytes(int cells) { + return cells * config.dataLayoutCellSize; + } + + /** + * Returns whether profiling ran long enough that the profile information is mature. Other + * informational data will still be valid even if the profile isn't mature. + */ + public boolean isProfileMature() { + return runtime().getCompilerToVM().isMature(metaspaceMethodData); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + String nl = String.format("%n"); + String nlIndent = String.format("%n%38s", ""); + if (hasNormalData()) { + int pos = 0; + HotSpotMethodDataAccessor data; + while ((data = getNormalData(pos)) != null) { + if (pos != 0) { + sb.append(nl); + } + int bci = data.getBCI(this, pos); + sb.append(String.format("%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); + sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); + pos = pos + data.getSize(this, pos); + } + } + + if (hasExtraData()) { + int pos = getExtraDataBeginOffset(); + HotSpotMethodDataAccessor data; + while ((data = getExtraData(pos)) != null) { + if (pos == getExtraDataBeginOffset()) { + sb.append(nl).append("--- Extra data:"); + } + int bci = data.getBCI(this, pos); + sb.append(String.format("%n%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); + sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); + pos = pos + data.getSize(this, pos); + } + + } + return sb.toString(); + } + + private abstract static class AbstractMethodData implements HotSpotMethodDataAccessor { + + /** + * Corresponds to {@code exception_seen_flag}. + */ + private static final int EXCEPTIONS_MASK = 0x2; + + private final Tag tag; + private final int staticSize; + + protected AbstractMethodData(Tag tag, int staticSize) { + this.tag = tag; + this.staticSize = staticSize; + } + + public Tag getTag() { + return tag; + } + + public static Tag readTag(HotSpotMethodData data, int position) { + final int tag = data.readUnsignedByte(position, config.dataLayoutTagOffset); + return Tag.getEnum(tag); + } + + @Override + public int getBCI(HotSpotMethodData data, int position) { + return data.readUnsignedShort(position, config.dataLayoutBCIOffset); + } + + @Override + public int getSize(HotSpotMethodData data, int position) { + return staticSize + getDynamicSize(data, position); + } + + @Override + public TriState getExceptionSeen(HotSpotMethodData data, int position) { + return TriState.get((getFlags(data, position) & EXCEPTIONS_MASK) != 0); + } + + @Override + public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { + return null; + } + + @Override + public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { + return null; + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + return -1; + } + + @Override + public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { + return null; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return -1; + } + + @Override + public TriState getNullSeen(HotSpotMethodData data, int position) { + return TriState.UNKNOWN; + } + + protected int getFlags(HotSpotMethodData data, int position) { + return data.readUnsignedByte(position, config.dataLayoutFlagsOffset); + } + + /** + * @param data + * @param position + */ + protected int getDynamicSize(HotSpotMethodData data, int position) { + return 0; + } + + public abstract StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos); + } + + private static class NoMethodData extends AbstractMethodData { + + private static final int NO_DATA_SIZE = cellIndexToOffset(0); + + private final TriState exceptionSeen; + + protected NoMethodData(TriState exceptionSeen) { + super(Tag.No, NO_DATA_SIZE); + this.exceptionSeen = exceptionSeen; + } + + @Override + public int getBCI(HotSpotMethodData data, int position) { + return -1; + } + + @Override + public TriState getExceptionSeen(HotSpotMethodData data, int position) { + return exceptionSeen; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb; + } + } + + private static class BitData extends AbstractMethodData { + + private static final int BIT_DATA_SIZE = cellIndexToOffset(0); + private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01; + + private BitData() { + super(Tag.BitData, BIT_DATA_SIZE); + } + + protected BitData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public TriState getNullSeen(HotSpotMethodData data, int position) { + return TriState.get((getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("exception_seen(%s)", getExceptionSeen(data, pos))); + } + } + + private static class CounterData extends BitData { + + private static final int COUNTER_DATA_SIZE = cellIndexToOffset(1); + private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(0); + + public CounterData() { + super(Tag.CounterData, COUNTER_DATA_SIZE); + } + + protected CounterData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return getCounterValue(data, position); + } + + protected int getCounterValue(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, COUNTER_DATA_COUNT_OFFSET); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("count(%d) null_seen(%s) exception_seen(%s)", getCounterValue(data, pos), getNullSeen(data, pos), getExceptionSeen(data, pos))); + } + } + + private static class JumpData extends AbstractMethodData { + + private static final int JUMP_DATA_SIZE = cellIndexToOffset(2); + protected static final int TAKEN_COUNT_OFFSET = cellIndexToOffset(0); + protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(1); + + public JumpData() { + super(Tag.JumpData, JUMP_DATA_SIZE); + } + + protected JumpData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + return getExecutionCount(data, position) != 0 ? 1 : 0; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET); + } + + public int getTakenDisplacement(HotSpotMethodData data, int position) { + return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("taken(%d) displacement(%d)", getExecutionCount(data, pos), getTakenDisplacement(data, pos))); + } + } + + static class RawItemProfile { + final int entries; + final T[] items; + final long[] counts; + final long totalCount; + + public RawItemProfile(int entries, T[] items, long[] counts, long totalCount) { + this.entries = entries; + this.items = items; + this.counts = counts; + this.totalCount = totalCount; + } + } + + private abstract static class AbstractTypeData extends CounterData { + + protected static final int TYPE_DATA_ROW_SIZE = cellsToBytes(2); + + protected static final int NONPROFILED_COUNT_OFFSET = cellIndexToOffset(1); + protected static final int TYPE_DATA_FIRST_TYPE_OFFSET = cellIndexToOffset(2); + protected static final int TYPE_DATA_FIRST_TYPE_COUNT_OFFSET = cellIndexToOffset(3); + + protected AbstractTypeData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { + return createTypeProfile(getNullSeen(data, position), getRawTypeProfile(data, position)); + } + + private RawItemProfile getRawTypeProfile(HotSpotMethodData data, int position) { + int typeProfileWidth = config.typeProfileWidth; + + ResolvedJavaType[] types = new ResolvedJavaType[typeProfileWidth]; + long[] counts = new long[typeProfileWidth]; + long totalCount = 0; + int entries = 0; + + outer: for (int i = 0; i < typeProfileWidth; i++) { + HotSpotResolvedObjectTypeImpl receiverKlass = data.readKlass(position, getTypeOffset(i)); + if (receiverKlass != null) { + HotSpotResolvedObjectTypeImpl klass = receiverKlass; + long count = data.readUnsignedInt(position, getTypeCountOffset(i)); + /* + * Because of races in the profile collection machinery it's possible for a + * class to appear multiple times so merge them to make the profile look + * rational. + */ + for (int j = 0; j < entries; j++) { + if (types[j].equals(klass)) { + totalCount += count; + counts[j] += count; + continue outer; + } + } + types[entries] = klass; + totalCount += count; + counts[entries] = count; + entries++; + } + } + + totalCount += getTypesNotRecordedExecutionCount(data, position); + return new RawItemProfile<>(entries, types, counts, totalCount); + } + + protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); + + private static JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile profile) { + if (profile.entries <= 0 || profile.totalCount <= 0) { + return null; + } + + ProfiledType[] ptypes = new ProfiledType[profile.entries]; + double totalProbability = 0.0; + for (int i = 0; i < profile.entries; i++) { + double p = profile.counts[i]; + p = p / profile.totalCount; + totalProbability += p; + ptypes[i] = new ProfiledType(profile.items[i], p); + } + + Arrays.sort(ptypes); + + double notRecordedTypeProbability = profile.entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); + assert notRecordedTypeProbability == 0 || profile.entries == config.typeProfileWidth; + return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes); + } + + private static int getTypeOffset(int row) { + return TYPE_DATA_FIRST_TYPE_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + protected static int getTypeCountOffset(int row) { + return TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + RawItemProfile profile = getRawTypeProfile(data, pos); + TriState nullSeen = getNullSeen(data, pos); + TriState exceptionSeen = getExceptionSeen(data, pos); + sb.append(format("count(%d) null_seen(%s) exception_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen, + getTypesNotRecordedExecutionCount(data, pos), profile.entries)); + for (int i = 0; i < profile.entries; i++) { + long count = profile.counts[i]; + sb.append(format("%n %s (%d, %4.2f)", profile.items[i].toJavaName(), count, (double) count / profile.totalCount)); + } + return sb; + } + } + + private static class TypeCheckData extends AbstractTypeData { + + private static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; + + public TypeCheckData() { + super(Tag.ReceiverTypeData, TYPE_CHECK_DATA_SIZE); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return -1; + } + + @Override + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); + } + } + + private static class VirtualCallData extends AbstractTypeData { + + private static final int VIRTUAL_CALL_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * (config.typeProfileWidth + config.methodProfileWidth); + private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET = TYPE_DATA_FIRST_TYPE_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; + private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; + + public VirtualCallData() { + super(Tag.VirtualCallData, VIRTUAL_CALL_DATA_SIZE); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + final int typeProfileWidth = config.typeProfileWidth; + + long total = 0; + for (int i = 0; i < typeProfileWidth; i++) { + total += data.readUnsignedInt(position, getTypeCountOffset(i)); + } + + total += getCounterValue(data, position); + return truncateLongToInt(total); + } + + @Override + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return getCounterValue(data, position); + } + + private static long getMethodsNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); + } + + @Override + public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { + return createMethodProfile(getRawMethodProfile(data, position)); + } + + private static RawItemProfile getRawMethodProfile(HotSpotMethodData data, int position) { + int profileWidth = config.methodProfileWidth; + + ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth]; + long[] counts = new long[profileWidth]; + long totalCount = 0; + int entries = 0; + + for (int i = 0; i < profileWidth; i++) { + HotSpotResolvedJavaMethod method = data.readMethod(position, getMethodOffset(i)); + if (method != null) { + methods[entries] = method; + long count = data.readUnsignedInt(position, getMethodCountOffset(i)); + totalCount += count; + counts[entries] = count; + + entries++; + } + } + + totalCount += getMethodsNotRecordedExecutionCount(data, position); + return new RawItemProfile<>(entries, methods, counts, totalCount); + } + + private static JavaMethodProfile createMethodProfile(RawItemProfile profile) { + if (profile.entries <= 0 || profile.totalCount <= 0) { + return null; + } + + ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries]; + double totalProbability = 0.0; + for (int i = 0; i < profile.entries; i++) { + double p = profile.counts[i]; + p = p / profile.totalCount; + totalProbability += p; + pmethods[i] = new ProfiledMethod(profile.items[i], p); + } + + Arrays.sort(pmethods); + + double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); + assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth; + return new JavaMethodProfile(notRecordedMethodProbability, pmethods); + } + + private static int getMethodOffset(int row) { + return VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + private static int getMethodCountOffset(int row) { + return VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + RawItemProfile profile = getRawMethodProfile(data, pos); + super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries)); + for (int i = 0; i < profile.entries; i++) { + long count = profile.counts[i]; + sb.append(format("%n %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount)); + } + return sb; + } + } + + private static class RetData extends CounterData { + + private static final int RET_DATA_ROW_SIZE = cellsToBytes(3); + private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth; + + public RetData() { + super(Tag.RetData, RET_DATA_SIZE); + } + } + + private static class BranchData extends JumpData { + + private static final int BRANCH_DATA_SIZE = cellIndexToOffset(3); + private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(2); + + public BranchData() { + super(Tag.BranchData, BRANCH_DATA_SIZE); + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET); + long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); + long total = takenCount + notTakenCount; + + return total <= 0 ? -1 : takenCount / (double) total; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); + return truncateLongToInt(count); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + long taken = data.readUnsignedInt(pos, TAKEN_COUNT_OFFSET); + long notTaken = data.readUnsignedInt(pos, NOT_TAKEN_COUNT_OFFSET); + double takenProbability = getBranchTakenProbability(data, pos); + return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos))); + } + } + + private static class ArrayData extends AbstractMethodData { + + private static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(0); + protected static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(1); + + public ArrayData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + protected int getDynamicSize(HotSpotMethodData data, int position) { + return cellsToBytes(getLength(data, position)); + } + + protected static int getLength(HotSpotMethodData data, int position) { + return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("length(%d)", getLength(data, pos))); + } + } + + private static class MultiBranchData extends ArrayData { + + private static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1); + private static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = 2; + private static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS); + private static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0); + private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1); + + public MultiBranchData() { + super(Tag.MultiBranchData, MULTI_BRANCH_DATA_SIZE); + } + + @Override + public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { + int arrayLength = getLength(data, position); + assert arrayLength > 0 : "switch must have at least the default case"; + assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; + + int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + long totalCount = 0; + double[] result = new double[length]; + + // default case is first in HotSpot but last for the compiler + long count = readCount(data, position, 0); + totalCount += count; + result[length - 1] = count; + + for (int i = 1; i < length; i++) { + count = readCount(data, position, i); + totalCount += count; + result[i - 1] = count; + } + + if (totalCount <= 0) { + return null; + } else { + for (int i = 0; i < length; i++) { + result[i] = result[i] / totalCount; + } + return result; + } + } + + private static long readCount(HotSpotMethodData data, int position, int i) { + int offset; + long count; + offset = getCountOffset(i); + count = data.readUnsignedInt(position, offset); + return count; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + int arrayLength = getLength(data, position); + assert arrayLength > 0 : "switch must have at least the default case"; + assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; + + int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + long totalCount = 0; + for (int i = 0; i < length; i++) { + int offset = getCountOffset(i); + totalCount += data.readUnsignedInt(position, offset); + } + + return truncateLongToInt(totalCount); + } + + private static int getCountOffset(int index) { + return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; + } + + private static int getDisplacementOffset(int index) { + return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + int entries = getLength(data, pos) / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + sb.append(format("entries(%d)", entries)); + for (int i = 0; i < entries; i++) { + sb.append(format("%n %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i)))); + } + return sb; + } + } + + private static class ArgInfoData extends ArrayData { + + private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1); + + public ArgInfoData() { + super(Tag.ArgInfoData, ARG_INFO_DATA_SIZE); + } + } + + public void setCompiledIRSize(int size) { + UNSAFE.putInt(metaspaceMethodData + config.methodDataIRSizeOffset, size); + } + + public int getCompiledIRSize() { + return UNSAFE.getInt(metaspaceMethodData + config.methodDataIRSizeOffset); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java new file mode 100644 index 00000000000..7f5ceacd986 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; + +import jdk.vm.ci.meta.*; + +/** + * Interface for accessor objects that encapsulate the logic for accessing the different kinds of + * data in a HotSpot methodDataOop. This interface is similar to the interface {@link ProfilingInfo} + * , but most methods require a MethodDataObject and the exact position within the methodData. + */ +public interface HotSpotMethodDataAccessor { + + /** + * {@code DataLayout} tag values. + */ + enum Tag { + No(config().dataLayoutNoTag), + BitData(config().dataLayoutBitDataTag), + CounterData(config().dataLayoutCounterDataTag), + JumpData(config().dataLayoutJumpDataTag), + ReceiverTypeData(config().dataLayoutReceiverTypeDataTag), + VirtualCallData(config().dataLayoutVirtualCallDataTag), + RetData(config().dataLayoutRetDataTag), + BranchData(config().dataLayoutBranchDataTag), + MultiBranchData(config().dataLayoutMultiBranchDataTag), + ArgInfoData(config().dataLayoutArgInfoDataTag), + CallTypeData(config().dataLayoutCallTypeDataTag), + VirtualCallTypeData(config().dataLayoutVirtualCallTypeDataTag), + ParametersTypeData(config().dataLayoutParametersTypeDataTag), + SpeculativeTrapData(config().dataLayoutSpeculativeTrapDataTag); + + private final int value; + + private Tag(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + private static HotSpotVMConfig config() { + return runtime().getConfig(); + } + + public static Tag getEnum(int value) { + Tag result = values()[value]; + assert value == result.value; + return result; + } + } + + /** + * Returns the {@link Tag} stored in the LayoutData header. + * + * @return tag stored in the LayoutData header + */ + Tag getTag(); + + /** + * Returns the BCI stored in the LayoutData header. + * + * @return An integer ≥ 0 and ≤ Short.MAX_VALUE, or -1 if not supported. + */ + int getBCI(HotSpotMethodData data, int position); + + /** + * Computes the size for the specific data at the given position. + * + * @return An integer > 0. + */ + int getSize(HotSpotMethodData data, int position); + + JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position); + + JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position); + + double getBranchTakenProbability(HotSpotMethodData data, int position); + + double[] getSwitchProbabilities(HotSpotMethodData data, int position); + + TriState getExceptionSeen(HotSpotMethodData data, int position); + + TriState getNullSeen(HotSpotMethodData data, int position); + + int getExecutionCount(HotSpotMethodData data, int position); + + StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java new file mode 100644 index 00000000000..40c1d67a869 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; + +public class HotSpotMethodHandleAccessProvider implements MethodHandleAccessProvider, HotSpotProxified { + + private final ConstantReflectionProvider constantReflection; + + public HotSpotMethodHandleAccessProvider(ConstantReflectionProvider constantReflection) { + this.constantReflection = constantReflection; + } + + /** + * Lazy initialization to break class initialization cycle. Field and method lookup is only + * possible after the {@link HotSpotJVMCIRuntime} is fully initialized. + */ + static class LazyInitialization { + static final ResolvedJavaField methodHandleFormField; + static final ResolvedJavaField lambdaFormVmentryField; + static final ResolvedJavaMethod lambdaFormCompileToBytecodeMethod; + static final HotSpotResolvedJavaField memberNameVmtargetField; + + /** + * Search for an instance field with the given name in a class. + * + * @param className name of the class to search in + * @param fieldName name of the field to be searched + * @return resolved java field + * @throws ClassNotFoundException + */ + private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException { + Class clazz = Class.forName(className); + ResolvedJavaType type = runtime().fromClass(clazz); + ResolvedJavaField[] fields = type.getInstanceFields(false); + for (ResolvedJavaField field : fields) { + if (field.getName().equals(fieldName)) { + return field; + } + } + return null; + } + + private static ResolvedJavaMethod findMethodInClass(String className, String methodName) throws ClassNotFoundException { + Class clazz = Class.forName(className); + HotSpotResolvedObjectTypeImpl type = fromObjectClass(clazz); + ResolvedJavaMethod result = null; + for (ResolvedJavaMethod method : type.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + assert result == null : "more than one method found: " + className + "." + methodName; + result = method; + } + } + assert result != null : "method not found: " + className + "." + methodName; + return result; + } + + static { + try { + methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form"); + lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry"); + lambdaFormCompileToBytecodeMethod = findMethodInClass("java.lang.invoke.LambdaForm", "compileToBytecode"); + memberNameVmtargetField = (HotSpotResolvedJavaField) findFieldInClass("java.lang.invoke.MemberName", "vmtarget"); + } catch (Throwable ex) { + throw new JVMCIError(ex); + } + } + } + + @Override + public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) { + int intrinsicId = ((HotSpotResolvedJavaMethodImpl) method).intrinsicId(); + if (intrinsicId != 0) { + return getMethodHandleIntrinsic(intrinsicId); + } + return null; + } + + public static IntrinsicMethod getMethodHandleIntrinsic(int intrinsicId) { + HotSpotVMConfig config = runtime().getConfig(); + if (intrinsicId == config.vmIntrinsicInvokeBasic) { + return IntrinsicMethod.INVOKE_BASIC; + } else if (intrinsicId == config.vmIntrinsicLinkToInterface) { + return IntrinsicMethod.LINK_TO_INTERFACE; + } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) { + return IntrinsicMethod.LINK_TO_SPECIAL; + } else if (intrinsicId == config.vmIntrinsicLinkToStatic) { + return IntrinsicMethod.LINK_TO_STATIC; + } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) { + return IntrinsicMethod.LINK_TO_VIRTUAL; + } + return null; + } + + @Override + public ResolvedJavaMethod resolveInvokeBasicTarget(JavaConstant methodHandle, boolean forceBytecodeGeneration) { + if (methodHandle.isNull()) { + return null; + } + + /* Load non-public field: LambdaForm MethodHandle.form */ + JavaConstant lambdaForm = constantReflection.readFieldValue(LazyInitialization.methodHandleFormField, methodHandle); + if (lambdaForm.isNull()) { + return null; + } + + JavaConstant memberName; + if (forceBytecodeGeneration) { + /* Invoke non-public method: MemberName LambdaForm.compileToBytecode() */ + memberName = LazyInitialization.lambdaFormCompileToBytecodeMethod.invoke(lambdaForm, new JavaConstant[0]); + } else { + /* Load non-public field: MemberName LambdaForm.vmentry */ + memberName = constantReflection.readFieldValue(LazyInitialization.lambdaFormVmentryField, lambdaForm); + } + return getTargetMethod(memberName); + } + + @Override + public ResolvedJavaMethod resolveLinkToTarget(JavaConstant memberName) { + return getTargetMethod(memberName); + } + + /** + * Returns the {@link ResolvedJavaMethod} for the vmtarget of a java.lang.invoke.MemberName. + */ + private static ResolvedJavaMethod getTargetMethod(JavaConstant memberName) { + if (memberName.isNull()) { + return null; + } + + Object object = ((HotSpotObjectConstantImpl) memberName).object(); + /* Read the ResolvedJavaMethod from the injected field MemberName.vmtarget */ + return runtime().compilerToVm.getResolvedJavaMethod(object, LazyInitialization.memberNameVmtargetField.offset()); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodUnresolved.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodUnresolved.java new file mode 100644 index 00000000000..134e69c28bb --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodUnresolved.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * Implementation of {@link JavaMethod} for unresolved HotSpot methods. + */ +public final class HotSpotMethodUnresolved extends HotSpotMethod { + + private final Signature signature; + protected JavaType holder; + + public HotSpotMethodUnresolved(String name, Signature signature, JavaType holder) { + super(name); + this.holder = holder; + this.signature = signature; + } + + @Override + public Signature getSignature() { + return signature; + } + + @Override + public JavaType getDeclaringClass() { + return holder; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof HotSpotMethodUnresolved)) { + return false; + } + HotSpotMethodUnresolved that = (HotSpotMethodUnresolved) obj; + return this.name.equals(that.name) && this.signature.equals(that.signature) && this.holder.equals(that.holder); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java new file mode 100644 index 00000000000..83219dec4b7 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.meta.*; + +/** + * Implementation of {@link InstalledCode} for code installed as an nmethod. The nmethod stores a + * weak reference to an instance of this class. This is necessary to keep the nmethod from being + * unloaded while the associated {@link HotSpotNmethod} instance is alive. + *

+ * Note that there is no (current) way for the reference from an nmethod to a {@link HotSpotNmethod} + * instance to be anything but weak. This is due to the fact that HotSpot does not treat nmethods as + * strong GC roots. + */ +public class HotSpotNmethod extends HotSpotInstalledCode { + + /** + * This (indirect) Method* reference is safe since class redefinition preserves all methods + * associated with nmethods in the code cache. + */ + private final HotSpotResolvedJavaMethod method; + + private final boolean isDefault; + private final boolean isExternal; + + public HotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault) { + this(method, name, isDefault, false); + } + + public HotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault, boolean isExternal) { + super(name); + this.method = method; + this.isDefault = isDefault; + this.isExternal = isExternal; + } + + public boolean isDefault() { + return isDefault; + } + + public boolean isExternal() { + return isExternal; + } + + public ResolvedJavaMethod getMethod() { + return method; + } + + @Override + public void invalidate() { + runtime().getCompilerToVM().invalidateInstalledCode(this); + } + + @Override + public String toString() { + return String.format("InstalledNmethod[method=%s, codeBlob=0x%x, isDefault=%b, name=%s]", method, getAddress(), isDefault, name); + } + + protected boolean checkThreeObjectArgs() { + assert method.getSignature().getParameterCount(!method.isStatic()) == 3; + assert method.getSignature().getParameterKind(0) == JavaKind.Object; + assert method.getSignature().getParameterKind(1) == JavaKind.Object; + assert !method.isStatic() || method.getSignature().getParameterKind(2) == JavaKind.Object; + return true; + } + + private boolean checkArgs(Object... args) { + JavaType[] sig = method.toParameterTypes(); + assert args.length == sig.length : method.format("%H.%n(%p): expected ") + sig.length + " args, got " + args.length; + for (int i = 0; i < sig.length; i++) { + Object arg = args[i]; + if (arg == null) { + assert sig[i].getJavaKind() == JavaKind.Object : method.format("%H.%n(%p): expected arg ") + i + " to be Object, not " + sig[i]; + } else if (sig[i].getJavaKind() != JavaKind.Object) { + assert sig[i].getJavaKind().toBoxedJavaClass() == arg.getClass() : method.format("%H.%n(%p): expected arg ") + i + " to be " + sig[i] + ", not " + arg.getClass(); + } + } + return true; + } + + @Override + public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { + assert checkArgs(args); + assert !isExternal(); + return runtime().getCompilerToVM().executeInstalledCode(args, this); + } + + @Override + public long getStart() { + return isValid() ? super.getStart() : 0; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstant.java new file mode 100644 index 00000000000..6edf5ac3339 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstant.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.lang.invoke.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Represents a constant non-{@code null} object reference, within the compiler and across the + * compiler/runtime interface. + */ +public interface HotSpotObjectConstant extends JavaConstant, HotSpotConstant, VMConstant { + + JavaConstant compress(); + + JavaConstant uncompress(); + + /** + * Gets the resolved Java type of the object represented by this constant. + */ + HotSpotResolvedObjectType getType(); + + /** + * Gets the result of {@link Class#getClassLoader()} for the {@link Class} object represented by + * this constant. + * + * @return {@code null} if this constant does not represent a {@link Class} object + */ + JavaConstant getClassLoader(); + + /** + * Gets the {@linkplain System#identityHashCode(Object) identity} has code for the object + * represented by this constant. + */ + int getIdentityHashCode(); + + /** + * Gets the result of {@link Class#getComponentType()} for the {@link Class} object represented + * by this constant. + * + * @return {@code null} if this constant does not represent a {@link Class} object + */ + JavaConstant getComponentType(); + + /** + * Gets the result of {@link Class#getSuperclass()} for the {@link Class} object represented by + * this constant. + * + * @return {@code null} if this constant does not represent a {@link Class} object + */ + JavaConstant getSuperclass(); + + /** + * Gets the result of {@link CallSite#getTarget()} for the {@link CallSite} object represented + * by this constant. + * + * @param assumptions used to register an assumption that the {@link CallSite}'s target does not + * change + * @return {@code null} if this constant does not represent a {@link CallSite} object + */ + JavaConstant getCallSiteTarget(Assumptions assumptions); + + /** + * Determines if this constant represents an {@linkplain String#intern() interned} string. + */ + boolean isInternedString(); + + /** + * Gets the object represented by this constant represents if it is of a given type. + * + * @param type the expected type of the object represented by this constant. If the object is + * required to be of this type, then wrap the call to this method in + * {@link Objects#requireNonNull(Object)}. + * @return the object value represented by this constant if it is an + * {@link ResolvedJavaType#isInstance(JavaConstant) instance of} {@code type} otherwise + * {@code null} + */ + T asObject(Class type); + + /** + * Gets the object represented by this constant represents if it is of a given type. + * + * @param type the expected type of the object represented by this constant. If the object is + * required to be of this type, then wrap the call to this method in + * {@link Objects#requireNonNull(Object)}. + * @return the object value represented by this constant if it is an + * {@link ResolvedJavaType#isInstance(JavaConstant) instance of} {@code type} otherwise + * {@code null} + */ + Object asObject(ResolvedJavaType type); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java new file mode 100644 index 00000000000..e3c7cb32da9 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.*; + +import java.lang.invoke.*; + +import jdk.vm.ci.inittimer.*; +import jdk.vm.ci.meta.*; + +/** + * Represents a constant non-{@code null} object reference, within the compiler and across the + * compiler/runtime interface. + */ +public final class HotSpotObjectConstantImpl implements HotSpotObjectConstant, HotSpotProxified { + + public static JavaConstant forObject(Object object) { + return forObject(object, false); + } + + static JavaConstant forObject(Object object, boolean compressed) { + if (object == null) { + return compressed ? HotSpotCompressedNullConstant.COMPRESSED_NULL : JavaConstant.NULL_POINTER; + } else { + return new HotSpotObjectConstantImpl(object, compressed); + } + } + + static JavaConstant forStableArray(Object object, int stableDimension, boolean isDefaultStable) { + if (object == null) { + return JavaConstant.NULL_POINTER; + } else { + assert object.getClass().isArray(); + return new HotSpotObjectConstantImpl(object, false, stableDimension, isDefaultStable); + } + } + + public static JavaConstant forBoxedValue(JavaKind kind, Object value) { + if (kind == JavaKind.Object) { + return HotSpotObjectConstantImpl.forObject(value); + } else { + return JavaConstant.forBoxedPrimitive(value); + } + } + + static Object asBoxedValue(Constant constant) { + if (JavaConstant.isNull(constant)) { + return null; + } else if (constant instanceof HotSpotObjectConstantImpl) { + return ((HotSpotObjectConstantImpl) constant).object; + } else { + return ((JavaConstant) constant).asBoxedPrimitive(); + } + } + + private final Object object; + private final boolean compressed; + private final byte stableDimension; + private final boolean isDefaultStable; + + private HotSpotObjectConstantImpl(Object object, boolean compressed, int stableDimension, boolean isDefaultStable) { + this.object = object; + this.compressed = compressed; + this.stableDimension = (byte) stableDimension; + this.isDefaultStable = isDefaultStable; + assert object != null; + assert stableDimension == 0 || (object != null && object.getClass().isArray()); + assert stableDimension >= 0 && stableDimension <= 255; + assert !isDefaultStable || stableDimension > 0; + } + + private HotSpotObjectConstantImpl(Object object, boolean compressed) { + this(object, compressed, 0, false); + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + /** + * Package-private accessor for the object represented by this constant. + */ + Object object() { + return object; + } + + /** + * Determines if the object represented by this constant is {@link Object#equals(Object) equal} + * to a given object. + */ + public boolean isEqualTo(Object obj) { + return object.equals(obj); + } + + /** + * Gets the class of the object represented by this constant. + */ + public Class getObjectClass() { + return object.getClass(); + } + + public boolean isCompressed() { + return compressed; + } + + public JavaConstant compress() { + assert !compressed; + return new HotSpotObjectConstantImpl(object, true, stableDimension, isDefaultStable); + } + + public JavaConstant uncompress() { + assert compressed; + return new HotSpotObjectConstantImpl(object, false, stableDimension, isDefaultStable); + } + + public HotSpotResolvedObjectType getType() { + return fromObjectClass(object.getClass()); + } + + public JavaConstant getClassLoader() { + if (object instanceof Class) { + /* + * This is an intrinsic for getClassLoader0, which occurs after any security checks. We + * can't call that directly so just call getClassLoader. + */ + return HotSpotObjectConstantImpl.forObject(((Class) object).getClassLoader()); + } + return null; + } + + public int getIdentityHashCode() { + return System.identityHashCode(object); + } + + public JavaConstant getComponentType() { + if (object instanceof Class) { + return HotSpotObjectConstantImpl.forObject(((Class) object).getComponentType()); + } + return null; + } + + public JavaConstant getSuperclass() { + if (object instanceof Class) { + return HotSpotObjectConstantImpl.forObject(((Class) object).getSuperclass()); + } + return null; + } + + public JavaConstant getCallSiteTarget(Assumptions assumptions) { + if (object instanceof CallSite) { + CallSite callSite = (CallSite) object; + MethodHandle target = callSite.getTarget(); + if (!(callSite instanceof ConstantCallSite)) { + if (assumptions == null) { + return null; + } + assumptions.record(new Assumptions.CallSiteTargetValue(callSite, target)); + } + return HotSpotObjectConstantImpl.forObject(target); + } + return null; + } + + @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality is what we want") + public boolean isInternedString() { + if (object instanceof String) { + String s = (String) object; + return s.intern() == s; + } + return false; + } + + public T asObject(Class type) { + if (type.isInstance(object)) { + return type.cast(object); + } + return null; + } + + public Object asObject(ResolvedJavaType type) { + if (type.isInstance(this)) { + return object; + } + return null; + } + + @Override + public boolean isNull() { + return false; + } + + @Override + public boolean isDefaultForKind() { + return false; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public int hashCode() { + return System.identityHashCode(object); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof HotSpotObjectConstantImpl) { + HotSpotObjectConstantImpl other = (HotSpotObjectConstantImpl) o; + return object == other.object && compressed == other.compressed && stableDimension == other.stableDimension && isDefaultStable == other.isDefaultStable; + } + return false; + } + + @Override + public String toValueString() { + if (object instanceof String) { + return "\"" + (String) object + "\""; + } else { + return JavaKind.Object.format(object); + } + } + + @Override + public String toString() { + return (compressed ? "NarrowOop" : getJavaKind().getJavaName()) + "[" + JavaKind.Object.format(object) + "]"; + } + + /** + * Number of stable dimensions if this constant is a stable array. + */ + public int getStableDimension() { + return stableDimension & 0xff; + } + + /** + * Returns {@code true} if this is a stable array constant and its elements should be considered + * as stable regardless of whether they are default values. + */ + public boolean isDefaultStable() { + return isDefaultStable; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotOopMap.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotOopMap.java new file mode 100644 index 00000000000..bedd564694c --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotOopMap.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +public class HotSpotOopMap { + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int offset; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int count; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] data; + + public byte[] data() { + return data; + } + + public int count() { + return count; + } + + public int offset() { + return offset; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java new file mode 100644 index 00000000000..7da7d4e042d --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java @@ -0,0 +1,237 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +public final class HotSpotProfilingInfo implements ProfilingInfo, HotSpotProxified { + + // private static final DebugMetric metricInsufficentSpace = + // Debug.metric("InsufficientSpaceForProfilingData"); + + private final HotSpotMethodData methodData; + private final HotSpotResolvedJavaMethod method; + + private boolean isMature; + private int position; + private int hintPosition; + private int hintBCI; + private HotSpotMethodDataAccessor dataAccessor; + + private boolean includeNormal; + private boolean includeOSR; + + public HotSpotProfilingInfo(HotSpotMethodData methodData, HotSpotResolvedJavaMethod method, boolean includeNormal, boolean includeOSR) { + this.methodData = methodData; + this.method = method; + this.includeNormal = includeNormal; + this.includeOSR = includeOSR; + this.isMature = methodData.isProfileMature(); + hintPosition = 0; + hintBCI = -1; + } + + @Override + public int getCodeSize() { + return method.getCodeSize(); + } + + @Override + public JavaTypeProfile getTypeProfile(int bci) { + if (!isMature) { + return null; + } + findBCI(bci, false); + return dataAccessor.getTypeProfile(methodData, position); + } + + @Override + public JavaMethodProfile getMethodProfile(int bci) { + if (!isMature) { + return null; + } + findBCI(bci, false); + return dataAccessor.getMethodProfile(methodData, position); + } + + @Override + public double getBranchTakenProbability(int bci) { + if (!isMature) { + return -1; + } + findBCI(bci, false); + return dataAccessor.getBranchTakenProbability(methodData, position); + } + + @Override + public double[] getSwitchProbabilities(int bci) { + if (!isMature) { + return null; + } + findBCI(bci, false); + return dataAccessor.getSwitchProbabilities(methodData, position); + } + + @Override + public TriState getExceptionSeen(int bci) { + findBCI(bci, true); + return dataAccessor.getExceptionSeen(methodData, position); + } + + @Override + public TriState getNullSeen(int bci) { + findBCI(bci, false); + return dataAccessor.getNullSeen(methodData, position); + } + + @Override + public int getExecutionCount(int bci) { + if (!isMature) { + return -1; + } + findBCI(bci, false); + return dataAccessor.getExecutionCount(methodData, position); + } + + @Override + public int getDeoptimizationCount(DeoptimizationReason reason) { + int count = 0; + if (includeNormal) { + count += methodData.getDeoptimizationCount(reason); + } + if (includeOSR) { + count += methodData.getOSRDeoptimizationCount(reason); + } + return count; + } + + private void findBCI(int targetBCI, boolean searchExtraData) { + assert targetBCI >= 0 : "invalid BCI"; + + if (methodData.hasNormalData()) { + int currentPosition = targetBCI < hintBCI ? 0 : hintPosition; + HotSpotMethodDataAccessor currentAccessor; + while ((currentAccessor = methodData.getNormalData(currentPosition)) != null) { + int currentBCI = currentAccessor.getBCI(methodData, currentPosition); + if (currentBCI == targetBCI) { + normalDataFound(currentAccessor, currentPosition, currentBCI); + return; + } else if (currentBCI > targetBCI) { + break; + } + currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); + } + } + + boolean exceptionPossiblyNotRecorded = false; + if (searchExtraData && methodData.hasExtraData()) { + int currentPosition = methodData.getExtraDataBeginOffset(); + HotSpotMethodDataAccessor currentAccessor; + while ((currentAccessor = methodData.getExtraData(currentPosition)) != null) { + int currentBCI = currentAccessor.getBCI(methodData, currentPosition); + if (currentBCI == targetBCI) { + extraDataFound(currentAccessor, currentPosition); + return; + } + currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); + } + + if (!methodData.isWithin(currentPosition)) { + exceptionPossiblyNotRecorded = true; + // metricInsufficentSpace.increment(); + } + } + + noDataFound(exceptionPossiblyNotRecorded); + } + + private void normalDataFound(HotSpotMethodDataAccessor data, int pos, int bci) { + setCurrentData(data, pos); + this.hintPosition = position; + this.hintBCI = bci; + } + + private void extraDataFound(HotSpotMethodDataAccessor data, int pos) { + setCurrentData(data, pos); + } + + private void noDataFound(boolean exceptionPossiblyNotRecorded) { + HotSpotMethodDataAccessor accessor = HotSpotMethodData.getNoDataAccessor(exceptionPossiblyNotRecorded); + setCurrentData(accessor, -1); + } + + private void setCurrentData(HotSpotMethodDataAccessor dataAccessor, int position) { + this.dataAccessor = dataAccessor; + this.position = position; + } + + @Override + public boolean isMature() { + return isMature; + } + + public void ignoreMature() { + isMature = true; + } + + @Override + public String toString() { + return "HotSpotProfilingInfo<" + this.toString(null, "; ") + ">"; + } + + @Override + public void setMature() { + isMature = true; + } + + /** + * {@code MethodData::_jvmci_ir_size} (currently) supports at most one JVMCI compiler IR type + * which will be determined by the first JVMCI compiler that calls + * {@link #setCompilerIRSize(Class, int)}. + */ + private static volatile Class supportedCompilerIRType; + + @Override + public boolean setCompilerIRSize(Class irType, int size) { + if (supportedCompilerIRType == null) { + synchronized (HotSpotProfilingInfo.class) { + if (supportedCompilerIRType == null) { + supportedCompilerIRType = irType; + } + } + } + if (supportedCompilerIRType != irType) { + return false; + } + methodData.setCompiledIRSize(size); + return true; + } + + @Override + public int getCompilerIRSize(Class irType) { + if (irType == supportedCompilerIRType) { + return methodData.getCompiledIRSize(); + } + return -1; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProxified.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProxified.java new file mode 100644 index 00000000000..90a8ece45bb --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProxified.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +/** + * Marker interface for classes whose values are proxied during replay compilation capture. + */ +public interface HotSpotProxified { +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotReferenceMap.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotReferenceMap.java new file mode 100644 index 00000000000..a35585a0d6c --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotReferenceMap.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.util.*; + +import jdk.vm.ci.code.*; + +public final class HotSpotReferenceMap extends ReferenceMap { + + final Location[] objects; + final Location[] derivedBase; + final int[] sizeInBytes; + final int maxRegisterSize; + + public HotSpotReferenceMap(Location[] objects, Location[] derivedBase, int[] sizeInBytes, int maxRegisterSize) { + this.objects = objects; + this.derivedBase = derivedBase; + this.sizeInBytes = sizeInBytes; + this.maxRegisterSize = maxRegisterSize; + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotReferenceMap) { + HotSpotReferenceMap that = (HotSpotReferenceMap) obj; + if (Arrays.equals(objects, that.objects)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return Arrays.toString(objects); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java new file mode 100644 index 00000000000..aba4598b016 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * Represents a field in a HotSpot type. + */ +public interface HotSpotResolvedJavaField extends ResolvedJavaField { + + /** + * Determines if a given object contains this field. + * + * @return true iff this is a non-static field and its declaring class is assignable from + * {@code object}'s class + */ + boolean isInObject(Object object); + + int offset(); + + /** + * Checks if this field has the {@link Stable} annotation. + * + * @return true if field has {@link Stable} annotation, false otherwise + */ + boolean isStable(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java new file mode 100644 index 00000000000..4535cefce85 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.HotSpotResolvedJavaFieldImpl.Options.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.options.*; + +/** + * Represents a field in a HotSpot type. + */ +public class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotProxified { + + static class Options { + //@formatter:off + @Option(help = "Mark well-known stable fields as such.", type = OptionType.Debug) + public static final OptionValue ImplicitStableValues = new OptionValue<>(true); + //@formatter:on + } + + private final HotSpotResolvedObjectTypeImpl holder; + private final String name; + private JavaType type; + private final int offset; + + /** + * This value contains all flags as stored in the VM including internal ones. + */ + private final int modifiers; + private final LocationIdentity locationIdentity = new FieldLocationIdentity(this); + + public static class FieldLocationIdentity extends LocationIdentity { + HotSpotResolvedJavaField inner; + + public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) { + this.inner = inner; + } + + @Override + public boolean isImmutable() { + return false; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof FieldLocationIdentity) { + FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj; + return inner.equals(fieldLocationIdentity.inner); + + } + return false; + } + + @Override + public int hashCode() { + return inner.hashCode(); + } + + @Override + public String toString() { + return inner.getName(); + } + } + + public HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, String name, JavaType type, long offset, int modifiers) { + this.holder = holder; + this.name = name; + this.type = type; + assert offset != -1; + assert offset == (int) offset : "offset larger than int"; + this.offset = (int) offset; + this.modifiers = modifiers; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotResolvedJavaField) { + HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; + if (that.offset != this.offset || that.isStatic() != this.isStatic()) { + return false; + } else if (this.holder.equals(that.holder)) { + assert this.name.equals(that.name) && this.type.equals(that.type); + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public int getModifiers() { + return modifiers & ModifiersProvider.jvmFieldModifiers(); + } + + @Override + public boolean isInternal() { + return (modifiers & runtime().getConfig().jvmAccFieldInternal) != 0; + } + + /** + * Determines if a given object contains this field. + * + * @return true iff this is a non-static field and its declaring class is assignable from + * {@code object}'s class + */ + public boolean isInObject(Object object) { + if (isStatic()) { + return false; + } + return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectTypeImpl.fromObjectClass(object.getClass())); + } + + @Override + public HotSpotResolvedObjectTypeImpl getDeclaringClass() { + return holder; + } + + @Override + public String getName() { + return name; + } + + @Override + public JavaType getType() { + // Pull field into local variable to prevent a race causing + // a ClassCastException below + JavaType currentType = type; + if (currentType instanceof HotSpotUnresolvedJavaType) { + // Don't allow unresolved types to hang around forever + HotSpotUnresolvedJavaType unresolvedType = (HotSpotUnresolvedJavaType) currentType; + ResolvedJavaType resolved = unresolvedType.reresolve(holder); + if (resolved != null) { + type = resolved; + } + } + return type; + } + + public int offset() { + return offset; + } + + @Override + public String toString() { + return format("HotSpotField<%H.%n %t:") + offset + ">"; + } + + @Override + public boolean isSynthetic() { + return (runtime().getConfig().syntheticFlag & modifiers) != 0; + } + + /** + * Checks if this field has the {@link Stable} annotation. + * + * @return true if field has {@link Stable} annotation, false otherwise + */ + public boolean isStable() { + if ((runtime().getConfig().jvmAccFieldStable & modifiers) != 0) { + return true; + } + assert getAnnotation(Stable.class) == null; + if (ImplicitStableValues.getValue() && isImplicitStableField()) { + return true; + } + return false; + } + + @Override + public Annotation[] getAnnotations() { + Field javaField = toJava(); + if (javaField != null) { + return javaField.getAnnotations(); + } + return new Annotation[0]; + } + + @Override + public T getAnnotation(Class annotationClass) { + Field javaField = toJava(); + if (javaField != null) { + return javaField.getAnnotation(annotationClass); + } + return null; + } + + private Field toJavaCache; + + private Field toJava() { + if (toJavaCache != null) { + return toJavaCache; + } + + if (isInternal()) { + return null; + } + try { + return toJavaCache = holder.mirror().getDeclaredField(name); + } catch (NoSuchFieldException | NoClassDefFoundError e) { + return null; + } + } + + private boolean isArray() { + JavaType fieldType = getType(); + return fieldType instanceof ResolvedJavaType && ((ResolvedJavaType) fieldType).isArray(); + } + + private boolean isImplicitStableField() { + if (isSynthetic()) { + if (isSyntheticImplicitStableField()) { + return true; + } + } else if (isWellKnownImplicitStableField()) { + return true; + } + return false; + } + + private boolean isSyntheticImplicitStableField() { + assert this.isSynthetic(); + if (isStatic() && isArray()) { + if (isFinal() && name.equals("$VALUES") || name.equals("ENUM$VALUES")) { + // generated int[] field for EnumClass::values() + return true; + } else if (name.startsWith("$SwitchMap$") || name.startsWith("$SWITCH_TABLE$")) { + // javac and ecj generate a static field in an inner class for a switch on an enum + // named $SwitchMap$p$k$g$EnumClass and $SWITCH_TABLE$p$k$g$EnumClass, respectively + return true; + } + } + return false; + } + + private boolean isWellKnownImplicitStableField() { + return WellKnownImplicitStableField.test(this); + } + + static class WellKnownImplicitStableField { + /** + * @return {@code true} if the field is a well-known stable field. + */ + public static boolean test(HotSpotResolvedJavaField field) { + return field.equals(STRING_VALUE_FIELD); + } + + private static final ResolvedJavaField STRING_VALUE_FIELD; + static { + try { + MetaAccessProvider metaAccess = runtime().getHostJVMCIBackend().getMetaAccess(); + STRING_VALUE_FIELD = metaAccess.lookupJavaField(String.class.getDeclaredField("value")); + } catch (SecurityException | NoSuchFieldException e) { + throw new JVMCIError(e); + } + } + } + + public LocationIdentity getLocationIdentity() { + return locationIdentity; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java new file mode 100644 index 00000000000..2f91cbe59dc --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.lang.reflect.*; + +import jdk.vm.ci.meta.*; + +/** + * Implementation of {@link JavaMethod} for resolved HotSpot methods. + */ +public interface HotSpotResolvedJavaMethod extends ResolvedJavaMethod { + + /** + * Returns true if this method has a {@code CallerSensitive} annotation. + * + * @return true if CallerSensitive annotation present, false otherwise + */ + boolean isCallerSensitive(); + + HotSpotResolvedObjectType getDeclaringClass(); + + /** + * Returns true if this method has a {@code ForceInline} annotation. + * + * @return true if ForceInline annotation present, false otherwise + */ + boolean isForceInline(); + + /** + * Returns true if this method has a {@code DontInline} annotation. + * + * @return true if DontInline annotation present, false otherwise + */ + boolean isDontInline(); + + /** + * Manually adds a DontInline annotation to this method. + */ + void setNotInlineable(); + + /** + * Returns true if this method is one of the special methods that is ignored by security stack + * walks. + * + * @return true if special method ignored by security stack walks, false otherwise + */ + boolean ignoredBySecurityStackWalk(); + + ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver); + + /** + * Returns whether this method has compiled code. + * + * @return true if this method has compiled code, false otherwise + */ + boolean hasCompiledCode(); + + /** + * @param level + * @return true if the currently installed code was generated at {@code level}. + */ + boolean hasCompiledCodeAtLevel(int level); + + default boolean isDefault() { + if (isConstructor()) { + return false; + } + // Copied from java.lang.Method.isDefault() + int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC; + return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface(); + } + + /** + * Returns the offset of this method into the v-table. The method must have a v-table entry as + * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is + * thrown. + * + * @return the offset of this method into the v-table + */ + int vtableEntryOffset(ResolvedJavaType resolved); + + int intrinsicId(); + + /** + * Allocates a compile id for this method by asking the VM for one. + * + * @param entryBCI entry bci + * @return compile id + */ + int allocateCompileId(int entryBCI); + + boolean hasCodeAtLevel(int entryBCI, int level); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java new file mode 100644 index 00000000000..7e931f370ee --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -0,0 +1,726 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl.Options.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.options.*; + +/** + * Implementation of {@link JavaMethod} for resolved HotSpot methods. + */ +public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, MetaspaceWrapperObject { + + public static class Options { + // @formatter:off + @Option(help = "", type = OptionType.Debug) + public static final OptionValue UseProfilingInformation = new OptionValue<>(true); + // @formatter:on + } + + /** + * Reference to metaspace Method object. + */ + private final long metaspaceMethod; + + private final HotSpotResolvedObjectTypeImpl holder; + private final HotSpotConstantPool constantPool; + private final HotSpotSignature signature; + private HotSpotMethodData methodData; + private byte[] code; + private Member toJavaCache; + + /** + * Gets the holder of a HotSpot metaspace method native object. + * + * @param metaspaceMethod a metaspace Method object + * @return the {@link ResolvedJavaType} corresponding to the holder of the + * {@code metaspaceMethod} + */ + private static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceMethod) { + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceConstMethod = UNSAFE.getAddress(metaspaceMethod + config.methodConstMethodOffset); + final long metaspaceConstantPool = UNSAFE.getAddress(metaspaceConstMethod + config.constMethodConstantsOffset); + return runtime().getCompilerToVM().getResolvedJavaType(null, metaspaceConstantPool + config.constantPoolHolderOffset, false); + } + + /** + * Gets the JVMCI mirror from a HotSpot method. The VM is responsible for ensuring that the + * Method* is kept alive for the duration of this call and the + * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. + * + * Called from the VM. + * + * @param metaspaceMethod a metaspace Method object + * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod} + */ + @SuppressWarnings("unused") + private static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceMethod) { + HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceMethod); + return holder.createMethod(metaspaceMethod); + } + + HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceMethod) { + // It would be too much work to get the method name here so we fill it in later. + super(null); + this.metaspaceMethod = metaspaceMethod; + this.holder = holder; + + HotSpotVMConfig config = runtime().getConfig(); + final long constMethod = getConstMethod(); + + /* + * Get the constant pool from the metaspace method. Some methods (e.g. intrinsics for + * signature-polymorphic method handle methods) have their own constant pool instead of the + * one from their holder. + */ + final long metaspaceConstantPool = UNSAFE.getAddress(constMethod + config.constMethodConstantsOffset); + if (metaspaceConstantPool == holder.getConstantPool().getMetaspaceConstantPool()) { + this.constantPool = holder.getConstantPool(); + } else { + this.constantPool = runtime().getCompilerToVM().getConstantPool(null, constMethod + config.constMethodConstantsOffset); + } + + final int nameIndex = UNSAFE.getChar(constMethod + config.constMethodNameIndexOffset); + this.name = constantPool.lookupUtf8(nameIndex); + + final int signatureIndex = UNSAFE.getChar(constMethod + config.constMethodSignatureIndexOffset); + this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex); + } + + /** + * Returns a pointer to this method's constant method data structure ( + * {@code Method::_constMethod}). This pointer isn't wrapped since it should be safe to use it + * within the context of this HotSpotResolvedJavaMethodImpl since the Method* and ConstMethod* + * are kept alive as a pair. + * + * @return pointer to this method's ConstMethod + */ + private long getConstMethod() { + assert metaspaceMethod != 0; + return UNSAFE.getAddress(metaspaceMethod + runtime().getConfig().methodConstMethodOffset); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotResolvedJavaMethodImpl) { + HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj; + return that.metaspaceMethod == metaspaceMethod; + } + return false; + } + + @Override + public int hashCode() { + return (int) metaspaceMethod; + } + + /** + * Returns this method's flags ({@code Method::_flags}). + * + * @return flags of this method + */ + private int getFlags() { + return UNSAFE.getByte(metaspaceMethod + runtime().getConfig().methodFlagsOffset); + } + + /** + * Returns this method's constant method flags ({@code ConstMethod::_flags}). + * + * @return flags of this method's ConstMethod + */ + private int getConstMethodFlags() { + return UNSAFE.getChar(getConstMethod() + runtime().getConfig().constMethodFlagsOffset); + } + + @Override + public HotSpotResolvedObjectTypeImpl getDeclaringClass() { + return holder; + } + + /** + * Gets the address of the C++ Method object for this method. + */ + public JavaConstant getMetaspaceMethodConstant() { + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(getHostWordKind(), metaspaceMethod, this, false); + } + + public long getMetaspaceMethod() { + return metaspaceMethod; + } + + public long getMetaspacePointer() { + return getMetaspaceMethod(); + } + + @Override + public JavaConstant getEncoding() { + return getMetaspaceMethodConstant(); + } + + /** + * Gets the complete set of modifiers for this method which includes the JVM specification + * modifiers as well as the HotSpot internal modifiers. + */ + public int getAllModifiers() { + return UNSAFE.getInt(metaspaceMethod + runtime().getConfig().methodAccessFlagsOffset); + } + + @Override + public int getModifiers() { + return getAllModifiers() & ModifiersProvider.jvmMethodModifiers(); + } + + @Override + public boolean canBeStaticallyBound() { + return (isFinal() || isPrivate() || isStatic() || holder.isLeaf()) && isConcrete(); + } + + @Override + public byte[] getCode() { + if (getCodeSize() == 0) { + return null; + } + if (code == null && holder.isLinked()) { + code = runtime().getCompilerToVM().getBytecode(this); + assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length; + } + return code; + } + + @Override + public int getCodeSize() { + return UNSAFE.getChar(getConstMethod() + runtime().getConfig().constMethodCodeSizeOffset); + } + + @Override + public ExceptionHandler[] getExceptionHandlers() { + final boolean hasExceptionTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasExceptionTable) != 0; + if (!hasExceptionTable) { + return new ExceptionHandler[0]; + } + + HotSpotVMConfig config = runtime().getConfig(); + final int exceptionTableLength = runtime().getCompilerToVM().getExceptionTableLength(this); + ExceptionHandler[] handlers = new ExceptionHandler[exceptionTableLength]; + long exceptionTableElement = runtime().getCompilerToVM().getExceptionTableStart(this); + + for (int i = 0; i < exceptionTableLength; i++) { + final int startPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementStartPcOffset); + final int endPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementEndPcOffset); + final int handlerPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementHandlerPcOffset); + int catchTypeIndex = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementCatchTypeIndexOffset); + + JavaType catchType; + if (catchTypeIndex == 0) { + catchType = null; + } else { + final int opcode = -1; // opcode is not used + catchType = constantPool.lookupType(catchTypeIndex, opcode); + + // Check for Throwable which catches everything. + if (catchType instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType; + if (resolvedType.mirror() == Throwable.class) { + catchTypeIndex = 0; + catchType = null; + } + } + } + handlers[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType); + + // Go to the next ExceptionTableElement + exceptionTableElement += config.exceptionTableElementSize; + } + + return handlers; + } + + /** + * Returns true if this method has a {@code CallerSensitive} annotation. + * + * @return true if CallerSensitive annotation present, false otherwise + */ + public boolean isCallerSensitive() { + return (getFlags() & runtime().getConfig().methodFlagsCallerSensitive) != 0; + } + + /** + * Returns true if this method has a {@code ForceInline} annotation. + * + * @return true if ForceInline annotation present, false otherwise + */ + public boolean isForceInline() { + return (getFlags() & runtime().getConfig().methodFlagsForceInline) != 0; + } + + /** + * Returns true if this method has a {@code DontInline} annotation. + * + * @return true if DontInline annotation present, false otherwise + */ + public boolean isDontInline() { + return (getFlags() & runtime().getConfig().methodFlagsDontInline) != 0; + } + + /** + * Manually adds a DontInline annotation to this method. + */ + public void setNotInlineable() { + runtime().getCompilerToVM().doNotInlineOrCompile(this); + } + + /** + * Returns true if this method is one of the special methods that is ignored by security stack + * walks. + * + * @return true if special method ignored by security stack walks, false otherwise + */ + public boolean ignoredBySecurityStackWalk() { + return runtime().getCompilerToVM().methodIsIgnoredBySecurityStackWalk(this); + } + + @Override + public boolean isClassInitializer() { + return "".equals(name) && isStatic(); + } + + @Override + public boolean isConstructor() { + return "".equals(name) && !isStatic(); + } + + @Override + public int getMaxLocals() { + if (isAbstract() || isNative()) { + return 0; + } + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getChar(getConstMethod() + config.methodMaxLocalsOffset); + } + + @Override + public int getMaxStackSize() { + if (isAbstract() || isNative()) { + return 0; + } + HotSpotVMConfig config = runtime().getConfig(); + return config.extraStackEntries + UNSAFE.getChar(getConstMethod() + config.constMethodMaxStackOffset); + } + + @Override + public StackTraceElement asStackTraceElement(int bci) { + if (bci < 0 || bci >= getCodeSize()) { + // HotSpot code can only construct stack trace elements for valid bcis + StackTraceElement ste = runtime().getCompilerToVM().getStackTraceElement(this, 0); + return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1); + } + return runtime().getCompilerToVM().getStackTraceElement(this, bci); + } + + public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) { + if (receiver.isInterface()) { + // Cannot trust interfaces. Because of: + // interface I { void foo(); } + // class A { public void foo() {} } + // class B extends A implements I { } + // class C extends B { public void foo() { } } + // class D extends B { } + // Would lead to identify C.foo() as the unique concrete method for I.foo() without + // seeing A.foo(). + return null; + } + return runtime().getCompilerToVM().findUniqueConcreteMethod(((HotSpotResolvedObjectTypeImpl) receiver), this); + } + + @Override + public HotSpotSignature getSignature() { + return signature; + } + + /** + * Gets the value of {@code Method::_code}. + * + * @return the value of {@code Method::_code} + */ + private long getCompiledCode() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getAddress(metaspaceMethod + config.methodCodeOffset); + } + + /** + * Returns whether this method has compiled code. + * + * @return true if this method has compiled code, false otherwise + */ + public boolean hasCompiledCode() { + return getCompiledCode() != 0L; + } + + /** + * @param level + * @return true if the currently installed code was generated at {@code level}. + */ + public boolean hasCompiledCodeAtLevel(int level) { + long compiledCode = getCompiledCode(); + if (compiledCode != 0) { + return UNSAFE.getInt(compiledCode + runtime().getConfig().nmethodCompLevelOffset) == level; + } + return false; + } + + private static final String TraceMethodDataFilter = System.getProperty("jvmci.traceMethodDataFilter"); + + @Override + public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { + ProfilingInfo info; + + if (UseProfilingInformation.getValue() && methodData == null) { + long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + runtime().getConfig().methodDataOffset); + if (metaspaceMethodData != 0) { + methodData = new HotSpotMethodData(metaspaceMethodData, this); + if (TraceMethodDataFilter != null && this.format("%H.%n").contains(TraceMethodDataFilter)) { + System.out.println("Raw method data for " + this.format("%H.%n(%p)") + ":"); + System.out.println(methodData.toString()); + } + } + } + + if (methodData == null || (!methodData.hasNormalData() && !methodData.hasExtraData())) { + // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in + // case of a deoptimization. + info = DefaultProfilingInfo.get(TriState.FALSE); + } else { + info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR); + } + return info; + } + + @Override + public void reprofile() { + runtime().getCompilerToVM().reprofile(this); + } + + @Override + public ConstantPool getConstantPool() { + return constantPool; + } + + @Override + public Annotation[][] getParameterAnnotations() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getParameterAnnotations(); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getParameterAnnotations(); + } + + @Override + public Annotation[] getAnnotations() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? new Annotation[0] : javaConstructor.getAnnotations(); + } + Method javaMethod = toJava(); + return javaMethod == null ? new Annotation[0] : javaMethod.getAnnotations(); + } + + @Override + public T getAnnotation(Class annotationClass) { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getAnnotation(annotationClass); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass); + } + + public boolean isDefault() { + if (isConstructor()) { + return false; + } + // Copied from java.lang.Method.isDefault() + int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC; + return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface(); + } + + @Override + public Type[] getGenericParameterTypes() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getGenericParameterTypes(); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getGenericParameterTypes(); + } + + public Class[] signatureToTypes() { + Signature sig = getSignature(); + int count = sig.getParameterCount(false); + Class[] result = new Class[count]; + for (int i = 0; i < result.length; ++i) { + JavaType parameterType = sig.getParameterType(i, holder); + HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder); + result[i] = resolvedParameterType.mirror(); + } + return result; + } + + private Method toJava() { + if (toJavaCache != null) { + return (Method) toJavaCache; + } + try { + Method result = holder.mirror().getDeclaredMethod(name, signatureToTypes()); + toJavaCache = result; + return result; + } catch (NoSuchMethodException | NoClassDefFoundError e) { + return null; + } + } + + private Constructor toJavaConstructor() { + if (toJavaCache != null) { + return (Constructor) toJavaCache; + } + try { + Constructor result = holder.mirror().getDeclaredConstructor(signatureToTypes()); + toJavaCache = result; + return result; + } catch (NoSuchMethodException | NoClassDefFoundError e) { + return null; + } + } + + @Override + public boolean canBeInlined() { + if (isDontInline()) { + return false; + } + return runtime().getCompilerToVM().canInlineMethod(this); + } + + @Override + public boolean shouldBeInlined() { + if (isForceInline()) { + return true; + } + return runtime().getCompilerToVM().shouldInlineMethod(this); + } + + @Override + public LineNumberTable getLineNumberTable() { + final boolean hasLineNumberTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLineNumberTable) != 0; + if (!hasLineNumberTable) { + return null; + } + + long[] values = runtime().getCompilerToVM().getLineNumberTable(this); + if (values == null || values.length == 0) { + // Empty table so treat is as non-existent + return null; + } + assert values.length % 2 == 0; + int[] bci = new int[values.length / 2]; + int[] line = new int[values.length / 2]; + + for (int i = 0; i < values.length / 2; i++) { + bci[i] = (int) values[i * 2]; + line[i] = (int) values[i * 2 + 1]; + } + + return new LineNumberTableImpl(line, bci); + } + + @Override + public LocalVariableTable getLocalVariableTable() { + final boolean hasLocalVariableTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLocalVariableTable) != 0; + if (!hasLocalVariableTable) { + return null; + } + + HotSpotVMConfig config = runtime().getConfig(); + long localVariableTableElement = runtime().getCompilerToVM().getLocalVariableTableStart(this); + final int localVariableTableLength = runtime().getCompilerToVM().getLocalVariableTableLength(this); + Local[] locals = new Local[localVariableTableLength]; + + for (int i = 0; i < localVariableTableLength; i++) { + final int startBci = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset); + final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset); + final int nameCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset); + final int typeCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset); + final int slot = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset); + + String localName = getConstantPool().lookupUtf8(nameCpIndex); + String localType = getConstantPool().lookupUtf8(typeCpIndex); + + locals[i] = new LocalImpl(localName, runtime().lookupType(localType, holder, false), startBci, endBci, slot); + + // Go to the next LocalVariableTableElement + localVariableTableElement += config.localVariableTableElementSize; + } + + return new LocalVariableTableImpl(locals); + } + + /** + * Returns the offset of this method into the v-table. The method must have a v-table entry as + * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is + * thrown. + * + * @return the offset of this method into the v-table + */ + public int vtableEntryOffset(ResolvedJavaType resolved) { + if (!isInVirtualMethodTable(resolved)) { + throw new JVMCIError("%s does not have a vtable entry in type %s", this, resolved); + } + HotSpotVMConfig config = runtime().getConfig(); + final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved); + return config.instanceKlassVtableStartOffset() + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset; + } + + @Override + public boolean isInVirtualMethodTable(ResolvedJavaType resolved) { + if (resolved instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved; + int vtableIndex = getVtableIndex(hotspotResolved); + return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength(); + } + return false; + } + + private int getVtableIndex(HotSpotResolvedObjectTypeImpl resolved) { + if (!holder.isLinked()) { + return runtime().getConfig().invalidVtableIndex; + } + if (holder.isInterface()) { + if (resolved.isInterface()) { + return runtime().getConfig().invalidVtableIndex; + } + return getVtableIndexForInterfaceMethod(resolved); + } + return getVtableIndex(); + } + + /** + * Returns this method's virtual table index. + * + * @return virtual table index + */ + private int getVtableIndex() { + assert!holder.isInterface(); + HotSpotVMConfig config = runtime().getConfig(); + int result = UNSAFE.getInt(metaspaceMethod + config.methodVtableIndexOffset); + assert result >= config.nonvirtualVtableIndex : "must be linked"; + return result; + } + + private int getVtableIndexForInterfaceMethod(ResolvedJavaType resolved) { + HotSpotResolvedObjectTypeImpl hotspotType = (HotSpotResolvedObjectTypeImpl) resolved; + return runtime().getCompilerToVM().getVtableIndexForInterfaceMethod(hotspotType, this); + } + + /** + * The {@link SpeculationLog} for methods compiled by JVMCI hang off this per-declaring-type + * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is + * never moves and b) we never read from it. + *

+ * One implication is that we will preserve {@link SpeculationLog}s for methods that have been + * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot + * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods + * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal). + */ + private static final ClassValue> SpeculationLogs = new ClassValue>() { + @Override + protected Map computeValue(java.lang.Class type) { + return new HashMap<>(4); + } + }; + + public SpeculationLog getSpeculationLog() { + Map map = SpeculationLogs.get(holder.mirror()); + synchronized (map) { + SpeculationLog log = map.get(this.metaspaceMethod); + if (log == null) { + log = new HotSpotSpeculationLog(); + map.put(metaspaceMethod, log); + } + return log; + } + } + + public int intrinsicId() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getChar(metaspaceMethod + config.methodIntrinsicIdOffset); + } + + @Override + public JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments) { + assert!isConstructor(); + Method javaMethod = toJava(); + javaMethod.setAccessible(true); + + Object[] objArguments = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + objArguments[i] = HotSpotObjectConstantImpl.asBoxedValue(arguments[i]); + } + Object objReceiver = receiver != null && !receiver.isNull() ? ((HotSpotObjectConstantImpl) receiver).object() : null; + + try { + Object objResult = javaMethod.invoke(objReceiver, objArguments); + return javaMethod.getReturnType() == void.class ? null : HotSpotObjectConstantImpl.forBoxedValue(getSignature().getReturnKind(), objResult); + + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new IllegalArgumentException(ex); + } + } + + /** + * Allocates a compile id for this method by asking the VM for one. + * + * @param entryBCI entry bci + * @return compile id + */ + public int allocateCompileId(int entryBCI) { + return runtime().getCompilerToVM().allocateCompileId(this, entryBCI); + } + + public boolean hasCodeAtLevel(int entryBCI, int level) { + if (entryBCI == runtime().getConfig().invocationEntryBci) { + return hasCompiledCodeAtLevel(level); + } + return runtime().getCompilerToVM().hasCompiledCodeForOSR(this, entryBCI, level); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java new file mode 100644 index 00000000000..365ff70b11e --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { + + public HotSpotResolvedJavaType(String name) { + super(name); + } + + public abstract Class mirror(); + + @Override + public final boolean equals(Object obj) { + if (!(obj instanceof HotSpotResolvedJavaType)) { + return false; + } + HotSpotResolvedJavaType that = (HotSpotResolvedJavaType) obj; + return this.mirror().equals(that.mirror()); + } + + @Override + public final int hashCode() { + return getName().hashCode(); + } + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java new file mode 100644 index 00000000000..18c04ece6bc --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.*; + +/** + * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. + */ +public interface HotSpotResolvedObjectType extends ResolvedJavaType { + + HotSpotResolvedObjectType getArrayClass(); + + ResolvedJavaType getComponentType(); + + AssumptionResult findLeafConcreteSubtype(); + + HotSpotResolvedObjectType getSuperclass(); + + HotSpotResolvedObjectType[] getInterfaces(); + + HotSpotResolvedObjectType getSupertype(); + + HotSpotResolvedObjectType findLeastCommonAncestor(ResolvedJavaType otherType); + + HotSpotResolvedObjectType asExactType(); + + default boolean isPrimitive() { + return false; + } + + default JavaKind getJavaKind() { + return JavaKind.Object; + } + + ConstantPool getConstantPool(); + + /** + * Gets the instance size of this type. If an instance of this type cannot be fast path + * allocated, then the returned value is negative (its absolute value gives the size). Must not + * be called if this is an array or interface type. + */ + int instanceSize(); + + int getVtableLength(); + + @Override + AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method); + + /** + * Performs a fast-path check that this type is resolved in the context of a given accessing + * class. A negative result does not mean this type is not resolved with respect to + * {@code accessingClass}. That can only be determined by + * {@linkplain HotSpotJVMCIRuntime#lookupType(String, HotSpotResolvedObjectType, boolean) + * re-resolving} the type. + */ + boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass); + + /** + * Gets the metaspace Klass boxed in a {@link JavaConstant}. + */ + Constant klass(); + + boolean isPrimaryType(); + + int superCheckOffset(); + + long prototypeMarkWord(); + + int layoutHelper(); + + HotSpotResolvedObjectType getEnclosingType(); + + ResolvedJavaMethod getClassInitializer(); + + ResolvedJavaField createField(String name, JavaType type, long offset, int modifiers); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java new file mode 100644 index 00000000000..735ff43f4eb --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -0,0 +1,889 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static java.util.Objects.*; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.*; +import java.nio.*; +import java.util.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.*; + +/** + * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. + */ +public final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, HotSpotProxified, MetaspaceWrapperObject { + + /** + * The Java class this type represents. + */ + private final Class javaClass; + private HashMap fieldCache; + private HashMap methodCache; + private HotSpotResolvedJavaField[] instanceFields; + private HotSpotResolvedObjectTypeImpl[] interfaces; + private HotSpotConstantPool constantPool; + final HotSpotJVMCIMetaAccessContext context; + private HotSpotResolvedObjectType arrayOfType; + + /** + * Gets the JVMCI mirror for a {@link Class} object. + * + * @return the {@link HotSpotResolvedJavaType} corresponding to {@code javaClass} + */ + public static HotSpotResolvedObjectTypeImpl fromObjectClass(Class javaClass) { + return (HotSpotResolvedObjectTypeImpl) runtime().fromClass(javaClass); + } + + /** + * Gets the JVMCI mirror from a HotSpot type. Since {@link Class} is already a proxy for the + * underlying Klass*, it is used instead of the raw Klass*. + * + * Called from the VM. + * + * @param javaClass a {@link Class} object + * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} + */ + @SuppressWarnings("unused") + private static HotSpotResolvedObjectTypeImpl fromMetaspace(Class javaClass) { + return fromObjectClass(javaClass); + } + + /** + * Creates the JVMCI mirror for a {@link Class} object. + * + *

+ * NOTE: Creating an instance of this class does not install the mirror for the + * {@link Class} type. Use {@link #fromObjectClass(Class)} or {@link #fromMetaspace(Class)} + * instead. + *

+ * + * @param javaClass the Class to create the mirror for + * @param context + */ + HotSpotResolvedObjectTypeImpl(Class javaClass, HotSpotJVMCIMetaAccessContext context) { + super(getSignatureName(javaClass)); + this.javaClass = javaClass; + this.context = context; + assert getName().charAt(0) != '[' || isArray() : getName(); + } + + /** + * Returns the name of this type as it would appear in a signature. + */ + private static String getSignatureName(Class javaClass) { + if (javaClass.isArray()) { + return javaClass.getName().replace('.', '/'); + } + return "L" + javaClass.getName().replace('.', '/') + ";"; + } + + /** + * Gets the metaspace Klass for this type. + */ + public long getMetaspaceKlass() { + if (HotSpotJVMCIRuntime.getHostWordKind() == JavaKind.Long) { + return UNSAFE.getLong(javaClass, (long) runtime().getConfig().klassOffset); + } + return UNSAFE.getInt(javaClass, (long) runtime().getConfig().klassOffset) & 0xFFFFFFFFL; + } + + public long getMetaspacePointer() { + return getMetaspaceKlass(); + } + + @Override + public int getModifiers() { + if (isArray()) { + return (getElementalType().getModifiers() & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED)) | Modifier.FINAL | Modifier.ABSTRACT; + } else { + return getAccessFlags() & ModifiersProvider.jvmClassModifiers(); + } + } + + public int getAccessFlags() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset); + } + + @Override + public HotSpotResolvedObjectType getArrayClass() { + if (arrayOfType == null) { + arrayOfType = fromObjectClass(Array.newInstance(mirror(), 0).getClass()); + } + return arrayOfType; + } + + @Override + public ResolvedJavaType getComponentType() { + Class javaComponentType = mirror().getComponentType(); + return javaComponentType == null ? null : runtime().fromClass(javaComponentType); + } + + @Override + public AssumptionResult findLeafConcreteSubtype() { + HotSpotVMConfig config = runtime().getConfig(); + if (isArray()) { + return getElementalType().isLeaf() ? new AssumptionResult<>(this) : null; + } else if (isInterface()) { + HotSpotResolvedObjectTypeImpl implementor = getSingleImplementor(); + /* + * If the implementor field contains itself that indicates that the interface has more + * than one implementors (see: InstanceKlass::add_implementor). + */ + if (implementor == null || implementor.equals(this)) { + return null; + } + + assert !implementor.isInterface(); + if (implementor.isAbstract() || !implementor.isLeafClass()) { + AssumptionResult leafConcreteSubtype = implementor.findLeafConcreteSubtype(); + if (leafConcreteSubtype != null) { + assert !leafConcreteSubtype.getResult().equals(implementor); + AssumptionResult newResult = new AssumptionResult<>(leafConcreteSubtype.getResult(), new ConcreteSubtype(this, implementor)); + // Accumulate leaf assumptions and return the combined result. + newResult.add(leafConcreteSubtype); + return newResult; + } + return null; + } + + return new AssumptionResult<>(implementor, new LeafType(implementor), new ConcreteSubtype(this, implementor)); + } else { + HotSpotResolvedObjectTypeImpl type = this; + while (type.isAbstract()) { + HotSpotResolvedObjectTypeImpl subklass = type.getSubklass(); + if (subklass == null || UNSAFE.getAddress(subklass.getMetaspaceKlass() + config.nextSiblingOffset) != 0) { + return null; + } + type = subklass; + } + if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) { + return null; + } + if (this.isAbstract()) { + return new AssumptionResult<>(type, new LeafType(type), new ConcreteSubtype(this, type)); + } else { + assert this.equals(type); + return new AssumptionResult<>(type, new LeafType(type)); + } + } + } + + /** + * Returns if type {@code type} is a leaf class. This is the case if the + * {@code Klass::_subklass} field of the underlying class is zero. + * + * @return true if the type is a leaf class + */ + private boolean isLeafClass() { + return getSubklass() == null; + } + + /** + * Returns the {@code Klass::_subklass} field of the underlying metaspace klass for the given + * type {@code type}. + * + * @return value of the subklass field as metaspace klass pointer + */ + private HotSpotResolvedObjectTypeImpl getSubklass() { + return runtime().getCompilerToVM().getResolvedJavaType(this, runtime().getConfig().subklassOffset, false); + } + + @Override + public HotSpotResolvedObjectTypeImpl getSuperclass() { + Class javaSuperclass = mirror().getSuperclass(); + return javaSuperclass == null ? null : fromObjectClass(javaSuperclass); + } + + @Override + public HotSpotResolvedObjectTypeImpl[] getInterfaces() { + if (interfaces == null) { + Class[] javaInterfaces = mirror().getInterfaces(); + HotSpotResolvedObjectTypeImpl[] result = new HotSpotResolvedObjectTypeImpl[javaInterfaces.length]; + for (int i = 0; i < javaInterfaces.length; i++) { + result[i] = fromObjectClass(javaInterfaces[i]); + } + interfaces = result; + } + return interfaces; + } + + @Override + public HotSpotResolvedObjectTypeImpl getSingleImplementor() { + if (!isInterface()) { + throw new JVMCIError("Cannot call getSingleImplementor() on a non-interface type: %s", this); + } + return runtime().getCompilerToVM().getImplementor(this); + } + + public HotSpotResolvedObjectTypeImpl getSupertype() { + if (isArray()) { + ResolvedJavaType componentType = getComponentType(); + if (mirror() == Object[].class || componentType.isPrimitive()) { + return fromObjectClass(Object.class); + } + return (HotSpotResolvedObjectTypeImpl) ((HotSpotResolvedObjectTypeImpl) componentType).getSupertype().getArrayClass(); + } + if (isInterface()) { + return fromObjectClass(Object.class); + } + return getSuperclass(); + } + + @Override + public HotSpotResolvedObjectType findLeastCommonAncestor(ResolvedJavaType otherType) { + if (otherType.isPrimitive()) { + return null; + } else { + HotSpotResolvedObjectTypeImpl t1 = this; + HotSpotResolvedObjectTypeImpl t2 = (HotSpotResolvedObjectTypeImpl) otherType; + while (true) { + if (t1.isAssignableFrom(t2)) { + return t1; + } + if (t2.isAssignableFrom(t1)) { + return t2; + } + t1 = t1.getSupertype(); + t2 = t2.getSupertype(); + } + } + } + + @Override + public HotSpotResolvedObjectType asExactType() { + return isLeaf() ? this : null; + } + + @Override + public JavaConstant getJavaClass() { + return HotSpotObjectConstantImpl.forObject(mirror()); + } + + @Override + public JavaConstant getObjectHub() { + return klass(); + } + + @Override + public AssumptionResult hasFinalizableSubclass() { + assert !isArray(); + if (!runtime().getCompilerToVM().hasFinalizableSubclass(this)) { + return new AssumptionResult<>(false, new NoFinalizableSubclass(this)); + } + return new AssumptionResult<>(true); + } + + @Override + public boolean hasFinalizer() { + HotSpotVMConfig config = runtime().getConfig(); + return (getAccessFlags() & config.klassHasFinalizerFlag) != 0; + } + + @Override + public boolean isPrimitive() { + return false; + } + + @Override + public boolean isArray() { + return mirror().isArray(); + } + + @Override + public boolean isInitialized() { + return isArray() ? true : getInitState() == runtime().getConfig().instanceKlassStateFullyInitialized; + } + + @Override + public boolean isLinked() { + return isArray() ? true : getInitState() >= runtime().getConfig().instanceKlassStateLinked; + } + + /** + * Returns the value of the state field {@code InstanceKlass::_init_state} of the metaspace + * klass. + * + * @return state field value of this type + */ + private int getInitState() { + assert !isArray() : "_init_state only exists in InstanceKlass"; + return UNSAFE.getByte(getMetaspaceKlass() + runtime().getConfig().instanceKlassInitStateOffset) & 0xFF; + } + + @Override + public void initialize() { + if (!isInitialized()) { + UNSAFE.ensureClassInitialized(mirror()); + assert isInitialized(); + } + } + + @Override + public boolean isInstance(JavaConstant obj) { + if (obj.getJavaKind() == JavaKind.Object && !obj.isNull()) { + return mirror().isInstance(((HotSpotObjectConstantImpl) obj).object()); + } + return false; + } + + @Override + public boolean isInstanceClass() { + return !isArray() && !isInterface(); + } + + @Override + public boolean isInterface() { + return mirror().isInterface(); + } + + @Override + public boolean isAssignableFrom(ResolvedJavaType other) { + assert other != null; + if (other instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl otherType = (HotSpotResolvedObjectTypeImpl) other; + return mirror().isAssignableFrom(otherType.mirror()); + } + return false; + } + + @Override + public boolean isJavaLangObject() { + return javaClass.equals(Object.class); + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + ResolvedJavaMethod resolvedMethod = resolveMethod(method, callerType); + if (resolvedMethod == null || resolvedMethod.isAbstract()) { + return null; + } + return resolvedMethod; + } + + @Override + public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + assert !callerType.isArray(); + if (method.isConcrete() && method.getDeclaringClass().equals(this) && method.isPublic()) { + return method; + } + if (!method.getDeclaringClass().isAssignableFrom(this)) { + return null; + } + HotSpotResolvedJavaMethodImpl hotSpotMethod = (HotSpotResolvedJavaMethodImpl) method; + HotSpotResolvedObjectTypeImpl hotSpotCallerType = (HotSpotResolvedObjectTypeImpl) callerType; + return runtime().getCompilerToVM().resolveMethod(this, hotSpotMethod, hotSpotCallerType); + } + + public HotSpotConstantPool getConstantPool() { + if (constantPool == null) { + constantPool = runtime().getCompilerToVM().getConstantPool(this, runtime().getConfig().instanceKlassConstantsOffset); + } + return constantPool; + } + + /** + * Gets the instance size of this type. If an instance of this type cannot be fast path + * allocated, then the returned value is negative (its absolute value gives the size). Must not + * be called if this is an array or interface type. + */ + public int instanceSize() { + assert !isArray(); + assert !isInterface(); + + HotSpotVMConfig config = runtime().getConfig(); + final int layoutHelper = layoutHelper(); + assert layoutHelper > config.klassLayoutHelperNeutralValue : "must be instance"; + + // See: Klass::layout_helper_size_in_bytes + int size = layoutHelper & ~config.klassLayoutHelperInstanceSlowPathBit; + + // See: Klass::layout_helper_needs_slow_path + boolean needsSlowPath = (layoutHelper & config.klassLayoutHelperInstanceSlowPathBit) != 0; + + return needsSlowPath ? -size : size; + } + + public int layoutHelper() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset); + } + + synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) { + HotSpotResolvedJavaMethodImpl method = null; + if (methodCache == null) { + methodCache = new HashMap<>(8); + } else { + method = methodCache.get(metaspaceMethod); + } + if (method == null) { + method = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod); + methodCache.put(metaspaceMethod, method); + context.add(method); + } + return method; + } + + public int getVtableLength() { + HotSpotVMConfig config = runtime().getConfig(); + if (isInterface() || isArray()) { + /* Everything has the core vtable of java.lang.Object */ + return config.baseVtableLength(); + } + int result = UNSAFE.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) / (config.vtableEntrySize / config.heapWordSize); + assert result >= config.baseVtableLength() : UNSAFE.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) + " " + config.vtableEntrySize; + return result; + } + + public synchronized HotSpotResolvedJavaField createField(String fieldName, JavaType type, long offset, int rawFlags) { + HotSpotResolvedJavaField result = null; + + final int flags = rawFlags & ModifiersProvider.jvmFieldModifiers(); + + final long id = offset + ((long) flags << 32); + + // Must cache the fields, because the local load elimination only works if the + // objects from two field lookups are identical. + if (fieldCache == null) { + fieldCache = new HashMap<>(8); + } else { + result = fieldCache.get(id); + } + + if (result == null) { + result = new HotSpotResolvedJavaFieldImpl(this, fieldName, type, offset, rawFlags); + fieldCache.put(id, result); + } else { + assert result.getName().equals(fieldName); + // assert result.getType().equals(type); + assert result.offset() == offset; + assert result.getModifiers() == flags; + } + + return result; + } + + @Override + public AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method) { + HotSpotResolvedJavaMethod hmethod = (HotSpotResolvedJavaMethod) method; + HotSpotResolvedObjectType declaredHolder = hmethod.getDeclaringClass(); + /* + * Sometimes the receiver type in the graph hasn't stabilized to a subtype of declared + * holder, usually because of phis, so make sure that the type is related to the declared + * type before using it for lookup. Unlinked types should also be ignored because we can't + * resolve the proper method to invoke. Generally unlinked types in invokes should result in + * a deopt instead since they can't really be used if they aren't linked yet. + */ + if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder) || !isLinked() || isInterface()) { + ResolvedJavaMethod result = hmethod.uniqueConcreteMethod(declaredHolder); + if (result != null) { + return new AssumptionResult<>(result, new ConcreteMethod(method, declaredHolder, result)); + } + return null; + } + /* + * The holder may be a subtype of the declaredHolder so make sure to resolve the method to + * the correct method for the subtype. + */ + HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) resolveMethod(hmethod, this); + if (resolvedMethod == null) { + // The type isn't known to implement the method. + return null; + } + + ResolvedJavaMethod result = resolvedMethod.uniqueConcreteMethod(this); + if (result != null) { + return new AssumptionResult<>(result, new ConcreteMethod(method, this, result)); + } + return null; + } + + /** + * This class represents the field information for one field contained in the fields array of an + * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. + */ + private class FieldInfo { + /** + * Native pointer into the array of Java shorts. + */ + private final long metaspaceData; + + /** + * Creates a field info for the field in the fields array at index {@code index}. + * + * @param index index to the fields array + */ + public FieldInfo(int index) { + HotSpotVMConfig config = runtime().getConfig(); + // Get Klass::_fields + final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); + assert config.fieldInfoFieldSlots == 6 : "revisit the field parsing code"; + metaspaceData = metaspaceFields + config.arrayU2DataOffset + config.fieldInfoFieldSlots * Short.BYTES * index; + } + + private int getAccessFlags() { + return readFieldSlot(runtime().getConfig().fieldInfoAccessFlagsOffset); + } + + private int getNameIndex() { + return readFieldSlot(runtime().getConfig().fieldInfoNameIndexOffset); + } + + private int getSignatureIndex() { + return readFieldSlot(runtime().getConfig().fieldInfoSignatureIndexOffset); + } + + public int getOffset() { + HotSpotVMConfig config = runtime().getConfig(); + final int lowPacked = readFieldSlot(config.fieldInfoLowPackedOffset); + final int highPacked = readFieldSlot(config.fieldInfoHighPackedOffset); + final int offset = ((highPacked << Short.SIZE) | lowPacked) >> config.fieldInfoTagSize; + return offset; + } + + /** + * Helper method to read an entry (slot) from the field array. Currently field info is laid + * on top an array of Java shorts. + */ + private int readFieldSlot(int index) { + return UNSAFE.getChar(metaspaceData + Short.BYTES * index); + } + + /** + * Returns the name of this field as a {@link String}. If the field is an internal field the + * name index is pointing into the vmSymbols table. + */ + public String getName() { + final int nameIndex = getNameIndex(); + return isInternal() ? HotSpotVmSymbols.symbolAt(nameIndex) : getConstantPool().lookupUtf8(nameIndex); + } + + /** + * Returns the signature of this field as {@link String}. If the field is an internal field + * the signature index is pointing into the vmSymbols table. + */ + public String getSignature() { + final int signatureIndex = getSignatureIndex(); + return isInternal() ? HotSpotVmSymbols.symbolAt(signatureIndex) : getConstantPool().lookupUtf8(signatureIndex); + } + + public JavaType getType() { + String signature = getSignature(); + return runtime().lookupType(signature, HotSpotResolvedObjectTypeImpl.this, false); + } + + private boolean isInternal() { + return (getAccessFlags() & runtime().getConfig().jvmAccFieldInternal) != 0; + } + + public boolean isStatic() { + return Modifier.isStatic(getAccessFlags()); + } + + public boolean hasGenericSignature() { + return (getAccessFlags() & runtime().getConfig().jvmAccFieldHasGenericSignature) != 0; + } + } + + private static class OffsetComparator implements java.util.Comparator { + @Override + public int compare(HotSpotResolvedJavaField o1, HotSpotResolvedJavaField o2) { + return o1.offset() - o2.offset(); + } + } + + @Override + public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { + if (instanceFields == null) { + if (isArray() || isInterface()) { + instanceFields = new HotSpotResolvedJavaField[0]; + } else { + final int fieldCount = getFieldCount(); + ArrayList fieldsArray = new ArrayList<>(fieldCount); + + for (int i = 0; i < fieldCount; i++) { + FieldInfo field = new FieldInfo(i); + + // We are only interested in instance fields. + if (!field.isStatic()) { + HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); + fieldsArray.add(resolvedJavaField); + } + } + + fieldsArray.sort(new OffsetComparator()); + + HotSpotResolvedJavaField[] myFields = fieldsArray.toArray(new HotSpotResolvedJavaField[0]); + + if (mirror() != Object.class) { + HotSpotResolvedJavaField[] superFields = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); + HotSpotResolvedJavaField[] fields = Arrays.copyOf(superFields, superFields.length + myFields.length); + System.arraycopy(myFields, 0, fields, superFields.length, myFields.length); + instanceFields = fields; + } else { + assert myFields.length == 0 : "java.lang.Object has fields!"; + instanceFields = myFields; + } + + } + } + if (!includeSuperclasses) { + int myFieldsStart = 0; + while (myFieldsStart < instanceFields.length && !instanceFields[myFieldsStart].getDeclaringClass().equals(this)) { + myFieldsStart++; + } + if (myFieldsStart == 0) { + return instanceFields; + } + if (myFieldsStart == instanceFields.length) { + return new HotSpotResolvedJavaField[0]; + } + return Arrays.copyOfRange(instanceFields, myFieldsStart, instanceFields.length); + } + return instanceFields; + } + + @Override + public ResolvedJavaField[] getStaticFields() { + if (isArray()) { + return new HotSpotResolvedJavaField[0]; + } else { + final int fieldCount = getFieldCount(); + ArrayList fieldsArray = new ArrayList<>(fieldCount); + + for (int i = 0; i < fieldCount; i++) { + FieldInfo field = new FieldInfo(i); + + // We are only interested in static fields. + if (field.isStatic()) { + HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); + fieldsArray.add(resolvedJavaField); + } + } + + fieldsArray.sort(new OffsetComparator()); + return fieldsArray.toArray(new HotSpotResolvedJavaField[fieldsArray.size()]); + } + } + + /** + * Returns the actual field count of this class's internal {@code InstanceKlass::_fields} array + * by walking the array and discounting the generic signature slots at the end of the array. + * + *

+ * See {@code FieldStreamBase::init_generic_signature_start_slot} + */ + private int getFieldCount() { + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); + int metaspaceFieldsLength = UNSAFE.getInt(metaspaceFields + config.arrayU1LengthOffset); + int fieldCount = 0; + + for (int i = 0, index = 0; i < metaspaceFieldsLength; i += config.fieldInfoFieldSlots, index++) { + FieldInfo field = new FieldInfo(index); + if (field.hasGenericSignature()) { + metaspaceFieldsLength--; + } + fieldCount++; + } + return fieldCount; + } + + @Override + public Class mirror() { + return javaClass; + } + + @Override + public String getSourceFileName() { + HotSpotVMConfig config = runtime().getConfig(); + final int sourceFileNameIndex = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassSourceFileNameIndexOffset); + if (sourceFileNameIndex == 0) { + return null; + } + return getConstantPool().lookupUtf8(sourceFileNameIndex); + } + + @Override + public Annotation[] getAnnotations() { + return mirror().getAnnotations(); + } + + @Override + public T getAnnotation(Class annotationClass) { + return mirror().getAnnotation(annotationClass); + } + + /** + * Performs a fast-path check that this type is resolved in the context of a given accessing + * class. A negative result does not mean this type is not resolved with respect to + * {@code accessingClass}. That can only be determined by + * {@linkplain HotSpotJVMCIRuntime#lookupType(String, HotSpotResolvedObjectType, boolean) + * re-resolving} the type. + */ + public boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass) { + assert accessingClass != null; + ResolvedJavaType elementType = getElementalType(); + if (elementType.isPrimitive()) { + // Primitive type resolution is context free. + return true; + } + if (elementType.getName().startsWith("Ljava/")) { + // Classes in a java.* package can only be defined by the + // boot class loader. This is enforced by ClassLoader.preDefineClass() + assert mirror().getClassLoader() == null; + return true; + } + ClassLoader thisCl = mirror().getClassLoader(); + ClassLoader accessingClassCl = ((HotSpotResolvedObjectTypeImpl) accessingClass).mirror().getClassLoader(); + return thisCl == accessingClassCl; + } + + @Override + public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { + if (isDefinitelyResolvedWithRespectTo(requireNonNull(accessingClass))) { + return this; + } + HotSpotResolvedObjectTypeImpl accessingType = (HotSpotResolvedObjectTypeImpl) accessingClass; + return (ResolvedJavaType) runtime().lookupType(getName(), accessingType, true); + } + + /** + * Gets the metaspace Klass boxed in a {@link JavaConstant}. + */ + public JavaConstant klass() { + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(runtime().getHostJVMCIBackend().getTarget().wordKind, getMetaspaceKlass(), this, false); + } + + public boolean isPrimaryType() { + return runtime().getConfig().secondarySuperCacheOffset != superCheckOffset(); + } + + public int superCheckOffset() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getInt(getMetaspaceKlass() + config.superCheckOffsetOffset); + } + + public long prototypeMarkWord() { + HotSpotVMConfig config = runtime().getConfig(); + if (isArray()) { + return config.arrayPrototypeMarkWord(); + } else { + return UNSAFE.getAddress(getMetaspaceKlass() + config.prototypeMarkWordOffset); + } + } + + @Override + public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedEntryKind) { + ResolvedJavaField[] declaredFields = getInstanceFields(true); + for (ResolvedJavaField field : declaredFields) { + HotSpotResolvedJavaField resolvedField = (HotSpotResolvedJavaField) field; + long resolvedFieldOffset = resolvedField.offset(); + // @formatter:off + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && + expectedEntryKind.isPrimitive() && + !expectedEntryKind.equals(JavaKind.Void) && + resolvedField.getJavaKind().isPrimitive()) { + resolvedFieldOffset += + resolvedField.getJavaKind().getByteCount() - + Math.min(resolvedField.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()); + } + if (resolvedFieldOffset == offset) { + return field; + } + // @formatter:on + } + return null; + } + + @Override + public URL getClassFilePath() { + Class cls = mirror(); + return cls.getResource(MetaUtil.getSimpleName(cls, true).replace('.', '$') + ".class"); + } + + @Override + public boolean isLocal() { + return mirror().isLocalClass(); + } + + @Override + public boolean isMember() { + return mirror().isMemberClass(); + } + + @Override + public HotSpotResolvedObjectTypeImpl getEnclosingType() { + final Class encl = mirror().getEnclosingClass(); + return encl == null ? null : fromObjectClass(encl); + } + + @Override + public ResolvedJavaMethod[] getDeclaredConstructors() { + Constructor[] constructors = mirror().getDeclaredConstructors(); + ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length]; + for (int i = 0; i < constructors.length; i++) { + result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(constructors[i]); + assert result[i].isConstructor(); + } + return result; + } + + @Override + public ResolvedJavaMethod[] getDeclaredMethods() { + Method[] methods = mirror().getDeclaredMethods(); + ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length]; + for (int i = 0; i < methods.length; i++) { + result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(methods[i]); + assert !result[i].isConstructor(); + } + return result; + } + + public ResolvedJavaMethod getClassInitializer() { + return runtime().getCompilerToVM().getClassInitializer(this); + } + + @Override + public String toString() { + return "HotSpotType<" + getName() + ", resolved>"; + } + + @Override + public boolean isTrustedInterfaceType() { + return TrustedInterface.class.isAssignableFrom(mirror()); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java new file mode 100644 index 00000000000..7d0491553f9 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static java.util.Objects.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.AssumptionResult; + +/** + * Implementation of {@link JavaType} for primitive HotSpot types. + */ +public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType implements HotSpotProxified { + + private final JavaKind kind; + + /** + * Creates the JVMCI mirror for a primitive {@link JavaKind}. + * + *

+ * NOTE: Creating an instance of this class does not install the mirror for the + * {@link Class} type. Use {@link HotSpotJVMCIRuntimeProvider#fromClass(Class)} instead. + *

+ * + * @param kind the Kind to create the mirror for + */ + public HotSpotResolvedPrimitiveType(JavaKind kind) { + super(String.valueOf(Character.toUpperCase(kind.getTypeChar()))); + this.kind = kind; + assert mirror().isPrimitive() : mirror() + " not a primitive type"; + } + + @Override + public int getModifiers() { + return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; + } + + @Override + public HotSpotResolvedObjectTypeImpl getArrayClass() { + if (kind == JavaKind.Void) { + return null; + } + Class javaArrayMirror = Array.newInstance(mirror(), 0).getClass(); + return HotSpotResolvedObjectTypeImpl.fromObjectClass(javaArrayMirror); + } + + public ResolvedJavaType getElementalType() { + return this; + } + + @Override + public ResolvedJavaType getComponentType() { + return null; + } + + @Override + public ResolvedJavaType asExactType() { + return this; + } + + @Override + public ResolvedJavaType getSuperclass() { + return null; + } + + @Override + public ResolvedJavaType[] getInterfaces() { + return new ResolvedJavaType[0]; + } + + @Override + public ResolvedJavaType getSingleImplementor() { + throw new JVMCIError("Cannot call getSingleImplementor() on a non-interface type: %s", this); + } + + @Override + public ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType) { + return null; + } + + @Override + public JavaConstant getObjectHub() { + throw JVMCIError.unimplemented(); + } + + @Override + public JavaConstant getJavaClass() { + throw JVMCIError.unimplemented(); + } + + @Override + public AssumptionResult hasFinalizableSubclass() { + return new AssumptionResult<>(false); + } + + @Override + public boolean hasFinalizer() { + return false; + } + + @Override + public boolean isArray() { + return false; + } + + @Override + public boolean isPrimitive() { + return true; + } + + @Override + public boolean isInitialized() { + return true; + } + + public boolean isLinked() { + return true; + } + + @Override + public boolean isInstance(JavaConstant obj) { + return false; + } + + @Override + public boolean isInstanceClass() { + return false; + } + + @Override + public boolean isInterface() { + return false; + } + + @Override + public boolean isAssignableFrom(ResolvedJavaType other) { + assert other != null; + return other.equals(this); + } + + @Override + public JavaKind getJavaKind() { + return kind; + } + + @Override + public boolean isJavaLangObject() { + return false; + } + + @Override + public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + return null; + } + + @Override + public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + return null; + } + + @Override + public String toString() { + return "HotSpotResolvedPrimitiveType<" + kind + ">"; + } + + @Override + public AssumptionResult findLeafConcreteSubtype() { + return new AssumptionResult<>(this); + } + + @Override + public AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method) { + return null; + } + + @Override + public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { + return new ResolvedJavaField[0]; + } + + @Override + public ResolvedJavaField[] getStaticFields() { + return new ResolvedJavaField[0]; + } + + @Override + public Annotation[] getAnnotations() { + return new Annotation[0]; + } + + @Override + public T getAnnotation(Class annotationClass) { + return null; + } + + @Override + public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { + requireNonNull(accessingClass); + return this; + } + + @Override + public void initialize() { + } + + @Override + public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedType) { + return null; + } + + @Override + public String getSourceFileName() { + throw JVMCIError.unimplemented(); + } + + @Override + public Class mirror() { + return kind.toJavaClass(); + } + + @Override + public URL getClassFilePath() { + return null; + } + + @Override + public boolean isLocal() { + return false; + } + + @Override + public boolean isMember() { + return false; + } + + @Override + public ResolvedJavaType getEnclosingType() { + return null; + } + + @Override + public ResolvedJavaMethod[] getDeclaredConstructors() { + return new ResolvedJavaMethod[0]; + } + + @Override + public ResolvedJavaMethod[] getDeclaredMethods() { + return new ResolvedJavaMethod[0]; + } + + @Override + public ResolvedJavaMethod getClassInitializer() { + return null; + } + + @Override + public boolean isTrustedInterfaceType() { + return false; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSentinelConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSentinelConstant.java new file mode 100644 index 00000000000..0ce340d12ac --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSentinelConstant.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +public final class HotSpotSentinelConstant extends Value implements JavaConstant, VMConstant { + + public HotSpotSentinelConstant(JavaKind kind) { + super(LIRKind.reference(kind)); + } + + public JavaKind getJavaKind() { + return (JavaKind) getLIRKind().getPlatformKind(); + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public boolean isDefaultForKind() { + return true; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public String toString() { + return JavaConstant.toString(this); + } + + @Override + public String toValueString() { + return "sentinel"; + } + + @Override + public int hashCode() { + return 13; + } + + @Override + public boolean equals(Object o) { + return o instanceof HotSpotSentinelConstant; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java new file mode 100644 index 00000000000..5d873e9ac95 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.util.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; + +/** + * Represents a method signature. + */ +public class HotSpotSignature implements Signature { + + private final List parameters = new ArrayList<>(); + private final String returnType; + private final String originalString; + private ResolvedJavaType[] parameterTypes; + private ResolvedJavaType returnTypeCache; + private final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotSignature(HotSpotJVMCIRuntimeProvider runtime, String signature) { + this.runtime = runtime; + assert signature.length() > 0; + this.originalString = signature; + + if (signature.charAt(0) == '(') { + int cur = 1; + while (cur < signature.length() && signature.charAt(cur) != ')') { + int nextCur = parseSignature(signature, cur); + parameters.add(signature.substring(cur, nextCur)); + cur = nextCur; + } + + cur++; + int nextCur = parseSignature(signature, cur); + returnType = signature.substring(cur, nextCur); + assert nextCur == signature.length(); + } else { + returnType = null; + } + } + + public HotSpotSignature(HotSpotJVMCIRuntimeProvider runtime, ResolvedJavaType returnType, ResolvedJavaType... parameterTypes) { + this.runtime = runtime; + this.parameterTypes = parameterTypes.clone(); + this.returnTypeCache = returnType; + this.returnType = returnType.getName(); + StringBuilder sb = new StringBuilder("("); + for (JavaType type : parameterTypes) { + parameters.add(type.getName()); + sb.append(type.getName()); + } + sb.append(")").append(returnType.getName()); + this.originalString = sb.toString(); + assert new HotSpotSignature(runtime, originalString).equals(this); + } + + private static int parseSignature(String signature, int start) { + int cur = start; + char first; + do { + first = signature.charAt(cur++); + } while (first == '['); + + switch (first) { + case 'L': + while (signature.charAt(cur) != ';') { + cur++; + } + cur++; + break; + case 'V': + case 'I': + case 'B': + case 'C': + case 'D': + case 'F': + case 'J': + case 'S': + case 'Z': + break; + default: + throw new JVMCIError("Invalid character at index %d in signature: %s", cur, signature); + } + return cur; + } + + @Override + public int getParameterCount(boolean withReceiver) { + return parameters.size() + (withReceiver ? 1 : 0); + } + + @Override + public JavaKind getParameterKind(int index) { + return JavaKind.fromTypeString(parameters.get(index)); + } + + private static boolean checkValidCache(ResolvedJavaType type, ResolvedJavaType accessingClass) { + assert accessingClass != null; + if (type == null) { + return false; + } else if (type instanceof HotSpotResolvedObjectTypeImpl) { + return ((HotSpotResolvedObjectTypeImpl) type).isDefinitelyResolvedWithRespectTo(accessingClass); + } + return true; + } + + private static JavaType getUnresolvedOrPrimitiveType(HotSpotJVMCIRuntimeProvider runtime, String name) { + if (name.length() == 1) { + JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); + return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(kind.toJavaClass()); + } + return new HotSpotUnresolvedJavaType(name, runtime); + } + + @Override + public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { + if (accessingClass == null) { + // Caller doesn't care about resolution context so return an unresolved + // or primitive type (primitive type resolution is context free) + return getUnresolvedOrPrimitiveType(runtime, parameters.get(index)); + } + if (parameterTypes == null) { + parameterTypes = new ResolvedJavaType[parameters.size()]; + } + + ResolvedJavaType type = parameterTypes[index]; + if (!checkValidCache(type, accessingClass)) { + JavaType result = runtime.lookupType(parameters.get(index), (HotSpotResolvedObjectType) accessingClass, false); + if (result instanceof ResolvedJavaType) { + type = (ResolvedJavaType) result; + parameterTypes[index] = type; + } else { + return result; + } + } + return type; + } + + @Override + public String toMethodDescriptor() { + assert originalString.equals(Signature.super.toMethodDescriptor()); + return originalString; + } + + @Override + public JavaKind getReturnKind() { + return JavaKind.fromTypeString(returnType); + } + + @Override + public JavaType getReturnType(ResolvedJavaType accessingClass) { + if (accessingClass == null) { + // Caller doesn't care about resolution context so return an unresolved + // or primitive type (primitive type resolution is context free) + return getUnresolvedOrPrimitiveType(runtime, returnType); + } + if (!checkValidCache(returnTypeCache, accessingClass)) { + JavaType result = runtime.lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false); + if (result instanceof ResolvedJavaType) { + returnTypeCache = (ResolvedJavaType) result; + } else { + return result; + } + } + return returnTypeCache; + } + + @Override + public String toString() { + return "HotSpotSignature<" + originalString + ">"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof HotSpotSignature) { + HotSpotSignature other = (HotSpotSignature) obj; + if (other.originalString.equals(originalString)) { + assert other.parameters.equals(parameters); + assert other.returnType.equals(returnType); + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return originalString.hashCode(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java new file mode 100644 index 00000000000..0f9c7a05ac3 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +public class HotSpotSpeculationLog extends SpeculationLog { + + @Override + public JavaConstant speculate(Object reason) { + addSpeculation(reason); + return HotSpotObjectConstantImpl.forObject(reason); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotStackFrameReference.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotStackFrameReference.java new file mode 100644 index 00000000000..5ece48ac8dc --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotStackFrameReference.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.util.*; + +import jdk.vm.ci.code.stack.*; +import jdk.vm.ci.meta.*; + +public class HotSpotStackFrameReference implements InspectedFrame { + + private CompilerToVM compilerToVM; + + // information used to find the stack frame + private long stackPointer; + private int frameNumber; + + // information about the stack frame's contents + private int bci; + private HotSpotResolvedJavaMethod method; + private Object[] locals; + private boolean[] localIsVirtual; + + public long getStackPointer() { + return stackPointer; + } + + public int getFrameNumber() { + return frameNumber; + } + + @Override + public Object getLocal(int index) { + return locals[index]; + } + + @Override + public boolean isVirtual(int index) { + return localIsVirtual == null ? false : localIsVirtual[index]; + } + + @Override + public void materializeVirtualObjects(boolean invalidateCode) { + compilerToVM.materializeVirtualObjects(this, invalidateCode); + } + + @Override + public int getBytecodeIndex() { + return bci; + } + + @Override + public ResolvedJavaMethod getMethod() { + return method; + } + + @Override + public boolean isMethod(ResolvedJavaMethod otherMethod) { + return method.equals(otherMethod); + } + + @Override + public boolean hasVirtualObjects() { + return localIsVirtual != null; + } + + @Override + public String toString() { + return "HotSpotStackFrameReference [stackPointer=" + stackPointer + ", frameNumber=" + frameNumber + ", bci=" + bci + ", method=" + getMethod() + ", locals=" + Arrays.toString(locals) + + ", localIsVirtual=" + Arrays.toString(localIsVirtual) + "]"; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotUnresolvedField.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotUnresolvedField.java new file mode 100644 index 00000000000..45fd7b9df44 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotUnresolvedField.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * A implementation of {@link JavaField} for an unresolved field. + */ +public class HotSpotUnresolvedField implements JavaField { + + private final String name; + private final JavaType holder; + private final JavaType type; + + public HotSpotUnresolvedField(JavaType holder, String name, JavaType type) { + this.name = name; + this.type = type; + this.holder = holder; + } + + public String getName() { + return name; + } + + public JavaType getType() { + return type; + } + + public JavaType getDeclaringClass() { + return holder; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof HotSpotUnresolvedField)) { + return false; + } + HotSpotUnresolvedField that = (HotSpotUnresolvedField) obj; + return this.holder.equals(that.holder) && this.name.equals(that.name) && this.type.equals(that.type); + } + + /** + * Converts this compiler interface field to a string. + */ + @Override + public String toString() { + return format("HotSpotField<%H.%n %t, unresolved>"); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotUnresolvedJavaType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotUnresolvedJavaType.java new file mode 100644 index 00000000000..1e945d48de1 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotUnresolvedJavaType.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * Implementation of {@link JavaType} for unresolved HotSpot classes. + */ +public class HotSpotUnresolvedJavaType extends HotSpotJavaType { + + private final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotUnresolvedJavaType(String name, HotSpotJVMCIRuntimeProvider runtime) { + super(name); + assert name.charAt(0) == '[' || name.charAt(name.length() - 1) == ';' : name; + this.runtime = runtime; + } + + /** + * Creates an unresolved type for a valid {@link JavaType#getName() type name}. + */ + public static HotSpotUnresolvedJavaType create(HotSpotJVMCIRuntimeProvider runtime, String name) { + return new HotSpotUnresolvedJavaType(name, runtime); + } + + @Override + public JavaType getComponentType() { + assert getName().charAt(0) == '[' : "no array class" + getName(); + return new HotSpotUnresolvedJavaType(getName().substring(1), runtime); + } + + @Override + public JavaType getArrayClass() { + return new HotSpotUnresolvedJavaType('[' + getName(), runtime); + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public int hashCode() { + return getName().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof HotSpotUnresolvedJavaType)) { + return false; + } + HotSpotUnresolvedJavaType that = (HotSpotUnresolvedJavaType) obj; + return this.getName().equals(that.getName()); + } + + @Override + public String toString() { + return "HotSpotType<" + getName() + ", unresolved>"; + } + + @Override + public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { + return (ResolvedJavaType) runtime.lookupType(getName(), (HotSpotResolvedObjectType) accessingClass, true); + } + + /** + * Try to find a loaded version of this class. + * + * @param accessingClass + * @return the resolved class or null. + */ + ResolvedJavaType reresolve(HotSpotResolvedObjectType accessingClass) { + JavaType type = runtime.lookupType(getName(), accessingClass, false); + if (type instanceof ResolvedJavaType) { + return (ResolvedJavaType) type; + } + return null; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java new file mode 100644 index 00000000000..f5cbf2f6de1 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -0,0 +1,1771 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.common.UnsafeUtil.readCString; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.reflect.*; +import java.util.*; + +import sun.misc.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.hotspotvmconfig.*; + +//JaCoCo Exclude + +/** + * Used to access native configuration details. + * + * All non-static, public fields in this class are so that they can be compiled as constants. + */ +public class HotSpotVMConfig { + + /** + * Maximum allowed size of allocated area for a frame. + */ + public final int maxFrameSize = 16 * 1024; + + public HotSpotVMConfig(CompilerToVM compilerToVm) { + // Get raw pointer to the array that contains all gHotSpotVM values. + final long gHotSpotVMData = compilerToVm.initializeConfiguration(); + assert gHotSpotVMData != 0; + + // Make FindBugs happy. + gHotSpotVMStructs = 0; + gHotSpotVMTypes = 0; + gHotSpotVMIntConstants = 0; + gHotSpotVMLongConstants = 0; + gHotSpotVMAddresses = 0; + + // Initialize the gHotSpotVM fields. + for (Field f : HotSpotVMConfig.class.getDeclaredFields()) { + if (f.isAnnotationPresent(HotSpotVMData.class)) { + HotSpotVMData annotation = f.getAnnotation(HotSpotVMData.class); + final int index = annotation.index(); + final long value = UNSAFE.getAddress(gHotSpotVMData + Unsafe.ADDRESS_SIZE * index); + try { + f.setLong(this, value); + } catch (IllegalAccessException e) { + throw new JVMCIError("index " + index, e); + } + } + } + + // Quick sanity check. + assert gHotSpotVMStructs != 0; + assert gHotSpotVMTypes != 0; + assert gHotSpotVMIntConstants != 0; + assert gHotSpotVMLongConstants != 0; + assert gHotSpotVMAddresses != 0; + + initialize(); + + oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment()); + klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment); + + final long barrierSetAddress = UNSAFE.getAddress(universeCollectedHeap + collectedHeapBarrierSetOffset); + final int kind = UNSAFE.getInt(barrierSetAddress + barrierSetFakeRttiOffset + fakeRttiConcreteTagOffset); + if ((kind == barrierSetCardTableModRef) || (kind == barrierSetCardTableForRS) || (kind == barrierSetCardTableExtension) || (kind == barrierSetG1SATBCT) || (kind == barrierSetG1SATBCTLogging)) { + final long base = UNSAFE.getAddress(barrierSetAddress + cardTableModRefBSByteMapBaseOffset); + assert base != 0 : "unexpected byte_map_base: " + base; + cardtableStartAddress = base; + cardtableShift = cardTableModRefBSCardShift; + } else if (kind == barrierSetModRef) { + // No post barriers + cardtableStartAddress = 0; + cardtableShift = 0; + } else { + cardtableStartAddress = -1; + cardtableShift = -1; + } + + // Now handle all HotSpotVMManual fields. + inlineCacheMissStub = inlineCacheMissBlob + UNSAFE.getInt(inlineCacheMissBlob + codeBlobCodeOffsetOffset); + handleWrongMethodStub = wrongMethodBlob + UNSAFE.getInt(wrongMethodBlob + codeBlobCodeOffsetOffset); + handleDeoptStub = deoptBlob + UNSAFE.getInt(deoptBlob + codeBlobCodeOffsetOffset) + UNSAFE.getInt(deoptBlob + deoptimizationBlobUnpackOffsetOffset); + uncommonTrapStub = deoptBlob + UNSAFE.getInt(deoptBlob + codeBlobCodeOffsetOffset) + UNSAFE.getInt(deoptBlob + deoptimizationBlobUncommonTrapOffsetOffset); + + assert check(); + assert HotSpotVMConfigVerifier.check(); + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + + /** + * Initialize fields by reading their values from vmStructs. + */ + private void initialize() { + // Fill the VM fields hash map. + HashMap vmFields = new HashMap<>(); + for (VMFields.Field e : new VMFields(gHotSpotVMStructs)) { + vmFields.put(e.getName(), e); + } + + // Fill the VM types hash map. + HashMap vmTypes = new HashMap<>(); + for (VMTypes.Type e : new VMTypes(gHotSpotVMTypes)) { + vmTypes.put(e.getTypeName(), e); + } + + // Fill the VM constants hash map. + HashMap vmConstants = new HashMap<>(); + for (AbstractConstant e : new VMIntConstants(gHotSpotVMIntConstants)) { + vmConstants.put(e.getName(), e); + } + for (AbstractConstant e : new VMAddresses(gHotSpotVMLongConstants)) { + vmConstants.put(e.getName(), e); + } + + // Fill the VM addresses hash map. + HashMap vmAddresses = new HashMap<>(); + for (VMAddresses.Address e : new VMAddresses(gHotSpotVMAddresses)) { + vmAddresses.put(e.getName(), e); + } + + // Fill the flags hash map. + HashMap flags = new HashMap<>(); + for (Flags.Flag e : new Flags(vmFields, vmTypes)) { + flags.put(e.getName(), e); + } + + String osName = getHostOSName(); + String osArch = getHostArchitectureName(); + + for (Field f : HotSpotVMConfig.class.getDeclaredFields()) { + if (f.isAnnotationPresent(HotSpotVMField.class)) { + HotSpotVMField annotation = f.getAnnotation(HotSpotVMField.class); + String name = annotation.name(); + String type = annotation.type(); + VMFields.Field entry = vmFields.get(name); + if (entry == null) { + if (!isRequired(osArch, annotation.archs())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM field not found: " + name); + } + + // Make sure the native type is still the type we expect. + if (!type.isEmpty()) { + if (!type.equals(entry.getTypeString())) { + throw new JVMCIError(f.getName() + ": compiler expects type " + type + " but VM field " + name + " is of type " + entry.getTypeString()); + } + } + + switch (annotation.get()) { + case OFFSET: + setField(f, entry.getOffset()); + break; + case ADDRESS: + setField(f, entry.getAddress()); + break; + case VALUE: + setField(f, entry.getValue()); + break; + default: + throw new JVMCIError(f.getName() + ": unknown kind: " + annotation.get()); + } + } else if (f.isAnnotationPresent(HotSpotVMType.class)) { + HotSpotVMType annotation = f.getAnnotation(HotSpotVMType.class); + String name = annotation.name(); + VMTypes.Type entry = vmTypes.get(name); + if (entry == null) { + throw new JVMCIError(f.getName() + ": expected VM type not found: " + name); + } + switch (annotation.get()) { + case SIZE: + setField(f, entry.getSize()); + break; + default: + throw new JVMCIError(f.getName() + ": unknown kind: " + annotation.get()); + } + } else if (f.isAnnotationPresent(HotSpotVMConstant.class)) { + HotSpotVMConstant annotation = f.getAnnotation(HotSpotVMConstant.class); + String name = annotation.name(); + AbstractConstant entry = vmConstants.get(name); + if (entry == null) { + if (!isRequired(osArch, annotation.archs())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM constant not found: " + name); + } + setField(f, entry.getValue()); + } else if (f.isAnnotationPresent(HotSpotVMAddress.class)) { + HotSpotVMAddress annotation = f.getAnnotation(HotSpotVMAddress.class); + String name = annotation.name(); + VMAddresses.Address entry = vmAddresses.get(name); + if (entry == null) { + if (!isRequired(osName, annotation.os())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM address not found: " + name); + } + setField(f, entry.getValue()); + } else if (f.isAnnotationPresent(HotSpotVMFlag.class)) { + HotSpotVMFlag annotation = f.getAnnotation(HotSpotVMFlag.class); + String name = annotation.name(); + Flags.Flag entry = flags.get(name); + if (entry == null) { + if (annotation.optional() || !isRequired(osArch, annotation.archs())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM flag not found: " + name); + + } + setField(f, entry.getValue()); + } + } + } + + private final CompressEncoding oopEncoding; + private final CompressEncoding klassEncoding; + + public CompressEncoding getOopEncoding() { + return oopEncoding; + } + + public CompressEncoding getKlassEncoding() { + return klassEncoding; + } + + private void setField(Field field, Object value) { + try { + Class fieldType = field.getType(); + if (fieldType == boolean.class) { + if (value instanceof String) { + field.setBoolean(this, Boolean.valueOf((String) value)); + } else if (value instanceof Boolean) { + field.setBoolean(this, (boolean) value); + } else if (value instanceof Long) { + field.setBoolean(this, ((long) value) != 0); + } else { + throw new JVMCIError(value.getClass().getSimpleName()); + } + } else if (fieldType == byte.class) { + if (value instanceof Long) { + field.setByte(this, (byte) (long) value); + } else { + throw new JVMCIError(value.getClass().getSimpleName()); + } + } else if (fieldType == int.class) { + if (value instanceof Integer) { + field.setInt(this, (int) value); + } else if (value instanceof Long) { + field.setInt(this, (int) (long) value); + } else { + throw new JVMCIError(value.getClass().getSimpleName()); + } + } else if (fieldType == long.class) { + field.setLong(this, (long) value); + } else { + throw new JVMCIError(field.toString()); + } + } catch (IllegalAccessException e) { + throw new JVMCIError("%s: %s", field, e); + } + } + + /** + * Gets the host operating system name. + */ + private static String getHostOSName() { + String osName = System.getProperty("os.name"); + switch (osName) { + case "Linux": + osName = "linux"; + break; + case "SunOS": + osName = "solaris"; + break; + case "Mac OS X": + osName = "bsd"; + break; + default: + // Of course Windows is different... + if (osName.startsWith("Windows")) { + osName = "windows"; + } else { + throw new JVMCIError("Unexpected OS name: " + osName); + } + } + return osName; + } + + /** + * Gets the host architecture name for the purpose of finding the corresponding + * {@linkplain HotSpotJVMCIBackendFactory backend}. + */ + public String getHostArchitectureName() { + String arch = System.getProperty("os.arch"); + switch (arch) { + case "x86_64": + arch = "amd64"; + break; + case "sparcv9": + arch = "sparc"; + break; + } + return arch; + } + + /** + * Determines if the current specification is included in a given set of specifications. + * + * @param current + * @param specification specifies a set of specifications, e.g. architectures or operating + * systems. A zero length value implies all. + */ + private static boolean isRequired(String current, String[] specification) { + if (specification.length == 0) { + return true; + } + for (String arch : specification) { + if (arch.equals(current)) { + return true; + } + } + return false; + } + + /** + * VMStructEntry (see {@code vmStructs.hpp}). + */ + @HotSpotVMData(index = 0) @Stable private long gHotSpotVMStructs; + @HotSpotVMData(index = 1) @Stable private long gHotSpotVMStructEntryTypeNameOffset; + @HotSpotVMData(index = 2) @Stable private long gHotSpotVMStructEntryFieldNameOffset; + @HotSpotVMData(index = 3) @Stable private long gHotSpotVMStructEntryTypeStringOffset; + @HotSpotVMData(index = 4) @Stable private long gHotSpotVMStructEntryIsStaticOffset; + @HotSpotVMData(index = 5) @Stable private long gHotSpotVMStructEntryOffsetOffset; + @HotSpotVMData(index = 6) @Stable private long gHotSpotVMStructEntryAddressOffset; + @HotSpotVMData(index = 7) @Stable private long gHotSpotVMStructEntryArrayStride; + + final class VMFields implements Iterable { + + private final long address; + + public VMFields(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Field current() { + return new Field(address + gHotSpotVMStructEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL fieldName. + */ + public boolean hasNext() { + Field entry = current(); + return entry.getFieldName() != null; + } + + public Field next() { + Field entry = current(); + index++; + return entry; + } + }; + } + + final class Field { + + private final long entryAddress; + + Field(long address) { + this.entryAddress = address; + } + + public String getTypeName() { + long typeNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryTypeNameOffset); + return readCString(UNSAFE, typeNameAddress); + } + + public String getFieldName() { + long fieldNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryFieldNameOffset); + return readCString(UNSAFE, fieldNameAddress); + } + + public String getTypeString() { + long typeStringAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryTypeStringOffset); + return readCString(UNSAFE, typeStringAddress); + } + + public boolean isStatic() { + return UNSAFE.getInt(entryAddress + gHotSpotVMStructEntryIsStaticOffset) != 0; + } + + public long getOffset() { + return UNSAFE.getLong(entryAddress + gHotSpotVMStructEntryOffsetOffset); + } + + public long getAddress() { + return UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryAddressOffset); + } + + public String getName() { + String typeName = getTypeName(); + String fieldName = getFieldName(); + return typeName + "::" + fieldName; + } + + public long getValue() { + String type = getTypeString(); + switch (type) { + case "bool": + return UNSAFE.getByte(getAddress()); + case "int": + return UNSAFE.getInt(getAddress()); + case "uint64_t": + return UNSAFE.getLong(getAddress()); + case "address": + case "intptr_t": + case "uintptr_t": + return UNSAFE.getAddress(getAddress()); + default: + // All foo* types are addresses. + if (type.endsWith("*")) { + return UNSAFE.getAddress(getAddress()); + } + throw new JVMCIError(type); + } + } + + @Override + public String toString() { + return String.format("Field[typeName=%s, fieldName=%s, typeString=%s, isStatic=%b, offset=%d, address=0x%x]", getTypeName(), getFieldName(), getTypeString(), isStatic(), getOffset(), + getAddress()); + } + } + } + + /** + * VMTypeEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 8) @Stable private long gHotSpotVMTypes; + @HotSpotVMData(index = 9) @Stable private long gHotSpotVMTypeEntryTypeNameOffset; + @HotSpotVMData(index = 10) @Stable private long gHotSpotVMTypeEntrySuperclassNameOffset; + @HotSpotVMData(index = 11) @Stable private long gHotSpotVMTypeEntryIsOopTypeOffset; + @HotSpotVMData(index = 12) @Stable private long gHotSpotVMTypeEntryIsIntegerTypeOffset; + @HotSpotVMData(index = 13) @Stable private long gHotSpotVMTypeEntryIsUnsignedOffset; + @HotSpotVMData(index = 14) @Stable private long gHotSpotVMTypeEntrySizeOffset; + @HotSpotVMData(index = 15) @Stable private long gHotSpotVMTypeEntryArrayStride; + + final class VMTypes implements Iterable { + + private final long address; + + public VMTypes(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Type current() { + return new Type(address + gHotSpotVMTypeEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL type name. + */ + public boolean hasNext() { + Type entry = current(); + return entry.getTypeName() != null; + } + + public Type next() { + Type entry = current(); + index++; + return entry; + } + }; + } + + final class Type { + + private final long entryAddress; + + Type(long address) { + this.entryAddress = address; + } + + public String getTypeName() { + long typeNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMTypeEntryTypeNameOffset); + return readCString(UNSAFE, typeNameAddress); + } + + public String getSuperclassName() { + long superclassNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMTypeEntrySuperclassNameOffset); + return readCString(UNSAFE, superclassNameAddress); + } + + public boolean isOopType() { + return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsOopTypeOffset) != 0; + } + + public boolean isIntegerType() { + return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsIntegerTypeOffset) != 0; + } + + public boolean isUnsigned() { + return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsUnsignedOffset) != 0; + } + + public long getSize() { + return UNSAFE.getLong(entryAddress + gHotSpotVMTypeEntrySizeOffset); + } + + @Override + public String toString() { + return String.format("Type[typeName=%s, superclassName=%s, isOopType=%b, isIntegerType=%b, isUnsigned=%b, size=%d]", getTypeName(), getSuperclassName(), isOopType(), isIntegerType(), + isUnsigned(), getSize()); + } + } + } + + public abstract class AbstractConstant { + + protected final long address; + protected final long nameOffset; + protected final long valueOffset; + + AbstractConstant(long address, long nameOffset, long valueOffset) { + this.address = address; + this.nameOffset = nameOffset; + this.valueOffset = valueOffset; + } + + public String getName() { + long nameAddress = UNSAFE.getAddress(address + nameOffset); + return readCString(UNSAFE, nameAddress); + } + + public abstract long getValue(); + } + + /** + * VMIntConstantEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 16) @Stable private long gHotSpotVMIntConstants; + @HotSpotVMData(index = 17) @Stable private long gHotSpotVMIntConstantEntryNameOffset; + @HotSpotVMData(index = 18) @Stable private long gHotSpotVMIntConstantEntryValueOffset; + @HotSpotVMData(index = 19) @Stable private long gHotSpotVMIntConstantEntryArrayStride; + + final class VMIntConstants implements Iterable { + + private final long address; + + public VMIntConstants(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Constant current() { + return new Constant(address + gHotSpotVMIntConstantEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Constant entry = current(); + return entry.getName() != null; + } + + public Constant next() { + Constant entry = current(); + index++; + return entry; + } + }; + } + + final class Constant extends AbstractConstant { + + Constant(long address) { + super(address, gHotSpotVMIntConstantEntryNameOffset, gHotSpotVMIntConstantEntryValueOffset); + } + + @Override + public long getValue() { + return UNSAFE.getInt(address + valueOffset); + } + + @Override + public String toString() { + return String.format("IntConstant[name=%s, value=%d (0x%x)]", getName(), getValue(), getValue()); + } + } + } + + /** + * VMLongConstantEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 20) @Stable private long gHotSpotVMLongConstants; + @HotSpotVMData(index = 21) @Stable private long gHotSpotVMLongConstantEntryNameOffset; + @HotSpotVMData(index = 22) @Stable private long gHotSpotVMLongConstantEntryValueOffset; + @HotSpotVMData(index = 23) @Stable private long gHotSpotVMLongConstantEntryArrayStride; + + final class VMLongConstants implements Iterable { + + private final long address; + + public VMLongConstants(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Constant currentEntry() { + return new Constant(address + gHotSpotVMLongConstantEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Constant entry = currentEntry(); + return entry.getName() != null; + } + + public Constant next() { + Constant entry = currentEntry(); + index++; + return entry; + } + }; + } + + final class Constant extends AbstractConstant { + + Constant(long address) { + super(address, gHotSpotVMLongConstantEntryNameOffset, gHotSpotVMLongConstantEntryValueOffset); + } + + @Override + public long getValue() { + return UNSAFE.getLong(address + valueOffset); + } + + @Override + public String toString() { + return String.format("LongConstant[name=%s, value=%d (0x%x)]", getName(), getValue(), getValue()); + } + } + } + + /** + * VMAddressEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 24) @Stable private long gHotSpotVMAddresses; + @HotSpotVMData(index = 25) @Stable private long gHotSpotVMAddressEntryNameOffset; + @HotSpotVMData(index = 26) @Stable private long gHotSpotVMAddressEntryValueOffset; + @HotSpotVMData(index = 27) @Stable private long gHotSpotVMAddressEntryArrayStride; + + final class VMAddresses implements Iterable { + + private final long address; + + public VMAddresses(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Address currentEntry() { + return new Address(address + gHotSpotVMAddressEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Address entry = currentEntry(); + return entry.getName() != null; + } + + public Address next() { + Address entry = currentEntry(); + index++; + return entry; + } + }; + } + + final class Address extends AbstractConstant { + + Address(long address) { + super(address, gHotSpotVMAddressEntryNameOffset, gHotSpotVMAddressEntryValueOffset); + } + + @Override + public long getValue() { + return UNSAFE.getLong(address + valueOffset); + } + + @Override + public String toString() { + return String.format("Address[name=%s, value=%d (0x%x)]", getName(), getValue(), getValue()); + } + } + } + + final class Flags implements Iterable { + + private final long address; + private final long entrySize; + private final long typeOffset; + private final long nameOffset; + private final long addrOffset; + + public Flags(HashMap vmStructs, HashMap vmTypes) { + address = vmStructs.get("Flag::flags").getValue(); + entrySize = vmTypes.get("Flag").getSize(); + typeOffset = vmStructs.get("Flag::_type").getOffset(); + nameOffset = vmStructs.get("Flag::_name").getOffset(); + addrOffset = vmStructs.get("Flag::_addr").getOffset(); + + assert vmTypes.get("bool").getSize() == Byte.BYTES; + assert vmTypes.get("intx").getSize() == Long.BYTES; + assert vmTypes.get("uintx").getSize() == Long.BYTES; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Flag current() { + return new Flag(address + entrySize * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Flag entry = current(); + return entry.getName() != null; + } + + public Flag next() { + Flag entry = current(); + index++; + return entry; + } + }; + } + + final class Flag { + + private final long entryAddress; + + Flag(long address) { + this.entryAddress = address; + } + + public String getType() { + long typeAddress = UNSAFE.getAddress(entryAddress + typeOffset); + return readCString(UNSAFE, typeAddress); + } + + public String getName() { + long nameAddress = UNSAFE.getAddress(entryAddress + nameOffset); + return readCString(UNSAFE, nameAddress); + } + + public long getAddr() { + return UNSAFE.getAddress(entryAddress + addrOffset); + } + + public Object getValue() { + switch (getType()) { + case "bool": + return Boolean.valueOf(UNSAFE.getByte(getAddr()) != 0); + case "intx": + case "uintx": + case "uint64_t": + return Long.valueOf(UNSAFE.getLong(getAddr())); + case "double": + return Double.valueOf(UNSAFE.getDouble(getAddr())); + case "ccstr": + case "ccstrlist": + return readCString(UNSAFE, getAddr()); + default: + throw new JVMCIError(getType()); + } + } + + @Override + public String toString() { + return String.format("Flag[type=%s, name=%s, value=%s]", getType(), getName(), getValue()); + } + } + } + + @HotSpotVMConstant(name = "ASSERT") @Stable public boolean cAssertions; + public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); + + @HotSpotVMFlag(name = "CodeEntryAlignment") @Stable public int codeEntryAlignment; + @HotSpotVMFlag(name = "VerifyOops") @Stable public boolean verifyOops; + @HotSpotVMFlag(name = "CITime") @Stable public boolean ciTime; + @HotSpotVMFlag(name = "CITimeEach") @Stable public boolean ciTimeEach; + @HotSpotVMFlag(name = "CompileTheWorldStartAt", optional = true) @Stable public int compileTheWorldStartAt; + @HotSpotVMFlag(name = "CompileTheWorldStopAt", optional = true) @Stable public int compileTheWorldStopAt; + @HotSpotVMFlag(name = "DontCompileHugeMethods") @Stable public boolean dontCompileHugeMethods; + @HotSpotVMFlag(name = "HugeMethodLimit") @Stable public int hugeMethodLimit; + @HotSpotVMFlag(name = "PrintInlining") @Stable public boolean printInlining; + @HotSpotVMFlag(name = "JVMCIUseFastLocking") @Stable public boolean useFastLocking; + @HotSpotVMFlag(name = "ForceUnreachable") @Stable public boolean forceUnreachable; + @HotSpotVMFlag(name = "CodeCacheSegmentSize") @Stable public int codeSegmentSize; + + @HotSpotVMFlag(name = "UseTLAB") @Stable public boolean useTLAB; + @HotSpotVMFlag(name = "UseBiasedLocking") @Stable public boolean useBiasedLocking; + @HotSpotVMFlag(name = "UsePopCountInstruction") @Stable public boolean usePopCountInstruction; + @HotSpotVMFlag(name = "UseCountLeadingZerosInstruction", archs = {"amd64"}) @Stable public boolean useCountLeadingZerosInstruction; + @HotSpotVMFlag(name = "UseCountTrailingZerosInstruction", archs = {"amd64"}) @Stable public boolean useCountTrailingZerosInstruction; + @HotSpotVMFlag(name = "UseAESIntrinsics") @Stable public boolean useAESIntrinsics; + @HotSpotVMFlag(name = "UseCRC32Intrinsics") @Stable public boolean useCRC32Intrinsics; + @HotSpotVMFlag(name = "UseG1GC") @Stable public boolean useG1GC; + @HotSpotVMFlag(name = "UseConcMarkSweepGC") @Stable public boolean useCMSGC; + + @HotSpotVMFlag(name = "AllocatePrefetchStyle") @Stable public int allocatePrefetchStyle; + @HotSpotVMFlag(name = "AllocatePrefetchInstr") @Stable public int allocatePrefetchInstr; + @HotSpotVMFlag(name = "AllocatePrefetchLines") @Stable public int allocatePrefetchLines; + @HotSpotVMFlag(name = "AllocateInstancePrefetchLines") @Stable public int allocateInstancePrefetchLines; + @HotSpotVMFlag(name = "AllocatePrefetchStepSize") @Stable public int allocatePrefetchStepSize; + @HotSpotVMFlag(name = "AllocatePrefetchDistance") @Stable public int allocatePrefetchDistance; + + @HotSpotVMFlag(name = "FlightRecorder", optional = true) @Stable public boolean flightRecorder; + + @HotSpotVMField(name = "Universe::_collectedHeap", type = "CollectedHeap*", get = HotSpotVMField.Type.VALUE) @Stable private long universeCollectedHeap; + @HotSpotVMField(name = "CollectedHeap::_total_collections", type = "unsigned int", get = HotSpotVMField.Type.OFFSET) @Stable private int collectedHeapTotalCollectionsOffset; + + public long gcTotalCollectionsAddress() { + return universeCollectedHeap + collectedHeapTotalCollectionsOffset; + } + + @HotSpotVMFlag(name = "ReduceInitialCardMarks") @Stable public boolean useDeferredInitBarriers; + + // Compressed Oops related values. + @HotSpotVMFlag(name = "UseCompressedOops") @Stable public boolean useCompressedOops; + @HotSpotVMFlag(name = "UseCompressedClassPointers") @Stable public boolean useCompressedClassPointers; + + @HotSpotVMField(name = "Universe::_narrow_oop._base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowOopBase; + @HotSpotVMField(name = "Universe::_narrow_oop._shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowOopShift; + @HotSpotVMFlag(name = "ObjectAlignmentInBytes") @Stable public int objectAlignment; + + public final int minObjAlignment() { + return objectAlignment / heapWordSize; + } + + public final int logMinObjAlignment() { + return (int) (Math.log(objectAlignment) / Math.log(2)); + } + + @HotSpotVMType(name = "narrowKlass", get = HotSpotVMType.Type.SIZE) @Stable public int narrowKlassSize; + @HotSpotVMField(name = "Universe::_narrow_klass._base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowKlassBase; + @HotSpotVMField(name = "Universe::_narrow_klass._shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowKlassShift; + @HotSpotVMConstant(name = "LogKlassAlignmentInBytes") @Stable public int logKlassAlignment; + + // CPU capabilities + @HotSpotVMFlag(name = "UseSSE") @Stable public int useSSE; + @HotSpotVMFlag(name = "UseAVX", archs = {"amd64"}) @Stable public int useAVX; + + @HotSpotVMField(name = "Abstract_VM_Version::_reserve_for_allocation_prefetch", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int abstractVmVersionReserveForAllocationPrefetch; + + // X86 specific values + @HotSpotVMField(name = "VM_Version::_cpuFeatures", type = "uint64_t", get = HotSpotVMField.Type.VALUE, archs = {"amd64"}) @Stable public long x86CPUFeatures; + @HotSpotVMConstant(name = "VM_Version::CPU_CX8", archs = {"amd64"}) @Stable public long cpuCX8; + @HotSpotVMConstant(name = "VM_Version::CPU_CMOV", archs = {"amd64"}) @Stable public long cpuCMOV; + @HotSpotVMConstant(name = "VM_Version::CPU_FXSR", archs = {"amd64"}) @Stable public long cpuFXSR; + @HotSpotVMConstant(name = "VM_Version::CPU_HT", archs = {"amd64"}) @Stable public long cpuHT; + @HotSpotVMConstant(name = "VM_Version::CPU_MMX", archs = {"amd64"}) @Stable public long cpuMMX; + @HotSpotVMConstant(name = "VM_Version::CPU_3DNOW_PREFETCH", archs = {"amd64"}) @Stable public long cpu3DNOWPREFETCH; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE", archs = {"amd64"}) @Stable public long cpuSSE; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE2", archs = {"amd64"}) @Stable public long cpuSSE2; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE3", archs = {"amd64"}) @Stable public long cpuSSE3; + @HotSpotVMConstant(name = "VM_Version::CPU_SSSE3", archs = {"amd64"}) @Stable public long cpuSSSE3; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4A", archs = {"amd64"}) @Stable public long cpuSSE4A; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4_1", archs = {"amd64"}) @Stable public long cpuSSE41; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4_2", archs = {"amd64"}) @Stable public long cpuSSE42; + @HotSpotVMConstant(name = "VM_Version::CPU_POPCNT", archs = {"amd64"}) @Stable public long cpuPOPCNT; + @HotSpotVMConstant(name = "VM_Version::CPU_LZCNT", archs = {"amd64"}) @Stable public long cpuLZCNT; + @HotSpotVMConstant(name = "VM_Version::CPU_TSC", archs = {"amd64"}) @Stable public long cpuTSC; + @HotSpotVMConstant(name = "VM_Version::CPU_TSCINV", archs = {"amd64"}) @Stable public long cpuTSCINV; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX", archs = {"amd64"}) @Stable public long cpuAVX; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX2", archs = {"amd64"}) @Stable public long cpuAVX2; + @HotSpotVMConstant(name = "VM_Version::CPU_AES", archs = {"amd64"}) @Stable public long cpuAES; + @HotSpotVMConstant(name = "VM_Version::CPU_ERMS", archs = {"amd64"}) @Stable public long cpuERMS; + @HotSpotVMConstant(name = "VM_Version::CPU_CLMUL", archs = {"amd64"}) @Stable public long cpuCLMUL; + @HotSpotVMConstant(name = "VM_Version::CPU_BMI1", archs = {"amd64"}) @Stable public long cpuBMI1; + + // SPARC specific values + @HotSpotVMField(name = "VM_Version::_features", type = "int", get = HotSpotVMField.Type.VALUE, archs = {"sparc"}) @Stable public int sparcFeatures; + @HotSpotVMConstant(name = "VM_Version::vis3_instructions_m", archs = {"sparc"}) @Stable public int vis3Instructions; + @HotSpotVMConstant(name = "VM_Version::vis2_instructions_m", archs = {"sparc"}) @Stable public int vis2Instructions; + @HotSpotVMConstant(name = "VM_Version::vis1_instructions_m", archs = {"sparc"}) @Stable public int vis1Instructions; + @HotSpotVMConstant(name = "VM_Version::cbcond_instructions_m", archs = {"sparc"}) @Stable public int cbcondInstructions; + @HotSpotVMFlag(name = "UseBlockZeroing", archs = {"sparc"}) @Stable public boolean useBlockZeroing; + @HotSpotVMFlag(name = "BlockZeroingLowLimit", archs = {"sparc"}) @Stable public int blockZeroingLowLimit; + + // offsets, ... + @HotSpotVMFlag(name = "StackShadowPages") @Stable public int stackShadowPages; + @HotSpotVMFlag(name = "UseStackBanging") @Stable public boolean useStackBanging; + @HotSpotVMConstant(name = "STACK_BIAS") @Stable public int stackBias; + + @HotSpotVMField(name = "oopDesc::_mark", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int markOffset; + @HotSpotVMField(name = "oopDesc::_metadata._klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int hubOffset; + + @HotSpotVMField(name = "Klass::_prototype_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int prototypeMarkWordOffset; + @HotSpotVMField(name = "Klass::_subklass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int subklassOffset; + @HotSpotVMField(name = "Klass::_next_sibling", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int nextSiblingOffset; + @HotSpotVMField(name = "Klass::_super_check_offset", type = "juint", get = HotSpotVMField.Type.OFFSET) @Stable public int superCheckOffsetOffset; + @HotSpotVMField(name = "Klass::_secondary_super_cache", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int secondarySuperCacheOffset; + @HotSpotVMField(name = "Klass::_secondary_supers", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int secondarySupersOffset; + + /** + * The offset of the _java_mirror field (of type {@link Class}) in a Klass. + */ + @HotSpotVMField(name = "Klass::_java_mirror", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int classMirrorOffset; + + @HotSpotVMField(name = "Klass::_super", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int klassSuperKlassOffset; + @HotSpotVMField(name = "Klass::_modifier_flags", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassModifierFlagsOffset; + @HotSpotVMField(name = "Klass::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int klassAccessFlagsOffset; + @HotSpotVMField(name = "Klass::_layout_helper", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassLayoutHelperOffset; + + @HotSpotVMConstant(name = "Klass::_lh_neutral_value") @Stable public int klassLayoutHelperNeutralValue; + @HotSpotVMConstant(name = "Klass::_lh_instance_slow_path_bit") @Stable public int klassLayoutHelperInstanceSlowPathBit; + @HotSpotVMConstant(name = "Klass::_lh_log2_element_size_shift") @Stable public int layoutHelperLog2ElementSizeShift; + @HotSpotVMConstant(name = "Klass::_lh_log2_element_size_mask") @Stable public int layoutHelperLog2ElementSizeMask; + @HotSpotVMConstant(name = "Klass::_lh_element_type_shift") @Stable public int layoutHelperElementTypeShift; + @HotSpotVMConstant(name = "Klass::_lh_element_type_mask") @Stable public int layoutHelperElementTypeMask; + @HotSpotVMConstant(name = "Klass::_lh_header_size_shift") @Stable public int layoutHelperHeaderSizeShift; + @HotSpotVMConstant(name = "Klass::_lh_header_size_mask") @Stable public int layoutHelperHeaderSizeMask; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_shift") @Stable public int layoutHelperArrayTagShift; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_type_value") @Stable public int layoutHelperArrayTagTypeValue; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_obj_value") @Stable public int layoutHelperArrayTagObjectValue; + + /** + * This filters out the bit that differentiates a type array from an object array. + */ + public int layoutHelperElementTypePrimitiveInPlace() { + return (layoutHelperArrayTagTypeValue & ~layoutHelperArrayTagObjectValue) << layoutHelperArrayTagShift; + } + + /** + * Bit pattern in the klass layout helper that can be used to identify arrays. + */ + public final int arrayKlassLayoutHelperIdentifier = 0x80000000; + + @HotSpotVMType(name = "vtableEntry", get = HotSpotVMType.Type.SIZE) @Stable public int vtableEntrySize; + @HotSpotVMField(name = "vtableEntry::_method", type = "Method*", get = HotSpotVMField.Type.OFFSET) @Stable public int vtableEntryMethodOffset; + + @HotSpotVMType(name = "InstanceKlass", get = HotSpotVMType.Type.SIZE) @Stable public int instanceKlassSize; + @HotSpotVMField(name = "InstanceKlass::_source_file_name_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassSourceFileNameIndexOffset; + @HotSpotVMField(name = "InstanceKlass::_init_state", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassInitStateOffset; + @HotSpotVMField(name = "InstanceKlass::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassConstantsOffset; + @HotSpotVMField(name = "InstanceKlass::_fields", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassFieldsOffset; + @HotSpotVMField(name = "InstanceKlass::_vtable_len", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassVtableLengthOffset; + + @HotSpotVMConstant(name = "InstanceKlass::linked") @Stable public int instanceKlassStateLinked; + @HotSpotVMConstant(name = "InstanceKlass::fully_initialized") @Stable public int instanceKlassStateFullyInitialized; + + /** + * See {@code InstanceKlass::vtable_start_offset()}. + */ + public final int instanceKlassVtableStartOffset() { + return roundUp(instanceKlassSize, heapWordSize); + } + + // TODO use CodeUtil method once it's moved from NumUtil + private static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } + + @HotSpotVMType(name = "arrayOopDesc", get = HotSpotVMType.Type.SIZE) @Stable public int arrayOopDescSize; + + /** + * The offset of the array length word in an array object's header. + * + * See {@code arrayOopDesc::length_offset_in_bytes()}. + */ + public final int arrayOopDescLengthOffset() { + return useCompressedClassPointers ? hubOffset + narrowKlassSize : arrayOopDescSize; + } + + @HotSpotVMField(name = "Array::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1LengthOffset; + @HotSpotVMField(name = "Array::_data", type = "", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1DataOffset; + @HotSpotVMField(name = "Array::_data", type = "", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU2DataOffset; + @HotSpotVMField(name = "Array::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayLengthOffset; + @HotSpotVMField(name = "Array::_data[0]", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayBaseOffset; + + @HotSpotVMField(name = "ObjArrayKlass::_element_klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayClassElementOffset; + + @HotSpotVMConstant(name = "FieldInfo::access_flags_offset") @Stable public int fieldInfoAccessFlagsOffset; + @HotSpotVMConstant(name = "FieldInfo::name_index_offset") @Stable public int fieldInfoNameIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::signature_index_offset") @Stable public int fieldInfoSignatureIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::initval_index_offset") @Stable public int fieldInfoInitvalIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::low_packed_offset") @Stable public int fieldInfoLowPackedOffset; + @HotSpotVMConstant(name = "FieldInfo::high_packed_offset") @Stable public int fieldInfoHighPackedOffset; + @HotSpotVMConstant(name = "FieldInfo::field_slots") @Stable public int fieldInfoFieldSlots; + + @HotSpotVMConstant(name = "FIELDINFO_TAG_SIZE") @Stable public int fieldInfoTagSize; + + @HotSpotVMConstant(name = "JVM_ACC_FIELD_INTERNAL") @Stable public int jvmAccFieldInternal; + @HotSpotVMConstant(name = "JVM_ACC_FIELD_STABLE") @Stable public int jvmAccFieldStable; + @HotSpotVMConstant(name = "JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE") @Stable public int jvmAccFieldHasGenericSignature; + @HotSpotVMConstant(name = "JVM_ACC_WRITTEN_FLAGS") @Stable public int jvmAccWrittenFlags; + + @HotSpotVMField(name = "Thread::_tlab", type = "ThreadLocalAllocBuffer", get = HotSpotVMField.Type.OFFSET) @Stable public int threadTlabOffset; + + @HotSpotVMField(name = "JavaThread::_anchor", type = "JavaFrameAnchor", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadAnchorOffset; + @HotSpotVMField(name = "JavaThread::_threadObj", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectOffset; + @HotSpotVMField(name = "JavaThread::_osthread", type = "OSThread*", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadOffset; + @HotSpotVMField(name = "JavaThread::_dirty_card_queue", type = "DirtyCardQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadDirtyCardQueueOffset; + @HotSpotVMField(name = "JavaThread::_is_method_handle_return", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int threadIsMethodHandleReturnOffset; + @HotSpotVMField(name = "JavaThread::_satb_mark_queue", type = "ObjPtrQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadSatbMarkQueueOffset; + @HotSpotVMField(name = "JavaThread::_vm_result", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectResultOffset; + @HotSpotVMField(name = "JavaThread::_jvmci_counters", type = "jlong*", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciCountersThreadOffset; + + /** + * An invalid value for {@link #rtldDefault}. + */ + public static final long INVALID_RTLD_DEFAULT_HANDLE = 0xDEADFACE; + + /** + * Address of the library lookup routine. The C signature of this routine is: + * + *
+     *     void* (const char *filename, char *ebuf, int ebuflen)
+     * 
+ */ + @HotSpotVMAddress(name = "os::dll_load") @Stable public long dllLoad; + + /** + * Address of the library lookup routine. The C signature of this routine is: + * + *
+     *     void* (void* handle, const char* name)
+     * 
+ */ + @HotSpotVMAddress(name = "os::dll_lookup") @Stable public long dllLookup; + + /** + * A pseudo-handle which when used as the first argument to {@link #dllLookup} means lookup will + * return the first occurrence of the desired symbol using the default library search order. If + * this field is {@value #INVALID_RTLD_DEFAULT_HANDLE}, then this capability is not supported on + * the current platform. + */ + @HotSpotVMAddress(name = "RTLD_DEFAULT", os = {"bsd", "linux"}) @Stable public long rtldDefault = INVALID_RTLD_DEFAULT_HANDLE; + + /** + * This field is used to pass exception objects into and out of the runtime system during + * exception handling for compiled code. + */ + @HotSpotVMField(name = "JavaThread::_exception_oop", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadExceptionOopOffset; + @HotSpotVMField(name = "JavaThread::_exception_pc", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int threadExceptionPcOffset; + @HotSpotVMField(name = "ThreadShadow::_pending_exception", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingExceptionOffset; + + @HotSpotVMField(name = "JavaThread::_pending_deoptimization", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingDeoptimizationOffset; + @HotSpotVMField(name = "JavaThread::_pending_failed_speculation", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingFailedSpeculationOffset; + @HotSpotVMField(name = "JavaThread::_pending_transfer_to_interpreter", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingTransferToInterpreterOffset; + + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_sp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaSpOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_pc", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaPcOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_fp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET, archs = {"amd64"}) @Stable private int javaFrameAnchorLastJavaFpOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_flags", type = "int", get = HotSpotVMField.Type.OFFSET, archs = {"sparc"}) @Stable private int javaFrameAnchorFlagsOffset; + + public int threadLastJavaSpOffset() { + return javaThreadAnchorOffset + javaFrameAnchorLastJavaSpOffset; + } + + public int threadLastJavaPcOffset() { + return javaThreadAnchorOffset + javaFrameAnchorLastJavaPcOffset; + } + + /** + * This value is only valid on AMD64. + */ + public int threadLastJavaFpOffset() { + // TODO add an assert for AMD64 + return javaThreadAnchorOffset + javaFrameAnchorLastJavaFpOffset; + } + + /** + * This value is only valid on SPARC. + */ + public int threadJavaFrameAnchorFlagsOffset() { + // TODO add an assert for SPARC + return javaThreadAnchorOffset + javaFrameAnchorFlagsOffset; + } + + // These are only valid on AMD64. + @HotSpotVMConstant(name = "frame::arg_reg_save_area_bytes", archs = {"amd64"}) @Stable public int runtimeCallStackSize; + @HotSpotVMConstant(name = "frame::interpreter_frame_sender_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameSenderSpOffset; + @HotSpotVMConstant(name = "frame::interpreter_frame_last_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameLastSpOffset; + + @HotSpotVMField(name = "PtrQueue::_active", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueActiveOffset; + @HotSpotVMField(name = "PtrQueue::_buf", type = "void**", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueBufferOffset; + @HotSpotVMField(name = "PtrQueue::_index", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueIndexOffset; + + @HotSpotVMField(name = "OSThread::_interrupted", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadInterruptedOffset; + + @HotSpotVMConstant(name = "markOopDesc::unlocked_value") @Stable public int unlockedMask; + @HotSpotVMConstant(name = "markOopDesc::biased_lock_mask_in_place") @Stable public int biasedLockMaskInPlace; + @HotSpotVMConstant(name = "markOopDesc::age_mask_in_place") @Stable public int ageMaskInPlace; + @HotSpotVMConstant(name = "markOopDesc::epoch_mask_in_place") @Stable public int epochMaskInPlace; + + @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public long markOopDescHashShift; + @HotSpotVMConstant(name = "markOopDesc::hash_mask") @Stable public long markOopDescHashMask; + @HotSpotVMConstant(name = "markOopDesc::hash_mask_in_place") @Stable public long markOopDescHashMaskInPlace; + + @HotSpotVMConstant(name = "markOopDesc::biased_lock_pattern") @Stable public int biasedLockPattern; + @HotSpotVMConstant(name = "markOopDesc::no_hash_in_place") @Stable public int markWordNoHashInPlace; + @HotSpotVMConstant(name = "markOopDesc::no_lock_in_place") @Stable public int markWordNoLockInPlace; + + /** + * See {@code markOopDesc::prototype()}. + */ + public long arrayPrototypeMarkWord() { + return markWordNoHashInPlace | markWordNoLockInPlace; + } + + /** + * See {@code markOopDesc::copy_set_hash()}. + */ + public long tlabIntArrayMarkWord() { + long tmp = arrayPrototypeMarkWord() & (~markOopDescHashMaskInPlace); + tmp |= ((0x2 & markOopDescHashMask) << markOopDescHashShift); + return tmp; + } + + /** + * Mark word right shift to get identity hash code. + */ + @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public int identityHashCodeShift; + + /** + * Identity hash code value when uninitialized. + */ + @HotSpotVMConstant(name = "markOopDesc::no_hash") @Stable public int uninitializedIdentityHashCodeValue; + + @HotSpotVMField(name = "Method::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int methodAccessFlagsOffset; + @HotSpotVMField(name = "Method::_constMethod", type = "ConstMethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodConstMethodOffset; + @HotSpotVMField(name = "Method::_intrinsic_id", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int methodIntrinsicIdOffset; + @HotSpotVMField(name = "Method::_flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodFlagsOffset; + @HotSpotVMField(name = "Method::_vtable_index", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodVtableIndexOffset; + + @HotSpotVMConstant(name = "Method::_jfr_towrite") @Stable public int methodFlagsJfrTowrite; + @HotSpotVMConstant(name = "Method::_caller_sensitive") @Stable public int methodFlagsCallerSensitive; + @HotSpotVMConstant(name = "Method::_force_inline") @Stable public int methodFlagsForceInline; + @HotSpotVMConstant(name = "Method::_dont_inline") @Stable public int methodFlagsDontInline; + @HotSpotVMConstant(name = "Method::_hidden") @Stable public int methodFlagsHidden; + @HotSpotVMConstant(name = "Method::nonvirtual_vtable_index") @Stable public int nonvirtualVtableIndex; + @HotSpotVMConstant(name = "Method::invalid_vtable_index") @Stable public int invalidVtableIndex; + + @HotSpotVMConstant(name = "InvocationEntryBci") @Stable public int invocationEntryBci; + + @HotSpotVMField(name = "JVMCIEnv::_task", type = "CompileTask*", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciEnvTaskOffset; + @HotSpotVMField(name = "JVMCIEnv::_jvmti_can_hotswap_or_post_breakpoint", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciEnvJvmtiCanHotswapOrPostBreakpointOffset; + @HotSpotVMField(name = "CompileTask::_num_inlined_bytecodes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskNumInlinedBytecodesOffset; + + /** + * See {@code Method::extra_stack_entries()}. + */ + @HotSpotVMConstant(name = "Method::extra_stack_entries_for_jsr292") @Stable public int extraStackEntries; + + @HotSpotVMField(name = "ConstMethod::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodConstantsOffset; + @HotSpotVMField(name = "ConstMethod::_flags", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodFlagsOffset; + @HotSpotVMField(name = "ConstMethod::_code_size", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodCodeSizeOffset; + @HotSpotVMField(name = "ConstMethod::_name_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodNameIndexOffset; + @HotSpotVMField(name = "ConstMethod::_signature_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodSignatureIndexOffset; + @HotSpotVMField(name = "ConstMethod::_max_stack", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodMaxStackOffset; + @HotSpotVMField(name = "ConstMethod::_max_locals", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int methodMaxLocalsOffset; + + @HotSpotVMConstant(name = "ConstMethod::_has_linenumber_table") @Stable public int constMethodHasLineNumberTable; + @HotSpotVMConstant(name = "ConstMethod::_has_localvariable_table") @Stable public int constMethodHasLocalVariableTable; + @HotSpotVMConstant(name = "ConstMethod::_has_exception_table") @Stable public int constMethodHasExceptionTable; + + @HotSpotVMType(name = "ExceptionTableElement", get = HotSpotVMType.Type.SIZE) @Stable public int exceptionTableElementSize; + @HotSpotVMField(name = "ExceptionTableElement::start_pc", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementStartPcOffset; + @HotSpotVMField(name = "ExceptionTableElement::end_pc", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementEndPcOffset; + @HotSpotVMField(name = "ExceptionTableElement::handler_pc", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementHandlerPcOffset; + @HotSpotVMField(name = "ExceptionTableElement::catch_type_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementCatchTypeIndexOffset; + + @HotSpotVMType(name = "LocalVariableTableElement", get = HotSpotVMType.Type.SIZE) @Stable public int localVariableTableElementSize; + @HotSpotVMField(name = "LocalVariableTableElement::start_bci", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementStartBciOffset; + @HotSpotVMField(name = "LocalVariableTableElement::length", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementLengthOffset; + @HotSpotVMField(name = "LocalVariableTableElement::name_cp_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementNameCpIndexOffset; + @HotSpotVMField(name = "LocalVariableTableElement::descriptor_cp_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementDescriptorCpIndexOffset; + @HotSpotVMField(name = "LocalVariableTableElement::signature_cp_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementSignatureCpIndexOffset; + @HotSpotVMField(name = "LocalVariableTableElement::slot", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementSlotOffset; + + @HotSpotVMType(name = "ConstantPool", get = HotSpotVMType.Type.SIZE) @Stable public int constantPoolSize; + @HotSpotVMField(name = "ConstantPool::_tags", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolTagsOffset; + @HotSpotVMField(name = "ConstantPool::_pool_holder", type = "InstanceKlass*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolHolderOffset; + @HotSpotVMField(name = "ConstantPool::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolLengthOffset; + + @HotSpotVMConstant(name = "ConstantPool::CPCACHE_INDEX_TAG") @Stable public int constantPoolCpCacheIndexTag; + + @HotSpotVMConstant(name = "JVM_CONSTANT_Utf8") @Stable public int jvmConstantUtf8; + @HotSpotVMConstant(name = "JVM_CONSTANT_Integer") @Stable public int jvmConstantInteger; + @HotSpotVMConstant(name = "JVM_CONSTANT_Long") @Stable public int jvmConstantLong; + @HotSpotVMConstant(name = "JVM_CONSTANT_Float") @Stable public int jvmConstantFloat; + @HotSpotVMConstant(name = "JVM_CONSTANT_Double") @Stable public int jvmConstantDouble; + @HotSpotVMConstant(name = "JVM_CONSTANT_Class") @Stable public int jvmConstantClass; + @HotSpotVMConstant(name = "JVM_CONSTANT_UnresolvedClass") @Stable public int jvmConstantUnresolvedClass; + @HotSpotVMConstant(name = "JVM_CONSTANT_UnresolvedClassInError") @Stable public int jvmConstantUnresolvedClassInError; + @HotSpotVMConstant(name = "JVM_CONSTANT_String") @Stable public int jvmConstantString; + @HotSpotVMConstant(name = "JVM_CONSTANT_Fieldref") @Stable public int jvmConstantFieldref; + @HotSpotVMConstant(name = "JVM_CONSTANT_Methodref") @Stable public int jvmConstantMethodref; + @HotSpotVMConstant(name = "JVM_CONSTANT_InterfaceMethodref") @Stable public int jvmConstantInterfaceMethodref; + @HotSpotVMConstant(name = "JVM_CONSTANT_NameAndType") @Stable public int jvmConstantNameAndType; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodHandle") @Stable public int jvmConstantMethodHandle; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodHandleInError") @Stable public int jvmConstantMethodHandleInError; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodType") @Stable public int jvmConstantMethodType; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodTypeInError") @Stable public int jvmConstantMethodTypeInError; + @HotSpotVMConstant(name = "JVM_CONSTANT_InvokeDynamic") @Stable public int jvmConstantInvokeDynamic; + + @HotSpotVMConstant(name = "JVM_CONSTANT_ExternalMax") @Stable public int jvmConstantExternalMax; + @HotSpotVMConstant(name = "JVM_CONSTANT_InternalMin") @Stable public int jvmConstantInternalMin; + @HotSpotVMConstant(name = "JVM_CONSTANT_InternalMax") @Stable public int jvmConstantInternalMax; + + @HotSpotVMConstant(name = "HeapWordSize") @Stable public int heapWordSize; + + @HotSpotVMType(name = "Symbol*", get = HotSpotVMType.Type.SIZE) @Stable public int symbolPointerSize; + @HotSpotVMField(name = "Symbol::_length", type = "unsigned short", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolLengthOffset; + @HotSpotVMField(name = "Symbol::_body[0]", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolBodyOffset; + + @HotSpotVMField(name = "vmSymbols::_symbols[0]", type = "Symbol*", get = HotSpotVMField.Type.ADDRESS) @Stable public long vmSymbolsSymbols; + @HotSpotVMConstant(name = "vmSymbols::FIRST_SID") @Stable public int vmSymbolsFirstSID; + @HotSpotVMConstant(name = "vmSymbols::SID_LIMIT") @Stable public int vmSymbolsSIDLimit; + + @HotSpotVMConstant(name = "JVM_ACC_HAS_FINALIZER") @Stable public int klassHasFinalizerFlag; + + // Modifier.SYNTHETIC is not public so we get it via vmStructs. + @HotSpotVMConstant(name = "JVM_ACC_SYNTHETIC") @Stable public int syntheticFlag; + + /** + * @see HotSpotResolvedObjectTypeImpl#createField + */ + @HotSpotVMConstant(name = "JVM_RECOGNIZED_FIELD_MODIFIERS") @Stable public int recognizedFieldModifiers; + + /** + * Bit pattern that represents a non-oop. Neither the high bits nor the low bits of this value + * are allowed to look like (respectively) the high or low bits of a real oop. + */ + @HotSpotVMField(name = "Universe::_non_oop_bits", type = "intptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long nonOopBits; + + @HotSpotVMField(name = "StubRoutines::_verify_oop_count", type = "jint", get = HotSpotVMField.Type.ADDRESS) @Stable public long verifyOopCounterAddress; + @HotSpotVMField(name = "Universe::_verify_oop_mask", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopMask; + @HotSpotVMField(name = "Universe::_verify_oop_bits", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopBits; + @HotSpotVMField(name = "Universe::_base_vtable_size", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int universeBaseVtableSize; + + public final int baseVtableLength() { + return universeBaseVtableSize / vtableEntrySize; + } + + @HotSpotVMField(name = "CollectedHeap::_barrier_set", type = "BarrierSet*", get = HotSpotVMField.Type.OFFSET) @Stable public int collectedHeapBarrierSetOffset; + + @HotSpotVMField(name = "HeapRegion::LogOfHRGrainBytes", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int logOfHRGrainBytes; + + @HotSpotVMField(name = "BarrierSet::_fake_rtti", type = "BarrierSet::FakeRtti", get = HotSpotVMField.Type.OFFSET) @Stable private int barrierSetFakeRttiOffset; + @HotSpotVMConstant(name = "BarrierSet::CardTableModRef") @Stable public int barrierSetCardTableModRef; + @HotSpotVMConstant(name = "BarrierSet::CardTableForRS") @Stable public int barrierSetCardTableForRS; + @HotSpotVMConstant(name = "BarrierSet::CardTableExtension") @Stable public int barrierSetCardTableExtension; + @HotSpotVMConstant(name = "BarrierSet::G1SATBCT") @Stable public int barrierSetG1SATBCT; + @HotSpotVMConstant(name = "BarrierSet::G1SATBCTLogging") @Stable public int barrierSetG1SATBCTLogging; + @HotSpotVMConstant(name = "BarrierSet::ModRef") @Stable public int barrierSetModRef; + + @HotSpotVMField(name = "BarrierSet::FakeRtti::_concrete_tag", type = "BarrierSet::Name", get = HotSpotVMField.Type.OFFSET) @Stable private int fakeRttiConcreteTagOffset; + + @HotSpotVMField(name = "CardTableModRefBS::byte_map_base", type = "jbyte*", get = HotSpotVMField.Type.OFFSET) @Stable private int cardTableModRefBSByteMapBaseOffset; + @HotSpotVMConstant(name = "CardTableModRefBS::card_shift") @Stable public int cardTableModRefBSCardShift; + + @HotSpotVMConstant(name = "CardTableModRefBS::dirty_card") @Stable public byte dirtyCardValue; + @HotSpotVMConstant(name = "G1SATBCardTableModRefBS::g1_young_gen") @Stable public byte g1YoungCardValue; + + private final long cardtableStartAddress; + private final int cardtableShift; + + public long cardtableStartAddress() { + if (cardtableStartAddress == -1) { + throw JVMCIError.shouldNotReachHere(); + } + return cardtableStartAddress; + } + + public int cardtableShift() { + if (cardtableShift == -1) { + throw JVMCIError.shouldNotReachHere(); + } + return cardtableShift; + } + + @HotSpotVMField(name = "os::_polling_page", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long safepointPollingAddress; + + // G1 Collector Related Values. + + public int g1CardQueueIndexOffset() { + return javaThreadDirtyCardQueueOffset + ptrQueueIndexOffset; + } + + public int g1CardQueueBufferOffset() { + return javaThreadDirtyCardQueueOffset + ptrQueueBufferOffset; + } + + public int g1SATBQueueMarkingOffset() { + return javaThreadSatbMarkQueueOffset + ptrQueueActiveOffset; + } + + public int g1SATBQueueIndexOffset() { + return javaThreadSatbMarkQueueOffset + ptrQueueIndexOffset; + } + + public int g1SATBQueueBufferOffset() { + return javaThreadSatbMarkQueueOffset + ptrQueueBufferOffset; + } + + @HotSpotVMField(name = "java_lang_Class::_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int klassOffset; + @HotSpotVMField(name = "java_lang_Class::_array_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int arrayKlassOffset; + + @HotSpotVMField(name = "Method::_method_counters", type = "MethodCounters*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCountersOffset; + @HotSpotVMField(name = "Method::_method_data", type = "MethodData*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOffset; + @HotSpotVMField(name = "Method::_from_compiled_entry", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCompiledEntryOffset; + @HotSpotVMField(name = "Method::_code", type = "nmethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCodeOffset; + + @HotSpotVMField(name = "MethodCounters::_invocation_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int invocationCounterOffset; + @HotSpotVMField(name = "MethodCounters::_backedge_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int backedgeCounterOffset; + @HotSpotVMConstant(name = "InvocationCounter::count_increment") @Stable public int invocationCounterIncrement; + @HotSpotVMConstant(name = "InvocationCounter::count_shift") @Stable public int invocationCounterShift; + + @HotSpotVMField(name = "MethodData::_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataSize; + @HotSpotVMField(name = "MethodData::_data_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataDataSize; + @HotSpotVMField(name = "MethodData::_data[0]", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopDataOffset; + @HotSpotVMField(name = "MethodData::_trap_hist._array[0]", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopTrapHistoryOffset; + @HotSpotVMField(name = "MethodData::_jvmci_ir_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataIRSizeOffset; + + @HotSpotVMField(name = "nmethod::_verified_entry_point", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodEntryOffset; + @HotSpotVMField(name = "nmethod::_comp_level", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodCompLevelOffset; + + @HotSpotVMConstant(name = "CompLevel_full_optimization") @Stable public int compilationLevelFullOptimization; + + @HotSpotVMType(name = "BasicLock", get = HotSpotVMType.Type.SIZE) @Stable public int basicLockSize; + @HotSpotVMField(name = "BasicLock::_displaced_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int basicLockDisplacedHeaderOffset; + + @HotSpotVMField(name = "Thread::_allocated_bytes", type = "jlong", get = HotSpotVMField.Type.OFFSET) @Stable public int threadAllocatedBytesOffset; + + @HotSpotVMFlag(name = "TLABWasteIncrement") @Stable public int tlabRefillWasteIncrement; + + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_start", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferStartOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_end", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferEndOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_top", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferTopOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_pf_top", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferPfTopOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_slow_allocations", type = "unsigned", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferSlowAllocationsOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_fast_refill_waste", type = "unsigned", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferFastRefillWasteOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_number_of_refills", type = "unsigned", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferNumberOfRefillsOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_refill_waste_limit", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferRefillWasteLimitOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_desired_size", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferDesiredSizeOffset; + + public int tlabSlowAllocationsOffset() { + return threadTlabOffset + threadLocalAllocBufferSlowAllocationsOffset; + } + + public int tlabFastRefillWasteOffset() { + return threadTlabOffset + threadLocalAllocBufferFastRefillWasteOffset; + } + + public int tlabNumberOfRefillsOffset() { + return threadTlabOffset + threadLocalAllocBufferNumberOfRefillsOffset; + } + + public int tlabRefillWasteLimitOffset() { + return threadTlabOffset + threadLocalAllocBufferRefillWasteLimitOffset; + } + + public int threadTlabSizeOffset() { + return threadTlabOffset + threadLocalAllocBufferDesiredSizeOffset; + } + + public int threadTlabStartOffset() { + return threadTlabOffset + threadLocalAllocBufferStartOffset; + } + + public int threadTlabEndOffset() { + return threadTlabOffset + threadLocalAllocBufferEndOffset; + } + + public int threadTlabTopOffset() { + return threadTlabOffset + threadLocalAllocBufferTopOffset; + } + + public int threadTlabPfTopOffset() { + return threadTlabOffset + threadLocalAllocBufferPfTopOffset; + } + + /** + * See: {@code ThreadLocalAllocBuffer::end_reserve()}. + */ + public final int threadLocalAllocBufferEndReserve() { + final int typeSizeInBytes = roundUp(arrayOopDescLengthOffset() + Integer.BYTES, heapWordSize); + // T_INT arrays need not be 8 byte aligned. + final int reserveSize = typeSizeInBytes / heapWordSize; + return Integer.max(reserveSize, abstractVmVersionReserveForAllocationPrefetch); + } + + /** + * See: {@code ThreadLocalAllocBuffer::alignment_reserve()}. + */ + public final int tlabAlignmentReserve() { + return roundUp(threadLocalAllocBufferEndReserve(), minObjAlignment()); + } + + @HotSpotVMFlag(name = "TLABStats") @Stable public boolean tlabStats; + + // FIXME This is only temporary until the GC code is changed. + @HotSpotVMField(name = "CompilerToVM::_supports_inline_contig_alloc", type = "bool", get = HotSpotVMField.Type.VALUE) @Stable public boolean inlineContiguousAllocationSupported; + @HotSpotVMField(name = "CompilerToVM::_heap_end_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapEndAddress; + @HotSpotVMField(name = "CompilerToVM::_heap_top_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapTopAddress; + + /** + * The DataLayout header size is the same as the cell size. + */ + @HotSpotVMConstant(name = "DataLayout::cell_size") @Stable public int dataLayoutHeaderSize; + @HotSpotVMField(name = "DataLayout::_header._struct._tag", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutTagOffset; + @HotSpotVMField(name = "DataLayout::_header._struct._flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutFlagsOffset; + @HotSpotVMField(name = "DataLayout::_header._struct._bci", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutBCIOffset; + @HotSpotVMField(name = "DataLayout::_cells[0]", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutCellsOffset; + @HotSpotVMConstant(name = "DataLayout::cell_size") @Stable public int dataLayoutCellSize; + + @HotSpotVMConstant(name = "DataLayout::no_tag") @Stable public int dataLayoutNoTag; + @HotSpotVMConstant(name = "DataLayout::bit_data_tag") @Stable public int dataLayoutBitDataTag; + @HotSpotVMConstant(name = "DataLayout::counter_data_tag") @Stable public int dataLayoutCounterDataTag; + @HotSpotVMConstant(name = "DataLayout::jump_data_tag") @Stable public int dataLayoutJumpDataTag; + @HotSpotVMConstant(name = "DataLayout::receiver_type_data_tag") @Stable public int dataLayoutReceiverTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::virtual_call_data_tag") @Stable public int dataLayoutVirtualCallDataTag; + @HotSpotVMConstant(name = "DataLayout::ret_data_tag") @Stable public int dataLayoutRetDataTag; + @HotSpotVMConstant(name = "DataLayout::branch_data_tag") @Stable public int dataLayoutBranchDataTag; + @HotSpotVMConstant(name = "DataLayout::multi_branch_data_tag") @Stable public int dataLayoutMultiBranchDataTag; + @HotSpotVMConstant(name = "DataLayout::arg_info_data_tag") @Stable public int dataLayoutArgInfoDataTag; + @HotSpotVMConstant(name = "DataLayout::call_type_data_tag") @Stable public int dataLayoutCallTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::virtual_call_type_data_tag") @Stable public int dataLayoutVirtualCallTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::parameters_type_data_tag") @Stable public int dataLayoutParametersTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::speculative_trap_data_tag") @Stable public int dataLayoutSpeculativeTrapDataTag; + + @HotSpotVMFlag(name = "BciProfileWidth") @Stable public int bciProfileWidth; + @HotSpotVMFlag(name = "TypeProfileWidth") @Stable public int typeProfileWidth; + @HotSpotVMFlag(name = "MethodProfileWidth") @Stable public int methodProfileWidth; + + @HotSpotVMField(name = "CodeBlob::_code_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int codeBlobCodeOffsetOffset; + @HotSpotVMField(name = "DeoptimizationBlob::_unpack_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int deoptimizationBlobUnpackOffsetOffset; + @HotSpotVMField(name = "DeoptimizationBlob::_uncommon_trap_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int deoptimizationBlobUncommonTrapOffsetOffset; + + @HotSpotVMField(name = "SharedRuntime::_ic_miss_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long inlineCacheMissBlob; + @HotSpotVMField(name = "SharedRuntime::_wrong_method_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long wrongMethodBlob; + @HotSpotVMField(name = "SharedRuntime::_deopt_blob", type = "DeoptimizationBlob*", get = HotSpotVMField.Type.VALUE) @Stable private long deoptBlob; + + @HotSpotVMManual(name = "SharedRuntime::get_ic_miss_stub()") public final long inlineCacheMissStub; + @HotSpotVMManual(name = "SharedRuntime::get_handle_wrong_method_stub()") public final long handleWrongMethodStub; + + @HotSpotVMManual(name = "SharedRuntime::deopt_blob()->unpack()") public final long handleDeoptStub; + @HotSpotVMManual(name = "SharedRuntime::deopt_blob()->uncommon_trap()") public final long uncommonTrapStub; + + @HotSpotVMField(name = "CodeCache::_low_bound", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long codeCacheLowBound; + @HotSpotVMField(name = "CodeCache::_high_bound", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long codeCacheHighBound; + + @HotSpotVMField(name = "StubRoutines::_aescrypt_encryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptEncryptBlockStub; + @HotSpotVMField(name = "StubRoutines::_aescrypt_decryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptDecryptBlockStub; + @HotSpotVMField(name = "StubRoutines::_cipherBlockChaining_encryptAESCrypt", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long cipherBlockChainingEncryptAESCryptStub; + @HotSpotVMField(name = "StubRoutines::_cipherBlockChaining_decryptAESCrypt", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long cipherBlockChainingDecryptAESCryptStub; + @HotSpotVMField(name = "StubRoutines::_updateBytesCRC32", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long updateBytesCRC32Stub; + @HotSpotVMField(name = "StubRoutines::_crc_table_adr", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long crcTableAddress; + + @HotSpotVMField(name = "StubRoutines::_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteArraycopy; + @HotSpotVMField(name = "StubRoutines::_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortArraycopy; + @HotSpotVMField(name = "StubRoutines::_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintArraycopy; + @HotSpotVMField(name = "StubRoutines::_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopDisjointArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedDisjointArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopy; + @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_unsafe_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long unsafeArraycopy; + @HotSpotVMField(name = "StubRoutines::_generic_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long genericArraycopy; + + @HotSpotVMAddress(name = "JVMCIRuntime::new_instance") @Stable public long newInstanceAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::new_array") @Stable public long newArrayAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::new_multi_array") @Stable public long newMultiArrayAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::dynamic_new_array") @Stable public long dynamicNewArrayAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::dynamic_new_instance") @Stable public long dynamicNewInstanceAddress; + + @HotSpotVMAddress(name = "JVMCIRuntime::thread_is_interrupted") @Stable public long threadIsInterruptedAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::vm_message") @Stable public long vmMessageAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::identity_hash_code") @Stable public long identityHashCodeAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::exception_handler_for_pc") @Stable public long exceptionHandlerForPcAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::monitorenter") @Stable public long monitorenterAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::monitorexit") @Stable public long monitorexitAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::create_null_exception") @Stable public long createNullPointerExceptionAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::create_out_of_bounds_exception") @Stable public long createOutOfBoundsExceptionAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::log_primitive") @Stable public long logPrimitiveAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::log_object") @Stable public long logObjectAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::log_printf") @Stable public long logPrintfAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::vm_error") @Stable public long vmErrorAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::load_and_clear_exception") @Stable public long loadAndClearExceptionAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::write_barrier_pre") @Stable public long writeBarrierPreAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::write_barrier_post") @Stable public long writeBarrierPostAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::validate_object") @Stable public long validateObject; + + @HotSpotVMAddress(name = "JVMCIRuntime::test_deoptimize_call_int") @Stable public long testDeoptimizeCallInt; + + @HotSpotVMAddress(name = "SharedRuntime::register_finalizer") @Stable public long registerFinalizerAddress; + @HotSpotVMAddress(name = "SharedRuntime::exception_handler_for_return_address") @Stable public long exceptionHandlerForReturnAddressAddress; + @HotSpotVMAddress(name = "SharedRuntime::OSR_migration_end") @Stable public long osrMigrationEndAddress; + + @HotSpotVMAddress(name = "os::javaTimeMillis") @Stable public long javaTimeMillisAddress; + @HotSpotVMAddress(name = "os::javaTimeNanos") @Stable public long javaTimeNanosAddress; + @HotSpotVMAddress(name = "SharedRuntime::dsin") @Stable public long arithmeticSinAddress; + @HotSpotVMAddress(name = "SharedRuntime::dcos") @Stable public long arithmeticCosAddress; + @HotSpotVMAddress(name = "SharedRuntime::dtan") @Stable public long arithmeticTanAddress; + @HotSpotVMAddress(name = "SharedRuntime::dexp") @Stable public long arithmeticExpAddress; + @HotSpotVMAddress(name = "SharedRuntime::dlog") @Stable public long arithmeticLogAddress; + @HotSpotVMAddress(name = "SharedRuntime::dlog10") @Stable public long arithmeticLog10Address; + @HotSpotVMAddress(name = "SharedRuntime::dpow") @Stable public long arithmeticPowAddress; + + @HotSpotVMFlag(name = "JVMCICounterSize") @Stable public int jvmciCountersSize; + + @HotSpotVMAddress(name = "Deoptimization::fetch_unroll_info") @Stable public long deoptimizationFetchUnrollInfo; + @HotSpotVMAddress(name = "Deoptimization::uncommon_trap") @Stable public long deoptimizationUncommonTrap; + @HotSpotVMAddress(name = "Deoptimization::unpack_frames") @Stable public long deoptimizationUnpackFrames; + + @HotSpotVMConstant(name = "Deoptimization::Reason_none") @Stable public int deoptReasonNone; + @HotSpotVMConstant(name = "Deoptimization::Reason_null_check") @Stable public int deoptReasonNullCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_range_check") @Stable public int deoptReasonRangeCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_class_check") @Stable public int deoptReasonClassCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_array_check") @Stable public int deoptReasonArrayCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_unreached0") @Stable public int deoptReasonUnreached0; + @HotSpotVMConstant(name = "Deoptimization::Reason_type_checked_inlining") @Stable public int deoptReasonTypeCheckInlining; + @HotSpotVMConstant(name = "Deoptimization::Reason_optimized_type_check") @Stable public int deoptReasonOptimizedTypeCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_not_compiled_exception_handler") @Stable public int deoptReasonNotCompiledExceptionHandler; + @HotSpotVMConstant(name = "Deoptimization::Reason_unresolved") @Stable public int deoptReasonUnresolved; + @HotSpotVMConstant(name = "Deoptimization::Reason_jsr_mismatch") @Stable public int deoptReasonJsrMismatch; + @HotSpotVMConstant(name = "Deoptimization::Reason_div0_check") @Stable public int deoptReasonDiv0Check; + @HotSpotVMConstant(name = "Deoptimization::Reason_constraint") @Stable public int deoptReasonConstraint; + @HotSpotVMConstant(name = "Deoptimization::Reason_loop_limit_check") @Stable public int deoptReasonLoopLimitCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_aliasing") @Stable public int deoptReasonAliasing; + @HotSpotVMConstant(name = "Deoptimization::Reason_transfer_to_interpreter") @Stable public int deoptReasonTransferToInterpreter; + @HotSpotVMConstant(name = "Deoptimization::Reason_LIMIT") @Stable public int deoptReasonOSROffset; + + @HotSpotVMConstant(name = "Deoptimization::Action_none") @Stable public int deoptActionNone; + @HotSpotVMConstant(name = "Deoptimization::Action_maybe_recompile") @Stable public int deoptActionMaybeRecompile; + @HotSpotVMConstant(name = "Deoptimization::Action_reinterpret") @Stable public int deoptActionReinterpret; + @HotSpotVMConstant(name = "Deoptimization::Action_make_not_entrant") @Stable public int deoptActionMakeNotEntrant; + @HotSpotVMConstant(name = "Deoptimization::Action_make_not_compilable") @Stable public int deoptActionMakeNotCompilable; + + @HotSpotVMConstant(name = "Deoptimization::_action_bits") @Stable public int deoptimizationActionBits; + @HotSpotVMConstant(name = "Deoptimization::_reason_bits") @Stable public int deoptimizationReasonBits; + @HotSpotVMConstant(name = "Deoptimization::_debug_id_bits") @Stable public int deoptimizationDebugIdBits; + @HotSpotVMConstant(name = "Deoptimization::_action_shift") @Stable public int deoptimizationActionShift; + @HotSpotVMConstant(name = "Deoptimization::_reason_shift") @Stable public int deoptimizationReasonShift; + @HotSpotVMConstant(name = "Deoptimization::_debug_id_shift") @Stable public int deoptimizationDebugIdShift; + + @HotSpotVMConstant(name = "Deoptimization::Unpack_deopt") @Stable public int deoptimizationUnpackDeopt; + @HotSpotVMConstant(name = "Deoptimization::Unpack_exception") @Stable public int deoptimizationUnpackException; + @HotSpotVMConstant(name = "Deoptimization::Unpack_uncommon_trap") @Stable public int deoptimizationUnpackUncommonTrap; + @HotSpotVMConstant(name = "Deoptimization::Unpack_reexecute") @Stable public int deoptimizationUnpackReexecute; + + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_size_of_deoptimized_frame", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_caller_adjustment", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockCallerAdjustmentOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_number_of_frames", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockNumberOfFramesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_total_frame_sizes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockTotalFrameSizesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_sizes", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFrameSizesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_pcs", type = "address*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFramePcsOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_initial_info", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockInitialInfoOffset; + + @HotSpotVMConstant(name = "vmIntrinsics::_invokeBasic") @Stable public int vmIntrinsicInvokeBasic; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToVirtual") @Stable public int vmIntrinsicLinkToVirtual; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToStatic") @Stable public int vmIntrinsicLinkToStatic; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToSpecial") @Stable public int vmIntrinsicLinkToSpecial; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToInterface") @Stable public int vmIntrinsicLinkToInterface; + + @HotSpotVMConstant(name = "JVMCIEnv::ok") @Stable public int codeInstallResultOk; + @HotSpotVMConstant(name = "JVMCIEnv::dependencies_failed") @Stable public int codeInstallResultDependenciesFailed; + @HotSpotVMConstant(name = "JVMCIEnv::dependencies_invalid") @Stable public int codeInstallResultDependenciesInvalid; + @HotSpotVMConstant(name = "JVMCIEnv::cache_full") @Stable public int codeInstallResultCacheFull; + @HotSpotVMConstant(name = "JVMCIEnv::code_too_large") @Stable public int codeInstallResultCodeTooLarge; + + public String getCodeInstallResultDescription(int codeInstallResult) { + if (codeInstallResult == codeInstallResultOk) { + return "ok"; + } + if (codeInstallResult == codeInstallResultDependenciesFailed) { + return "dependencies failed"; + } + if (codeInstallResult == codeInstallResultDependenciesInvalid) { + return "dependencies invalid"; + } + if (codeInstallResult == codeInstallResultCacheFull) { + return "code cache is full"; + } + if (codeInstallResult == codeInstallResultCodeTooLarge) { + return "code is too large"; + } + assert false : codeInstallResult; + return "unknown"; + } + + @HotSpotVMConstant(name = "CompilerToVM::KLASS_TAG") @Stable public int compilerToVMKlassTag; + @HotSpotVMConstant(name = "CompilerToVM::SYMBOL_TAG") @Stable public int compilerToVMSymbolTag; + + // Checkstyle: stop + @HotSpotVMConstant(name = "CodeInstaller::VERIFIED_ENTRY") @Stable public int MARKID_VERIFIED_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::UNVERIFIED_ENTRY") @Stable public int MARKID_UNVERIFIED_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::OSR_ENTRY") @Stable public int MARKID_OSR_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::EXCEPTION_HANDLER_ENTRY") @Stable public int MARKID_EXCEPTION_HANDLER_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::DEOPT_HANDLER_ENTRY") @Stable public int MARKID_DEOPT_HANDLER_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::INVOKEINTERFACE") @Stable public int MARKID_INVOKEINTERFACE; + @HotSpotVMConstant(name = "CodeInstaller::INVOKEVIRTUAL") @Stable public int MARKID_INVOKEVIRTUAL; + @HotSpotVMConstant(name = "CodeInstaller::INVOKESTATIC") @Stable public int MARKID_INVOKESTATIC; + @HotSpotVMConstant(name = "CodeInstaller::INVOKESPECIAL") @Stable public int MARKID_INVOKESPECIAL; + @HotSpotVMConstant(name = "CodeInstaller::INLINE_INVOKE") @Stable public int MARKID_INLINE_INVOKE; + @HotSpotVMConstant(name = "CodeInstaller::POLL_NEAR") @Stable public int MARKID_POLL_NEAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_NEAR") @Stable public int MARKID_POLL_RETURN_NEAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_FAR") @Stable public int MARKID_POLL_FAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_FAR") @Stable public int MARKID_POLL_RETURN_FAR; + @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_ADDRESS") @Stable public int MARKID_CARD_TABLE_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::HEAP_TOP_ADDRESS") @Stable public int MARKID_HEAP_TOP_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::HEAP_END_ADDRESS") @Stable public int MARKID_HEAP_END_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::NARROW_KLASS_BASE_ADDRESS") @Stable public int MARKID_NARROW_KLASS_BASE_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::CRC_TABLE_ADDRESS") @Stable public int MARKID_CRC_TABLE_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::INVOKE_INVALID") @Stable public int MARKID_INVOKE_INVALID; + + // Checkstyle: resume + + private boolean check() { + for (Field f : getClass().getDeclaredFields()) { + int modifiers = f.getModifiers(); + if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) { + assert Modifier.isFinal(modifiers) || f.getAnnotation(Stable.class) != null : "field should either be final or @Stable: " + f; + } + } + + assert codeEntryAlignment > 0 : codeEntryAlignment; + assert (layoutHelperArrayTagObjectValue & (1 << (Integer.SIZE - 1))) != 0 : "object array must have first bit set"; + assert (layoutHelperArrayTagTypeValue & (1 << (Integer.SIZE - 1))) != 0 : "type array must have first bit set"; + + return true; + } + + /** + * A compact representation of the different encoding strategies for Objects and metadata. + */ + public static class CompressEncoding { + public final long base; + public final int shift; + public final int alignment; + + CompressEncoding(long base, int shift, int alignment) { + this.base = base; + this.shift = shift; + this.alignment = alignment; + } + + public int compress(long ptr) { + if (ptr == 0L) { + return 0; + } else { + return (int) ((ptr - base) >>> shift); + } + } + + public long uncompress(int ptr) { + if (ptr == 0) { + return 0L; + } else { + return ((ptr & 0xFFFFFFFFL) << shift) + base; + } + } + + @Override + public String toString() { + return "base: " + base + " shift: " + shift + " alignment: " + alignment; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + alignment; + result = prime * result + (int) (base ^ (base >>> 32)); + result = prime * result + shift; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CompressEncoding) { + CompressEncoding other = (CompressEncoding) obj; + return alignment == other.alignment && base == other.base && shift == other.shift; + } else { + return false; + } + } + } + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigVerifier.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigVerifier.java new file mode 100644 index 00000000000..3a449db38b0 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigVerifier.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static java.lang.String.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.org.objectweb.asm.*; +import jdk.internal.org.objectweb.asm.Type; +import jdk.vm.ci.common.*; +import sun.misc.*; + +/** + * A {@link ClassVisitor} that verifies {@link HotSpotVMConfig} does not access {@link Unsafe} from + * any of its non-static, non-constructor methods. This ensures that a deserialized + * {@link HotSpotVMConfig} object does not perform any unsafe reads on addresses that are only valid + * in the context in which the object was serialized. Note that this does not catch cases where a + * client uses an address stored in a {@link HotSpotVMConfig} field. + */ +final class HotSpotVMConfigVerifier extends ClassVisitor { + + public static boolean check() { + Class cls = HotSpotVMConfig.class; + String classFilePath = "/" + cls.getName().replace('.', '/') + ".class"; + try { + InputStream classfile = cls.getResourceAsStream(classFilePath); + ClassReader cr = new ClassReader(Objects.requireNonNull(classfile, "Could not find class file for " + cls.getName())); + ClassVisitor cv = new HotSpotVMConfigVerifier(); + cr.accept(cv, 0); + return true; + } catch (IOException e) { + throw new JVMCIError(e); + } + } + + /** + * Source file context for error reporting. + */ + String sourceFile = null; + + /** + * Line number for error reporting. + */ + int lineNo = -1; + + private static Class resolve(String name) { + try { + return Class.forName(name.replace('/', '.')); + } catch (ClassNotFoundException e) { + throw new JVMCIError(e); + } + } + + HotSpotVMConfigVerifier() { + super(Opcodes.ASM5); + } + + @Override + public void visitSource(String source, String debug) { + this.sourceFile = source; + } + + void verify(boolean condition, String message) { + if (!condition) { + error(message); + } + } + + void error(String message) { + String errorMessage = format("%s:%d: %s is not allowed in the context of compilation replay. The unsafe access should be moved into the %s constructor and the result cached in a field", + sourceFile, lineNo, message, HotSpotVMConfig.class.getSimpleName()); + throw new JVMCIError(errorMessage); + + } + + @Override + public MethodVisitor visitMethod(int access, String name, String d, String signature, String[] exceptions) { + if (!Modifier.isStatic(access) && Modifier.isPublic(access) && !name.equals("")) { + return new MethodVisitor(Opcodes.ASM5) { + + @Override + public void visitLineNumber(int line, Label start) { + lineNo = line; + } + + private Executable resolveMethod(String owner, String methodName, String methodDesc) { + Class declaringClass = resolve(owner); + while (declaringClass != null) { + if (methodName.equals("")) { + for (Constructor c : declaringClass.getDeclaredConstructors()) { + if (methodDesc.equals(Type.getConstructorDescriptor(c))) { + return c; + } + } + } else { + Type[] argumentTypes = Type.getArgumentTypes(methodDesc); + for (Method m : declaringClass.getDeclaredMethods()) { + if (m.getName().equals(methodName)) { + if (Arrays.equals(argumentTypes, Type.getArgumentTypes(m))) { + if (Type.getReturnType(methodDesc).equals(Type.getReturnType(m))) { + return m; + } + } + } + } + } + declaringClass = declaringClass.getSuperclass(); + } + throw new NoSuchMethodError(owner + "." + methodName + methodDesc); + } + + /** + * Checks whether a given method is allowed to be called. + */ + private boolean checkInvokeTarget(Executable method) { + if (method.getDeclaringClass().equals(Unsafe.class)) { + return false; + } + return true; + } + + @Override + public void visitMethodInsn(int opcode, String owner, String methodName, String methodDesc, boolean itf) { + Executable callee = resolveMethod(owner, methodName, methodDesc); + verify(checkInvokeTarget(callee), "invocation of " + callee); + } + }; + } else { + return null; + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMEventListener.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMEventListener.java new file mode 100644 index 00000000000..520a3da4cc9 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMEventListener.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.meta.*; + +public interface HotSpotVMEventListener { + + /** + * Notifies this client that the VM is shutting down. + */ + default void notifyShutdown() { + } + + /** + * Notify on successful install into the CodeCache. + * + * @param hotSpotCodeCacheProvider + * @param installedCode + * @param compResult + */ + default void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompilationResult compResult) { + } + + /** + * Perform any extra initialization required. + * + * @param runtime + */ + default void completeInitialization(HotSpotJVMCIRuntime runtime) { + } + + /** + * Create a custom {@link JVMCIMetaAccessContext} to be used for managing the lifetime of loaded + * metadata. It a custom one isn't created then the default implementation will be a single + * context with globally shared instances of {@link ResolvedJavaType} that are never released. + * + * @param hotSpotJVMCIRuntime + * @return a custom context or null + */ + default JVMCIMetaAccessContext createMetaAccessContext(HotSpotJVMCIRuntime hotSpotJVMCIRuntime) { + return null; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVmSymbols.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVmSymbols.java new file mode 100644 index 00000000000..8c06c321ace --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVmSymbols.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import sun.misc.*; + +/** + * Class to access the C++ {@code vmSymbols} table. + */ +public final class HotSpotVmSymbols { + + /** + * Returns the symbol in the {@code vmSymbols} table at position {@code index} as {@link String} + * . + * + * @param index position in the symbol table + * @return the symbol at position id + */ + public static String symbolAt(int index) { + HotSpotJVMCIRuntimeProvider runtime = runtime(); + HotSpotVMConfig config = runtime.getConfig(); + assert config.vmSymbolsFirstSID <= index && index < config.vmSymbolsSIDLimit : "index " + index + " is out of bounds"; + assert config.symbolPointerSize == Unsafe.ADDRESS_SIZE : "the following address read is broken"; + return runtime.getCompilerToVM().getSymbol(UNSAFE.getAddress(config.vmSymbolsSymbols + index * config.symbolPointerSize)); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceWrapperObject.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceWrapperObject.java new file mode 100644 index 00000000000..d1df11f0eb1 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceWrapperObject.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +/** + * A tag interface indicating that this type is a wrapper around a HotSpot metaspace object. + * + * It would preferable if this were the base class containing the pointer but that would require + * mixins since most of the wrapper types have complex supertype hierarchies. + */ +public interface MetaspaceWrapperObject { + + long getMetaspacePointer(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java new file mode 100644 index 00000000000..2cda0c24241 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.vm.ci.hotspot; + +import java.lang.annotation.*; + +/** + * This annotation functions as an alias for the sun.invoke.Stable annotation within JVMCI code. It + * is specially recognized during class file parsing in the same way as that annotation. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Stable { +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SuppressFBWarnings.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SuppressFBWarnings.java new file mode 100644 index 00000000000..c9567f72284 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SuppressFBWarnings.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +/** + * Used to suppress FindBugs warnings. + */ +public @interface SuppressFBWarnings { + /** + * The set of FindBugs warnings that are to be + * suppressed in annotated element. The value can be a bug category, kind or pattern. + */ + String[] value(); + + /** + * Reason why the warning is suppressed. + */ + String justification(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java new file mode 100644 index 00000000000..cff2ced4100 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +/** + * Package private access to the {@link Unsafe} capability. + */ +class UnsafeAccess { + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/events/EmptyEventProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/events/EmptyEventProvider.java new file mode 100644 index 00000000000..9e5df8268db --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/events/EmptyEventProvider.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot.events; + +import jdk.vm.ci.common.*; + +/** + * An empty implementation for {@link EventProvider}. This implementation is used when no logging is + * requested. + */ +public final class EmptyEventProvider implements EventProvider { + + public CompilationEvent newCompilationEvent() { + return new EmptyCompilationEvent(); + } + + public static class EmptyCompilationEvent implements CompilationEvent { + public void commit() { + throw JVMCIError.shouldNotReachHere(); + } + + public boolean shouldWrite() { + // Events of this class should never been written. + return false; + } + + public void begin() { + } + + public void end() { + } + + public void setMethod(String method) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setCompileId(int compileId) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setCompileLevel(int compileLevel) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setSucceeded(boolean succeeded) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setIsOsr(boolean isOsr) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setCodeSize(int codeSize) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setInlinedBytes(int inlinedBytes) { + throw JVMCIError.shouldNotReachHere(); + } + } + + public CompilerFailureEvent newCompilerFailureEvent() { + return new EmptyCompilerFailureEvent(); + } + + public static class EmptyCompilerFailureEvent implements CompilerFailureEvent { + public void commit() { + throw JVMCIError.shouldNotReachHere(); + } + + public boolean shouldWrite() { + // Events of this class should never been written. + return false; + } + + public void setCompileId(int compileId) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setMessage(String message) { + throw JVMCIError.shouldNotReachHere(); + } + } + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/events/EventProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/events/EventProvider.java new file mode 100644 index 00000000000..469868d0bf7 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/events/EventProvider.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot.events; + +/** + * A provider that provides a specific implementation for events that can be logged in the compiler. + */ +public interface EventProvider { + + /** + * An instant event is an event that is not considered to have taken any time. + */ + interface InstantEvent { + /** + * Commits the event. + */ + void commit(); + + /** + * Determines if this particular event instance would be committed to the data stream right + * now if application called {@link #commit()}. This in turn depends on whether the event is + * enabled and possible other factors. + * + * @return if this event would be committed on a call to {@link #commit()}. + */ + boolean shouldWrite(); + } + + /** + * Timed events describe an operation that somehow consumes time. + */ + interface TimedEvent extends InstantEvent { + /** + * Starts the timing for this event. + */ + void begin(); + + /** + * Ends the timing period for this event. + */ + void end(); + } + + /** + * Creates a new {@link CompilationEvent}. + * + * @return a compilation event + */ + CompilationEvent newCompilationEvent(); + + /** + * A compilation event. + */ + interface CompilationEvent extends TimedEvent { + void setMethod(String method); + + void setCompileId(int compileId); + + void setCompileLevel(int compileLevel); + + void setSucceeded(boolean succeeded); + + void setIsOsr(boolean isOsr); + + void setCodeSize(int codeSize); + + void setInlinedBytes(int inlinedBytes); + } + + /** + * Creates a new {@link CompilerFailureEvent}. + * + * @return a compiler failure event + */ + CompilerFailureEvent newCompilerFailureEvent(); + + /** + * A compiler failure event. + */ + interface CompilerFailureEvent extends InstantEvent { + void setCompileId(int compileId); + + void setMessage(String message); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/logging/package-info.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/logging/package-info.java new file mode 100644 index 00000000000..eb58e4c3336 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/logging/package-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * Logging framework for the HotSpot CRI implementation. + */ +package jdk.vm.ci.hotspot.logging; + diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMAddress.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMAddress.java new file mode 100644 index 00000000000..4e810f9bedd --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMAddress.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ address in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMAddress { + + /** + * Returns the name of the symbol this address is referring to. + * + * @return name of symbol of this address + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; + + /** + * List of operating systems where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostOSName()}. An empty list implies that the constant is required + * on all operating systems. + */ + @SuppressWarnings("javadoc") + String[] os() default {}; + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMConstant.java new file mode 100644 index 00000000000..bf8a465f52f --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMConstant.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ constant in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMConstant { + + /** + * Returns the name of the constant. + * + * @return name of constant + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMData.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMData.java new file mode 100644 index 00000000000..7cf45a51c0f --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMData.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a entry in {@code gHotSpotVMData}. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMData { + + /** + * Returns the array index of this field. + * + * @return array index of field + */ + int index(); + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMField.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMField.java new file mode 100644 index 00000000000..158a6879309 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMField.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ field in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMField { + + /** + * Types of information this annotation can return. + */ + enum Type { + /** + * Returns the offset of this field within the type. Only valid for instance fields. + */ + OFFSET, + + /** + * Returns the absolute address of this field. Only valid for static fields. + */ + ADDRESS, + + /** + * Returns the value of this field. Only valid for static fields. + */ + VALUE; + } + + /** + * Specifies what type of information to return. + * + * @see Type + */ + Type get(); + + /** + * Returns the type name containing this field. + * + * @return name of containing type + */ + String type(); + + /** + * Returns the name of this field. + * + * @return name of field + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMFlag.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMFlag.java new file mode 100644 index 00000000000..d8b5d3e13de --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMFlag.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ flag in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMFlag { + + /** + * Returns the name of this flag. + * + * @return name of flag. + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; + + boolean optional() default false; +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMManual.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMManual.java new file mode 100644 index 00000000000..7aed441a2d6 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMManual.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Annotates a field in HotSpotVMConfig which is not read from the VM but is calculated manually. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMManual { + + /** + * Returns the name associated with that field. + * + * @return name associated with field + */ + String name(); + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMType.java new file mode 100644 index 00000000000..4e22c3948da --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMType.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ type in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMType { + + /** + * Types of information this annotation can return. + */ + enum Type { + /** + * Returns the size of the type (C++ {@code sizeof()}). + */ + SIZE; + } + + /** + * Specifies what type of information to return. + * + * @see Type + */ + Type get(); + + /** + * Returns the name of the type. + * + * @return name of type + */ + String name(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java new file mode 100644 index 00000000000..608285e7e92 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.inittimer; + +/** + * A facility for timing a step in the runtime initialization sequence. This is independent from all + * other JVMCI code so as to not perturb the initialization sequence. It is enabled by setting the + * {@code "jvmci.inittimer"} system property to {@code "true"}. + */ +public final class InitTimer implements AutoCloseable { + final String name; + final long start; + + private InitTimer(String name) { + this.name = name; + this.start = System.currentTimeMillis(); + System.out.println("START: " + SPACES.substring(0, timerDepth * 2) + name); + assert Thread.currentThread() == initializingThread : Thread.currentThread() + " != " + initializingThread; + timerDepth++; + } + + @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "only the initializing thread accesses this field") + public void close() { + final long end = System.currentTimeMillis(); + timerDepth--; + System.out.println(" DONE: " + SPACES.substring(0, timerDepth * 2) + name + " [" + (end - start) + " ms]"); + } + + public static InitTimer timer(String name) { + return ENABLED ? new InitTimer(name) : null; + } + + public static InitTimer timer(String name, Object suffix) { + return ENABLED ? new InitTimer(name + suffix) : null; + } + + /** + * Specifies if initialization timing is enabled. + */ + private static final boolean ENABLED = Boolean.getBoolean("jvmci.inittimer") || Boolean.getBoolean("jvmci.runtime.TimeInit"); + + public static int timerDepth = 0; + public static final String SPACES = " "; + + /** + * Used to assert the invariant that all initialization happens on the same thread. + */ + public static final Thread initializingThread; + static { + if (ENABLED) { + initializingThread = Thread.currentThread(); + System.out.println("INITIALIZING THREAD: " + initializingThread); + } else { + initializingThread = null; + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/SuppressFBWarnings.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/SuppressFBWarnings.java new file mode 100644 index 00000000000..0105893e7f9 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/SuppressFBWarnings.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.inittimer; + +/** + * Used to suppress FindBugs warnings. + */ +public @interface SuppressFBWarnings { + /** + * The set of FindBugs warnings that are to be + * suppressed in annotated element. The value can be a bug category, kind or pattern. + */ + String[] value(); + + /** + * Reason why the warning is suppressed. + */ + String justification(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/overview.html b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/overview.html new file mode 100644 index 00000000000..3da323679a1 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/overview.html @@ -0,0 +1,38 @@ + + + + + + + + +The jdk.vm.ci.meta project provides an API to the runtime data structures +for various Java elements. Unlike standard Java reflection, it can model elements that are not yet loaded. +It can also expose profiling information collected by the runtime system. + + + diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractJavaProfile.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractJavaProfile.java new file mode 100644 index 00000000000..27eac0ec032 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractJavaProfile.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * This object holds probability information for a set of items that were profiled at a specific + * BCI. The precision of the supplied values may vary, but a runtime that provides this information + * should be aware that it will be used to guide performance-critical decisions like speculative + * inlining, etc. + * + * @param a subclass of AbstractProfiledItem + * @param the class of the items that are profiled at the specific BCI and for which + * probabilities are stored. E.g., a ResolvedJavaType or a ResolvedJavaMethod. + */ +public abstract class AbstractJavaProfile, U> { + + private final double notRecordedProbability; + private final T[] pitems; + + public AbstractJavaProfile(double notRecordedProbability, T[] pitems) { + this.pitems = pitems; + assert !Double.isNaN(notRecordedProbability); + this.notRecordedProbability = notRecordedProbability; + assert isSorted(); + assert totalProbablility() >= 0 && totalProbablility() <= 1.0001 : totalProbablility() + " " + this; + } + + private double totalProbablility() { + double total = notRecordedProbability; + for (T item : pitems) { + total += item.probability; + } + return total; + } + + /** + * Determines if an array of profiled items are sorted in descending order of their + * probabilities. + */ + private boolean isSorted() { + for (int i = 1; i < pitems.length; i++) { + if (pitems[i - 1].getProbability() < pitems[i].getProbability()) { + return false; + } + } + return true; + } + + /** + * Returns the estimated probability of all types that could not be recorded due to profiling + * limitations. + * + * @return double value ≥ 0.0 and ≤ 1.0 + */ + public double getNotRecordedProbability() { + return notRecordedProbability; + } + + protected T[] getItems() { + return pitems; + } + + /** + * Searches for an entry of a given resolved Java type. + * + * @param type the type for which an entry should be searched + * @return the entry or null if no entry for this type can be found + */ + public T findEntry(ResolvedJavaType type) { + if (pitems != null) { + for (T pt : pitems) { + if (pt.getItem().equals(type)) { + return pt; + } + } + } + return null; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getName()); + builder.append("["); + if (pitems != null) { + for (T pt : pitems) { + builder.append(pt.toString()); + builder.append(", "); + } + } + builder.append(this.notRecordedProbability); + builder.append("]"); + return builder.toString(); + } + + public boolean isIncluded(U item) { + if (this.getNotRecordedProbability() > 0.0) { + return true; + } else { + for (int i = 0; i < getItems().length; i++) { + T pitem = getItems()[i]; + U curType = pitem.getItem(); + if (curType == item) { + return true; + } + } + } + return false; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof AbstractJavaProfile)) { + return false; + } + AbstractJavaProfile that = (AbstractJavaProfile) obj; + if (that.notRecordedProbability != notRecordedProbability) { + return false; + } + if (that.pitems.length != pitems.length) { + return false; + } + for (int i = 0; i < pitems.length; ++i) { + if (!pitems[i].equals(that.pitems[i])) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return (int) Double.doubleToLongBits(notRecordedProbability) + pitems.length * 13; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractProfiledItem.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractProfiledItem.java new file mode 100644 index 00000000000..d4e551d40ae --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractProfiledItem.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * A profiled type that has a probability. Profiled types are naturally sorted in descending order + * of their probabilities. + */ +public abstract class AbstractProfiledItem implements Comparable> { + + protected final T item; + protected final double probability; + + public AbstractProfiledItem(T item, double probability) { + assert item != null; + assert probability >= 0.0D && probability <= 1.0D; + this.item = item; + this.probability = probability; + } + + protected T getItem() { + return item; + } + + /** + * Returns the estimated probability of {@link #getItem()}. + * + * @return double value ≥ 0.0 and ≤ 1.0 + */ + public double getProbability() { + return probability; + } + + @Override + public int compareTo(AbstractProfiledItem o) { + if (getProbability() > o.getProbability()) { + return -1; + } else if (getProbability() < o.getProbability()) { + return 1; + } + return 0; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(probability); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + item.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + AbstractProfiledItem other = (AbstractProfiledItem) obj; + if (Double.doubleToLongBits(probability) != Double.doubleToLongBits(other.probability)) { + return false; + } + return item.equals(other.item); + } + + @Override + public abstract String toString(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AllocatableValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AllocatableValue.java new file mode 100644 index 00000000000..17fc39b9cfd --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AllocatableValue.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Common base class for values that are stored in some location that's managed by the register + * allocator (e.g. register, stack slot). + */ +public abstract class AllocatableValue extends Value implements JavaValue { + + public static final AllocatableValue[] NONE = {}; + + public AllocatableValue(LIRKind lirKind) { + super(lirKind); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Assumptions.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Assumptions.java new file mode 100644 index 00000000000..f90e9fa33ff --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Assumptions.java @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.lang.invoke.*; +import java.util.*; + +/** + * Class for recording assumptions made during compilation. + */ +public final class Assumptions implements Iterable { + + /** + * Abstract base class for assumptions. An assumption assumes a property of the runtime that may + * be invalidated by subsequent execution (e.g., that a class has no subclasses implementing + * {@link NoFinalizableSubclass Object.finalize()}). + */ + public abstract static class Assumption { + } + + /** + * A class for providing information that is only valid in association with a set of + * {@link Assumption}s. + * + * @param + */ + public static class AssumptionResult { + Assumption[] assumptions; + final T result; + + private static final Assumption[] EMPTY = new Assumption[0]; + + public AssumptionResult(T result, Assumption... assumptions) { + this.result = result; + this.assumptions = assumptions; + } + + public AssumptionResult(T result) { + this(result, EMPTY); + } + + public T getResult() { + return result; + } + + public boolean isAssumptionFree() { + return assumptions.length == 0; + } + + public void add(AssumptionResult other) { + Assumption[] newAssumptions = Arrays.copyOf(this.assumptions, this.assumptions.length + other.assumptions.length); + System.arraycopy(other.assumptions, 0, newAssumptions, this.assumptions.length, other.assumptions.length); + this.assumptions = newAssumptions; + } + + public boolean canRecordTo(Assumptions target) { + /* + * We can use the result if it is either assumption free, or if we have a valid + * Assumptions object where we can record assumptions. + */ + return assumptions.length == 0 || target != null; + } + + public void recordTo(Assumptions target) { + assert canRecordTo(target); + + if (assumptions.length > 0) { + for (Assumption assumption : assumptions) { + target.record(assumption); + } + } + } + } + + /** + * An assumption that a given class has no subclasses implementing {@link Object#finalize()}). + */ + public static final class NoFinalizableSubclass extends Assumption { + + private ResolvedJavaType receiverType; + + public NoFinalizableSubclass(ResolvedJavaType receiverType) { + this.receiverType = receiverType; + } + + @Override + public int hashCode() { + return 31 + receiverType.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NoFinalizableSubclass) { + NoFinalizableSubclass other = (NoFinalizableSubclass) obj; + return other.receiverType.equals(receiverType); + } + return false; + } + + @Override + public String toString() { + return "NoFinalizableSubclass[receiverType=" + receiverType.toJavaName() + "]"; + } + + } + + /** + * An assumption that a given abstract or interface type has one direct concrete subtype. There + * is no requirement that the subtype is a leaf type. + */ + public static final class ConcreteSubtype extends Assumption { + + /** + * Type the assumption is made about. + */ + public final ResolvedJavaType context; + + /** + * Assumed concrete sub-type of the context type. + */ + public final ResolvedJavaType subtype; + + public ConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) { + this.context = context; + this.subtype = subtype; + assert context.isAbstract(); + assert subtype.isConcrete() || context.isInterface() : subtype.toString() + " : " + context.toString(); + assert !subtype.isArray() || subtype.getElementalType().isFinalFlagSet() : subtype.toString() + " : " + context.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + context.hashCode(); + result = prime * result + subtype.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConcreteSubtype) { + ConcreteSubtype other = (ConcreteSubtype) obj; + return other.context.equals(context) && other.subtype.equals(subtype); + } + return false; + } + + @Override + public String toString() { + return "ConcreteSubtype[context=" + context.toJavaName() + ", subtype=" + subtype.toJavaName() + "]"; + } + } + + /** + * An assumption that a given type has no subtypes. + */ + public static final class LeafType extends Assumption { + + /** + * Type the assumption is made about. + */ + public final ResolvedJavaType context; + + public LeafType(ResolvedJavaType context) { + this.context = context; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + context.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof LeafType) { + LeafType other = (LeafType) obj; + return other.context.equals(context); + } + return false; + } + + @Override + public String toString() { + return "LeafSubtype[context=" + context.toJavaName() + "]"; + } + } + + /** + * An assumption that a given virtual method has a given unique implementation. + */ + public static final class ConcreteMethod extends Assumption { + + /** + * A virtual (or interface) method whose unique implementation for the receiver type in + * {@link #context} is {@link #impl}. + */ + public final ResolvedJavaMethod method; + + /** + * A receiver type. + */ + public final ResolvedJavaType context; + + /** + * The unique implementation of {@link #method} for {@link #context}. + */ + public final ResolvedJavaMethod impl; + + public ConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { + this.method = method; + this.context = context; + this.impl = impl; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + method.hashCode(); + result = prime * result + context.hashCode(); + result = prime * result + impl.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConcreteMethod) { + ConcreteMethod other = (ConcreteMethod) obj; + return other.method.equals(method) && other.context.equals(context) && other.impl.equals(impl); + } + return false; + } + + @Override + public String toString() { + return "ConcreteMethod[method=" + method.format("%H.%n(%p)%r") + ", context=" + context.toJavaName() + ", impl=" + impl.format("%H.%n(%p)%r") + "]"; + } + } + + /** + * An assumption that a given call site's method handle did not change. + */ + public static final class CallSiteTargetValue extends Assumption { + + public final CallSite callSite; + public final MethodHandle methodHandle; + + public CallSiteTargetValue(CallSite callSite, MethodHandle methodHandle) { + this.callSite = callSite; + this.methodHandle = methodHandle; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + callSite.hashCode(); + result = prime * result + methodHandle.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CallSiteTargetValue) { + CallSiteTargetValue other = (CallSiteTargetValue) obj; + return callSite.equals(other.callSite) && methodHandle.equals(other.methodHandle); + } + return false; + } + + @Override + public String toString() { + return "CallSiteTargetValue[callSite=" + callSite + ", methodHandle=" + methodHandle + "]"; + } + } + + private final Set assumptions = new HashSet<>(); + + /** + * Returns whether any assumptions have been registered. + * + * @return {@code true} if at least one assumption has been registered, {@code false} otherwise. + */ + public boolean isEmpty() { + return assumptions.isEmpty(); + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Assumptions) { + Assumptions that = (Assumptions) obj; + if (!this.assumptions.equals(that.assumptions)) { + return false; + } + return true; + } + return false; + } + + @Override + public Iterator iterator() { + return assumptions.iterator(); + } + + /** + * Records an assumption that the specified type has no finalizable subclasses. + * + * @param receiverType the type that is assumed to have no finalizable subclasses + */ + public void recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) { + record(new NoFinalizableSubclass(receiverType)); + } + + /** + * Records that {@code subtype} is the only concrete subtype in the class hierarchy below + * {@code context}. + * + * @param context the root of the subtree of the class hierarchy that this assumptions is about + * @param subtype the one concrete subtype + */ + public void recordConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) { + record(new ConcreteSubtype(context, subtype)); + } + + /** + * Records that {@code impl} is the only possible concrete target for a virtual call to + * {@code method} with a receiver of type {@code context}. + * + * @param method a method that is the target of a virtual call + * @param context the receiver type of a call to {@code method} + * @param impl the concrete method that is the only possible target for the virtual call + */ + public void recordConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { + record(new ConcreteMethod(method, context, impl)); + } + + public void record(Assumption assumption) { + assumptions.add(assumption); + } + + /** + * Gets a copy of the assumptions recorded in this object as an array. + */ + public Assumption[] toArray() { + return assumptions.toArray(new Assumption[assumptions.size()]); + } + + /** + * Copies assumptions recorded by another {@link Assumptions} object into this object. + */ + public void record(Assumptions other) { + assert other != this; + assumptions.addAll(other.assumptions); + } + + @Override + public String toString() { + return "Assumptions[" + assumptions + "]"; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java new file mode 100644 index 00000000000..c7cc3895987 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Represents a compile-time constant (boxed) value within the compiler. + */ +public interface Constant { + + boolean isDefaultForKind(); + + String toValueString(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantPool.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantPool.java new file mode 100644 index 00000000000..f56e802431e --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantPool.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Represents the runtime representation of the constant pool that is used by the compiler when + * parsing bytecode. Provides methods to look up a constant pool entry without performing + * resolution. They are used during compilation. + */ +public interface ConstantPool { + + /** + * Returns the number of entries the constant pool. + * + * @return number of entries in the constant pool + */ + int length(); + + /** + * Ensures that the type referenced by the specified constant pool entry is loaded and + * initialized. This can be used to compile time resolve a type. It works for field, method, or + * type constant pool entries. + * + * @param cpi the index of the constant pool entry that references the type + * @param opcode the opcode of the instruction that references the type + */ + void loadReferencedType(int cpi, int opcode); + + /** + * Looks up a reference to a field. If {@code opcode} is non-negative, then resolution checks + * specific to the bytecode it denotes are performed if the field is already resolved. Should + * any of these checks fail, an unresolved field reference is returned. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return a reference to the field at {@code cpi} in this pool + * @throws ClassFormatError if the entry at {@code cpi} is not a field + */ + JavaField lookupField(int cpi, int opcode); + + /** + * Looks up a reference to a method. If {@code opcode} is non-negative, then resolution checks + * specific to the bytecode it denotes are performed if the method is already resolved. Should + * any of these checks fail, an unresolved method reference is returned. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return a reference to the method at {@code cpi} in this pool + * @throws ClassFormatError if the entry at {@code cpi} is not a method + */ + JavaMethod lookupMethod(int cpi, int opcode); + + /** + * Looks up a reference to a type. If {@code opcode} is non-negative, then resolution checks + * specific to the bytecode it denotes are performed if the type is already resolved. Should any + * of these checks fail, an unresolved type reference is returned. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return a reference to the compiler interface type + */ + JavaType lookupType(int cpi, int opcode); + + /** + * Looks up an Utf8 string. + * + * @param cpi the constant pool index + * @return the Utf8 string at index {@code cpi} in this constant pool + */ + String lookupUtf8(int cpi); + + /** + * Looks up a method signature. + * + * @param cpi the constant pool index + * @return the method signature at index {@code cpi} in this constant pool + */ + Signature lookupSignature(int cpi); + + /** + * Looks up a constant at the specified index. + * + * @param cpi the constant pool index + * @return the {@code Constant} or {@code JavaType} instance representing the constant pool + * entry + */ + Object lookupConstant(int cpi); + + /** + * Looks up the appendix at the specified index. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return the appendix if it exists and is resolved or {@code null} + */ + JavaConstant lookupAppendix(int cpi, int opcode); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java new file mode 100644 index 00000000000..6e130abb446 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.lang.invoke.*; + +/** + * Reflection operations on values represented as {@linkplain JavaConstant constants}. All methods + * in this interface require the VM to access the actual object encapsulated in + * {@link JavaKind#Object object} constants. This access is not always possible, depending on kind + * of VM and the state that the VM is in. Therefore, all methods can return {@code null} at any + * time, to indicate that the result is not available at this point. The caller is responsible to + * check for {@code null} results and handle them properly, e.g., not perform an optimization. + */ +public interface ConstantReflectionProvider { + + /** + * Compares two constants for equality. The equality relationship is symmetric. Returns + * {@link Boolean#TRUE true} if the two constants represent the same run time value, + * {@link Boolean#FALSE false} if they are different. Returns {@code null} if the constants + * cannot be compared at this point. + */ + Boolean constantEquals(Constant x, Constant y); + + /** + * Returns the length of the array constant. Returns {@code null} if the constant is not an + * array, or if the array length is not available at this point. + */ + Integer readArrayLength(JavaConstant array); + + /** + * Reads a value from the given array at the given index. Returns {@code null} if the constant + * is not an array, if the index is out of bounds, or if the value is not available at this + * point. + */ + JavaConstant readArrayElement(JavaConstant array, int index); + + /** + * Reads a value from the given array at the given index if it is a stable array. Returns + * {@code null} if the constant is not a stable array, if it is a default value, if the index is + * out of bounds, or if the value is not available at this point. + */ + JavaConstant readConstantArrayElement(JavaConstant array, int index); + + /** + * Reads a value from the given array at the given offset if it is a stable array. The offset + * will be decoded relative to the platform addressing into an index into the array. Returns + * {@code null} if the constant is not a stable array, if it is a default value, if the offset + * is out of bounds, or if the value is not available at this point. + */ + JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset); + + /** + * Gets the constant value of this field. Note that a {@code static final} field may not be + * considered constant if its declaring class is not yet initialized or if it is a well known + * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}). + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @return the constant value of this field or {@code null} if this field is not considered + * constant by the runtime + */ + JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver); + + /** + * Gets the current value of this field for a given object, if available. + * + * There is no guarantee that the same value will be returned by this method for a field unless + * the field is considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant) + * constant} by the runtime. + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @return the value of this field or {@code null} if the value is not available (e.g., because + * the field holder is not yet initialized). + */ + JavaConstant readFieldValue(JavaField field, JavaConstant receiver); + + /** + * Gets the current value of this field for a given object, if available. Like + * {@link #readFieldValue(JavaField, JavaConstant)} but treats array fields as stable. + * + * There is no guarantee that the same value will be returned by this method for a field unless + * the field is considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant) + * constant} by the runtime. + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @param isDefaultStable if {@code true}, default values are considered stable + * @return the value of this field or {@code null} if the value is not available (e.g., because + * the field holder is not yet initialized). + */ + JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable); + + /** + * Converts the given {@link JavaKind#isPrimitive() primitive} constant to a boxed + * {@link JavaKind#Object object} constant, according to the Java boxing rules. Returns + * {@code null} if the source is is not a primitive constant, or the boxed value is not + * available at this point. + */ + JavaConstant boxPrimitive(JavaConstant source); + + /** + * Converts the given {@link JavaKind#Object object} constant to a + * {@link JavaKind#isPrimitive() primitive} constant, according to the Java unboxing rules. + * Returns {@code null} if the source is is not an object constant that can be unboxed, or the + * unboxed value is not available at this point. + */ + JavaConstant unboxPrimitive(JavaConstant source); + + /** + * Gets a string as a {@link JavaConstant}. + */ + JavaConstant forString(String value); + + /** + * Returns the {@link ResolvedJavaType} for a {@link Class} object (or any other object regarded + * as a class by the VM) encapsulated in the given constant. Returns {@code null} if the + * constant does not encapsulate a class, or if the type is not available at this point. + */ + ResolvedJavaType asJavaType(Constant constant); + + /** + * Check if the constant is embeddable in the code. + */ + boolean isEmbeddable(Constant constant); + + /** + * Gets access to the internals of {@link MethodHandle}. + */ + MethodHandleAccessProvider getMethodHandleAccess(); + + /** + * Gets raw memory access. + */ + MemoryAccessProvider getMemoryAccessProvider(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DefaultProfilingInfo.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DefaultProfilingInfo.java new file mode 100644 index 00000000000..f5a9979a4ba --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DefaultProfilingInfo.java @@ -0,0 +1,110 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * An implementation of {@link ProfilingInfo} that can used in the absence of real profile + * information. + */ +public final class DefaultProfilingInfo implements ProfilingInfo { + + private static final ProfilingInfo[] NO_PROFILING_INFO = new ProfilingInfo[]{new DefaultProfilingInfo(TriState.TRUE), new DefaultProfilingInfo(TriState.FALSE), + new DefaultProfilingInfo(TriState.UNKNOWN)}; + + private final TriState exceptionSeen; + + DefaultProfilingInfo(TriState exceptionSeen) { + this.exceptionSeen = exceptionSeen; + } + + @Override + public int getCodeSize() { + return 0; + } + + @Override + public JavaTypeProfile getTypeProfile(int bci) { + return null; + } + + @Override + public JavaMethodProfile getMethodProfile(int bci) { + return null; + } + + @Override + public double getBranchTakenProbability(int bci) { + return -1; + } + + @Override + public double[] getSwitchProbabilities(int bci) { + return null; + } + + @Override + public TriState getExceptionSeen(int bci) { + return exceptionSeen; + } + + @Override + public TriState getNullSeen(int bci) { + return TriState.UNKNOWN; + } + + @Override + public int getExecutionCount(int bci) { + return -1; + } + + public static ProfilingInfo get(TriState exceptionSeen) { + return NO_PROFILING_INFO[exceptionSeen.ordinal()]; + } + + @Override + public int getDeoptimizationCount(DeoptimizationReason reason) { + return 0; + } + + @Override + public boolean isMature() { + return false; + } + + @Override + public String toString() { + return "BaseProfilingInfo<" + this.toString(null, "; ") + ">"; + } + + public void setMature() { + // Do nothing + } + + public boolean setCompilerIRSize(Class irType, int nodeCount) { + return false; + } + + public int getCompilerIRSize(Class irType) { + return -1; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationAction.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationAction.java new file mode 100644 index 00000000000..70ebd06348a --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationAction.java @@ -0,0 +1,70 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Specifies the action that should be taken by the runtime in case a certain deoptimization is + * triggered. + */ +public enum DeoptimizationAction { + /** + * Do not invalidate the machine code. This is typically used when deoptimizing at a point where + * it's highly likely nothing will change the likelihood of the deoptimization happening again. + * For example, a compiled array allocation where the size is negative. + */ + None(false), + + /** + * Do not invalidate the machine code, but schedule a recompilation if this deoptimization is + * triggered too often. + */ + RecompileIfTooManyDeopts(true), + + /** + * Invalidate the machine code and reset the profiling information. + */ + InvalidateReprofile(true), + + /** + * Invalidate the machine code and immediately schedule a recompilation. This is typically used + * when deoptimizing to resolve an unresolved symbol in which case extra profiling is not + * required to determine that the deoptimization will not re-occur. + */ + InvalidateRecompile(true), + + /** + * Invalidate the machine code and stop compiling the outermost method of this compilation. + */ + InvalidateStopCompiling(true); + + private final boolean invalidatesCompilation; + + private DeoptimizationAction(boolean invalidatesCompilation) { + this.invalidatesCompilation = invalidatesCompilation; + } + + public boolean doesInvalidateCompilation() { + return invalidatesCompilation; + } + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java new file mode 100644 index 00000000000..bcefe66cc79 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Enumeration of reasons for why a deoptimization is happening. + */ +public enum DeoptimizationReason { + None, + NullCheckException, + BoundsCheckException, + ClassCastException, + ArrayStoreException, + UnreachedCode, + TypeCheckedInliningViolated, + OptimizedTypeCheckViolated, + NotCompiledExceptionHandler, + Unresolved, + JavaSubroutineMismatch, + ArithmeticException, + RuntimeConstraint, + LoopLimitCheck, + Aliasing, + TransferToInterpreter, +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ExceptionHandler.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ExceptionHandler.java new file mode 100644 index 00000000000..8b03551ee8b --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ExceptionHandler.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2009, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +/** + * Represents an exception handler within the bytecodes. + */ +public final class ExceptionHandler { + + private final int startBCI; + private final int endBCI; + private final int handlerBCI; + private final int catchTypeCPI; + private final JavaType catchType; + + /** + * Creates a new exception handler with the specified ranges. + * + * @param startBCI the start index of the protected range + * @param endBCI the end index of the protected range + * @param catchBCI the index of the handler + * @param catchTypeCPI the index of the throwable class in the constant pool + * @param catchType the type caught by this exception handler + */ + public ExceptionHandler(int startBCI, int endBCI, int catchBCI, int catchTypeCPI, JavaType catchType) { + this.startBCI = startBCI; + this.endBCI = endBCI; + this.handlerBCI = catchBCI; + this.catchTypeCPI = catchTypeCPI; + this.catchType = catchType; + } + + /** + * Returns the start bytecode index of the protected range of this handler. + */ + public int getStartBCI() { + return startBCI; + } + + /** + * Returns the end bytecode index of the protected range of this handler. + */ + public int getEndBCI() { + return endBCI; + } + + /** + * Returns the bytecode index of the handler block of this handler. + */ + public int getHandlerBCI() { + return handlerBCI; + } + + /** + * Returns the index into the constant pool representing the type of exception caught by this + * handler. + */ + public int catchTypeCPI() { + return catchTypeCPI; + } + + /** + * Checks whether this handler catches all exceptions. + * + * @return {@code true} if this handler catches all exceptions + */ + public boolean isCatchAll() { + return catchTypeCPI == 0; + } + + /** + * Returns the type of exception caught by this exception handler. + */ + public JavaType getCatchType() { + return catchType; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ExceptionHandler)) { + return false; + } + ExceptionHandler that = (ExceptionHandler) obj; + if (this.startBCI != that.startBCI || this.endBCI != that.endBCI || this.handlerBCI != that.handlerBCI || this.catchTypeCPI != that.catchTypeCPI) { + return false; + } + return Objects.equals(this.catchType, that.catchType); + } + + @Override + public String toString() { + return "ExceptionHandler"; + } + + @Override + public int hashCode() { + return catchTypeCPI ^ endBCI ^ handlerBCI; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java new file mode 100644 index 00000000000..afaa0f635c6 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Represents the resolved target of an invocation. + */ +public interface InvokeTarget { +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JVMCIMetaAccessContext.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JVMCIMetaAccessContext.java new file mode 100644 index 00000000000..6af1dac11c5 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JVMCIMetaAccessContext.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * A context in which the results looking up the {@link ResolvedJavaType} for a {@link Class} are + * cached. + */ +public interface JVMCIMetaAccessContext { + + /** + * Gets the JVMCI mirror for a {@link Class} object. + * + * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} + */ + + ResolvedJavaType fromClass(Class clazz); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaConstant.java new file mode 100644 index 00000000000..fee7e3218b3 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaConstant.java @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Represents a constant (boxed) value, such as an integer, floating point number, or object + * reference, within the compiler and across the compiler/runtime interface. Exports a set of + * {@code JavaConstant} instances that represent frequently used constant values, such as + * {@link #NULL_POINTER}. + */ +public interface JavaConstant extends Constant, JavaValue { + /* + * Using a larger cache for integers leads to only a slight increase in cache hit ratio which is + * not enough to justify the impact on startup time. + */ + JavaConstant NULL_POINTER = new NullConstant(); + PrimitiveConstant INT_MINUS_1 = new PrimitiveConstant(JavaKind.Int, -1); + PrimitiveConstant INT_0 = new PrimitiveConstant(JavaKind.Int, 0); + PrimitiveConstant INT_1 = new PrimitiveConstant(JavaKind.Int, 1); + PrimitiveConstant INT_2 = new PrimitiveConstant(JavaKind.Int, 2); + PrimitiveConstant LONG_0 = new PrimitiveConstant(JavaKind.Long, 0L); + PrimitiveConstant LONG_1 = new PrimitiveConstant(JavaKind.Long, 1L); + PrimitiveConstant FLOAT_0 = new PrimitiveConstant(JavaKind.Float, Float.floatToRawIntBits(0.0F)); + PrimitiveConstant FLOAT_1 = new PrimitiveConstant(JavaKind.Float, Float.floatToRawIntBits(1.0F)); + PrimitiveConstant DOUBLE_0 = new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(0.0D)); + PrimitiveConstant DOUBLE_1 = new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(1.0D)); + PrimitiveConstant TRUE = new PrimitiveConstant(JavaKind.Boolean, 1L); + PrimitiveConstant FALSE = new PrimitiveConstant(JavaKind.Boolean, 0L); + + /** + * Returns the Java kind of this constant. + */ + JavaKind getJavaKind(); + + /** + * Checks whether this constant is null. + * + * @return {@code true} if this constant is the null constant + */ + boolean isNull(); + + static boolean isNull(Constant c) { + if (c instanceof JavaConstant) { + return ((JavaConstant) c).isNull(); + } else { + return false; + } + } + + /** + * Checks whether this constant is non-null. + * + * @return {@code true} if this constant is a primitive, or an object constant that is not null + */ + default boolean isNonNull() { + return !isNull(); + } + + /** + * Checks whether this constant is the default value for its kind (null, 0, 0.0, false). + * + * @return {@code true} if this constant is the default value for its kind + */ + boolean isDefaultForKind(); + + /** + * Returns the value of this constant as a boxed Java value. + * + * @return the value of this constant + */ + Object asBoxedPrimitive(); + + /** + * Returns the primitive int value this constant represents. The constant must have a + * {@link JavaKind#getStackKind()} of {@link JavaKind#Int}. + * + * @return the constant value + */ + int asInt(); + + /** + * Returns the primitive boolean value this constant represents. The constant must have kind + * {@link JavaKind#Boolean}. + * + * @return the constant value + */ + boolean asBoolean(); + + /** + * Returns the primitive long value this constant represents. The constant must have kind + * {@link JavaKind#Long}, a {@link JavaKind#getStackKind()} of {@link JavaKind#Int}. + * + * @return the constant value + */ + long asLong(); + + /** + * Returns the primitive float value this constant represents. The constant must have kind + * {@link JavaKind#Float}. + * + * @return the constant value + */ + float asFloat(); + + /** + * Returns the primitive double value this constant represents. The constant must have kind + * {@link JavaKind#Double}. + * + * @return the constant value + */ + double asDouble(); + + default String toValueString() { + if (getJavaKind() == JavaKind.Illegal) { + return "illegal"; + } else { + return getJavaKind().format(asBoxedPrimitive()); + } + } + + static String toString(JavaConstant constant) { + if (constant.getJavaKind() == JavaKind.Illegal) { + return "illegal"; + } else { + return constant.getJavaKind().getJavaName() + "[" + constant.toValueString() + "]"; + } + } + + /** + * Creates a boxed double constant. + * + * @param d the double value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forDouble(double d) { + if (Double.compare(0.0D, d) == 0) { + return DOUBLE_0; + } + if (Double.compare(d, 1.0D) == 0) { + return DOUBLE_1; + } + return new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(d)); + } + + /** + * Creates a boxed float constant. + * + * @param f the float value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forFloat(float f) { + if (Float.compare(f, 0.0F) == 0) { + return FLOAT_0; + } + if (Float.compare(f, 1.0F) == 0) { + return FLOAT_1; + } + return new PrimitiveConstant(JavaKind.Float, Float.floatToRawIntBits(f)); + } + + /** + * Creates a boxed long constant. + * + * @param i the long value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forLong(long i) { + if (i == 0) { + return LONG_0; + } else if (i == 1) { + return LONG_1; + } else { + return new PrimitiveConstant(JavaKind.Long, i); + } + } + + /** + * Creates a boxed integer constant. + * + * @param i the integer value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forInt(int i) { + switch (i) { + case -1: + return INT_MINUS_1; + case 0: + return INT_0; + case 1: + return INT_1; + case 2: + return INT_2; + default: + return new PrimitiveConstant(JavaKind.Int, i); + } + } + + /** + * Creates a boxed byte constant. + * + * @param i the byte value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forByte(byte i) { + return new PrimitiveConstant(JavaKind.Byte, i); + } + + /** + * Creates a boxed boolean constant. + * + * @param i the boolean value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forBoolean(boolean i) { + return i ? TRUE : FALSE; + } + + /** + * Creates a boxed char constant. + * + * @param i the char value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forChar(char i) { + return new PrimitiveConstant(JavaKind.Char, i); + } + + /** + * Creates a boxed short constant. + * + * @param i the short value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forShort(short i) { + return new PrimitiveConstant(JavaKind.Short, i); + } + + /** + * Creates a {@link JavaConstant} from a primitive integer of a certain kind. + */ + static PrimitiveConstant forIntegerKind(JavaKind kind, long i) { + switch (kind) { + case Boolean: + return forBoolean(i != 0); + case Byte: + return forByte((byte) i); + case Short: + return forShort((short) i); + case Char: + return forChar((char) i); + case Int: + return forInt((int) i); + case Long: + return forLong(i); + default: + throw new IllegalArgumentException("not an integer kind: " + kind); + } + } + + /** + * Creates a {@link JavaConstant} from a primitive integer of a certain width. + */ + static PrimitiveConstant forPrimitiveInt(int bits, long i) { + assert bits <= 64; + switch (bits) { + case 1: + return forBoolean(i != 0); + case 8: + return forByte((byte) i); + case 16: + return forShort((short) i); + case 32: + return forInt((int) i); + case 64: + return forLong(i); + default: + throw new IllegalArgumentException("unsupported integer width: " + bits); + } + } + + /** + * Creates a boxed constant for the given boxed primitive value. + * + * @param value the Java boxed value + * @return the primitive constant holding the {@code value} + */ + static PrimitiveConstant forBoxedPrimitive(Object value) { + if (value instanceof Boolean) { + return forBoolean((Boolean) value); + } else if (value instanceof Byte) { + return forByte((Byte) value); + } else if (value instanceof Character) { + return forChar((Character) value); + } else if (value instanceof Short) { + return forShort((Short) value); + } else if (value instanceof Integer) { + return forInt((Integer) value); + } else if (value instanceof Long) { + return forLong((Long) value); + } else if (value instanceof Float) { + return forFloat((Float) value); + } else if (value instanceof Double) { + return forDouble((Double) value); + } else { + return null; + } + } + + static PrimitiveConstant forIllegal() { + return new PrimitiveConstant(JavaKind.Illegal, 0); + } + + /** + * Returns a constant with the default value for the given kind. + */ + static JavaConstant defaultForKind(JavaKind kind) { + switch (kind) { + case Boolean: + return FALSE; + case Byte: + return forByte((byte) 0); + case Char: + return forChar((char) 0); + case Short: + return forShort((short) 0); + case Int: + return INT_0; + case Double: + return DOUBLE_0; + case Float: + return FLOAT_0; + case Long: + return LONG_0; + case Object: + return NULL_POINTER; + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Returns the zero value for a given numeric kind. + */ + static JavaConstant zero(JavaKind kind) { + switch (kind) { + case Boolean: + return FALSE; + case Byte: + return forByte((byte) 0); + case Char: + return forChar((char) 0); + case Double: + return DOUBLE_0; + case Float: + return FLOAT_0; + case Int: + return INT_0; + case Long: + return LONG_0; + case Short: + return forShort((short) 0); + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Returns the one value for a given numeric kind. + */ + static JavaConstant one(JavaKind kind) { + switch (kind) { + case Boolean: + return TRUE; + case Byte: + return forByte((byte) 1); + case Char: + return forChar((char) 1); + case Double: + return DOUBLE_1; + case Float: + return FLOAT_1; + case Int: + return INT_1; + case Long: + return LONG_1; + case Short: + return forShort((short) 1); + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Adds two numeric constants. + */ + static JavaConstant add(JavaConstant x, JavaConstant y) { + assert x.getJavaKind() == y.getJavaKind(); + switch (x.getJavaKind()) { + case Byte: + return forByte((byte) (x.asInt() + y.asInt())); + case Char: + return forChar((char) (x.asInt() + y.asInt())); + case Double: + return forDouble(x.asDouble() + y.asDouble()); + case Float: + return forFloat(x.asFloat() + y.asFloat()); + case Int: + return forInt(x.asInt() + y.asInt()); + case Long: + return forLong(x.asLong() + y.asLong()); + case Short: + return forShort((short) (x.asInt() + y.asInt())); + default: + throw new IllegalArgumentException(x.getJavaKind().toString()); + } + } + + /** + * Multiplies two numeric constants. + */ + static PrimitiveConstant mul(JavaConstant x, JavaConstant y) { + assert x.getJavaKind() == y.getJavaKind(); + switch (x.getJavaKind()) { + case Byte: + return forByte((byte) (x.asInt() * y.asInt())); + case Char: + return forChar((char) (x.asInt() * y.asInt())); + case Double: + return forDouble(x.asDouble() * y.asDouble()); + case Float: + return forFloat(x.asFloat() * y.asFloat()); + case Int: + return forInt(x.asInt() * y.asInt()); + case Long: + return forLong(x.asLong() * y.asLong()); + case Short: + return forShort((short) (x.asInt() * y.asInt())); + default: + throw new IllegalArgumentException(x.getJavaKind().toString()); + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaField.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaField.java new file mode 100644 index 00000000000..dcf965c03a0 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaField.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +/** + * Represents a reference to a Java field, either resolved or unresolved fields. Fields, like + * methods and types, are resolved through {@link ConstantPool constant pools}. + */ +public interface JavaField extends TrustedInterface { + + /** + * Returns the name of this field. + */ + String getName(); + + /** + * Returns a {@link JavaType} object that identifies the declared type for this field. + */ + JavaType getType(); + + /** + * Returns the kind of this field. This is the same as calling {@link #getType}. + * {@link JavaType#getJavaKind getJavaKind}. + */ + default JavaKind getJavaKind() { + return getType().getJavaKind(); + } + + /** + * Returns the {@link JavaType} object representing the class or interface that declares this + * field. + */ + JavaType getDeclaringClass(); + + /** + * Gets a string for this field formatted according to a given format specification. A format + * specification is composed of characters that are to be copied verbatim to the result and + * specifiers that denote an attribute of this field that is to be copied to the result. A + * specifier is a single character preceded by a '%' character. The accepted specifiers and the + * field attributes they denote are described below: + * + *
+     *     Specifier | Description                                          | Example(s)
+     *     ----------+------------------------------------------------------------------------------------------
+     *     'T'       | Qualified type                                       | "int" "java.lang.String"
+     *     't'       | Unqualified type                                     | "int" "String"
+     *     'H'       | Qualified holder                                     | "java.util.Map.Entry"
+     *     'h'       | Unqualified holder                                   | "Entry"
+     *     'n'       | Field name                                           | "age"
+     *     'f'       | Indicator if field is unresolved, static or instance | "unresolved" "static" "instance"
+     *     '%'       | A '%' character                                      | "%"
+     * 
+ * + * @param format a format specification + * @return the result of formatting this field according to {@code format} + * @throws IllegalFormatException if an illegal specifier is encountered in {@code format} + */ + @SuppressWarnings("fallthrough") + default String format(String format) throws IllegalFormatException { + StringBuilder sb = new StringBuilder(); + int index = 0; + JavaType type = getType(); + while (index < format.length()) { + char ch = format.charAt(index++); + if (ch == '%') { + if (index >= format.length()) { + throw new UnknownFormatConversionException("An unquoted '%' character cannot terminate a field format specification"); + } + char specifier = format.charAt(index++); + switch (specifier) { + case 'T': + case 't': { + sb.append(type.toJavaName(specifier == 'T')); + break; + } + case 'H': + case 'h': { + sb.append(getDeclaringClass().toJavaName(specifier == 'H')); + break; + } + case 'n': { + sb.append(getName()); + break; + } + case 'f': { + sb.append(!(this instanceof ResolvedJavaField) ? "unresolved" : ((ResolvedJavaField) this).isStatic() ? "static" : "instance"); + break; + } + case '%': { + sb.append('%'); + break; + } + default: { + throw new UnknownFormatConversionException(String.valueOf(specifier)); + } + } + } else { + sb.append(ch); + } + } + return sb.toString(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java new file mode 100644 index 00000000000..2b2139097a4 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.lang.reflect.*; + +//JaCoCo Exclude + +/** + * Denotes the basic kinds of types in CRI, including the all the Java primitive types, for example, + * {@link JavaKind#Int} for {@code int} and {@link JavaKind#Object} for all object types. A kind has + * a single character short name, a Java name, and a set of flags further describing its behavior. + */ +public enum JavaKind implements PlatformKind { + /** The primitive boolean kind, represented as an int on the stack. */ + Boolean('z', "boolean", 1, true, java.lang.Boolean.TYPE, java.lang.Boolean.class), + + /** The primitive byte kind, represented as an int on the stack. */ + Byte('b', "byte", 1, true, java.lang.Byte.TYPE, java.lang.Byte.class), + + /** The primitive short kind, represented as an int on the stack. */ + Short('s', "short", 1, true, java.lang.Short.TYPE, java.lang.Short.class), + + /** The primitive char kind, represented as an int on the stack. */ + Char('c', "char", 1, true, java.lang.Character.TYPE, java.lang.Character.class), + + /** The primitive int kind, represented as an int on the stack. */ + Int('i', "int", 1, true, java.lang.Integer.TYPE, java.lang.Integer.class), + + /** The primitive float kind. */ + Float('f', "float", 1, false, java.lang.Float.TYPE, java.lang.Float.class), + + /** The primitive long kind. */ + Long('j', "long", 2, false, java.lang.Long.TYPE, java.lang.Long.class), + + /** The primitive double kind. */ + Double('d', "double", 2, false, java.lang.Double.TYPE, java.lang.Double.class), + + /** The Object kind, also used for arrays. */ + Object('a', "Object", 1, false, null, null), + + /** The void float kind. */ + Void('v', "void", 0, false, java.lang.Void.TYPE, java.lang.Void.class), + + /** The non-type. */ + Illegal('-', "illegal", 0, false, null, null); + + private final char typeChar; + private final String javaName; + private final boolean isStackInt; + private final Class primitiveJavaClass; + private final Class boxedJavaClass; + private final EnumKey key = new EnumKey<>(this); + private final int slotCount; + + private JavaKind(char typeChar, String javaName, int slotCount, boolean isStackInt, Class primitiveJavaClass, Class boxedJavaClass) { + this.typeChar = typeChar; + this.javaName = javaName; + this.slotCount = slotCount; + this.isStackInt = isStackInt; + this.primitiveJavaClass = primitiveJavaClass; + this.boxedJavaClass = boxedJavaClass; + assert primitiveJavaClass == null || javaName.equals(primitiveJavaClass.getName()); + } + + /** + * Returns the number of stack slots occupied by this kind according to the Java bytecodes + * specification. + */ + public int getSlotCount() { + return this.slotCount; + } + + /** + * Returns whether this kind occupied two stack slots. + */ + public boolean needsTwoSlots() { + return this.slotCount == 2; + } + + /** + * Returns the name of the kind as a single character. + */ + public char getTypeChar() { + return typeChar; + } + + /** + * Returns the name of this kind which will also be it Java programming language name if it is + * {@linkplain #isPrimitive() primitive} or {@code void}. + */ + public String getJavaName() { + return javaName; + } + + public Key getKey() { + return key; + } + + /** + * Checks whether this type is a Java primitive type. + * + * @return {@code true} if this is {@link #Boolean}, {@link #Byte}, {@link #Char}, + * {@link #Short}, {@link #Int}, {@link #Long}, {@link #Float}, {@link #Double}, or + * {@link #Void}. + */ + public boolean isPrimitive() { + return primitiveJavaClass != null; + } + + /** + * Returns the kind that represents this kind when on the Java operand stack. + * + * @return the kind used on the operand stack + */ + public JavaKind getStackKind() { + if (isStackInt) { + return Int; + } + return this; + } + + /** + * Checks whether this type is a Java primitive type representing an integer number. + * + * @return {@code true} if the stack kind is {@link #Int} or {@link #Long}. + */ + public boolean isNumericInteger() { + return isStackInt || this == JavaKind.Long; + } + + /** + * Checks whether this type is a Java primitive type representing an unsigned number. + * + * @return {@code true} if the kind is {@link #Boolean} or {@link #Char}. + */ + public boolean isUnsigned() { + return this == JavaKind.Boolean || this == JavaKind.Char; + } + + /** + * Checks whether this type is a Java primitive type representing a floating point number. + * + * @return {@code true} if this is {@link #Float} or {@link #Double}. + */ + public boolean isNumericFloat() { + return this == JavaKind.Float || this == JavaKind.Double; + } + + /** + * Checks whether this represent an Object of some sort. + * + * @return {@code true} if this is {@link #Object}. + */ + public boolean isObject() { + return this == JavaKind.Object; + } + + /** + * Returns the kind corresponding to the Java type string. + * + * @param typeString the Java type string + * @return the kind + */ + public static JavaKind fromTypeString(String typeString) { + assert typeString.length() > 0; + final char first = typeString.charAt(0); + if (first == '[' || first == 'L') { + return JavaKind.Object; + } + return JavaKind.fromPrimitiveOrVoidTypeChar(first); + } + + /** + * Returns the kind of a word given the size of a word in bytes. + * + * @param wordSizeInBytes the size of a word in bytes + * @return the kind representing a word value + */ + public static JavaKind fromWordSize(int wordSizeInBytes) { + if (wordSizeInBytes == 8) { + return JavaKind.Long; + } else { + assert wordSizeInBytes == 4 : "Unsupported word size!"; + return JavaKind.Int; + } + } + + /** + * Returns the kind from the character describing a primitive or void. + * + * @param ch the character + * @return the kind + */ + public static JavaKind fromPrimitiveOrVoidTypeChar(char ch) { + switch (ch) { + case 'Z': + return Boolean; + case 'C': + return Char; + case 'F': + return Float; + case 'D': + return Double; + case 'B': + return Byte; + case 'S': + return Short; + case 'I': + return Int; + case 'J': + return Long; + case 'V': + return Void; + } + throw new IllegalArgumentException("unknown primitive or void type character: " + ch); + } + + /** + * Returns the Kind representing the given Java class. + * + * @param klass the class + * @return the kind + */ + public static JavaKind fromJavaClass(Class klass) { + if (klass == Boolean.primitiveJavaClass) { + return Boolean; + } else if (klass == Byte.primitiveJavaClass) { + return Byte; + } else if (klass == Short.primitiveJavaClass) { + return Short; + } else if (klass == Char.primitiveJavaClass) { + return Char; + } else if (klass == Int.primitiveJavaClass) { + return Int; + } else if (klass == Long.primitiveJavaClass) { + return Long; + } else if (klass == Float.primitiveJavaClass) { + return Float; + } else if (klass == Double.primitiveJavaClass) { + return Double; + } else if (klass == Void.primitiveJavaClass) { + return Void; + } else { + return Object; + } + } + + /** + * Returns the Java class representing this kind. + * + * @return the Java class + */ + public Class toJavaClass() { + return primitiveJavaClass; + } + + /** + * Returns the Java class for instances of boxed values of this kind. + * + * @return the Java class + */ + public Class toBoxedJavaClass() { + return boxedJavaClass; + } + + /** + * Converts this value type to a string. + */ + @Override + public String toString() { + return javaName; + } + + /** + * Marker interface for types that should be {@linkplain JavaKind#format(Object) formatted} with + * their {@link Object#toString()} value. Calling {@link Object#toString()} on other objects + * poses a security risk because it can potentially call user code. + */ + public interface FormatWithToString { + } + + /** + * Classes for which invoking {@link Object#toString()} does not run user code. + */ + private static boolean isToStringSafe(Class c) { + return c == Boolean.class || c == Byte.class || c == Character.class || c == Short.class || c == Integer.class || c == Float.class || c == Long.class || c == Double.class; + } + + /** + * Gets a formatted string for a given value of this kind. + * + * @param value a value of this kind + * @return a formatted string for {@code value} based on this kind + */ + public String format(Object value) { + if (isPrimitive()) { + assert isToStringSafe(value.getClass()); + return value.toString(); + } else { + if (value == null) { + return "null"; + } else { + if (value instanceof String) { + String s = (String) value; + if (s.length() > 50) { + return "String:\"" + s.substring(0, 30) + "...\""; + } else { + return "String:\"" + s + '"'; + } + } else if (value instanceof JavaType) { + return "JavaType:" + ((JavaType) value).toJavaName(); + } else if (value instanceof Enum) { + return MetaUtil.getSimpleName(value.getClass(), true) + ":" + ((Enum) value).name(); + } else if (value instanceof FormatWithToString) { + return MetaUtil.getSimpleName(value.getClass(), true) + ":" + String.valueOf(value); + } else if (value instanceof Class) { + return "Class:" + ((Class) value).getName(); + } else if (isToStringSafe(value.getClass())) { + return value.toString(); + } else if (value.getClass().isArray()) { + return formatArray(value); + } else { + return MetaUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value); + } + } + } + } + + private static final int MAX_FORMAT_ARRAY_LENGTH = 5; + + private static String formatArray(Object array) { + Class componentType = array.getClass().getComponentType(); + assert componentType != null; + int arrayLength = Array.getLength(array); + StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{"); + int length = Math.min(MAX_FORMAT_ARRAY_LENGTH, arrayLength); + boolean primitive = componentType.isPrimitive(); + for (int i = 0; i < length; i++) { + if (primitive) { + buf.append(Array.get(array, i)); + } else { + Object o = ((Object[]) array)[i]; + buf.append(JavaKind.Object.format(o)); + } + if (i != length - 1) { + buf.append(", "); + } + } + if (arrayLength != length) { + buf.append(", ..."); + } + return buf.append('}').toString(); + } + + /** + * The minimum value that can be represented as a value of this kind. + * + * @return the minimum value + */ + public long getMinValue() { + switch (this) { + case Boolean: + return 0; + case Byte: + return java.lang.Byte.MIN_VALUE; + case Char: + return java.lang.Character.MIN_VALUE; + case Short: + return java.lang.Short.MIN_VALUE; + case Int: + return java.lang.Integer.MIN_VALUE; + case Long: + return java.lang.Long.MIN_VALUE; + default: + throw new IllegalArgumentException("illegal call to minValue on " + this); + } + } + + /** + * The maximum value that can be represented as a value of this kind. + * + * @return the maximum value + */ + public long getMaxValue() { + switch (this) { + case Boolean: + return 1; + case Byte: + return java.lang.Byte.MAX_VALUE; + case Char: + return java.lang.Character.MAX_VALUE; + case Short: + return java.lang.Short.MAX_VALUE; + case Int: + return java.lang.Integer.MAX_VALUE; + case Long: + return java.lang.Long.MAX_VALUE; + default: + throw new IllegalArgumentException("illegal call to maxValue on " + this); + } + } + + /** + * Number of bytes that are necessary to represent a value of this kind. + * + * @return the number of bytes + */ + public int getByteCount() { + if (this == Boolean) { + return 1; + } else { + return getBitCount() >> 3; + } + } + + /** + * Number of bits that are necessary to represent a value of this kind. + * + * @return the number of bits + */ + public int getBitCount() { + switch (this) { + case Boolean: + return 1; + case Byte: + return 8; + case Char: + case Short: + return 16; + case Float: + return 32; + case Int: + return 32; + case Double: + return 64; + case Long: + return 64; + default: + throw new IllegalArgumentException("illegal call to bits on " + this); + } + } + + public JavaConstant getDefaultValue() { + switch (this) { + case Boolean: + return JavaConstant.FALSE; + case Int: + return JavaConstant.INT_0; + case Long: + return JavaConstant.LONG_0; + case Float: + return JavaConstant.FLOAT_0; + case Double: + return JavaConstant.DOUBLE_0; + case Object: + return JavaConstant.NULL_POINTER; + case Byte: + case Char: + case Short: + return new PrimitiveConstant(this, 0); + default: + throw new IllegalArgumentException("illegal call to getDefaultValue on " + this); + } + } + + @Override + public int getSizeInBytes() { + return getByteCount(); + } + + @Override + public int getVectorLength() { + return 1; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethod.java new file mode 100644 index 00000000000..8244a1701d0 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethod.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2009, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +/** + * Represents a reference to a Java method, either resolved or unresolved. Methods, like fields and + * types, are resolved through {@link ConstantPool constant pools}. + */ +public interface JavaMethod extends TrustedInterface { + + /** + * Returns the name of this method. + */ + String getName(); + + /** + * Returns the {@link JavaType} object representing the class or interface that declares this + * method. + */ + JavaType getDeclaringClass(); + + /** + * Returns the signature of this method. + */ + Signature getSignature(); + + /** + * Gets a string for this method formatted according to a given format specification. A format + * specification is composed of characters that are to be copied verbatim to the result and + * specifiers that denote an attribute of this method that is to be copied to the result. A + * specifier is a single character preceded by a '%' character. The accepted specifiers and the + * method attributes they denote are described below: + * + *
+     *     Specifier | Description                                          | Example(s)
+     *     ----------+------------------------------------------------------------------------------------------
+     *     'R'       | Qualified return type                                | "int" "java.lang.String"
+     *     'r'       | Unqualified return type                              | "int" "String"
+     *     'H'       | Qualified holder                                     | "java.util.Map.Entry"
+     *     'h'       | Unqualified holder                                   | "Entry"
+     *     'n'       | Method name                                          | "add"
+     *     'P'       | Qualified parameter types, separated by ', '         | "int, java.lang.String"
+     *     'p'       | Unqualified parameter types, separated by ', '       | "int, String"
+     *     'f'       | Indicator if method is unresolved, static or virtual | "unresolved" "static" "virtual"
+     *     '%'       | A '%' character                                      | "%"
+     * 
+ * + * @param format a format specification + * @return the result of formatting this method according to {@code format} + * @throws IllegalFormatException if an illegal specifier is encountered in {@code format} + */ + @SuppressWarnings("fallthrough") + default String format(String format) throws IllegalFormatException { + StringBuilder sb = new StringBuilder(); + int index = 0; + Signature sig = null; + while (index < format.length()) { + char ch = format.charAt(index++); + if (ch == '%') { + if (index >= format.length()) { + throw new UnknownFormatConversionException("An unquoted '%' character cannot terminate a method format specification"); + } + char specifier = format.charAt(index++); + switch (specifier) { + case 'R': + case 'r': { + if (sig == null) { + sig = getSignature(); + } + sb.append(sig.getReturnType(null).toJavaName(specifier == 'R')); + break; + } + case 'H': + case 'h': { + sb.append(getDeclaringClass().toJavaName(specifier == 'H')); + break; + } + case 'n': { + sb.append(getName()); + break; + } + case 'P': + case 'p': { + if (sig == null) { + sig = getSignature(); + } + for (int i = 0; i < sig.getParameterCount(false); i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(sig.getParameterType(i, null).toJavaName(specifier == 'P')); + } + break; + } + case 'f': { + sb.append(!(this instanceof ResolvedJavaMethod) ? "unresolved" : ((ResolvedJavaMethod) this).isStatic() ? "static" : "virtual"); + break; + } + case '%': { + sb.append('%'); + break; + } + default: { + throw new UnknownFormatConversionException(String.valueOf(specifier)); + } + } + } else { + sb.append(ch); + } + } + return sb.toString(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethodProfile.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethodProfile.java new file mode 100644 index 00000000000..afa6ee3c7d2 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethodProfile.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import jdk.vm.ci.meta.JavaMethodProfile.*; + +/** + * This profile object represents the method profile at a specific BCI. The precision of the + * supplied values may vary, but a runtime that provides this information should be aware that it + * will be used to guide performance-critical decisions like speculative inlining, etc. + */ +public final class JavaMethodProfile extends AbstractJavaProfile { + + public JavaMethodProfile(double notRecordedProbability, ProfiledMethod[] pitems) { + super(notRecordedProbability, pitems); + } + + public ProfiledMethod[] getMethods() { + return super.getItems(); + } + + public static class ProfiledMethod extends AbstractProfiledItem { + + public ProfiledMethod(ResolvedJavaMethod method, double probability) { + super(method, probability); + } + + /** + * Returns the type for this profile entry. + */ + public ResolvedJavaMethod getMethod() { + return getItem(); + } + + @Override + public String toString() { + return "{" + item.getName() + ", " + probability + "}"; + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaType.java new file mode 100644 index 00000000000..4e3b20f69b0 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaType.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import static jdk.vm.ci.meta.MetaUtil.*; + +/** + * Represents a resolved or unresolved type. Types include primitives, objects, {@code void}, and + * arrays thereof. + */ +public interface JavaType extends TrustedInterface { + + /** + * Returns the name of this type in internal form. The following are examples of strings + * returned by this method: + * + *
+     *     "Ljava/lang/Object;"
+     *     "I"
+     *     "[[B"
+     * 
+ */ + String getName(); + + /** + * Returns an unqualified name of this type. + * + *
+     *     "Object"
+     *     "Integer"
+     * 
+ */ + default String getUnqualifiedName() { + String name = getName(); + if (name.indexOf('/') != -1) { + name = name.substring(name.lastIndexOf('/') + 1); + } + if (name.endsWith(";")) { + name = name.substring(0, name.length() - 1); + } + return name; + } + + /** + * For array types, gets the type of the components, or {@code null} if this is not an array + * type. This method is analogous to {@link Class#getComponentType()}. + */ + JavaType getComponentType(); + + /** + * Gets the elemental type for this given type. The elemental type is the corresponding zero + * dimensional type of an array type. For example, the elemental type of {@code int[][][]} is + * {@code int}. A non-array type is its own elemental type. + */ + default JavaType getElementalType() { + JavaType t = this; + while (t.getComponentType() != null) { + t = t.getComponentType(); + } + return t; + } + + /** + * Gets the array class type representing an array with elements of this type. + */ + JavaType getArrayClass(); + + /** + * Gets the {@link JavaKind} of this type. + */ + JavaKind getJavaKind(); + + /** + * Resolves this type to a {@link ResolvedJavaType}. + * + * @param accessingClass the context of resolution (must not be null) + * @return the resolved Java type + * @throws LinkageError if the resolution failed + * @throws NullPointerException if {@code accessingClass} is {@code null} + */ + ResolvedJavaType resolve(ResolvedJavaType accessingClass); + + /** + * Gets the Java programming language name for this type. The following are examples of strings + * returned by this method: + * + *
+     *      java.lang.Object
+     *      int
+     *      boolean[][]
+     * 
+ * + * @return the Java name corresponding to this type + */ + default String toJavaName() { + return internalNameToJava(getName(), true, false); + } + + /** + * Gets the Java programming language name for this type. The following are examples of strings + * returned by this method: + * + *
+     *     qualified == true:
+     *         java.lang.Object
+     *         int
+     *         boolean[][]
+     *     qualified == false:
+     *         Object
+     *         int
+     *         boolean[][]
+     * 
+ * + * @param qualified specifies if the package prefix of this type should be included in the + * returned name + * @return the Java name corresponding to this type + */ + default String toJavaName(boolean qualified) { + JavaKind kind = getJavaKind(); + if (kind == JavaKind.Object) { + return internalNameToJava(getName(), qualified, false); + } + return getJavaKind().getJavaName(); + } + + /** + * Returns this type's name in the same format as {@link Class#getName()}. + */ + default String toClassName() { + return internalNameToJava(getName(), true, true); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaTypeProfile.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaTypeProfile.java new file mode 100644 index 00000000000..e76f70935d6 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaTypeProfile.java @@ -0,0 +1,195 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +import jdk.vm.ci.meta.JavaTypeProfile.*; + +/** + * This profile object represents the type profile at a specific BCI. The precision of the supplied + * values may vary, but a runtime that provides this information should be aware that it will be + * used to guide performance-critical decisions like speculative inlining, etc. + */ +public final class JavaTypeProfile extends AbstractJavaProfile { + + private static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0]; + + private final TriState nullSeen; + + public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType[] pitems) { + super(notRecordedProbability, pitems); + this.nullSeen = nullSeen; + } + + /** + * Returns whether a null value was at the type check. + */ + public TriState getNullSeen() { + return nullSeen; + } + + /** + * A list of types for which the runtime has recorded probability information. Note that this + * includes both positive and negative types where a positive type is a subtype of the checked + * type and a negative type is not. + */ + public ProfiledType[] getTypes() { + return getItems(); + } + + public JavaTypeProfile restrict(JavaTypeProfile otherProfile) { + if (otherProfile.getNotRecordedProbability() > 0.0) { + // Not useful for restricting since there is an unknown set of types occurring. + return this; + } + + if (this.getNotRecordedProbability() > 0.0) { + // We are unrestricted, so the other profile is always a better estimate. + return otherProfile; + } + + ArrayList result = new ArrayList<>(); + for (int i = 0; i < getItems().length; i++) { + ProfiledType ptype = getItems()[i]; + ResolvedJavaType type = ptype.getItem(); + if (otherProfile.isIncluded(type)) { + result.add(ptype); + } + } + + TriState newNullSeen = (otherProfile.getNullSeen() == TriState.FALSE) ? TriState.FALSE : getNullSeen(); + double newNotRecorded = getNotRecordedProbability(); + return createAdjustedProfile(result, newNullSeen, newNotRecorded); + } + + public JavaTypeProfile restrict(ResolvedJavaType declaredType, boolean nonNull) { + ArrayList result = new ArrayList<>(); + for (int i = 0; i < getItems().length; i++) { + ProfiledType ptype = getItems()[i]; + ResolvedJavaType type = ptype.getItem(); + if (declaredType.isAssignableFrom(type)) { + result.add(ptype); + } + } + + TriState newNullSeen = (nonNull) ? TriState.FALSE : getNullSeen(); + double newNotRecorded = this.getNotRecordedProbability(); + // Assume for the types not recorded, the incompatibility rate is the same. + if (getItems().length != 0) { + newNotRecorded *= ((double) result.size() / (double) getItems().length); + } + return createAdjustedProfile(result, newNullSeen, newNotRecorded); + } + + private JavaTypeProfile createAdjustedProfile(ArrayList result, TriState newNullSeen, double newNotRecorded) { + if (result.size() != this.getItems().length || newNotRecorded != getNotRecordedProbability() || newNullSeen != getNullSeen()) { + if (result.size() == 0) { + return new JavaTypeProfile(newNullSeen, 1.0, EMPTY_ARRAY); + } + double factor; + if (result.size() == this.getItems().length) { + /* List of types did not change, no need to recompute probabilities. */ + factor = 1.0; + } else { + double probabilitySum = 0.0; + for (int i = 0; i < result.size(); i++) { + probabilitySum += result.get(i).getProbability(); + } + probabilitySum += newNotRecorded; + + factor = 1.0 / probabilitySum; // Normalize to 1.0 + assert factor >= 1.0; + } + ProfiledType[] newResult = new ProfiledType[result.size()]; + for (int i = 0; i < newResult.length; ++i) { + ProfiledType curType = result.get(i); + newResult[i] = new ProfiledType(curType.getItem(), Math.min(1.0, curType.getProbability() * factor)); + } + double newNotRecordedTypeProbability = Math.min(1.0, newNotRecorded * factor); + return new JavaTypeProfile(newNullSeen, newNotRecordedTypeProbability, newResult); + } + return this; + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && nullSeen.equals(((JavaTypeProfile) other).nullSeen); + } + + @Override + public int hashCode() { + return nullSeen.hashCode() + super.hashCode(); + } + + public static class ProfiledType extends AbstractProfiledItem { + + public ProfiledType(ResolvedJavaType type, double probability) { + super(type, probability); + assert type.isArray() || type.isConcrete() : type; + } + + /** + * Returns the type for this profile entry. + */ + public ResolvedJavaType getType() { + return getItem(); + } + + @Override + public String toString() { + return String.format("%.6f#%s", probability, item); + } + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder("JavaTypeProfile", getNotRecordedProbability())).toString(); + } + + /** + * Returns {@code true} if all types seen at this location have been recorded in the profile. + */ + public boolean allTypesRecorded() { + return this.getNotRecordedProbability() == 0.0; + } + + /** + * Returns the single monormorphic type representing this profile or {@code null} if no such + * type exists. + */ + public ResolvedJavaType asSingleType() { + if (allTypesRecorded() && this.getTypes().length == 1) { + return getTypes()[0].getType(); + } + return null; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaValue.java new file mode 100644 index 00000000000..95864edb136 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaValue.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Marker interface for things that represent a Java value. + */ +public interface JavaValue { +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LIRKind.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LIRKind.java new file mode 100644 index 00000000000..9840aaa5367 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LIRKind.java @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +/** + * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the + * low level representation of the value, and a {@link #referenceMask} that describes the location + * of object references in the value, and optionally a {@link #derivedReferenceBase}. + * + *

Constructing {@link LIRKind} instances

+ * + * During LIR generation, every new {@link Value} should get a {@link LIRKind} of the correct + * {@link PlatformKind} that also contains the correct reference information. {@linkplain LIRKind + * LIRKinds} should be created as follows: + * + *

+ * If the result value is created from one or more input values, the {@link LIRKind} should be + * created with {@link LIRKind#combine}(inputs). If the result has a different {@link PlatformKind} + * than the inputs, {@link LIRKind#combine}(inputs).{@link #changeType}(resultKind) should be used. + *

+ * If the result is an exact copy of one of the inputs, {@link Value#getLIRKind()} can be used. Note + * that this is only correct for move-like operations, like conditional move or compare-and-swap. + * For convert operations, {@link LIRKind#combine} should be used. + *

+ * If it is known that the result will be a reference (e.g. pointer arithmetic where the end result + * is a valid oop), {@link LIRKind#reference} should be used. + *

+ * If it is known that the result will neither be a reference nor be derived from a reference, + * {@link LIRKind#value} can be used. If the operation producing this value has inputs, this is very + * likely wrong, and {@link LIRKind#combine} should be used instead. + *

+ * If it is known that the result is derived from a reference in a way that the garbage collector + * can not track, {@link LIRKind#unknownReference} can be used. In most cases, + * {@link LIRKind#combine} should be used instead, since it is able to detect this automatically. + */ +public final class LIRKind { + + /** + * The non-type. This uses {@link #unknownReference}, so it can never be part of an oop map. + */ + public static final LIRKind Illegal = unknownReference(JavaKind.Illegal); + + private final PlatformKind platformKind; + private final int referenceMask; + + private AllocatableValue derivedReferenceBase; + + private static final int UNKNOWN_REFERENCE = -1; + + private LIRKind(PlatformKind platformKind, int referenceMask, AllocatableValue derivedReferenceBase) { + assert platformKind != JavaKind.Object : "Kind.Object shouldn't be used in the backend"; + this.platformKind = platformKind; + this.referenceMask = referenceMask; + this.derivedReferenceBase = derivedReferenceBase; + + assert derivedReferenceBase == null || !derivedReferenceBase.getLIRKind().isDerivedReference() : "derived reference can't have another derived reference as base"; + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a primitive value. Should + * be only used when it's guaranteed that the value is not even indirectly derived from a + * reference. Otherwise, {@link #combine(Value...)} should be used instead. + */ + public static LIRKind value(PlatformKind platformKind) { + return new LIRKind(platformKind, 0, null); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a single tracked oop + * reference. + */ + public static LIRKind reference(PlatformKind platformKind) { + return derivedReference(platformKind, null); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a derived reference. + */ + public static LIRKind derivedReference(PlatformKind platformKind, AllocatableValue base) { + int length = platformKind.getVectorLength(); + assert 0 < length && length < 32 : "vector of " + length + " references not supported"; + return new LIRKind(platformKind, (1 << length) - 1, base); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a value that is derived + * from a reference in a non-linear way. Values of this {@link LIRKind} can not be live at + * safepoints. In most cases, this should not be called directly. {@link #combine} should be + * used instead to automatically propagate this information. + */ + public static LIRKind unknownReference(PlatformKind platformKind) { + return new LIRKind(platformKind, UNKNOWN_REFERENCE, null); + } + + /** + * Create a derived reference. + * + * @param base An {@link AllocatableValue} containing the base pointer of the derived reference. + */ + public LIRKind makeDerivedReference(AllocatableValue base) { + assert !isUnknownReference() && derivedReferenceBase == null; + if (Value.ILLEGAL.equals(base)) { + return makeUnknownReference(); + } else { + if (isValue()) { + return derivedReference(platformKind, base); + } else { + return new LIRKind(platformKind, referenceMask, base); + } + } + } + + /** + * Derive a new type from inputs. The result will have the {@link PlatformKind} of one of the + * inputs. If all inputs are values, the result is a value. Otherwise, the result is an unknown + * reference. + * + * This method should be used to construct the result {@link LIRKind} of any operation that + * modifies values (e.g. arithmetics). + */ + public static LIRKind combine(Value... inputs) { + assert inputs.length > 0; + for (Value input : inputs) { + LIRKind kind = input.getLIRKind(); + if (kind.isUnknownReference()) { + return kind; + } else if (!kind.isValue()) { + return kind.makeUnknownReference(); + } + } + + // all inputs are values, just return one of them + return inputs[0].getLIRKind(); + } + + /** + * Merge the types of the inputs. The result will have the {@link PlatformKind} of one of the + * inputs. If all inputs are values (references), the result is a value (reference). Otherwise, + * the result is an unknown reference. + * + * This method should be used to construct the result {@link LIRKind} of merge operation that + * does not modify values (e.g. phis). + */ + public static LIRKind merge(Value... inputs) { + assert inputs.length > 0; + ArrayList kinds = new ArrayList<>(inputs.length); + for (int i = 0; i < inputs.length; i++) { + kinds.add(inputs[i].getLIRKind()); + } + return merge(kinds); + } + + /** + * Helper method to construct derived reference kinds. Returns the base value of a reference or + * derived reference. For values it returns {@code null}, and for unknown references it returns + * {@link Value#ILLEGAL}. + */ + public static AllocatableValue derivedBaseFromValue(AllocatableValue value) { + LIRKind kind = value.getLIRKind(); + if (kind.isValue()) { + return null; + } else if (kind.isDerivedReference()) { + return kind.getDerivedReferenceBase(); + } else if (kind.isUnknownReference()) { + return Value.ILLEGAL; + } else { + // kind is a reference + return value; + } + } + + /** + * Helper method to construct derived reference kinds. If one of {@code base1} or {@code base2} + * are set, it creates a derived reference using it as the base. If both are set, the result is + * an unknown reference. + */ + public static LIRKind combineDerived(LIRKind kind, AllocatableValue base1, AllocatableValue base2) { + if (base1 == null && base2 == null) { + return kind; + } else if (base1 == null) { + return kind.makeDerivedReference(base2); + } else if (base2 == null) { + return kind.makeDerivedReference(base1); + } else { + return kind.makeUnknownReference(); + } + } + + /** + * @see #merge(Value...) + */ + public static LIRKind merge(Iterable kinds) { + LIRKind mergeKind = null; + + for (LIRKind kind : kinds) { + + if (kind.isUnknownReference()) { + /** + * Kind is an unknown reference, therefore the result can only be also an unknown + * reference. + */ + mergeKind = kind; + break; + } + if (mergeKind == null) { + mergeKind = kind; + continue; + } + + if (kind.isValue()) { + /* Kind is a value. */ + if (mergeKind.referenceMask != 0) { + /* + * Inputs consists of values and references. Make the result an unknown + * reference. + */ + mergeKind = mergeKind.makeUnknownReference(); + break; + } + /* Check that other inputs are also values. */ + } else { + /* Kind is a reference. */ + if (mergeKind.referenceMask != kind.referenceMask) { + /* + * Reference maps do not match so the result can only be an unknown reference. + */ + mergeKind = mergeKind.makeUnknownReference(); + break; + } + } + + } + assert mergeKind != null && verifyMerge(mergeKind, kinds); + + // all inputs are values or references, just return one of them + return mergeKind; + } + + private static boolean verifyMerge(LIRKind mergeKind, Iterable kinds) { + for (LIRKind kind : kinds) { + assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind); + } + return true; + } + + /** + * Create a new {@link LIRKind} with the same reference information and a new + * {@linkplain #getPlatformKind platform kind}. If the new kind is a longer vector than this, + * the new elements are marked as untracked values. + */ + public LIRKind changeType(PlatformKind newPlatformKind) { + if (newPlatformKind == platformKind) { + return this; + } else if (isUnknownReference()) { + return unknownReference(newPlatformKind); + } else if (referenceMask == 0) { + // value type + return LIRKind.value(newPlatformKind); + } else { + // reference type + int newLength = Math.min(32, newPlatformKind.getVectorLength()); + int newReferenceMask = referenceMask & (0xFFFFFFFF >>> (32 - newLength)); + assert newReferenceMask != UNKNOWN_REFERENCE; + return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase); + } + } + + /** + * Create a new {@link LIRKind} with a new {@linkplain #getPlatformKind platform kind}. If the + * new kind is longer than this, the reference positions are repeated to fill the vector. + */ + public LIRKind repeat(PlatformKind newPlatformKind) { + if (isUnknownReference()) { + return unknownReference(newPlatformKind); + } else if (referenceMask == 0) { + // value type + return LIRKind.value(newPlatformKind); + } else { + // reference type + int oldLength = platformKind.getVectorLength(); + int newLength = newPlatformKind.getVectorLength(); + assert oldLength <= newLength && newLength < 32 && (newLength % oldLength) == 0; + + // repeat reference mask to fill new kind + int newReferenceMask = 0; + for (int i = 0; i < newLength; i += platformKind.getVectorLength()) { + newReferenceMask |= referenceMask << i; + } + + assert newReferenceMask != UNKNOWN_REFERENCE; + return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase); + } + } + + /** + * Create a new {@link LIRKind} with the same type, but marked as containing an + * {@link LIRKind#unknownReference}. + */ + public LIRKind makeUnknownReference() { + return new LIRKind(platformKind, UNKNOWN_REFERENCE, null); + } + + /** + * Get the low level type that is used in code generation. + */ + public PlatformKind getPlatformKind() { + return platformKind; + } + + /** + * Check whether this value is a derived reference. + */ + public boolean isDerivedReference() { + return getDerivedReferenceBase() != null; + } + + /** + * Get the base value of a derived reference. + */ + public AllocatableValue getDerivedReferenceBase() { + return derivedReferenceBase; + } + + /** + * Change the base value of a derived reference. This must be called on derived references only. + */ + public void setDerivedReferenceBase(AllocatableValue derivedReferenceBase) { + assert isDerivedReference(); + this.derivedReferenceBase = derivedReferenceBase; + } + + /** + * Check whether this value is derived from a reference in a non-linear way. If this returns + * {@code true}, this value must not be live at safepoints. + */ + public boolean isUnknownReference() { + return referenceMask == UNKNOWN_REFERENCE; + } + + public int getReferenceCount() { + assert !isUnknownReference(); + return Integer.bitCount(referenceMask); + } + + /** + * Check whether the {@code idx}th part of this value is a reference that must be tracked at + * safepoints. + * + * @param idx The index into the vector if this is a vector kind. Must be 0 if this is a scalar + * kind. + */ + public boolean isReference(int idx) { + assert 0 <= idx && idx < platformKind.getVectorLength() : "invalid index " + idx + " in " + this; + return !isUnknownReference() && (referenceMask & 1 << idx) != 0; + } + + /** + * Check whether this kind is a value type that doesn't need to be tracked at safepoints. + */ + public boolean isValue() { + return referenceMask == 0; + } + + @Override + public String toString() { + if (isValue()) { + return platformKind.name(); + } else if (isUnknownReference()) { + return platformKind.name() + "[*]"; + } else { + StringBuilder ret = new StringBuilder(); + ret.append(platformKind.name()); + ret.append('['); + for (int i = 0; i < platformKind.getVectorLength(); i++) { + if (isReference(i)) { + ret.append('.'); + } else { + ret.append(' '); + } + } + ret.append(']'); + return ret.toString(); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((platformKind == null) ? 0 : platformKind.hashCode()); + result = prime * result + referenceMask; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof LIRKind)) { + return false; + } + + LIRKind other = (LIRKind) obj; + return platformKind == other.platformKind && referenceMask == other.referenceMask; + } + + public static boolean verifyMoveKinds(LIRKind dst, LIRKind src) { + if (src.equals(dst)) { + return true; + } + /* + * TODO(je,rs) What we actually want is toStackKind(src.getPlatformKind()).equals( + * dst.getPlatformKind()) but due to the handling of sub-integer at the current point + * (phi-)moves from e.g. integer to short can happen. Therefore we compare stack kinds. + */ + if (toStackKind(src.getPlatformKind()).equals(toStackKind(dst.getPlatformKind()))) { + return !src.isUnknownReference() || dst.isUnknownReference(); + } + return false; + } + + private static PlatformKind toStackKind(PlatformKind platformKind) { + if (platformKind instanceof JavaKind) { + return ((JavaKind) platformKind).getStackKind(); + } + return platformKind; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTable.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTable.java new file mode 100644 index 00000000000..13a0d0a466d --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTable.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public interface LineNumberTable { + + int[] getLineNumberEntries(); + + int[] getBciEntries(); + + int getLineNumber(int bci); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTableImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTableImpl.java new file mode 100644 index 00000000000..699a11faa7b --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTableImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public class LineNumberTableImpl implements LineNumberTable { + + private final int[] lineNumbers; + private final int[] bci; + + public LineNumberTableImpl(int[] lineNumbers, int[] bci) { + this.lineNumbers = lineNumbers; + this.bci = bci; + } + + @Override + public int[] getLineNumberEntries() { + return lineNumbers; + } + + @Override + public int[] getBciEntries() { + return bci; + } + + @Override + public int getLineNumber(@SuppressWarnings("hiding") int bci) { + for (int i = 0; i < this.bci.length - 1; i++) { + if (this.bci[i] <= bci && bci < this.bci[i + 1]) { + return lineNumbers[i]; + } + } + return lineNumbers[lineNumbers.length - 1]; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Local.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Local.java new file mode 100644 index 00000000000..ea0ac16acda --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Local.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public interface Local { + + int getStartBCI(); + + int getEndBCI(); + + int getSlot(); + + String getName(); + + JavaType getType(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalImpl.java new file mode 100644 index 00000000000..06e8fba0865 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalImpl.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public class LocalImpl implements Local { + + private final String name; + private final int startBci; + private final int endBci; + private final int slot; + private final JavaType type; + + public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) { + this.name = name; + this.startBci = startBci; + this.endBci = endBci; + this.slot = slot; + this.type = type; + } + + @Override + public int getStartBCI() { + return startBci; + } + + @Override + public int getEndBCI() { + return endBci; + } + + @Override + public String getName() { + return name; + } + + @Override + public JavaType getType() { + return type; + } + + @Override + public int getSlot() { + return slot; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof LocalImpl)) { + return false; + } + LocalImpl that = (LocalImpl) obj; + return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public String toString() { + return "LocalImpl"; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTable.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTable.java new file mode 100644 index 00000000000..ce140106396 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTable.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public interface LocalVariableTable { + + Local[] getLocals(); + + Local[] getLocalsAt(int bci); + + Local getLocal(int slot, int bci); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTableImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTableImpl.java new file mode 100644 index 00000000000..68a652655ca --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTableImpl.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +public class LocalVariableTableImpl implements LocalVariableTable { + + private final Local[] locals; + + public LocalVariableTableImpl(Local[] locals) { + this.locals = locals; + } + + @Override + public Local getLocal(int slot, int bci) { + Local result = null; + for (Local local : locals) { + if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) { + if (result == null) { + result = local; + } else { + throw new IllegalStateException("Locals overlap!"); + } + } + } + return result; + } + + @Override + public Local[] getLocals() { + return locals; + } + + @Override + public Local[] getLocalsAt(int bci) { + List result = new ArrayList<>(); + for (Local l : locals) { + if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) { + result.add(l); + } + } + return result.toArray(new Local[result.size()]); + } + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocationIdentity.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocationIdentity.java new file mode 100644 index 00000000000..3715ab4994e --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocationIdentity.java @@ -0,0 +1,78 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +// JaCoCo Exclude + +/** + * Marker interface for location identities. A different location identity of two memory accesses + * guarantees that the two accesses do not interfere. + * + * Clients of {@link LocationIdentity} must use {@link #equals(Object)}, not {@code ==}, when + * comparing two {@link LocationIdentity} values for equality. Likewise, they must not use + * {@link IdentityHashMap}s with {@link LocationIdentity} values as keys. + */ +public abstract class LocationIdentity { + + private static final class AnyLocationIdentity extends LocationIdentity { + @Override + public boolean isImmutable() { + return false; + } + + @Override + public String toString() { + return "ANY_LOCATION"; + } + } + + public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity(); + + public static LocationIdentity any() { + return ANY_LOCATION; + } + + /** + * Denotes a location is unchanging in all cases. Not that this is different than the Java + * notion of final which only requires definite assignment. + */ + public abstract boolean isImmutable(); + + public final boolean isMutable() { + return !isImmutable(); + } + + public final boolean isAny() { + return this == ANY_LOCATION; + } + + public final boolean isSingle() { + return this != ANY_LOCATION; + } + + public final boolean overlaps(LocationIdentity other) { + return isAny() || other.isAny() || this.equals(other); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java new file mode 100644 index 00000000000..71b75ecd01a --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Provides memory access operations for the target VM. + */ +public interface MemoryAccessProvider { + + /** + * Reads a value of this kind using a base address and a displacement. No bounds checking or + * type checking is performed. Returns {@code null} if the value is not available at this point. + * + * @param base the base address from which the value is read. + * @param displacement the displacement within the object in bytes + * @return the read value encapsulated in a {@link JavaConstant} object, or {@code null} if the + * value cannot be read. + */ + JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant base, long displacement); + + /** + * Reads a primitive value using a base address and a displacement. + * + * @param kind the {@link JavaKind} of the returned {@link JavaConstant} object + * @param base the base address from which the value is read + * @param displacement the displacement within the object in bytes + * @param bits the number of bits to read from memory + * @return the read value encapsulated in a {@link JavaConstant} object of {@link JavaKind} kind + */ + JavaConstant readPrimitiveConstant(JavaKind kind, Constant base, long displacement, int bits); + + /** + * Reads a Java {@link Object} value using a base address and a displacement. + * + * @param base the base address from which the value is read + * @param displacement the displacement within the object in bytes + * @return the read value encapsulated in a {@link Constant} object + */ + JavaConstant readObjectConstant(Constant base, long displacement); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java new file mode 100644 index 00000000000..1c54ec5c5ea --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.lang.reflect.*; + +/** + * Provides access to the metadata of a class typically provided in a class file. + */ +public interface MetaAccessProvider { + + /** + * Returns the resolved Java type representing a given Java class. + * + * @param clazz the Java class object + * @return the resolved Java type object + */ + ResolvedJavaType lookupJavaType(Class clazz); + + /** + * Returns the resolved Java types representing some given Java classes. + * + * @param classes the Java class objects + * @return the resolved Java type objects + */ + default ResolvedJavaType[] lookupJavaTypes(Class[] classes) { + ResolvedJavaType[] result = new ResolvedJavaType[classes.length]; + for (int i = 0; i < result.length; i++) { + result[i] = lookupJavaType(classes[i]); + } + return result; + } + + /** + * Provides the {@link ResolvedJavaMethod} for a {@link Method} or {@link Constructor} obtained + * via reflection. + */ + ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod); + + /** + * Provides the {@link ResolvedJavaField} for a {@link Field} obtained via reflection. + */ + ResolvedJavaField lookupJavaField(Field reflectionField); + + /** + * Returns the resolved Java type of the given {@link JavaConstant} object. + * + * @return {@code null} if {@code constant.isNull() || !constant.kind.isObject()} + */ + ResolvedJavaType lookupJavaType(JavaConstant constant); + + /** + * Returns the number of bytes occupied by this constant value or constant object. + * + * @param constant the constant whose bytes should be measured + * @return the number of bytes occupied by this constant + */ + long getMemorySize(JavaConstant constant); + + /** + * Parses a method + * descriptor into a {@link Signature}. The behavior of this method is undefined if the + * method descriptor is not well formed. + */ + Signature parseMethodDescriptor(String methodDescriptor); + + /** + * Encodes a deoptimization action and a deoptimization reason in an integer value. + * + * @param debugId an integer that can be used to track the origin of a deoptimization at + * runtime. There is no guarantee that the runtime will use this value. The runtime + * may even keep fewer than 32 bits. + * + * @return the encoded value as an integer + */ + JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int debugId); + + DeoptimizationReason decodeDeoptReason(JavaConstant constant); + + DeoptimizationAction decodeDeoptAction(JavaConstant constant); + + int decodeDebugId(JavaConstant constant); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java new file mode 100644 index 00000000000..7bc325087af --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +/** + * Miscellaneous collection of utility methods used by {@code jdk.vm.ci.meta} and its clients. + */ +public class MetaUtil { + + private static class ClassInfo { + public long totalSize; + public long instanceCount; + + @Override + public String toString() { + return "totalSize=" + totalSize + ", instanceCount=" + instanceCount; + } + } + + /** + * Returns the number of bytes occupied by this constant value or constant object and + * recursively all values reachable from this value. + * + * @param constant the constant whose bytes should be measured + * @param printTopN print total size and instance count of the top n classes is desired + * @return the number of bytes occupied by this constant + */ + public static long getMemorySizeRecursive(MetaAccessProvider access, ConstantReflectionProvider constantReflection, JavaConstant constant, PrintStream out, int printTopN) { + Set marked = new HashSet<>(); + Deque stack = new ArrayDeque<>(); + if (constant.getJavaKind() == JavaKind.Object && constant.isNonNull()) { + marked.add(constant); + } + final HashMap histogram = new HashMap<>(); + stack.push(constant); + long sum = 0; + while (!stack.isEmpty()) { + JavaConstant c = stack.pop(); + long memorySize = access.getMemorySize(constant); + sum += memorySize; + if (c.getJavaKind() == JavaKind.Object && c.isNonNull()) { + ResolvedJavaType clazz = access.lookupJavaType(c); + if (!histogram.containsKey(clazz)) { + histogram.put(clazz, new ClassInfo()); + } + ClassInfo info = histogram.get(clazz); + info.instanceCount++; + info.totalSize += memorySize; + ResolvedJavaType type = access.lookupJavaType(c); + if (type.isArray()) { + if (!type.getComponentType().isPrimitive()) { + int length = constantReflection.readArrayLength(c); + for (int i = 0; i < length; i++) { + JavaConstant value = constantReflection.readArrayElement(c, i); + pushConstant(marked, stack, value); + } + } + } else { + ResolvedJavaField[] instanceFields = type.getInstanceFields(true); + for (ResolvedJavaField f : instanceFields) { + if (f.getJavaKind() == JavaKind.Object) { + JavaConstant value = constantReflection.readFieldValue(f, c); + pushConstant(marked, stack, value); + } + } + } + } + } + ArrayList clazzes = new ArrayList<>(); + clazzes.addAll(histogram.keySet()); + Collections.sort(clazzes, new Comparator() { + + @Override + public int compare(ResolvedJavaType o1, ResolvedJavaType o2) { + long l1 = histogram.get(o1).totalSize; + long l2 = histogram.get(o2).totalSize; + if (l1 > l2) { + return -1; + } else if (l1 == l2) { + return 0; + } else { + return 1; + } + } + }); + + int z = 0; + for (ResolvedJavaType c : clazzes) { + if (z > printTopN) { + break; + } + out.println("Class " + c + ", " + histogram.get(c)); + ++z; + } + + return sum; + } + + private static void pushConstant(Set marked, Deque stack, JavaConstant value) { + if (value.isNonNull()) { + if (!marked.contains(value)) { + marked.add(value); + stack.push(value); + } + } + } + + /** + * Calls {@link JavaType#resolve(ResolvedJavaType)} on an array of types. + */ + public static ResolvedJavaType[] resolveJavaTypes(JavaType[] types, ResolvedJavaType accessingClass) { + ResolvedJavaType[] result = new ResolvedJavaType[types.length]; + for (int i = 0; i < result.length; i++) { + result[i] = types[i].resolve(accessingClass); + } + return result; + } + + /** + * Extends the functionality of {@link Class#getSimpleName()} to include a non-empty string for + * anonymous and local classes. + * + * @param clazz the class for which the simple name is being requested + * @param withEnclosingClass specifies if the returned name should be qualified with the name(s) + * of the enclosing class/classes of {@code clazz} (if any). This option is ignored + * if {@code clazz} denotes an anonymous or local class. + * @return the simple name + */ + public static String getSimpleName(Class clazz, boolean withEnclosingClass) { + final String simpleName = clazz.getSimpleName(); + if (simpleName.length() != 0) { + if (withEnclosingClass) { + String prefix = ""; + Class enclosingClass = clazz; + while ((enclosingClass = enclosingClass.getEnclosingClass()) != null) { + prefix = enclosingClass.getSimpleName() + "." + prefix; + } + return prefix + simpleName; + } + return simpleName; + } + // Must be an anonymous or local class + final String name = clazz.getName(); + int index = name.indexOf('$'); + if (index == -1) { + return name; + } + index = name.lastIndexOf('.', index); + if (index == -1) { + return name; + } + return name.substring(index + 1); + } + + static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) { + switch (name.charAt(0)) { + case 'L': { + String result = name.substring(1, name.length() - 1).replace('/', '.'); + if (!qualified) { + final int lastDot = result.lastIndexOf('.'); + if (lastDot != -1) { + result = result.substring(lastDot + 1); + } + } + return result; + } + case '[': + return classForNameCompatible ? name.replace('/', '.') : internalNameToJava(name.substring(1), qualified, classForNameCompatible) + "[]"; + default: + if (name.length() != 1) { + throw new IllegalArgumentException("Illegal internal name: " + name); + } + return JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)).getJavaName(); + } + } + + /** + * Turns an class name in internal format into a resolved Java type. + */ + public static ResolvedJavaType classForName(String internal, MetaAccessProvider metaAccess, ClassLoader cl) { + JavaKind k = JavaKind.fromTypeString(internal); + try { + String n = internalNameToJava(internal, true, true); + return metaAccess.lookupJavaType(k.isPrimitive() ? k.toJavaClass() : Class.forName(n, true, cl)); + } catch (ClassNotFoundException cnfe) { + throw new IllegalArgumentException("could not instantiate class described by " + internal, cnfe); + } + } + + /** + * Convenient shortcut for calling + * {@link #appendLocation(StringBuilder, ResolvedJavaMethod, int)} without having to supply a + * {@link StringBuilder} instance and convert the result to a string. + */ + public static String toLocation(ResolvedJavaMethod method, int bci) { + return appendLocation(new StringBuilder(), method, bci).toString(); + } + + /** + * Appends a string representation of a location specified by a given method and bci to a given + * {@link StringBuilder}. If a stack trace element with a non-null file name and non-negative + * line number is {@linkplain ResolvedJavaMethod#asStackTraceElement(int) available} for the + * given method, then the string returned is the {@link StackTraceElement#toString()} value of + * the stack trace element, suffixed by the bci location. For example: + * + *

+     *     java.lang.String.valueOf(String.java:2930) [bci: 12]
+     * 
+ * + * Otherwise, the string returned is the value of applying {@link JavaMethod#format(String)} + * with the format string {@code "%H.%n(%p)"}, suffixed by the bci location. For example: + * + *
+     *     java.lang.String.valueOf(int) [bci: 12]
+     * 
+ * + * @param sb + * @param method + * @param bci + */ + public static StringBuilder appendLocation(StringBuilder sb, ResolvedJavaMethod method, int bci) { + if (method != null) { + StackTraceElement ste = method.asStackTraceElement(bci); + if (ste.getFileName() != null && ste.getLineNumber() > 0) { + sb.append(ste); + } else { + sb.append(method.format("%H.%n(%p)")); + } + } else { + sb.append("Null method"); + } + return sb.append(" [bci: ").append(bci).append(']'); + } + + static void appendProfile(StringBuilder buf, AbstractJavaProfile profile, int bci, String type, String sep) { + if (profile != null) { + AbstractProfiledItem[] pitems = profile.getItems(); + if (pitems != null) { + buf.append(String.format("%s@%d:", type, bci)); + for (int j = 0; j < pitems.length; j++) { + AbstractProfiledItem pitem = pitems[j]; + buf.append(String.format(" %.6f (%s)%s", pitem.getProbability(), pitem.getItem(), sep)); + } + if (profile.getNotRecordedProbability() != 0) { + buf.append(String.format(" %.6f %s", profile.getNotRecordedProbability(), type, sep)); + } else { + buf.append(String.format(" %s", type, sep)); + } + } + } + } + + /** + * Converts a Java source-language class name into the internal form. + * + * @param className the class name + * @return the internal name form of the class name + */ + public static String toInternalName(String className) { + if (className.startsWith("[")) { + /* Already in the correct array style. */ + return className.replace('.', '/'); + } + + StringBuilder result = new StringBuilder(); + String base = className; + while (base.endsWith("[]")) { + result.append("["); + base = base.substring(0, base.length() - 2); + } + + switch (base) { + case "boolean": + result.append("Z"); + break; + case "byte": + result.append("B"); + break; + case "short": + result.append("S"); + break; + case "char": + result.append("C"); + break; + case "int": + result.append("I"); + break; + case "float": + result.append("F"); + break; + case "long": + result.append("J"); + break; + case "double": + result.append("D"); + break; + case "void": + result.append("V"); + break; + default: + result.append("L").append(base.replace('.', '/')).append(";"); + break; + } + return result.toString(); + } + + /** + * Prepends the String {@code indentation} to every line in String {@code lines}, including a + * possibly non-empty line following the final newline. + */ + public static String indent(String lines, String indentation) { + if (lines.length() == 0) { + return lines; + } + final String newLine = "\n"; + if (lines.endsWith(newLine)) { + return indentation + (lines.substring(0, lines.length() - 1)).replace(newLine, newLine + indentation) + newLine; + } + return indentation + lines.replace(newLine, newLine + indentation); + } + + /** + * Gets a string representation of an object based soley on its class and its + * {@linkplain System#identityHashCode(Object) identity hash code}. This avoids and calls to + * virtual methods on the object such as {@link Object#hashCode()}. + */ + public static String identityHashCodeString(Object obj) { + if (obj == null) { + return "null"; + } + return obj.getClass().getName() + "@" + System.identityHashCode(obj); + } + + /** + * Used to lookup constants from {@link Modifier} that are not public (VARARGS, SYNTHETIC etc.). + */ + static int getNonPublicModifierStaticField(String name) { + try { + Field field = Modifier.class.getDeclaredField(name); + field.setAccessible(true); + return field.getInt(null); + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + throw new InternalError(e); + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java new file mode 100644 index 00000000000..e4de0de87c8 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.lang.invoke.*; + +/** + * Interface to access the internals of the {@link MethodHandle} implementation of the VM. An + * implementation of this interface is usually required to access non-public classes, methods, and + * fields of {@link MethodHandle}, i.e., data that is not standardized by the Java specification. + */ +public interface MethodHandleAccessProvider { + + /** + * Identification for methods defined on the class {@link MethodHandle} that are processed by + * the {@link MethodHandleAccessProvider}. + */ + public enum IntrinsicMethod { + /** The method {@code MethodHandle.invokeBasic}. */ + INVOKE_BASIC, + /** The method {@code MethodHandle.linkToStatic}. */ + LINK_TO_STATIC, + /** The method {@code MethodHandle.linkToSpecial}. */ + LINK_TO_SPECIAL, + /** The method {@code MethodHandle.linkToVirtual}. */ + LINK_TO_VIRTUAL, + /** The method {@code MethodHandle.linkToInterface}. */ + LINK_TO_INTERFACE + } + + /** + * Returns the method handle method intrinsic identifier for the provided method, or + * {@code null} if the method is not an intrinsic processed by this interface. + */ + IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method); + + /** + * Resolves the invocation target for an invocation of {@link IntrinsicMethod#INVOKE_BASIC + * MethodHandle.invokeBasic} with the given constant receiver {@link MethodHandle}. Returns + * {@code null} if the invocation target is not available at this time. + *

+ * The first invocations of a method handle can use an interpreter to lookup the actual invoked + * method; frequently executed method handles can use Java bytecode generation to avoid the + * interpreter overhead. If the parameter forceBytecodeGeneration is set to true, the VM should + * try to generate bytecodes before this method returns. + */ + ResolvedJavaMethod resolveInvokeBasicTarget(JavaConstant methodHandle, boolean forceBytecodeGeneration); + + /** + * Resolves the invocation target for an invocation of a {@code MethodHandle.linkTo*} method + * with the given constant member name. The member name is the last parameter of the + * {@code linkTo*} method. Returns {@code null} if the invocation target is not available at + * this time. + */ + ResolvedJavaMethod resolveLinkToTarget(JavaConstant memberName); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ModifiersProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ModifiersProvider.java new file mode 100644 index 00000000000..f6c20bba1a4 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ModifiersProvider.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import static java.lang.reflect.Modifier.*; + +import java.lang.reflect.*; + +/** + * A Java element (i.e., a class, interface, field or method) that is described by a set of Java + * language {@linkplain #getModifiers() modifiers}. + */ +public interface ModifiersProvider { + int BRIDGE = MetaUtil.getNonPublicModifierStaticField("BRIDGE"); + int VARARGS = MetaUtil.getNonPublicModifierStaticField("VARARGS"); + int SYNTHETIC = MetaUtil.getNonPublicModifierStaticField("SYNTHETIC"); + int ANNOTATION = MetaUtil.getNonPublicModifierStaticField("ANNOTATION"); + int ENUM = MetaUtil.getNonPublicModifierStaticField("ENUM"); + int MANDATED = MetaUtil.getNonPublicModifierStaticField("MANDATED"); + + /** + * Returns the Java Virtual Machine modifiers for this element. Note that this can differ from + * standard Java Reflection modifiers. For example at the JVM level, classes ( + * {@link ResolvedJavaType}) can not be private or protected. + */ + int getModifiers(); + + /** + * @see Modifier#isInterface(int) + */ + default boolean isInterface() { + return Modifier.isInterface(getModifiers()); + } + + /** + * @see Modifier#isSynchronized(int) + */ + default boolean isSynchronized() { + return Modifier.isSynchronized(getModifiers()); + } + + /** + * @see Modifier#isStatic(int) + */ + default boolean isStatic() { + return Modifier.isStatic(getModifiers()); + } + + /** + * The setting of the final modifier bit for types is somewhat confusing, so don't export + * isFinal by default. Subclasses like {@link ResolvedJavaField} and {@link ResolvedJavaMethod} + * can export it as isFinal, but {@link ResolvedJavaType} can provide a more sensible equivalent + * like {@link ResolvedJavaType#isLeaf}. + * + * @see Modifier#isFinal(int) + */ + default boolean isFinalFlagSet() { + return Modifier.isFinal(getModifiers()); + } + + /** + * @see Modifier#isPublic(int) + */ + default boolean isPublic() { + return Modifier.isPublic(getModifiers()); + } + + /** + * Determines if this element is neither {@linkplain #isPublic() public}, + * {@linkplain #isProtected() protected} nor {@linkplain #isPrivate() private}. + */ + default boolean isPackagePrivate() { + return ((PUBLIC | PROTECTED | PRIVATE) & getModifiers()) == 0; + } + + /** + * @see Modifier#isPrivate(int) + */ + default boolean isPrivate() { + return Modifier.isPrivate(getModifiers()); + } + + /** + * @see Modifier#isProtected(int) + */ + default boolean isProtected() { + return Modifier.isProtected(getModifiers()); + } + + /** + * @see Modifier#isTransient(int) + */ + default boolean isTransient() { + return Modifier.isTransient(getModifiers()); + } + + /** + * @see Modifier#isStrict(int) + */ + default boolean isStrict() { + return Modifier.isStrict(getModifiers()); + } + + /** + * @see Modifier#isVolatile(int) + */ + default boolean isVolatile() { + return Modifier.isVolatile(getModifiers()); + } + + /** + * @see Modifier#isNative(int) + */ + default boolean isNative() { + return Modifier.isNative(getModifiers()); + } + + /** + * @see Modifier#isAbstract(int) + */ + default boolean isAbstract() { + return Modifier.isAbstract(getModifiers()); + } + + /** + * Checks that the method is concrete and not abstract. + * + * @return whether the method is a concrete method + */ + default boolean isConcrete() { + return !isAbstract(); + } + + static int jvmClassModifiers() { + // no SUPER + return PUBLIC | FINAL | INTERFACE | ABSTRACT | ANNOTATION | ENUM | SYNTHETIC; + } + + static int jvmMethodModifiers() { + return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | SYNCHRONIZED | BRIDGE | VARARGS | NATIVE | ABSTRACT | STRICT | SYNTHETIC; + } + + static int jvmFieldModifiers() { + return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | VOLATILE | TRANSIENT | ENUM | SYNTHETIC; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/NullConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/NullConstant.java new file mode 100644 index 00000000000..3f95674a648 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/NullConstant.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * The implementation type of the {@link JavaConstant#NULL_POINTER null constant}. + */ +final class NullConstant implements JavaConstant { + + protected NullConstant() { + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public boolean isDefaultForKind() { + return true; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public String toString() { + return JavaConstant.toString(this); + } + + @Override + public String toValueString() { + return "null"; + } + + @Override + public int hashCode() { + return 13; + } + + @Override + public boolean equals(Object o) { + return o instanceof NullConstant; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PlatformKind.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PlatformKind.java new file mode 100644 index 00000000000..e1deacac143 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PlatformKind.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Represents a platform-specific low-level type for values. + */ +public interface PlatformKind { + + String name(); + + JavaConstant getDefaultValue(); + + public interface Key { + + } + + public class EnumKey> implements Key { + private final Enum e; + + public EnumKey(Enum e) { + this.e = e; + } + + @Override + public int hashCode() { + return e.ordinal() ^ e.name().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof EnumKey) { + EnumKey that = (EnumKey) obj; + return this.e == that.e; + } + return false; + } + } + + /** + * Gets a value associated with this object that can be used as a stable key in a map. The + * {@link Object#hashCode()} implementation of the returned value should be stable between VM + * executions. + */ + Key getKey(); + + /** + * Get the size in bytes of this {@link PlatformKind}. + */ + int getSizeInBytes(); + + /** + * Returns how many primitive values fit in this {@link PlatformKind}. For scalar types this is + * one, for SIMD types it may be higher. + */ + int getVectorLength(); + + /** + * Gets a single type char that identifies this type for use in debug output. + */ + char getTypeChar(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PrimitiveConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PrimitiveConstant.java new file mode 100644 index 00000000000..bf599debc7e --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PrimitiveConstant.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.nio.*; + +/** + * Represents a primitive constant value, such as an integer or floating point number, within the + * compiler and across the compiler/runtime interface. + */ +public class PrimitiveConstant implements JavaConstant, SerializableConstant { + + private final JavaKind kind; + + /** + * The boxed primitive value as a {@code long}. For {@code float} and {@code double} values, + * this value is the result of {@link Float#floatToRawIntBits(float)} and + * {@link Double#doubleToRawLongBits(double)} respectively. + */ + private final long primitive; + + protected PrimitiveConstant(JavaKind kind, long primitive) { + this.primitive = primitive; + this.kind = kind; + + assert kind.isPrimitive() || kind == JavaKind.Illegal; + } + + @Override + public JavaKind getJavaKind() { + return kind; + } + + @Override + public boolean isNull() { + return false; + } + + @Override + public boolean isDefaultForKind() { + return primitive == 0; + } + + @Override + public boolean asBoolean() { + assert getJavaKind() == JavaKind.Boolean; + return primitive != 0L; + } + + @Override + public int asInt() { + assert getJavaKind().getStackKind() == JavaKind.Int : getJavaKind().getStackKind(); + return (int) primitive; + } + + @Override + public long asLong() { + assert getJavaKind().isNumericInteger(); + return primitive; + } + + @Override + public float asFloat() { + assert getJavaKind() == JavaKind.Float; + return Float.intBitsToFloat((int) primitive); + } + + @Override + public double asDouble() { + assert getJavaKind() == JavaKind.Double; + return Double.longBitsToDouble(primitive); + } + + @Override + public Object asBoxedPrimitive() { + switch (getJavaKind()) { + case Byte: + return Byte.valueOf((byte) primitive); + case Boolean: + return Boolean.valueOf(asBoolean()); + case Short: + return Short.valueOf((short) primitive); + case Char: + return Character.valueOf((char) primitive); + case Int: + return Integer.valueOf(asInt()); + case Long: + return Long.valueOf(asLong()); + case Float: + return Float.valueOf(asFloat()); + case Double: + return Double.valueOf(asDouble()); + default: + throw new IllegalArgumentException("unexpected kind " + getJavaKind()); + } + } + + @Override + public int getSerializedSize() { + return getJavaKind().getByteCount(); + } + + @Override + public void serialize(ByteBuffer buffer) { + switch (getJavaKind()) { + case Byte: + case Boolean: + buffer.put((byte) primitive); + break; + case Short: + buffer.putShort((short) primitive); + break; + case Char: + buffer.putChar((char) primitive); + break; + case Int: + buffer.putInt(asInt()); + break; + case Long: + buffer.putLong(asLong()); + break; + case Float: + buffer.putFloat(asFloat()); + break; + case Double: + buffer.putDouble(asDouble()); + break; + default: + throw new IllegalArgumentException("unexpected kind " + getJavaKind()); + } + } + + @Override + public int hashCode() { + return (int) (primitive ^ (primitive >>> 32)) * (getJavaKind().ordinal() + 31); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof PrimitiveConstant)) { + return false; + } + PrimitiveConstant other = (PrimitiveConstant) o; + return this.kind.equals(other.kind) && this.primitive == other.primitive; + } + + @Override + public String toString() { + if (getJavaKind() == JavaKind.Illegal) { + return "illegal"; + } else { + return getJavaKind().getJavaName() + "[" + asBoxedPrimitive() + "|0x" + Long.toHexString(primitive) + "]"; + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java new file mode 100644 index 00000000000..2ba915c9892 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2012, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Provides access to the profiling information of one specific method. Every accessor method + * returns the information that is available at the time of invocation. If a method is invoked + * multiple times, it may return significantly different results for every invocation as the + * profiling information may be changed by other Java threads at any time. + */ +public interface ProfilingInfo { + + /** + * Returns the length of the bytecodes associated with this profile. + */ + int getCodeSize(); + + /** + * Returns an estimate of how often the branch at the given byte code was taken. + * + * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or -1 if + * this information is not available. + */ + double getBranchTakenProbability(int bci); + + /** + * Returns an estimate of how often the switch cases are taken at the given BCI. The default + * case is stored as the last entry. + * + * @return A double value that contains the estimated probabilities, with 0.0 meaning never and + * 1.0 meaning always, or -1 if this information is not available. + */ + double[] getSwitchProbabilities(int bci); + + /** + * Returns the TypeProfile for the given BCI. + * + * @return Returns a JavaTypeProfile object, or null if not available. + */ + JavaTypeProfile getTypeProfile(int bci); + + /** + * Returns the MethodProfile for the given BCI. + * + * @return Returns a JavaMethodProfile object, or null if not available. + */ + JavaMethodProfile getMethodProfile(int bci); + + /** + * Returns information if the given BCI did ever throw an exception. + * + * @return {@link TriState#TRUE} if the instruction has thrown an exception at least once, + * {@link TriState#FALSE} if it never threw an exception, and {@link TriState#UNKNOWN} + * if this information was not recorded. + */ + TriState getExceptionSeen(int bci); + + /** + * Returns information if null was ever seen for the given BCI. This information is collected + * for the aastore, checkcast and instanceof bytecodes. + * + * @return {@link TriState#TRUE} if null was seen for the instruction, {@link TriState#FALSE} if + * null was NOT seen, and {@link TriState#UNKNOWN} if this information was not recorded. + */ + TriState getNullSeen(int bci); + + /** + * Returns an estimate how often the current BCI was executed. Avoid comparing execution counts + * to each other, as the returned value highly depends on the time of invocation. + * + * @return the estimated execution count or -1 if not available. + */ + int getExecutionCount(int bci); + + /** + * Returns how frequently a method was deoptimized for the given deoptimization reason. This + * only indicates how often the method did fall back to the interpreter for the execution and + * does not indicate how often it was recompiled. + * + * @param reason the reason for which the number of deoptimizations should be queried + * @return the number of times the compiled method deoptimized for the given reason. + */ + int getDeoptimizationCount(DeoptimizationReason reason); + + /** + * Records the size of the compiler intermediate representation (IR) associated with this + * method. + * + * @param irType the IR type for which the size is being recorded + * @param irSize the IR size to be recorded. The unit depends on the IR. + * @return whether recording this information for {@code irType} is supported + */ + boolean setCompilerIRSize(Class irType, int irSize); + + /** + * Gets the size of the compiler intermediate representation (IR) associated with this method + * last recorded by {@link #setCompilerIRSize(Class, int)}. + * + * @param irType the IR type for which the size is being requested + * @return the requested IR size or -1 if it is unavailable for {@code irType} + */ + int getCompilerIRSize(Class irType); + + /** + * Returns true if the profiling information can be assumed as sufficiently accurate. + * + * @return true if the profiling information was recorded often enough mature enough, false + * otherwise. + */ + boolean isMature(); + + /** + * Force data to be treated as mature if possible. + */ + void setMature(); + + /** + * Formats this profiling information to a string. + * + * @param method an optional method that augments the profile string returned + * @param sep the separator to use for each separate profile record + */ + default String toString(ResolvedJavaMethod method, String sep) { + StringBuilder buf = new StringBuilder(100); + if (method != null) { + buf.append(String.format("canBeStaticallyBound: %b%s", method.canBeStaticallyBound(), sep)); + } + for (int i = 0; i < getCodeSize(); i++) { + if (getExecutionCount(i) != -1) { + buf.append(String.format("executionCount@%d: %d%s", i, getExecutionCount(i), sep)); + } + + if (getBranchTakenProbability(i) != -1) { + buf.append(String.format("branchProbability@%d: %.6f%s", i, getBranchTakenProbability(i), sep)); + } + + double[] switchProbabilities = getSwitchProbabilities(i); + if (switchProbabilities != null) { + buf.append(String.format("switchProbabilities@%d:", i)); + for (int j = 0; j < switchProbabilities.length; j++) { + buf.append(String.format(" %.6f", switchProbabilities[j])); + } + buf.append(sep); + } + + if (getExceptionSeen(i) != TriState.UNKNOWN) { + buf.append(String.format("exceptionSeen@%d: %s%s", i, getExceptionSeen(i).name(), sep)); + } + + if (getNullSeen(i) != TriState.UNKNOWN) { + buf.append(String.format("nullSeen@%d: %s%s", i, getNullSeen(i).name(), sep)); + } + + JavaTypeProfile typeProfile = getTypeProfile(i); + MetaUtil.appendProfile(buf, typeProfile, i, "types", sep); + + JavaMethodProfile methodProfile = getMethodProfile(i); + MetaUtil.appendProfile(buf, methodProfile, i, "methods", sep); + } + + boolean firstDeoptReason = true; + for (DeoptimizationReason reason : DeoptimizationReason.values()) { + int count = getDeoptimizationCount(reason); + if (count > 0) { + if (firstDeoptReason) { + buf.append("deoptimization history").append(sep); + firstDeoptReason = false; + } + buf.append(String.format(" %s: %d%s", reason.name(), count, sep)); + } + } + if (buf.length() == 0) { + return ""; + } + String s = buf.toString(); + return s.substring(0, s.length() - sep.length()); + } + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/RawConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/RawConstant.java new file mode 100644 index 00000000000..b622a1c958e --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/RawConstant.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public class RawConstant extends PrimitiveConstant { + + public RawConstant(long rawValue) { + super(JavaKind.Int, rawValue); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaField.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaField.java new file mode 100644 index 00000000000..7a695f083a5 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaField.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.lang.annotation.*; +import java.lang.reflect.*; + +/** + * Represents a reference to a resolved Java field. Fields, like methods and types, are resolved + * through {@link ConstantPool constant pools}. + */ +public interface ResolvedJavaField extends JavaField, ModifiersProvider { + + /** + * {@inheritDoc} + *

+ * Only the {@linkplain Modifier#fieldModifiers() field flags} specified in the JVM + * specification will be included in the returned mask. + */ + int getModifiers(); + + default boolean isFinal() { + return ModifiersProvider.super.isFinalFlagSet(); + } + + /** + * Determines if this field was injected by the VM. Such a field, for example, is not derived + * from a class file. + */ + boolean isInternal(); + + /** + * Determines if this field is a synthetic field as defined by the Java Language Specification. + */ + boolean isSynthetic(); + + /** + * Returns the {@link ResolvedJavaType} object representing the class or interface that declares + * this field. + */ + ResolvedJavaType getDeclaringClass(); + + /** + * Returns all annotations of this field. If no annotations are present, an array of length 0 is + * returned. + */ + Annotation[] getAnnotations(); + + /** + * Returns the annotation for the specified type of this field, if such an annotation is + * present. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return this element's annotation for the specified annotation type if present on this field, + * else {@code null} + */ + T getAnnotation(Class annotationClass); + + /** + * Returns an object representing the unique location identity of this resolved Java field. + * + * @return the location identity of the field + */ + LocationIdentity getLocationIdentity(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java new file mode 100644 index 00000000000..9e516534d16 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.lang.annotation.*; +import java.lang.invoke.*; +import java.lang.reflect.*; +import java.util.*; + +/** + * Represents a resolved Java method. Methods, like fields and types, are resolved through + * {@link ConstantPool constant pools}. + */ +public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersProvider { + + /** + * Returns the bytecode of this method, if the method has code. The returned byte array does not + * contain breakpoints or non-Java bytecodes. This may return null if the + * {@link #getDeclaringClass() holder} is not {@link ResolvedJavaType#isLinked() linked}. + * + * The contained constant pool indices may not be the ones found in the original class file but + * they can be used with the JVMCI API (e.g. methods in {@link ConstantPool}). + * + * @return the bytecode of the method, or {@code null} if {@code getCodeSize() == 0} or if the + * code is not ready. + */ + byte[] getCode(); + + /** + * Returns the size of the bytecode of this method, if the method has code. This is equivalent + * to {@link #getCode()}. {@code length} if the method has code. + * + * @return the size of the bytecode in bytes, or 0 if no bytecode is available + */ + int getCodeSize(); + + /** + * Returns the {@link ResolvedJavaType} object representing the class or interface that declares + * this method. + */ + ResolvedJavaType getDeclaringClass(); + + /** + * Returns the maximum number of locals used in this method's bytecodes. + */ + int getMaxLocals(); + + /** + * Returns the maximum number of stack slots used in this method's bytecodes. + */ + int getMaxStackSize(); + + /** + * {@inheritDoc} + *

+ * Only the {@linkplain Modifier#methodModifiers() method flags} specified in the JVM + * specification will be included in the returned mask. + */ + int getModifiers(); + + default boolean isFinal() { + return ModifiersProvider.super.isFinalFlagSet(); + } + + /** + * Determines if this method is a synthetic method as defined by the Java Language + * Specification. + */ + default boolean isSynthetic() { + return (SYNTHETIC & getModifiers()) == SYNTHETIC; + } + + /** + * Checks that the method is a varargs + * method. + * + * @return whether the method is a varargs method + */ + default boolean isVarArgs() { + return (VARARGS & getModifiers()) == VARARGS; + } + + /** + * Checks that the method is a bridge + * method. + * + * @return whether the method is a bridge method + */ + default boolean isBridge() { + return (BRIDGE & getModifiers()) == BRIDGE; + } + + /** + * Returns {@code true} if this method is a default method; returns {@code false} otherwise. + * + * A default method is a public non-abstract instance method, that is, a non-static method with + * a body, declared in an interface type. + * + * @return true if and only if this method is a default method as defined by the Java Language + * Specification. + */ + boolean isDefault(); + + /** + * Checks whether this method is a class initializer. + * + * @return {@code true} if the method is a class initializer + */ + boolean isClassInitializer(); + + /** + * Checks whether this method is a constructor. + * + * @return {@code true} if the method is a constructor + */ + boolean isConstructor(); + + /** + * Checks whether this method can be statically bound (usually, that means it is final or + * private or static, but not abstract, or the declaring class is final). + * + * @return {@code true} if this method can be statically bound + */ + boolean canBeStaticallyBound(); + + /** + * Returns the list of exception handlers for this method. + */ + ExceptionHandler[] getExceptionHandlers(); + + /** + * Returns a stack trace element for this method and a given bytecode index. + */ + StackTraceElement asStackTraceElement(int bci); + + /** + * Returns an object that provides access to the profiling information recorded for this method. + */ + default ProfilingInfo getProfilingInfo() { + return getProfilingInfo(true, true); + } + + /** + * Returns an object that provides access to the profiling information recorded for this method. + * + * @param includeNormal if true, + * {@linkplain ProfilingInfo#getDeoptimizationCount(DeoptimizationReason) + * deoptimization counts} will include deoptimization that happened during execution + * of standard non-osr methods. + * @param includeOSR if true, + * {@linkplain ProfilingInfo#getDeoptimizationCount(DeoptimizationReason) + * deoptimization counts} will include deoptimization that happened during execution + * of on-stack-replacement methods. + */ + ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR); + + /** + * Invalidates the profiling information and restarts profiling upon the next invocation. + */ + void reprofile(); + + /** + * Returns the constant pool of this method. + */ + ConstantPool getConstantPool(); + + /** + * Returns all annotations of this method. If no annotations are present, an array of length 0 + * is returned. + */ + Annotation[] getAnnotations(); + + /** + * Returns the annotation for the specified type of this method, if such an annotation is + * present. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return this element's annotation for the specified annotation type if present on this + * method, else {@code null} + */ + T getAnnotation(Class annotationClass); + + /** + * Returns an array of arrays that represent the annotations on the formal parameters, in + * declaration order, of this method. + * + * @see Method#getParameterAnnotations() + */ + Annotation[][] getParameterAnnotations(); + + /** + * Returns an array of {@link Type} objects that represent the formal parameter types, in + * declaration order, of this method. + * + * @see Method#getGenericParameterTypes() + */ + Type[] getGenericParameterTypes(); + + /** + * Returns {@code true} if this method is not excluded from inlining and has associated Java + * bytecodes (@see {@link ResolvedJavaMethod#hasBytecodes()}). + */ + boolean canBeInlined(); + + /** + * Returns {@code true} if the inlining of this method should be forced. + */ + boolean shouldBeInlined(); + + /** + * Returns the LineNumberTable of this method or null if this method does not have a line + * numbers table. + */ + LineNumberTable getLineNumberTable(); + + /** + * Returns the local variable table of this method or null if this method does not have a local + * variable table. + */ + LocalVariableTable getLocalVariableTable(); + + /** + * Invokes the underlying method represented by this object, on the specified object with the + * specified parameters. This method is similar to a reflective method invocation by + * {@link Method#invoke}. + * + * @param receiver The receiver for the invocation, or {@code null} if it is a static method. + * @param arguments The arguments for the invocation. + * @return The value returned by the method invocation, or {@code null} if the return type is + * {@code void}. + */ + JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments); + + /** + * Gets the encoding of (that is, a constant representing the value of) this method. + * + * @return a constant representing a reference to this method + */ + Constant getEncoding(); + + /** + * Checks if this method is present in the virtual table for subtypes of the specified + * {@linkplain ResolvedJavaType type}. + * + * @return true is this method is present in the virtual table for subtypes of this type. + */ + boolean isInVirtualMethodTable(ResolvedJavaType resolved); + + /** + * Gets the annotation of a particular type for a formal parameter of this method. + * + * @param annotationClass the Class object corresponding to the annotation type + * @param parameterIndex the index of a formal parameter of {@code method} + * @return the annotation of type {@code annotationClass} for the formal parameter present, else + * null + * @throws IndexOutOfBoundsException if {@code parameterIndex} does not denote a formal + * parameter + */ + default T getParameterAnnotation(Class annotationClass, int parameterIndex) { + if (parameterIndex >= 0) { + Annotation[][] parameterAnnotations = getParameterAnnotations(); + for (Annotation a : parameterAnnotations[parameterIndex]) { + if (a.annotationType() == annotationClass) { + return annotationClass.cast(a); + } + } + } + return null; + } + + default JavaType[] toParameterTypes() { + JavaType receiver = isStatic() || isConstructor() ? null : getDeclaringClass(); + return getSignature().toParameterTypes(receiver); + } + + /** + * Gets the annotations of a particular type for the formal parameters of this method. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return the annotation of type {@code annotationClass} (if any) for each formal parameter + * present + */ + @SuppressWarnings("unchecked") + default T[] getParameterAnnotations(Class annotationClass) { + Annotation[][] parameterAnnotations = getParameterAnnotations(); + T[] result = (T[]) Array.newInstance(annotationClass, parameterAnnotations.length); + for (int i = 0; i < parameterAnnotations.length; i++) { + for (Annotation a : parameterAnnotations[i]) { + if (a.annotationType() == annotationClass) { + result[i] = annotationClass.cast(a); + } + } + } + return result; + } + + /** + * Checks whether the method has bytecodes associated with it. Methods without bytecodes are + * either abstract or native methods. + * + * @return whether the definition of this method is Java bytecodes + */ + default boolean hasBytecodes() { + return isConcrete() && !isNative(); + } + + /** + * Checks whether the method has a receiver parameter - i.e., whether it is not static. + * + * @return whether the method has a receiver parameter + */ + default boolean hasReceiver() { + return !isStatic(); + } + + /** + * Determines if this method is {@link java.lang.Object#Object()}. + */ + default boolean isJavaLangObjectInit() { + return getDeclaringClass().isJavaLangObject() && getName().equals(""); + } + + SpeculationLog getSpeculationLog(); + + /** + * Determines if the method identified by its holder and name is a signature + * polymorphic method. + */ + static boolean isSignaturePolymorphic(JavaType holder, String name, MetaAccessProvider metaAccess) { + if (!holder.getName().equals("Ljava/lang/invoke/MethodHandle;")) { + return false; + } + ResolvedJavaType methodHandleType = metaAccess.lookupJavaType(MethodHandle.class); + Signature signature = metaAccess.parseMethodDescriptor("([Ljava/lang/Object;)Ljava/lang/Object;"); + ResolvedJavaMethod method = methodHandleType.findMethod(name, signature); + if (method == null) { + return false; + } + return method.isNative() && method.isVarArgs(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java new file mode 100644 index 00000000000..1f2bdf3e329 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.lang.annotation.*; +import java.net.*; + +import jdk.vm.ci.meta.Assumptions.*; + +/** + * Represents a resolved Java type. Types include primitives, objects, {@code void}, and arrays + * thereof. Types, like fields and methods, are resolved through {@link ConstantPool constant pools} + * . + */ +public interface ResolvedJavaType extends JavaType, ModifiersProvider { + /** + * Gets the runtime representation of the Java class object of this type. + */ + JavaConstant getJavaClass(); + + /** + * Gets the runtime representation of the "hub" of this type--that is, the closest part of the + * type representation which is typically stored in the object header. + */ + Constant getObjectHub(); + + /** + * Checks whether this type has a finalizer method. + * + * @return {@code true} if this class has a finalizer + */ + boolean hasFinalizer(); + + /** + * Checks whether this type has any finalizable subclasses so far. Any decisions based on this + * information require the registration of a dependency, since this information may change. + * + * @return {@code true} if this class has any subclasses with finalizers + */ + AssumptionResult hasFinalizableSubclass(); + + /** + * Checks whether this type is an interface. + * + * @return {@code true} if this type is an interface + */ + boolean isInterface(); + + /** + * Checks whether this type is an instance class. + * + * @return {@code true} if this type is an instance class + */ + boolean isInstanceClass(); + + /** + * Checks whether this type is an array class. + * + * @return {@code true} if this type is an array class + */ + boolean isArray(); + + /** + * Checks whether this type is primitive. + * + * @return {@code true} if this type is primitive + */ + boolean isPrimitive(); + + /** + * {@inheritDoc} + *

+ * Only the flags specified in the JVM specification will be included in the returned mask. This + * method is identical to {@link Class#getModifiers()} in terms of the value return for this + * type. + */ + int getModifiers(); + + /* + * The setting of the final bit for types is a bit confusing since arrays are marked as final. + * This method provides a semantically equivalent test that appropriate for types. + */ + default boolean isLeaf() { + return getElementalType().isFinalFlagSet(); + } + + /** + * Checks whether this type is initialized. If a type is initialized it implies that it was + * {@link #isLinked() linked} and that the static initializer has run. + * + * @return {@code true} if this type is initialized + */ + boolean isInitialized(); + + /** + * Initializes this type. + */ + void initialize(); + + /** + * Checks whether this type is linked and verified. When a type is linked the static initializer + * has not necessarily run. An {@link #isInitialized() initialized} type is always linked. + * + * @return {@code true} if this type is linked + */ + boolean isLinked(); + + /** + * Determines if this type is either the same as, or is a superclass or superinterface of, the + * type represented by the specified parameter. This method is identical to + * {@link Class#isAssignableFrom(Class)} in terms of the value return for this type. + */ + boolean isAssignableFrom(ResolvedJavaType other); + + /** + * Returns true if this type is exactly the type {@link java.lang.Object}. + */ + default boolean isJavaLangObject() { + // Removed assertion due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=434442 + return getSuperclass() == null && !isInterface() && getJavaKind() == JavaKind.Object; + } + + /** + * Checks whether the specified object is an instance of this type. + * + * @param obj the object to test + * @return {@code true} if the object is an instance of this type + */ + boolean isInstance(JavaConstant obj); + + /** + * Returns this type if it is an exact type otherwise returns null. This type is exact if it is + * void, primitive, final, or an array of a final or primitive type. + * + * @return this type if it is exact; {@code null} otherwise + */ + ResolvedJavaType asExactType(); + + /** + * Gets the super class of this type. If this type represents either the {@code Object} class, + * an interface, a primitive type, or void, then null is returned. If this object represents an + * array class then the type object representing the {@code Object} class is returned. + */ + ResolvedJavaType getSuperclass(); + + /** + * Gets the interfaces implemented or extended by this type. This method is analogous to + * {@link Class#getInterfaces()} and as such, only returns the interfaces directly implemented + * or extended by this type. + */ + ResolvedJavaType[] getInterfaces(); + + /** + * Gets the single implementor of this type. Calling this method on a non-interface type causes + * an exception. + *

+ * If the compiler uses the result of this method for its compilation, the usage must be guarded + * because the verifier can not guarantee that the assigned type really implements this + * interface. Additionally, class loading can invalidate the result of this method. + * + * @return {@code null} if there is no implementor, the implementor if there is only one, or + * {@code this} if there are more than one. + */ + ResolvedJavaType getSingleImplementor(); + + /** + * Walks the class hierarchy upwards and returns the least common class that is a superclass of + * both the current and the given type. + * + * @return the least common type that is a super type of both the current and the given type, or + * {@code null} if primitive types are involved. + */ + ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType); + + /** + * Attempts to get a leaf concrete subclass of this type. + *

+ * For an {@linkplain #isArray() array} type A, the leaf concrete subclass is A if the + * {@linkplain #getElementalType() elemental} type of A is final (which includes primitive + * types). Otherwise {@code null} is returned for A. + *

+ * For a non-array type T, the result is the leaf concrete type in the current hierarchy of T. + *

+ * A runtime may decide not to manage or walk a large hierarchy and so the result is + * conservative. That is, a non-null result is guaranteed to be the leaf concrete class in T's + * hierarchy at the current point in time but a null result does not necessarily imply + * that there is no leaf concrete class in T's hierarchy. + *

+ * If the compiler uses the result of this method for its compilation, it must register the + * {@link AssumptionResult} in its {@link Assumptions} because dynamic class loading can + * invalidate the result of this method. + * + * @return an {@link AssumptionResult} containing the leaf concrete subclass for this type as + * described above + */ + AssumptionResult findLeafConcreteSubtype(); + + ResolvedJavaType getComponentType(); + + default ResolvedJavaType getElementalType() { + ResolvedJavaType t = this; + while (t.isArray()) { + t = t.getComponentType(); + } + return t; + } + + ResolvedJavaType getArrayClass(); + + /** + * Resolves the method implementation for virtual dispatches on objects of this dynamic type. + * This resolution process only searches "up" the class hierarchy of this type. + * + * @param method the method to select the implementation of + * @param callerType the caller or context type used to perform access checks + * @return the link-time resolved method (might be abstract) or {@code null} if it can not be + * linked + */ + ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType); + + /** + * Resolves the method implementation for virtual dispatches on objects of this dynamic type. + * This resolution process only searches "up" the class hierarchy of this type. A broader search + * that also walks "down" the hierarchy is implemented by + * {@link #findUniqueConcreteMethod(ResolvedJavaMethod)}. + * + * @param method the method to select the implementation of + * @param callerType the caller or context type used to perform access checks + * @return the concrete method that would be selected at runtime, or {@code null} if there is no + * concrete implementation of {@code method} in this type or any of its superclasses + */ + ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType); + + /** + * Given a {@link ResolvedJavaMethod} A, returns a concrete {@link ResolvedJavaMethod} B that is + * the only possible unique target for a virtual call on A(). Returns {@code null} if either no + * such concrete method or more than one such method exists. Returns the method A if A is a + * concrete method that is not overridden. + *

+ * If the compiler uses the result of this method for its compilation, it must register an + * assumption because dynamic class loading can invalidate the result of this method. + * + * @param method the method A for which a unique concrete target is searched + * @return the unique concrete target or {@code null} if no such target exists or assumptions + * are not supported by this runtime + */ + AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method); + + /** + * Returns the instance fields of this class, including + * {@linkplain ResolvedJavaField#isInternal() internal} fields. A zero-length array is returned + * for array and primitive types. The order of fields returned by this method is stable. That + * is, for a single JVM execution the same order is returned each time this method is called. It + * is also the "natural" order, which means that the JVM would expect the fields in this order + * if no specific order is given. + * + * @param includeSuperclasses if true, then instance fields for the complete hierarchy of this + * type are included in the result + * @return an array of instance fields + */ + ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses); + + /** + * Returns the static fields of this class, including + * {@linkplain ResolvedJavaField#isInternal() internal} fields. A zero-length array is returned + * for array and primitive types. The order of fields returned by this method is stable. That + * is, for a single JVM execution the same order is returned each time this method is called. + */ + ResolvedJavaField[] getStaticFields(); + + /** + * Returns all annotations of this class. If no annotations are present, an array of length 0 is + * returned. + */ + Annotation[] getAnnotations(); + + /** + * Returns the annotation for the specified type of this class, if such an annotation is + * present. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return this element's annotation for the specified annotation type if present on this class, + * else {@code null} + */ + T getAnnotation(Class annotationClass); + + /** + * Returns the instance field of this class (or one of its super classes) at the given offset, + * or {@code null} if there is no such field. + * + * @param offset the offset of the field to look for + * @return the field with the given offset, or {@code null} if there is no such field. + */ + ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedKind); + + /** + * Returns name of source file of this type. + */ + String getSourceFileName(); + + /** + * Returns the class file path - if available - of this type, or {@code null}. + */ + URL getClassFilePath(); + + /** + * Returns {@code true} if the type is a local type. + */ + boolean isLocal(); + + /** + * Returns {@code true} if the type is a member type. + */ + boolean isMember(); + + /** + * Returns the enclosing type of this type, if it exists, or {@code null}. + */ + ResolvedJavaType getEnclosingType(); + + /** + * Returns an array reflecting all the constructors declared by this type. This method is + * similar to {@link Class#getDeclaredConstructors()} in terms of returned constructors. + */ + ResolvedJavaMethod[] getDeclaredConstructors(); + + /** + * Returns an array reflecting all the methods declared by this type. This method is similar to + * {@link Class#getDeclaredMethods()} in terms of returned methods. + */ + ResolvedJavaMethod[] getDeclaredMethods(); + + /** + * Returns the {@code } method for this class if there is one. + */ + ResolvedJavaMethod getClassInitializer(); + + /** + * Returns true if this type represents an interface and it should be trusted even in places + * where the JVM verifier would not give any guarantees other than {@link Object}. + */ + boolean isTrustedInterfaceType(); + + default ResolvedJavaMethod findMethod(String name, Signature signature) { + for (ResolvedJavaMethod method : getDeclaredMethods()) { + if (method.getName().equals(name) && method.getSignature().equals(signature)) { + return method; + } + } + return null; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SerializableConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SerializableConstant.java new file mode 100644 index 00000000000..3c63b25298d --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SerializableConstant.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.nio.*; + +/** + * Represents a compile-time constant that can be converted to a byte array. + */ +public interface SerializableConstant extends Constant { + + /** + * Return the size in bytes of the serialized representation of this constant. + */ + int getSerializedSize(); + + /** + * Serialize the constant into the ByteBuffer. There must be at least + * {@link #getSerializedSize()} bytes available capacity in the buffer. + */ + void serialize(ByteBuffer buffer); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Signature.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Signature.java new file mode 100644 index 00000000000..ae3faeea21b --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Signature.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Represents a method signature provided by the runtime. + * + * @see Method + * Descriptors + */ +public interface Signature { + + /** + * Returns the number of parameters in this signature, adding 1 for a receiver if requested. + * + * @param receiver true if 1 is to be added to the result for a receiver + * @return the number of parameters; + 1 iff {@code receiver == true} + */ + int getParameterCount(boolean receiver); + + /** + * Gets the parameter type at the specified position. + * + * @param index the index into the parameters, with {@code 0} indicating the first parameter + * @param accessingClass the context of the type lookup. If non-null, its class loader is used + * for resolving the type. If {@code null}, then the type returned is either + * unresolved or a resolved type whose resolution is context free (e.g., a primitive + * type or a type in a java.* package). + * @return the {@code index}'th parameter type + * @throws LinkageError if {@code accessingClass != null} and resolution fails + * + */ + JavaType getParameterType(int index, ResolvedJavaType accessingClass); + + /** + * Gets the parameter kind at the specified position. This is the same as calling + * {@link #getParameterType}. {@link JavaType#getJavaKind getJavaKind}. + * + * @param index the index into the parameters, with {@code 0} indicating the first parameter + * @return the kind of the parameter at the specified position + */ + default JavaKind getParameterKind(int index) { + return getParameterType(index, null).getJavaKind(); + } + + /** + * Gets the return type of this signature. + * + * @param accessingClass the context of the type lookup. If non-null, its class loader is used + * for resolving the type. If {@code null}, then the type returned is either + * unresolved or a resolved type whose resolution is context free (e.g., a primitive + * type or a type in a java.* package). + * @return the return type + * @throws LinkageError if {@code accessingClass != null} and resolution fails + */ + JavaType getReturnType(ResolvedJavaType accessingClass); + + /** + * Gets the return kind of this signature. This is the same as calling {@link #getReturnType}. + * {@link JavaType#getJavaKind getJavaKind}. + */ + default JavaKind getReturnKind() { + return getReturnType(null).getJavaKind(); + } + + /** + * Gets the method + * descriptor corresponding to this signature. For example: + * + *

+     * (ILjava/lang/String;D)V
+     * 
+ * + * @return the signature as a string + */ + default String toMethodDescriptor() { + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < getParameterCount(false); ++i) { + sb.append(getParameterType(i, null).getName()); + } + sb.append(')').append(getReturnType(null).getName()); + return sb.toString(); + } + + default JavaType[] toParameterTypes(JavaType receiverType) { + int args = getParameterCount(false); + JavaType[] result; + int i = 0; + if (receiverType != null) { + result = new JavaType[args + 1]; + result[0] = receiverType; + i = 1; + } else { + result = new JavaType[args]; + } + for (int j = 0; j < args; j++) { + result[i + j] = getParameterType(j, null); + } + return result; + } + + default JavaKind[] toParameterKinds(boolean receiver) { + int args = getParameterCount(false); + JavaKind[] result; + int i = 0; + if (receiver) { + result = new JavaKind[args + 1]; + result[0] = JavaKind.Object; + i = 1; + } else { + result = new JavaKind[args]; + } + for (int j = 0; j < args; j++) { + result[i + j] = getParameterKind(j); + } + return result; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java new file mode 100644 index 00000000000..57ed095a363 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; +import java.util.concurrent.*; + +/** + * Manages a list of unique deoptimization reasons. + * + */ +public abstract class SpeculationLog { + private volatile Object lastFailed; + private volatile Collection speculations; + private Set failedSpeculations; + + public synchronized void collectFailedSpeculations() { + if (lastFailed != null) { + if (failedSpeculations == null) { + failedSpeculations = new HashSet<>(2); + } + failedSpeculations.add(lastFailed); + lastFailed = null; + speculations = null; + } + } + + public boolean maySpeculate(Object reason) { + if (failedSpeculations != null && failedSpeculations.contains(reason)) { + return false; + } + return true; + } + + protected void addSpeculation(Object reason) { + assert maySpeculate(reason); + if (speculations == null) { + synchronized (this) { + if (speculations == null) { + speculations = new ConcurrentLinkedQueue<>(); + } + } + } + speculations.add(reason); + } + + public abstract JavaConstant speculate(Object reason); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TriState.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TriState.java new file mode 100644 index 00000000000..cf85e651067 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TriState.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Represents a logic value that can be either {@link #TRUE}, {@link #FALSE}, or {@link #UNKNOWN}. + */ +public enum TriState { + TRUE, + FALSE, + UNKNOWN; + + public static TriState get(boolean value) { + return value ? TRUE : FALSE; + } + + /** + * This is optimistic about {@link #UNKNOWN} (it prefers known values over {@link #UNKNOWN}) and + * pesimistic about known (it perfers {@link #TRUE} over {@link #FALSE}). + */ + public static TriState merge(TriState a, TriState b) { + if (a == TRUE || b == TRUE) { + return TRUE; + } + if (a == FALSE || b == FALSE) { + return FALSE; + } + assert a == UNKNOWN && b == UNKNOWN; + return UNKNOWN; + } + + public boolean isTrue() { + return this == TRUE; + } + + public boolean isFalse() { + return this == FALSE; + } + + public boolean isUnknown() { + return this == UNKNOWN; + } + + public boolean isKnown() { + return this != UNKNOWN; + } + + public boolean toBoolean() { + if (isTrue()) { + return true; + } else if (isFalse()) { + return false; + } else { + throw new IllegalStateException("Cannot convert to boolean, TriState is in an unknown state"); + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TrustedInterface.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TrustedInterface.java new file mode 100644 index 00000000000..ace5c0145bf --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TrustedInterface.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Interfaces extending this interface should be trusted by the compiler. See + * {@link ResolvedJavaType#isTrustedInterfaceType()}. + * + */ +public interface TrustedInterface { + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java new file mode 100644 index 00000000000..4b7cd4afa07 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public interface VMConstant extends Constant { +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Value.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Value.java new file mode 100644 index 00000000000..1e084abe80a --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Value.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Abstract base class for values. + */ +public abstract class Value { + + public static final Value[] NO_VALUES = new Value[0]; + + public static final AllocatableValue ILLEGAL = new IllegalValue(); + + private static final class IllegalValue extends AllocatableValue { + private IllegalValue() { + super(LIRKind.Illegal); + } + + @Override + public String toString() { + return "-"; + } + + @Override + public boolean equals(Object other) { + // Due to de-serialization this object may exist multiple times. So we compare classes + // instead of the individual objects. (This anonymous class has always the same meaning) + return other instanceof IllegalValue; + } + } + + private final LIRKind lirKind; + + /** + * Initializes a new value of the specified kind. + * + * @param lirKind the kind + */ + protected Value(LIRKind lirKind) { + this.lirKind = lirKind; + } + + /** + * Returns a String representation of the kind, which should be the end of all + * {@link #toString()} implementation of subclasses. + */ + protected final String getKindSuffix() { + return "|" + getPlatformKind().getTypeChar(); + } + + public final LIRKind getLIRKind() { + return lirKind; + } + + /** + * Returns the platform specific kind used to store this value. + */ + public final PlatformKind getPlatformKind() { + return lirKind.getPlatformKind(); + } + + @Override + public int hashCode() { + return 41 + lirKind.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Value) { + Value that = (Value) obj; + return lirKind.equals(that.lirKind); + } + return false; + } + + /** + * Checks if this value is identical to {@code other}. + * + * Warning: Use with caution! Usually equivalence {@link #equals(Object)} is sufficient and + * should be used. + */ + public final boolean identityEquals(Value other) { + return this == other; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/package-info.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/package-info.java new file mode 100644 index 00000000000..0b769e44202 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/package-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Package that defines the interface between a runtime and a Java application that wants to access meta information. The runtime + * provides an implementation of the {@link jdk.vm.ci.meta.MetaAccessProvider} interface. + */ +package jdk.vm.ci.meta; + diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/META-INF/services/javax.annotation.processing.Processor b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000000..3aab30fa3c7 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +jdk.vm.ci.options.processor.OptionProcessor diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/jdk/vm/ci/options/processor/OptionProcessor.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/jdk/vm/ci/options/processor/OptionProcessor.java new file mode 100644 index 00000000000..28153496314 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/jdk/vm/ci/options/processor/OptionProcessor.java @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options.processor; + +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import javax.tools.Diagnostic.Kind; + +import jdk.vm.ci.options.*; + +import javax.tools.*; + +/** + * Processes static fields annotated with {@link Option}. An {@link OptionDescriptors} + * implementation is generated for each top level class containing at least one such field. The name + * of the generated class for top level class {@code com.foo.Bar} is + * {@code com.foo.Bar_OptionDescriptors}. + */ +@SupportedAnnotationTypes({"jdk.vm.ci.options.Option"}) +public class OptionProcessor extends AbstractProcessor { + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + private final Set processed = new HashSet<>(); + + private void processElement(Element element, OptionsInfo info) { + + if (!element.getModifiers().contains(Modifier.STATIC)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element); + return; + } + + Option annotation = element.getAnnotation(Option.class); + assert annotation != null; + assert element instanceof VariableElement; + assert element.getKind() == ElementKind.FIELD; + VariableElement field = (VariableElement) element; + String fieldName = field.getSimpleName().toString(); + + Elements elements = processingEnv.getElementUtils(); + Types types = processingEnv.getTypeUtils(); + + TypeMirror fieldType = field.asType(); + if (fieldType.getKind() != TypeKind.DECLARED) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + OptionValue.class.getName(), element); + return; + } + DeclaredType declaredFieldType = (DeclaredType) fieldType; + + TypeMirror optionValueType = elements.getTypeElement(OptionValue.class.getName()).asType(); + if (!types.isSubtype(fieldType, types.erasure(optionValueType))) { + String msg = String.format("Option field type %s is not a subclass of %s", fieldType, optionValueType); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); + return; + } + + if (!field.getModifiers().contains(Modifier.STATIC)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element); + return; + } + + String help = annotation.help(); + if (help.length() != 0) { + char firstChar = help.charAt(0); + if (!Character.isUpperCase(firstChar)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with upper case letter", element); + return; + } + } + + String optionName = annotation.name(); + if (optionName.equals("")) { + optionName = fieldName; + } + + DeclaredType declaredOptionValueType = declaredFieldType; + while (!types.isSameType(types.erasure(declaredOptionValueType), types.erasure(optionValueType))) { + List directSupertypes = types.directSupertypes(declaredFieldType); + assert!directSupertypes.isEmpty(); + declaredOptionValueType = (DeclaredType) directSupertypes.get(0); + } + + assert!declaredOptionValueType.getTypeArguments().isEmpty(); + String optionType = declaredOptionValueType.getTypeArguments().get(0).toString(); + if (optionType.startsWith("java.lang.")) { + optionType = optionType.substring("java.lang.".length()); + } + + Element enclosing = element.getEnclosingElement(); + String declaringClass = ""; + String separator = ""; + Set originatingElementsList = info.originatingElements; + originatingElementsList.add(field); + while (enclosing != null) { + if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { + if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { + String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); + return; + } + originatingElementsList.add(enclosing); + declaringClass = enclosing.getSimpleName() + separator + declaringClass; + separator = "."; + } else { + assert enclosing.getKind() == ElementKind.PACKAGE; + } + enclosing = enclosing.getEnclosingElement(); + } + + info.options.add(new OptionInfo(optionName, help, optionType, declaringClass, field)); + } + + private void createFiles(OptionsInfo info) { + String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); + Name topDeclaringClass = info.topDeclaringType.getSimpleName(); + Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]); + + createOptionsDescriptorsFile(info, pkg, topDeclaringClass, originatingElements); + } + + private void createOptionsDescriptorsFile(OptionsInfo info, String pkg, Name topDeclaringClass, Element[] originatingElements) { + String optionsClassName = topDeclaringClass + "_" + OptionDescriptors.class.getSimpleName(); + + Filer filer = processingEnv.getFiler(); + try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) { + + out.println("// CheckStyle: stop header check"); + out.println("// CheckStyle: stop line length check"); + out.println("// GENERATED CONTENT - DO NOT EDIT"); + out.println("// Source: " + topDeclaringClass + ".java"); + out.println("package " + pkg + ";"); + out.println(""); + out.println("import java.util.*;"); + out.println("import " + OptionDescriptors.class.getPackage().getName() + ".*;"); + out.println(""); + out.println("public class " + optionsClassName + " implements " + OptionDescriptors.class.getSimpleName() + " {"); + + String desc = OptionDescriptor.class.getSimpleName(); + + boolean needPrivateFieldAccessor = false; + int i = 0; + Collections.sort(info.options); + + out.println(" @Override"); + out.println(" public OptionDescriptor get(String value) {"); + out.println(" // CheckStyle: stop line length check"); + if (info.options.size() == 1) { + out.println(" if (value.equals(\"" + info.options.get(0).name + "\")) {"); + } else { + out.println(" switch (value) {"); + } + for (OptionInfo option : info.options) { + String name = option.name; + String optionValue; + if (option.field.getModifiers().contains(Modifier.PRIVATE)) { + needPrivateFieldAccessor = true; + optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; + } else { + optionValue = option.declaringClass + "." + option.field.getSimpleName(); + } + String type = option.type; + String help = option.help; + String declaringClass = option.declaringClass; + Name fieldName = option.field.getSimpleName(); + if (info.options.size() == 1) { + out.printf(" return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionValue); + } else { + out.printf(" case \"" + name + "\": return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, + optionValue); + } + } + out.println(" }"); + out.println(" // CheckStyle: resume line length check"); + out.println(" return null;"); + out.println(" }"); + out.println(); + out.println(" @Override"); + out.println(" public Iterator<" + desc + "> iterator() {"); + out.println(" // CheckStyle: stop line length check"); + out.println(" List<" + desc + "> options = Arrays.asList("); + for (OptionInfo option : info.options) { + String optionValue; + if (option.field.getModifiers().contains(Modifier.PRIVATE)) { + needPrivateFieldAccessor = true; + optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; + } else { + optionValue = option.declaringClass + "." + option.field.getSimpleName(); + } + String name = option.name; + String type = option.type; + String help = option.help; + String declaringClass = option.declaringClass; + Name fieldName = option.field.getSimpleName(); + String comma = i == info.options.size() - 1 ? "" : ","; + out.printf(" %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s)%s\n", desc, name, type, help, declaringClass, fieldName, optionValue, comma); + i++; + } + out.println(" );"); + out.println(" // CheckStyle: resume line length check"); + out.println(" return options.iterator();"); + out.println(" }"); + if (needPrivateFieldAccessor) { + out.println(" private static " + OptionValue.class.getSimpleName() + " field(Class declaringClass, String fieldName) {"); + out.println(" try {"); + out.println(" java.lang.reflect.Field field = declaringClass.getDeclaredField(fieldName);"); + out.println(" field.setAccessible(true);"); + out.println(" return (" + OptionValue.class.getSimpleName() + ") field.get(null);"); + out.println(" } catch (Exception e) {"); + out.println(" throw (InternalError) new InternalError().initCause(e);"); + out.println(" }"); + out.println(" }"); + } + out.println("}"); + } + + try { + createOptionsFile(pkg, topDeclaringClass.toString(), originatingElements); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType); + } + } + + private void createOptionsFile(String pkg, String relativeName, Element... originatingElements) throws IOException { + String filename = "META-INF/jvmci.options/" + pkg + "." + relativeName; + FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, originatingElements); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8")); + writer.close(); + } + + protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) { + try { + // Ensure Unix line endings to comply with code style guide checked by Checkstyle + JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements); + return new PrintWriter(sourceFile.openWriter()) { + + @Override + public void println() { + print("\n"); + } + }; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + static class OptionInfo implements Comparable { + + final String name; + final String help; + final String type; + final String declaringClass; + final VariableElement field; + + public OptionInfo(String name, String help, String type, String declaringClass, VariableElement field) { + this.name = name; + this.help = help; + this.type = type; + this.declaringClass = declaringClass; + this.field = field; + } + + @Override + public int compareTo(OptionInfo other) { + return name.compareTo(other.name); + } + + @Override + public String toString() { + return declaringClass + "." + field; + } + } + + static class OptionsInfo { + + final Element topDeclaringType; + final List options = new ArrayList<>(); + final Set originatingElements = new HashSet<>(); + + public OptionsInfo(Element topDeclaringType) { + this.topDeclaringType = topDeclaringType; + } + } + + private static Element topDeclaringType(Element element) { + Element enclosing = element.getEnclosingElement(); + if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) { + assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE; + return element; + } + return topDeclaringType(enclosing); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return true; + } + + Map map = new HashMap<>(); + for (Element element : roundEnv.getElementsAnnotatedWith(Option.class)) { + if (!processed.contains(element)) { + processed.add(element); + Element topDeclaringType = topDeclaringType(element); + OptionsInfo options = map.get(topDeclaringType); + if (options == null) { + options = new OptionsInfo(topDeclaringType); + map.put(topDeclaringType, options); + } + processElement(element, options); + } + } + + boolean ok = true; + Map uniqueness = new HashMap<>(); + for (OptionsInfo info : map.values()) { + for (OptionInfo option : info.options) { + OptionInfo conflict = uniqueness.put(option.name, option); + if (conflict != null) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Duplicate option names for " + option + " and " + conflict, option.field); + ok = false; + } + } + } + + if (ok) { + for (OptionsInfo info : map.values()) { + createFiles(info); + } + } + + return true; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/DerivedOptionValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/DerivedOptionValue.java new file mode 100644 index 00000000000..267692a1c07 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/DerivedOptionValue.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +import java.io.*; +import java.util.function.*; + +import jdk.vm.ci.options.OptionValue.*; + +/** + * A cached value that needs to be recomputed when an option changes. + */ +public class DerivedOptionValue { + + public interface OptionSupplier extends Supplier, Serializable { + } + + private final T initialValue; + private final OptionSupplier supplier; + + public DerivedOptionValue(OptionSupplier supplier) { + this.supplier = supplier; + assert OptionValue.getOverrideScope() == null : "derived option value should be initialized outside any override scope"; + this.initialValue = createValue(); + } + + public T getValue() { + OverrideScope overrideScope = OptionValue.getOverrideScope(); + if (overrideScope != null) { + return overrideScope.getDerived(this); + } else { + return initialValue; + } + } + + T createValue() { + return supplier.get(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/JVMCIJarsOptionDescriptorsProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/JVMCIJarsOptionDescriptorsProvider.java new file mode 100644 index 00000000000..a3603a4323a --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/JVMCIJarsOptionDescriptorsProvider.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +import java.io.*; +import java.util.*; +import java.util.jar.*; +import java.util.zip.*; + +import jdk.vm.ci.options.OptionsParser.*; + +/** + * Access to the {@link OptionDescriptors} declared by + * {@code META-INF/services/jdk.vm.ci.options.OptionDescriptors} files in {@code + * /lib/jvmci/*.jar}. + */ +class JVMCIJarsOptionDescriptorsProvider implements OptionDescriptorsProvider { + + static final String OptionDescriptorsServiceFile = "META-INF/services/" + OptionDescriptors.class.getName(); + + private final Iterator jars; + private final List optionsDescriptorsList; + + JVMCIJarsOptionDescriptorsProvider() { + List jarsList = findJVMCIJars(); + this.jars = jarsList.iterator(); + this.optionsDescriptorsList = new ArrayList<>(jarsList.size() * 3); + } + + /** + * Finds the list of JVMCI jars. + */ + private static List findJVMCIJars() { + File javaHome = new File(System.getProperty("java.home")); + File lib = new File(javaHome, "lib"); + File jvmci = new File(lib, "jvmci"); + + List jarFiles = new ArrayList<>(); + if (jvmci.exists()) { + for (String fileName : jvmci.list()) { + if (fileName.endsWith(".jar")) { + File file = new File(jvmci, fileName); + if (file.isDirectory()) { + continue; + } + jarFiles.add(file); + } + } + } + return jarFiles; + } + + public OptionDescriptor get(String name) { + // Look up loaded option descriptors first + for (OptionDescriptors optionDescriptors : optionsDescriptorsList) { + OptionDescriptor desc = optionDescriptors.get(name); + if (desc != null) { + return desc; + } + } + while (jars.hasNext()) { + File path = jars.next(); + try (JarFile jar = new JarFile(path)) { + ZipEntry entry = jar.getEntry(OptionDescriptorsServiceFile); + if (entry != null) { + BufferedReader br = new BufferedReader(new InputStreamReader(jar.getInputStream(entry))); + String line = null; + OptionDescriptor desc = null; + while ((line = br.readLine()) != null) { + OptionDescriptors options; + try { + options = (OptionDescriptors) Class.forName(line).newInstance(); + optionsDescriptorsList.add(options); + if (desc == null) { + desc = options.get(name); + } + } catch (Exception e) { + throw new InternalError("Error instantiating class " + line + " read from " + path, e); + } + } + if (desc != null) { + return desc; + } + } + } catch (IOException e) { + throw new InternalError("Error reading " + path, e); + } + } + return null; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/NestedBooleanOptionValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/NestedBooleanOptionValue.java new file mode 100644 index 00000000000..ffbaf4d0bd6 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/NestedBooleanOptionValue.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +/** + * A nested Boolean {@link OptionValue} that can be overridden by a {@link #masterOption master + * option}. + *

+ *

  • If the option is present on the command line the specified value is used. + *
  • Otherwise {@link #getValue()} depends on the {@link #masterOption} and evaluates as follows: + *
      + *
    • If {@link #masterOption} is set, this value equals to {@link #initialValue}. + *
    • Otherwise, if {@link #masterOption} is {@code false}, this option is {@code false}. + */ +public class NestedBooleanOptionValue extends OptionValue { + private final OptionValue masterOption; + private final Boolean initialValue; + + public NestedBooleanOptionValue(OptionValue masterOption, Boolean initialValue) { + super(null); + this.masterOption = masterOption; + this.initialValue = initialValue; + } + + public OptionValue getMasterOption() { + return masterOption; + } + + @Override + public Boolean getValue() { + Boolean v = super.getValue(); + if (v == null) { + return initialValue && masterOption.getValue(); + } + return v; + } + +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/Option.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/Option.java new file mode 100644 index 00000000000..5a9f920a198 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/Option.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +import java.lang.annotation.*; + +/** + * Describes the attributes of an option whose {@link OptionValue value} is in a static field + * annotated by this annotation type. + * + * @see OptionDescriptor + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.FIELD) +public @interface Option { + + /** + * Gets a help message for the option. New lines can be embedded in the message with + * {@code "%n"}. + */ + String help(); + + /** + * The name of the option. By default, the name of the annotated field should be used. + */ + String name() default ""; + + /** + * Specifies the type of the option. + */ + OptionType type() default OptionType.Debug; +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptor.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptor.java new file mode 100644 index 00000000000..b0bde8a71e0 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptor.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +/** + * Describes the attributes of a static field {@linkplain Option option} and provides access to its + * {@linkplain OptionValue value}. + */ +public final class OptionDescriptor { + + protected final String name; + protected final Class type; + protected final String help; + protected final OptionValue option; + protected final Class declaringClass; + protected final String fieldName; + + public static OptionDescriptor create(String name, Class type, String help, Class declaringClass, String fieldName, OptionValue option) { + OptionDescriptor result = option.getDescriptor(); + if (result == null) { + result = new OptionDescriptor(name, type, help, declaringClass, fieldName, option); + option.setDescriptor(result); + } + assert result.name.equals(name) && result.type == type && result.declaringClass == declaringClass && result.fieldName.equals(fieldName) && result.option == option; + return result; + } + + private OptionDescriptor(String name, Class type, String help, Class declaringClass, String fieldName, OptionValue option) { + this.name = name; + this.type = type; + this.help = help; + this.option = option; + this.declaringClass = declaringClass; + this.fieldName = fieldName; + assert !type.isPrimitive() : "must used boxed type instead of " + type; + } + + /** + * Gets the type of values stored in the option. This will be the boxed type for a primitive + * option. + */ + public Class getType() { + return type; + } + + /** + * Gets a descriptive help message for the option. + */ + public String getHelp() { + return help; + } + + /** + * Gets the name of the option. It's up to the client of this object how to use the name to get + * a user specified value for the option from the environment. + */ + public String getName() { + return name; + } + + /** + * Gets the boxed option value. + */ + public OptionValue getOptionValue() { + return option; + } + + public Class getDeclaringClass() { + return declaringClass; + } + + public String getFieldName() { + return fieldName; + } + + /** + * Gets a description of the location where this option is stored. + */ + public String getLocation() { + return getDeclaringClass().getName() + "." + getFieldName(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptors.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptors.java new file mode 100644 index 00000000000..a2aef68e95e --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptors.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +/** + * An interface to a set of {@link OptionDescriptor}s. + */ +public interface OptionDescriptors extends Iterable { + /** + * Gets the {@link OptionDescriptor} matching a given option name or {@code null} if this option + * descriptor set doesn't contain a matching option. + */ + OptionDescriptor get(String value); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionType.java new file mode 100644 index 00000000000..d30ac8db430 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionType.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +/** + * Classifies JVMCI options in several categories depending on who this option is relevant for. + * + */ +public enum OptionType { + /** + * An option common for users to apply. + */ + User, + + /** + * An option only relevant in corner cases and for fine-tuning. + */ + Expert, + + /** + * An option only relevant when debugging the compiler. + */ + Debug +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionValue.java new file mode 100644 index 00000000000..343edb1d113 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionValue.java @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +import java.io.*; +import java.util.*; +import java.util.Map.Entry; + +/** + * An option value. + */ +public class OptionValue { + /** + * Temporarily changes the value for an option. The {@linkplain OptionValue#getValue() value} of + * {@code option} is set to {@code value} until {@link OverrideScope#close()} is called on the + * object returned by this method. + *

      + * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be + * used: + * + *

      +     * try (OverrideScope s = OptionValue.override(myOption, myValue) {
      +     *     // code that depends on myOption == myValue
      +     * }
      +     * 
      + */ + public static OverrideScope override(OptionValue option, Object value) { + OverrideScope current = getOverrideScope(); + if (current == null) { + if (!value.equals(option.getValue())) { + return new SingleOverrideScope(option, value); + } + Map, Object> overrides = Collections.emptyMap(); + return new MultipleOverridesScope(current, overrides); + } + return new MultipleOverridesScope(current, option, value); + } + + /** + * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue() + * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value} + * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by + * this method. + *

      + * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be + * used: + * + *

      +     * Map<OptionValue, Object> overrides = new HashMap<>();
      +     * overrides.put(myOption1, myValue1);
      +     * overrides.put(myOption2, myValue2);
      +     * try (OverrideScope s = OptionValue.override(overrides) {
      +     *     // code that depends on myOption == myValue
      +     * }
      +     * 
      + */ + public static OverrideScope override(Map, Object> overrides) { + OverrideScope current = getOverrideScope(); + if (current == null && overrides.size() == 1) { + Entry, Object> single = overrides.entrySet().iterator().next(); + OptionValue option = single.getKey(); + Object overrideValue = single.getValue(); + if (!overrideValue.equals(option.getValue())) { + return new SingleOverrideScope(option, overrideValue); + } + } + return new MultipleOverridesScope(current, overrides); + } + + /** + * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue() + * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value} + * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by + * this method. + *

      + * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be + * used: + * + *

      +     * try (OverrideScope s = OptionValue.override(myOption1, myValue1, myOption2, myValue2) {
      +     *     // code that depends on myOption == myValue
      +     * }
      +     * 
      + * + * @param overrides overrides in the form {@code [option1, override1, option2, override2, ...]} + */ + public static OverrideScope override(Object... overrides) { + OverrideScope current = getOverrideScope(); + if (current == null && overrides.length == 2) { + OptionValue option = (OptionValue) overrides[0]; + Object overrideValue = overrides[1]; + if (!overrideValue.equals(option.getValue())) { + return new SingleOverrideScope(option, overrideValue); + } + } + Map, Object> map = Collections.emptyMap(); + for (int i = 0; i < overrides.length; i += 2) { + OptionValue option = (OptionValue) overrides[i]; + Object overrideValue = overrides[i + 1]; + if (!overrideValue.equals(option.getValue())) { + if (map.isEmpty()) { + map = new HashMap<>(); + } + map.put(option, overrideValue); + } + } + return new MultipleOverridesScope(current, map); + } + + private static final ThreadLocal overrideScopeTL = new ThreadLocal<>(); + + protected static OverrideScope getOverrideScope() { + return overrideScopeTL.get(); + } + + protected static void setOverrideScope(OverrideScope overrideScope) { + overrideScopeTL.set(overrideScope); + } + + private T defaultValue; + + /** + * The raw option value. + */ + protected T value; + + private OptionDescriptor descriptor; + + private long reads; + private OptionValue next; + private static OptionValue head; + + private static final boolean ShowReadsHistogram = Boolean.getBoolean("jvmci.showOptionValueReadsHistogram"); + + private static void addToHistogram(OptionValue option) { + if (ShowReadsHistogram) { + synchronized (OptionValue.class) { + option.next = head; + head = option; + } + } + } + + @SuppressWarnings("unchecked") + public OptionValue(T value) { + this.defaultValue = value; + this.value = (T) DEFAULT; + addToHistogram(this); + } + + private static final Object DEFAULT = "DEFAULT"; + private static final Object UNINITIALIZED = "UNINITIALIZED"; + + /** + * Creates an uninitialized option value for a subclass that initializes itself + * {@link #defaultValue() lazily}. + */ + @SuppressWarnings("unchecked") + protected OptionValue() { + this.defaultValue = (T) UNINITIALIZED; + this.value = (T) DEFAULT; + addToHistogram(this); + } + + /** + * Lazy initialization of default value. + */ + protected T defaultValue() { + throw new InternalError("Option without a default value value must override defaultValue()"); + } + + /** + * Sets the descriptor for this option. + */ + public void setDescriptor(OptionDescriptor descriptor) { + assert this.descriptor == null : "Overwriting existing descriptor"; + this.descriptor = descriptor; + } + + /** + * Returns the descriptor for this option, if it has been set by + * {@link #setDescriptor(OptionDescriptor)}. + */ + public OptionDescriptor getDescriptor() { + return descriptor; + } + + /** + * Gets the name of this option. The name for an option value with a null + * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is the value of + * {@link Object#toString()}. + */ + public String getName() { + return descriptor == null ? super.toString() : (descriptor.getDeclaringClass().getName() + "." + descriptor.getName()); + } + + @Override + public String toString() { + return getName() + "=" + getValue(); + } + + /** + * The initial value specified in source code. The returned value is not affected by calls to + * {@link #setValue(Object)} or registering {@link OverrideScope}s. Therefore, it is also not + * affected by options set on the command line. + */ + public T getDefaultValue() { + if (defaultValue == UNINITIALIZED) { + defaultValue = defaultValue(); + } + return defaultValue; + } + + /** + * Returns true if the option has the same value that was set in the source code. + */ + public boolean hasDefaultValue() { + if (!(this instanceof StableOptionValue)) { + getValue(); // ensure initialized + } + return value == DEFAULT || Objects.equals(value, getDefaultValue()); + } + + /** + * Gets the value of this option. + */ + public T getValue() { + if (ShowReadsHistogram) { + reads++; + } + if (!(this instanceof StableOptionValue)) { + OverrideScope overrideScope = getOverrideScope(); + if (overrideScope != null) { + T override = overrideScope.getOverride(this); + if (override != null) { + return override; + } + } + } + if (value != DEFAULT) { + return value; + } else { + return getDefaultValue(); + } + } + + /** + * Gets the values of this option including overridden values. + * + * @param c the collection to which the values are added. If null, one is allocated. + * @return the collection to which the values were added in order from most overridden to + * current value + */ + @SuppressWarnings("unchecked") + public Collection getValues(Collection c) { + Collection values = c == null ? new ArrayList<>() : c; + if (!(this instanceof StableOptionValue)) { + OverrideScope overrideScope = getOverrideScope(); + if (overrideScope != null) { + overrideScope.getOverrides(this, (Collection) values); + } + } + if (value != DEFAULT) { + values.add(value); + } else { + values.add(getDefaultValue()); + } + return values; + } + + /** + * Sets the value of this option. + */ + @SuppressWarnings("unchecked") + public void setValue(Object v) { + this.value = (T) v; + } + + /** + * An object whose {@link #close()} method reverts the option value overriding initiated by + * {@link OptionValue#override(OptionValue, Object)} or {@link OptionValue#override(Map)}. + */ + public abstract static class OverrideScope implements AutoCloseable { + + private Map, Object> derivedCache = null; + + public T getDerived(DerivedOptionValue key) { + if (derivedCache == null) { + derivedCache = new HashMap<>(); + } + @SuppressWarnings("unchecked") + T ret = (T) derivedCache.get(key); + if (ret == null) { + ret = key.createValue(); + derivedCache.put(key, ret); + } + return ret; + } + + abstract void addToInherited(Map, Object> inherited); + + abstract T getOverride(OptionValue option); + + abstract void getOverrides(OptionValue option, Collection c); + + public abstract void close(); + } + + static class SingleOverrideScope extends OverrideScope { + + private final OptionValue option; + private final Object value; + + public SingleOverrideScope(OptionValue option, Object value) { + if (option instanceof StableOptionValue) { + throw new IllegalArgumentException("Cannot override stable option " + option); + } + this.option = option; + this.value = value; + setOverrideScope(this); + } + + @Override + void addToInherited(Map, Object> inherited) { + inherited.put(option, value); + } + + @SuppressWarnings("unchecked") + @Override + T getOverride(OptionValue key) { + if (key == this.option) { + return (T) value; + } + return null; + } + + @Override + void getOverrides(OptionValue key, Collection c) { + if (key == this.option) { + c.add(value); + } + } + + @Override + public void close() { + setOverrideScope(null); + } + } + + static class MultipleOverridesScope extends OverrideScope { + final OverrideScope parent; + final Map, Object> overrides; + + public MultipleOverridesScope(OverrideScope parent, OptionValue option, Object value) { + this.parent = parent; + this.overrides = new HashMap<>(); + if (parent != null) { + parent.addToInherited(overrides); + } + if (option instanceof StableOptionValue) { + throw new IllegalArgumentException("Cannot override stable option " + option); + } + if (!value.equals(option.getValue())) { + this.overrides.put(option, value); + } + if (!overrides.isEmpty()) { + setOverrideScope(this); + } + } + + MultipleOverridesScope(OverrideScope parent, Map, Object> overrides) { + this.parent = parent; + if (overrides.isEmpty() && parent == null) { + this.overrides = Collections.emptyMap(); + return; + } + this.overrides = new HashMap<>(); + if (parent != null) { + parent.addToInherited(this.overrides); + } + for (Map.Entry, Object> e : overrides.entrySet()) { + OptionValue option = e.getKey(); + if (option instanceof StableOptionValue) { + throw new IllegalArgumentException("Cannot override stable option " + option); + } + if (!e.getValue().equals(option.getValue())) { + this.overrides.put(option, e.getValue()); + } + } + if (!this.overrides.isEmpty()) { + setOverrideScope(this); + } + } + + @Override + void addToInherited(Map, Object> inherited) { + if (parent != null) { + parent.addToInherited(inherited); + } + inherited.putAll(overrides); + } + + @SuppressWarnings("unchecked") + @Override + T getOverride(OptionValue option) { + return (T) overrides.get(option); + } + + @Override + void getOverrides(OptionValue option, Collection c) { + Object v = overrides.get(option); + if (v != null) { + c.add(v); + } + if (parent != null) { + parent.getOverrides(option, c); + } + } + + @Override + public void close() { + if (!overrides.isEmpty()) { + setOverrideScope(parent); + } + } + } + + static { + if (ShowReadsHistogram) { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + ArrayList> options = new ArrayList<>(); + for (OptionValue option = head; option != null; option = option.next) { + options.add(option); + } + Collections.sort(options, new Comparator>() { + + public int compare(OptionValue o1, OptionValue o2) { + if (o1.reads < o2.reads) { + return -1; + } else if (o1.reads > o2.reads) { + return 1; + } else { + return o1.getName().compareTo(o2.getName()); + } + } + }); + PrintStream out = System.out; + out.println("=== OptionValue reads histogram ==="); + for (OptionValue option : options) { + out.println(option.reads + "\t" + option); + } + } + }); + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsLoader.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsLoader.java new file mode 100644 index 00000000000..62cb9c80831 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsLoader.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +import java.util.*; + +/** + * Helper class used to load option descriptors. Only to be used in the slow-path. + */ +public class OptionsLoader { + public static final SortedMap options = new TreeMap<>(); + + /** + * Initializes {@link #options} from {@link Options} services. + */ + static { + for (OptionDescriptors opts : ServiceLoader.load(OptionDescriptors.class, OptionsLoader.class.getClassLoader())) { + for (OptionDescriptor desc : opts) { + String name = desc.getName(); + OptionDescriptor existing = options.put(name, desc); + assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation(); + } + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsParser.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsParser.java new file mode 100644 index 00000000000..59893978ae0 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsParser.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +import static jdk.vm.ci.inittimer.InitTimer.*; + +import java.io.*; +import java.util.*; + +import jdk.vm.ci.inittimer.*; + +/** + * This class contains methods for parsing JVMCI options and matching them against a set of + * {@link OptionDescriptors}. The {@link OptionDescriptors} are loaded from JVMCI jars, either + * {@linkplain JVMCIJarsOptionDescriptorsProvider directly} or via a {@link ServiceLoader}. + */ +public class OptionsParser { + + private static final OptionValue PrintFlags = new OptionValue<>(false); + + /** + * A service for looking up {@link OptionDescriptor}s. + */ + public interface OptionDescriptorsProvider { + /** + * Gets the {@link OptionDescriptor} matching a given option {@linkplain Option#name() name} + * or null if no option of that name is provided by this object. + */ + OptionDescriptor get(String name); + } + + public interface OptionConsumer { + void set(OptionDescriptor desc, Object value); + } + + /** + * Parses the options in {@code /lib/jvmci/options} if {@code parseOptionsFile == true} and + * the file exists followed by the JVMCI options in {@code options} if {@code options != null}. + * + * Called from VM. This method has an object return type to allow it to be called with a VM + * utility function used to call other static initialization methods. + * + * @param options JVMCI options as serialized (name, value) pairs + * @param parseOptionsFile specifies whether to look for and parse + * {@code /lib/jvmci/options} + */ + @SuppressWarnings("try") + public static Boolean parseOptionsFromVM(String[] options, boolean parseOptionsFile) { + try (InitTimer t = timer("ParseOptions")) { + JVMCIJarsOptionDescriptorsProvider odp = new JVMCIJarsOptionDescriptorsProvider(); + + if (parseOptionsFile) { + File javaHome = new File(System.getProperty("java.home")); + File lib = new File(javaHome, "lib"); + File jvmci = new File(lib, "jvmci"); + File jvmciOptions = new File(jvmci, "options"); + if (jvmciOptions.exists()) { + try (BufferedReader br = new BufferedReader(new FileReader(jvmciOptions))) { + String optionSetting = null; + int lineNo = 1; + while ((optionSetting = br.readLine()) != null) { + if (!optionSetting.isEmpty() && optionSetting.charAt(0) != '#') { + try { + parseOptionSetting(optionSetting, null, odp); + } catch (Throwable e) { + throw new InternalError("Error parsing " + jvmciOptions + ", line " + lineNo, e); + } + } + lineNo++; + } + } catch (IOException e) { + throw new InternalError("Error reading " + jvmciOptions, e); + } + } + } + + if (options != null) { + assert options.length % 2 == 0; + for (int i = 0; i < options.length / 2; i++) { + String name = options[i * 2]; + String value = options[i * 2 + 1]; + parseOption(OptionsLoader.options, name, value, null, odp); + } + } + } + return Boolean.TRUE; + } + + /** + * Parses a given option setting. + * + * @param optionSetting a string matching the pattern {@code =} + * @param setter the object to notify of the parsed option and value + */ + public static void parseOptionSetting(String optionSetting, OptionConsumer setter, OptionDescriptorsProvider odp) { + int eqIndex = optionSetting.indexOf('='); + if (eqIndex == -1) { + throw new InternalError("Option setting has does not match the pattern =: " + optionSetting); + } + String name = optionSetting.substring(0, eqIndex); + String value = optionSetting.substring(eqIndex + 1); + parseOption(OptionsLoader.options, name, value, setter, odp); + } + + /** + * Parses a given option name and value. + * + * @param options + * @param name the option name + * @param valueString the option value as a string + * @param setter the object to notify of the parsed option and value + * @param odp + * + * @throws IllegalArgumentException if there's a problem parsing {@code option} + */ + public static void parseOption(SortedMap options, String name, String valueString, OptionConsumer setter, OptionDescriptorsProvider odp) { + OptionDescriptor desc = options.get(name); + if (desc == null && odp != null) { + desc = odp.get(name); + } + if (desc == null && name.equals("PrintFlags")) { + desc = OptionDescriptor.create("PrintFlags", Boolean.class, "Prints all JVMCI flags and exits", OptionsParser.class, "PrintFlags", PrintFlags); + } + if (desc == null) { + List matches = fuzzyMatch(options, name); + Formatter msg = new Formatter(); + msg.format("Could not find option %s", name); + if (!matches.isEmpty()) { + msg.format("%nDid you mean one of the following?"); + for (OptionDescriptor match : matches) { + msg.format("%n %s=", match.getName()); + } + } + throw new IllegalArgumentException(msg.toString()); + } + + Class optionType = desc.getType(); + Object value; + if (optionType == Boolean.class) { + if ("true".equals(valueString)) { + value = Boolean.TRUE; + } else if ("false".equals(valueString)) { + value = Boolean.FALSE; + } else { + throw new IllegalArgumentException("Boolean option '" + name + "' must have value \"true\" or \"false\", not \"" + valueString + "\""); + } + } else if (optionType == Float.class) { + value = Float.parseFloat(valueString); + } else if (optionType == Double.class) { + value = Double.parseDouble(valueString); + } else if (optionType == Integer.class) { + value = Integer.valueOf((int) parseLong(valueString)); + } else if (optionType == Long.class) { + value = Long.valueOf(parseLong(valueString)); + } else if (optionType == String.class) { + value = valueString; + } else { + throw new IllegalArgumentException("Wrong value for option '" + name + "'"); + } + if (setter == null) { + desc.getOptionValue().setValue(value); + } else { + setter.set(desc, value); + } + + if (PrintFlags.getValue()) { + printFlags(options, "JVMCI", System.out); + System.exit(0); + } + } + + private static long parseLong(String v) { + String valueString = v.toLowerCase(); + long scale = 1; + if (valueString.endsWith("k")) { + scale = 1024L; + } else if (valueString.endsWith("m")) { + scale = 1024L * 1024L; + } else if (valueString.endsWith("g")) { + scale = 1024L * 1024L * 1024L; + } else if (valueString.endsWith("t")) { + scale = 1024L * 1024L * 1024L * 1024L; + } + + if (scale != 1) { + /* Remove trailing scale character. */ + valueString = valueString.substring(0, valueString.length() - 1); + } + + return Long.parseLong(valueString) * scale; + } + + /** + * Wraps some given text to one or more lines of a given maximum width. + * + * @param text text to wrap + * @param width maximum width of an output line, exception for words in {@code text} longer than + * this value + * @return {@code text} broken into lines + */ + private static List wrap(String text, int width) { + List lines = Collections.singletonList(text); + if (text.length() > width) { + String[] chunks = text.split("\\s+"); + lines = new ArrayList<>(); + StringBuilder line = new StringBuilder(); + for (String chunk : chunks) { + if (line.length() + chunk.length() > width) { + lines.add(line.toString()); + line.setLength(0); + } + if (line.length() != 0) { + line.append(' '); + } + String[] embeddedLines = chunk.split("%n", -2); + if (embeddedLines.length == 1) { + line.append(chunk); + } else { + for (int i = 0; i < embeddedLines.length; i++) { + line.append(embeddedLines[i]); + if (i < embeddedLines.length - 1) { + lines.add(line.toString()); + line.setLength(0); + } + } + } + } + if (line.length() != 0) { + lines.add(line.toString()); + } + } + return lines; + } + + public static void printFlags(SortedMap sortedOptions, String prefix, PrintStream out) { + out.println("[List of " + prefix + " options]"); + for (Map.Entry e : sortedOptions.entrySet()) { + e.getKey(); + OptionDescriptor desc = e.getValue(); + Object value = desc.getOptionValue().getValue(); + List helpLines = wrap(desc.getHelp(), 70); + out.println(String.format("%9s %-40s = %-14s %s", desc.getType().getSimpleName(), e.getKey(), value, helpLines.get(0))); + for (int i = 1; i < helpLines.size(); i++) { + out.println(String.format("%67s %s", " ", helpLines.get(i))); + } + } + } + + /** + * Compute string similarity based on Dice's coefficient. + * + * Ported from str_similar() in globals.cpp. + */ + static float stringSimiliarity(String str1, String str2) { + int hit = 0; + for (int i = 0; i < str1.length() - 1; ++i) { + for (int j = 0; j < str2.length() - 1; ++j) { + if ((str1.charAt(i) == str2.charAt(j)) && (str1.charAt(i + 1) == str2.charAt(j + 1))) { + ++hit; + break; + } + } + } + return 2.0f * hit / (str1.length() + str2.length()); + } + + private static final float FUZZY_MATCH_THRESHOLD = 0.7F; + + /** + * Returns the set of options that fuzzy match a given option name. + */ + private static List fuzzyMatch(SortedMap options, String optionName) { + List matches = new ArrayList<>(); + for (Map.Entry e : options.entrySet()) { + float score = stringSimiliarity(e.getKey(), optionName); + if (score >= FUZZY_MATCH_THRESHOLD) { + matches.add(e.getValue()); + } + } + return matches; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/StableOptionValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/StableOptionValue.java new file mode 100644 index 00000000000..533e5002b47 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/StableOptionValue.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +/** + * An option that always returns the same {@linkplain #getValue() value}. + */ +public class StableOptionValue extends OptionValue { + + /** + * Creates a stable option value. + */ + public StableOptionValue(T value) { + super(value); + } + + /** + * Used to assert the invariant for stability. Without using locks, this check is not safe + * against races and so it's only an assertion. + */ + private boolean getValueCalled; + + /** + * Creates an uninitialized stable option value for a subclass that initializes itself + * {@link #defaultValue() lazily}. + */ + public StableOptionValue() { + } + + /** + * Gets the value of this option. + */ + @Override + public final T getValue() { + T result = super.getValue(); + assert initGetValueCalled(); + return result; + } + + private boolean initGetValueCalled() { + getValueCalled = true; + return true; + } + + /** + * {@inheritDoc} + *

      + * This must only be called if {@link #getValue()} has never been called. + */ + @Override + public final void setValue(Object v) { + assert !getValueCalled; + super.setValue(v); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCI.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCI.java new file mode 100644 index 00000000000..886702a5485 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCI.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.runtime; + +import java.util.*; + +public class JVMCI { + + private static final JVMCIRuntime runtime; + + private static native JVMCIRuntime initializeRuntime(); + + public static void initialize() { + // force static initializer + } + + /** + * Gets the singleton {@link JVMCIRuntime} instance available to the application. + * + * @throws UnsupportedOperationException if JVMCI is not supported + */ + public static JVMCIRuntime getRuntime() { + if (runtime == null) { + String javaHome = System.getProperty("java.home"); + String vmName = System.getProperty("java.vm.name"); + Formatter errorMessage = new Formatter(); + errorMessage.format("The VM does not support the JVMCI API.%n"); + errorMessage.format("Currently used Java home directory is %s.%n", javaHome); + errorMessage.format("Currently used VM configuration is: %s", vmName); + throw new UnsupportedOperationException(errorMessage.toString()); + } + return runtime; + } + + static { + JVMCIRuntime rt = null; + try { + rt = initializeRuntime(); + } catch (UnsatisfiedLinkError e) { + } + runtime = rt; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIBackend.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIBackend.java new file mode 100644 index 00000000000..98b02cf4cca --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIBackend.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.runtime; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.meta.*; + +/** + * A JVMCI backend encapsulates the capabilities needed by a Java based compiler for compiling and + * installing code for a single compute unit within a JVM. In a JVM with support for heterogeneous + * computing, more than one backend may be exposed. + */ +public class JVMCIBackend { + + private final MetaAccessProvider metaAccess; + private final CodeCacheProvider codeCache; + private final ConstantReflectionProvider constantReflection; + + public JVMCIBackend(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ConstantReflectionProvider constantReflection) { + this.metaAccess = metaAccess; + this.codeCache = codeCache; + this.constantReflection = constantReflection; + } + + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + public CodeCacheProvider getCodeCache() { + return codeCache; + } + + public ConstantReflectionProvider getConstantReflection() { + return constantReflection; + } + + public TargetDescription getTarget() { + return codeCache.getTarget(); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIRuntime.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIRuntime.java new file mode 100644 index 00000000000..960a1d62e53 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIRuntime.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.runtime; + +import jdk.vm.ci.code.*; + +/** + * Interface for accessing the {@link JVMCI} APIs supported by the runtime. + */ +public interface JVMCIRuntime { + + /** + * Gets the host JVMCI backend. + */ + JVMCIBackend getHostJVMCIBackend(); + + /** + * Gets the backend for a given architecture. + * + * @param arch a specific architecture class + */ + JVMCIBackend getJVMCIBackend(Class arch); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service.processor/src/META-INF/services/javax.annotation.processing.Processor b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service.processor/src/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000000..72506df9cb8 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service.processor/src/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +jdk.vm.ci.service.processor.ServiceProviderProcessor diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service.processor/src/jdk/vm/ci/service/processor/ServiceProviderProcessor.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service.processor/src/jdk/vm/ci/service/processor/ServiceProviderProcessor.java new file mode 100644 index 00000000000..4b027c3c0bb --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service.processor/src/jdk/vm/ci/service/processor/ServiceProviderProcessor.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.service.processor; + +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.tools.Diagnostic.Kind; + +import jdk.vm.ci.service.*; + +import javax.tools.*; + +@SupportedAnnotationTypes("jdk.vm.ci.service.ServiceProvider") +public class ServiceProviderProcessor extends AbstractProcessor { + + private final Set processed = new HashSet<>(); + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + private boolean verifyAnnotation(TypeMirror serviceInterface, TypeElement serviceProvider) { + if (!processingEnv.getTypeUtils().isSubtype(serviceProvider.asType(), serviceInterface)) { + String msg = String.format("Service provider class %s must implement service interface %s", serviceProvider.getSimpleName(), serviceInterface); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider); + return false; + } + + return true; + } + + private void processElement(TypeElement serviceProvider) { + if (processed.contains(serviceProvider)) { + return; + } + + processed.add(serviceProvider); + ServiceProvider annotation = serviceProvider.getAnnotation(ServiceProvider.class); + if (annotation != null) { + try { + annotation.value(); + } catch (MirroredTypeException ex) { + TypeMirror serviceInterface = ex.getTypeMirror(); + if (verifyAnnotation(serviceInterface, serviceProvider)) { + String interfaceName = ex.getTypeMirror().toString(); + createProviderFile(serviceProvider, interfaceName); + } + } + } + } + + private void createProviderFile(TypeElement serviceProvider, String interfaceName) { + if (serviceProvider.getNestingKind().isNested()) { + // This is a simplifying constraint that means we don't have to + // processed the qualified name to insert '$' characters at + // the relevant positions. + String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider); + return; + } + + String filename = "META-INF/jvmci.providers/" + serviceProvider.getQualifiedName(); + try { + FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, serviceProvider); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8")); + writer.println(interfaceName); + writer.close(); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), serviceProvider); + } + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return true; + } + + for (Element element : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) { + assert element.getKind().isClass(); + processElement((TypeElement) element); + } + + return true; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/.checkstyle_checks.xml b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/.checkstyle_checks.xml new file mode 100644 index 00000000000..4ae5b12b06a --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/.checkstyle_checks.xml @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/src/jdk/vm/ci/service/ServiceProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/src/jdk/vm/ci/service/ServiceProvider.java new file mode 100644 index 00000000000..0263d5afd59 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/src/jdk/vm/ci/service/ServiceProvider.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.service; + +import java.lang.annotation.*; + +/** + * Annotates a service provider than can be loaded via {@linkplain Services#load(Class)} or + * {@link Services#loadSingle(Class, boolean)}. + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface ServiceProvider { + + Class value(); +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/src/jdk/vm/ci/service/Services.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/src/jdk/vm/ci/service/Services.java new file mode 100644 index 00000000000..6b574badf24 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/src/jdk/vm/ci/service/Services.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.service; + +import java.util.*; + +/** + * A mechanism for accessing service providers via JVMCI. + */ +public final class Services { + + private Services() { + } + + /** + * Gets an {@link Iterable} of the JVMCI providers available for a given service. + */ + public static Iterable load(Class service) { + return ServiceLoader.load(service); + } + + /** + * Gets the JVMCI provider for a given service for which at most one provider must be available. + * + * @param service the service whose provider is being requested + * @param required specifies if an {@link InternalError} should be thrown if no provider of + * {@code service} is available + */ + public static S loadSingle(Class service, boolean required) { + Iterable providers = ServiceLoader.load(service); + S singleProvider = null; + try { + for (Iterator it = providers.iterator(); it.hasNext();) { + singleProvider = it.next(); + if (it.hasNext()) { + throw new InternalError(String.format("Multiple %s providers found", service.getName())); + } + } + } catch (ServiceConfigurationError e) { + // If the service is required we will bail out below. + } + if (singleProvider == null && required) { + String javaHome = System.getProperty("java.home"); + String vmName = System.getProperty("java.vm.name"); + Formatter errorMessage = new Formatter(); + errorMessage.format("The VM does not expose required service %s.%n", service.getName()); + errorMessage.format("Currently used Java home directory is %s.%n", javaHome); + errorMessage.format("Currently used VM configuration is: %s", vmName); + throw new UnsupportedOperationException(errorMessage.toString()); + } + return singleProvider; + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java new file mode 100644 index 00000000000..a68c68e6adb --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.sparc; + +import static java.nio.ByteOrder.*; +import static jdk.vm.ci.code.MemoryBarriers.*; + +import java.util.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.meta.*; + +/** + * Represents the SPARC architecture. + */ +public class SPARC extends Architecture { + + public static final RegisterCategory CPU = new RegisterCategory("CPU"); + + // General purpose registers + public static final Register r0 = new Register(0, 0, "g0", CPU); + public static final Register r1 = new Register(1, 1, "g1", CPU); + public static final Register r2 = new Register(2, 2, "g2", CPU); + public static final Register r3 = new Register(3, 3, "g3", CPU); + public static final Register r4 = new Register(4, 4, "g4", CPU); + public static final Register r5 = new Register(5, 5, "g5", CPU); + public static final Register r6 = new Register(6, 6, "g6", CPU); + public static final Register r7 = new Register(7, 7, "g7", CPU); + + public static final Register r8 = new Register(8, 8, "o0", CPU); + public static final Register r9 = new Register(9, 9, "o1", CPU); + public static final Register r10 = new Register(10, 10, "o2", CPU); + public static final Register r11 = new Register(11, 11, "o3", CPU); + public static final Register r12 = new Register(12, 12, "o4", CPU); + public static final Register r13 = new Register(13, 13, "o5", CPU); + public static final Register r14 = new Register(14, 14, "o6", CPU); + public static final Register r15 = new Register(15, 15, "o7", CPU); + + public static final Register r16 = new Register(16, 16, "l0", CPU); + public static final Register r17 = new Register(17, 17, "l1", CPU); + public static final Register r18 = new Register(18, 18, "l2", CPU); + public static final Register r19 = new Register(19, 19, "l3", CPU); + public static final Register r20 = new Register(20, 20, "l4", CPU); + public static final Register r21 = new Register(21, 21, "l5", CPU); + public static final Register r22 = new Register(22, 22, "l6", CPU); + public static final Register r23 = new Register(23, 23, "l7", CPU); + + public static final Register r24 = new Register(24, 24, "i0", CPU); + public static final Register r25 = new Register(25, 25, "i1", CPU); + public static final Register r26 = new Register(26, 26, "i2", CPU); + public static final Register r27 = new Register(27, 27, "i3", CPU); + public static final Register r28 = new Register(28, 28, "i4", CPU); + public static final Register r29 = new Register(29, 29, "i5", CPU); + public static final Register r30 = new Register(30, 30, "i6", CPU); + public static final Register r31 = new Register(31, 31, "i7", CPU); + + public static final Register g0 = r0; + public static final Register g1 = r1; + public static final Register g2 = r2; + public static final Register g3 = r3; + public static final Register g4 = r4; + public static final Register g5 = r5; + public static final Register g6 = r6; + public static final Register g7 = r7; + + public static final Register o0 = r8; + public static final Register o1 = r9; + public static final Register o2 = r10; + public static final Register o3 = r11; + public static final Register o4 = r12; + public static final Register o5 = r13; + public static final Register o6 = r14; + public static final Register o7 = r15; + + public static final Register l0 = r16; + public static final Register l1 = r17; + public static final Register l2 = r18; + public static final Register l3 = r19; + public static final Register l4 = r20; + public static final Register l5 = r21; + public static final Register l6 = r22; + public static final Register l7 = r23; + + public static final Register i0 = r24; + public static final Register i1 = r25; + public static final Register i2 = r26; + public static final Register i3 = r27; + public static final Register i4 = r28; + public static final Register i5 = r29; + public static final Register i6 = r30; + public static final Register i7 = r31; + + public static final Register sp = o6; + public static final Register fp = i6; + + // @formatter:off + public static final Register[] cpuRegisters = { + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15, + r16, r17, r18, r19, r20, r21, r22, r23, + r24, r25, r26, r27, r28, r29, r30, r31 + }; + // @formatter:on + + public static final RegisterCategory FPUs = new RegisterCategory("FPUs", cpuRegisters.length); + public static final RegisterCategory FPUd = new RegisterCategory("FPUd", cpuRegisters.length + 32); + + // Floating point registers + public static final Register f0 = new Register(32, 0, "f0", FPUs); + public static final Register f1 = new Register(33, 1, "f1", FPUs); + public static final Register f2 = new Register(34, 2, "f2", FPUs); + public static final Register f3 = new Register(35, 3, "f3", FPUs); + public static final Register f4 = new Register(36, 4, "f4", FPUs); + public static final Register f5 = new Register(37, 5, "f5", FPUs); + public static final Register f6 = new Register(38, 6, "f6", FPUs); + public static final Register f7 = new Register(39, 7, "f7", FPUs); + + public static final Register f8 = new Register(40, 8, "f8", FPUs); + public static final Register f9 = new Register(41, 9, "f9", FPUs); + public static final Register f10 = new Register(42, 10, "f10", FPUs); + public static final Register f11 = new Register(43, 11, "f11", FPUs); + public static final Register f12 = new Register(44, 12, "f12", FPUs); + public static final Register f13 = new Register(45, 13, "f13", FPUs); + public static final Register f14 = new Register(46, 14, "f14", FPUs); + public static final Register f15 = new Register(47, 15, "f15", FPUs); + + public static final Register f16 = new Register(48, 16, "f16", FPUs); + public static final Register f17 = new Register(49, 17, "f17", FPUs); + public static final Register f18 = new Register(50, 18, "f18", FPUs); + public static final Register f19 = new Register(51, 19, "f19", FPUs); + public static final Register f20 = new Register(52, 20, "f20", FPUs); + public static final Register f21 = new Register(53, 21, "f21", FPUs); + public static final Register f22 = new Register(54, 22, "f22", FPUs); + public static final Register f23 = new Register(55, 23, "f23", FPUs); + + public static final Register f24 = new Register(56, 24, "f24", FPUs); + public static final Register f25 = new Register(57, 25, "f25", FPUs); + public static final Register f26 = new Register(58, 26, "f26", FPUs); + public static final Register f27 = new Register(59, 27, "f27", FPUs); + public static final Register f28 = new Register(60, 28, "f28", FPUs); + public static final Register f29 = new Register(61, 29, "f29", FPUs); + public static final Register f30 = new Register(62, 30, "f30", FPUs); + public static final Register f31 = new Register(63, 31, "f31", FPUs); + + public static final Register d0 = new Register(32, getDoubleEncoding(0), "d0", FPUs); + public static final Register d2 = new Register(34, getDoubleEncoding(2), "d2", FPUs); + public static final Register d4 = new Register(36, getDoubleEncoding(4), "d4", FPUs); + public static final Register d6 = new Register(38, getDoubleEncoding(6), "d6", FPUs); + public static final Register d8 = new Register(40, getDoubleEncoding(8), "d8", FPUs); + public static final Register d10 = new Register(42, getDoubleEncoding(10), "d10", FPUs); + public static final Register d12 = new Register(44, getDoubleEncoding(12), "d12", FPUs); + public static final Register d14 = new Register(46, getDoubleEncoding(14), "d14", FPUs); + + public static final Register d16 = new Register(48, getDoubleEncoding(16), "d16", FPUs); + public static final Register d18 = new Register(50, getDoubleEncoding(18), "d18", FPUs); + public static final Register d20 = new Register(52, getDoubleEncoding(20), "d20", FPUs); + public static final Register d22 = new Register(54, getDoubleEncoding(22), "d22", FPUs); + public static final Register d24 = new Register(56, getDoubleEncoding(24), "d24", FPUs); + public static final Register d26 = new Register(58, getDoubleEncoding(26), "d26", FPUs); + public static final Register d28 = new Register(60, getDoubleEncoding(28), "d28", FPUs); + public static final Register d30 = new Register(62, getDoubleEncoding(28), "d28", FPUs); + + public static final Register d32 = new Register(64, getDoubleEncoding(32), "d32", FPUd); + public static final Register d34 = new Register(65, getDoubleEncoding(34), "d34", FPUd); + public static final Register d36 = new Register(66, getDoubleEncoding(36), "d36", FPUd); + public static final Register d38 = new Register(67, getDoubleEncoding(38), "d38", FPUd); + public static final Register d40 = new Register(68, getDoubleEncoding(40), "d40", FPUd); + public static final Register d42 = new Register(69, getDoubleEncoding(42), "d42", FPUd); + public static final Register d44 = new Register(70, getDoubleEncoding(44), "d44", FPUd); + public static final Register d46 = new Register(71, getDoubleEncoding(46), "d46", FPUd); + + public static final Register d48 = new Register(72, getDoubleEncoding(48), "d48", FPUd); + public static final Register d50 = new Register(73, getDoubleEncoding(50), "d50", FPUd); + public static final Register d52 = new Register(74, getDoubleEncoding(52), "d52", FPUd); + public static final Register d54 = new Register(75, getDoubleEncoding(54), "d54", FPUd); + public static final Register d56 = new Register(76, getDoubleEncoding(56), "d56", FPUd); + public static final Register d58 = new Register(77, getDoubleEncoding(58), "d58", FPUd); + public static final Register d60 = new Register(78, getDoubleEncoding(60), "d60", FPUd); + public static final Register d62 = new Register(79, getDoubleEncoding(62), "d62", FPUd); + + // @formatter:off + public static final Register[] fpuRegisters = { + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + + // @formatter:off + public static final Register[] allRegisters = { + // CPU + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15, + r16, r17, r18, r19, r20, r21, r22, r23, + r24, r25, r26, r27, r28, r29, r30, r31, + // FPU + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + + /** + * Stack bias for stack and frame pointer loads. + */ + public static final int STACK_BIAS = 0x7ff; + /** + * In fact there are 64 single floating point registers, 32 of them could be accessed. TODO: + * Improve handling of these float registers + */ + public static final int FLOAT_REGISTER_COUNT = 64; + + /** + * Alignment for valid memory access. + */ + public static final int MEMORY_ACCESS_ALIGN = 4; + + public static final int INSTRUCTION_SIZE = 4; + + /** + * Size to keep free for flushing the register-window to stack. + */ + public static final int REGISTER_SAFE_AREA_SIZE = 128; + + public final Set features; + + public SPARC(Set features) { + super("SPARC", JavaKind.Long, BIG_ENDIAN, false, allRegisters, LOAD_LOAD | LOAD_STORE | STORE_STORE, 1, r31.encoding + FLOAT_REGISTER_COUNT + 1, 8); + this.features = features; + } + + @Override + public boolean canStoreValue(RegisterCategory category, PlatformKind lirKind) { + if (!(lirKind instanceof JavaKind)) { + return false; + } + + JavaKind kind = (JavaKind) lirKind; + if (category.equals(CPU)) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + return true; + } + } else if (category.equals(FPUs) && kind.equals(JavaKind.Float)) { + return true; + } else if (category.equals(FPUd) && kind.equals(JavaKind.Double)) { + return true; + } + return false; + } + + @Override + public PlatformKind getLargestStorableKind(RegisterCategory category) { + if (category.equals(CPU)) { + return JavaKind.Long; + } else if (category.equals(FPUd)) { + return JavaKind.Double; + } else if (category.equals(FPUs)) { + return JavaKind.Float; + } else { + return JavaKind.Illegal; + } + } + + @Override + public PlatformKind getPlatformKind(JavaKind javaKind) { + if (javaKind.isObject()) { + return JavaKind.Long; + } else { + return javaKind; + } + } + + public static int spillSlotSize(TargetDescription td, PlatformKind kind) { + return Math.max(td.getSizeInBytes(kind), MEMORY_ACCESS_ALIGN); + } + + public static int getDoubleEncoding(int reg) { + assert reg < 64 && ((reg & 1) == 0); + // ignore v8 assertion for now + return (reg & 0x1e) | ((reg & 0x20) >> 5); + } + + public static boolean isCPURegister(Register r) { + return r.getRegisterCategory().equals(CPU); + } + + public static boolean isCPURegister(Register... regs) { + for (Register reg : regs) { + if (!isCPURegister(reg)) { + return false; + } + } + return true; + } + + public static boolean isGlobalRegister(Register r) { + return isCPURegister(r) && g0.number <= r.number && r.number <= g7.number; + } + + public static boolean isSingleFloatRegister(Register r) { + return r.name.startsWith("f"); + } + + public static boolean isDoubleFloatRegister(Register r) { + return r.name.startsWith("d"); + } + + public Set getFeatures() { + return features; + } + + public boolean hasFeature(CPUFeature feature) { + return features.contains(feature); + } + + public enum CPUFeature { + VIS1, + VIS2, + VIS3, + CBCOND, + BLOCK_ZEROING + } +} diff --git a/hotspot/src/os/aix/vm/globals_aix.hpp b/hotspot/src/os/aix/vm/globals_aix.hpp index b002e51bcd8..ef12d703159 100644 --- a/hotspot/src/os/aix/vm/globals_aix.hpp +++ b/hotspot/src/os/aix/vm/globals_aix.hpp @@ -39,15 +39,16 @@ /* a scarce resource and there may be situations where we do not want the VM */ \ /* to run with 16M pages. (Will fall back to 64K pages). */ \ product_pd(bool, Use16MPages, \ - "Use 16M pages if available.") \ + "Use 16M pages if available.") \ \ /* use optimized addresses for the polling page, */ \ /* e.g. map it to a special 32-bit address. */ \ product_pd(bool, OptimizePollingPageLocation, \ - "Optimize the location of the polling page used for Safepoints") \ + "Optimize the location of the polling page used for Safepoints") \ \ product_pd(intx, AttachListenerTimeout, \ - "Timeout in ms the attach listener waits for a request") \ + "Timeout in ms the attach listener waits for a request") \ + range(0, 2147483) \ \ // Per default, do not allow 16M pages. 16M pages have to be switched on specifically. diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index f2c3933f35f..fb3ea648414 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -2286,7 +2286,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, if (!pd_commit_memory(addr, size, exec)) { // Add extra info in product mode for vm_exit_out_of_memory(): PRODUCT_ONLY(warn_fail_commit_memory(addr, size, exec, errno);) - vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "%s", mesg); } } @@ -3120,8 +3120,8 @@ void os::Aix::set_signal_handler(int sig, bool set_installed) { // libjsig also interposes the sigaction() call below and saves the // old sigaction on it own. } else { - fatal(err_msg("Encountered unexpected pre-existing sigaction handler " - "%#lx for signal %d.", (long)oldhand, sig)); + fatal("Encountered unexpected pre-existing sigaction handler " + "%#lx for signal %d.", (long)oldhand, sig); } } @@ -3699,7 +3699,7 @@ void os::make_polling_page_unreadable(void) { void os::make_polling_page_readable(void) { // Changed according to os_linux.cpp. if (!checked_mprotect((char *)_polling_page, Aix::page_size(), PROT_READ)) { - fatal(err_msg("Could not enable polling page at " PTR_FORMAT, _polling_page)); + fatal("Could not enable polling page at " PTR_FORMAT, _polling_page); } }; diff --git a/hotspot/src/os/aix/vm/vmError_aix.cpp b/hotspot/src/os/aix/vm/vmError_aix.cpp index e7c48971588..cfa88dbe4f7 100644 --- a/hotspot/src/os/aix/vm/vmError_aix.cpp +++ b/hotspot/src/os/aix/vm/vmError_aix.cpp @@ -117,8 +117,7 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { return; } - VMError err(NULL, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(NULL, sig, pc, info, ucVoid); } void VMError::reset_signal_handlers() { diff --git a/hotspot/src/os/aix/vm/vmStructs_aix.hpp b/hotspot/src/os/aix/vm/vmStructs_aix.hpp new file mode 100644 index 00000000000..d86287d94c2 --- /dev/null +++ b/hotspot/src/os/aix/vm/vmStructs_aix.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_AIX_VM_VMSTRUCTS_AIX_HPP +#define OS_AIX_VM_VMSTRUCTS_AIX_HPP + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) + +#endif // OS_AIX_VM_VMSTRUCTS_AIX_HPP diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 1c243ae387f..cce3906e0c9 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -128,8 +128,6 @@ #define LARGEPAGES_BIT (1 << 6) -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - //////////////////////////////////////////////////////////////////////////////// // global variables julong os::Bsd::_physical_memory = 0; @@ -1977,7 +1975,7 @@ static const char* sem_init_strerror(kern_return_t value) { OSXSemaphore::OSXSemaphore(uint value) { kern_return_t ret = SEM_INIT(_semaphore, value); - guarantee(ret == KERN_SUCCESS, err_msg("Failed to create semaphore: %s", sem_init_strerror(ret))); + guarantee(ret == KERN_SUCCESS, "Failed to create semaphore: %s", sem_init_strerror(ret)); } OSXSemaphore::~OSXSemaphore() { @@ -2213,7 +2211,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, if (!pd_commit_memory(addr, size, exec)) { // add extra info in product mode for vm_exit_out_of_memory(): PRODUCT_ONLY(warn_fail_commit_memory(addr, size, exec, errno);) - vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "%s", mesg); } } @@ -3100,8 +3098,8 @@ void os::Bsd::set_signal_handler(int sig, bool set_installed) { // libjsig also interposes the sigaction() call below and saves the // old sigaction on it own. } else { - fatal(err_msg("Encountered unexpected pre-existing sigaction handler " - "%#lx for signal %d.", (long)oldhand, sig)); + fatal("Encountered unexpected pre-existing sigaction handler " + "%#lx for signal %d.", (long)oldhand, sig); } } @@ -3459,8 +3457,7 @@ void os::init(void) { Bsd::set_page_size(getpagesize()); if (Bsd::page_size() == -1) { - fatal(err_msg("os_bsd.cpp: os::init: sysconf failed (%s)", - strerror(errno))); + fatal("os_bsd.cpp: os::init: sysconf failed (%s)", strerror(errno)); } init_page_sizes((size_t) Bsd::page_size()); diff --git a/hotspot/src/os/bsd/vm/vmError_bsd.cpp b/hotspot/src/os/bsd/vm/vmError_bsd.cpp index 388f4858d88..1b34a701276 100644 --- a/hotspot/src/os/bsd/vm/vmError_bsd.cpp +++ b/hotspot/src/os/bsd/vm/vmError_bsd.cpp @@ -121,8 +121,7 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { return; } - VMError err(NULL, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(NULL, sig, pc, info, ucVoid); } void VMError::reset_signal_handlers() { diff --git a/hotspot/src/os/bsd/vm/vmStructs_bsd.hpp b/hotspot/src/os/bsd/vm/vmStructs_bsd.hpp new file mode 100644 index 00000000000..7e35c42e2bf --- /dev/null +++ b/hotspot/src/os/bsd/vm/vmStructs_bsd.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_BSD_VM_VMSTRUCTS_BSD_HPP +#define OS_BSD_VM_VMSTRUCTS_BSD_HPP + +#include + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ + declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) + +#endif // OS_BSD_VM_VMSTRUCTS_BSD_HPP diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 5ddf9ac53af..05d1850d52e 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -106,8 +106,6 @@ # include # include -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // if RUSAGE_THREAD for getrusage() has not been defined, do it here. The code calling // getrusage() is prepared to handle the associated failure. #ifndef RUSAGE_THREAD @@ -1969,7 +1967,8 @@ int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *pa char name[PATH_MAX + 1]; // Parse fields from line - sscanf(line, "%lx-%lx %4s %lx %5s %ld %s", &base, &top, permissions, &offset, device, &inode, name); + sscanf(line, UINT64_FORMAT_X "-" UINT64_FORMAT_X " %4s " UINT64_FORMAT_X " %5s " INT64_FORMAT " %s", + &base, &top, permissions, &offset, device, &inode, name); // Filter by device id '00:00' so that we only get file system mapped files. if (strcmp(device, "00:00") != 0) { @@ -2632,7 +2631,7 @@ static bool recoverable_mmap_error(int err) { static void warn_fail_commit_memory(char* addr, size_t size, bool exec, int err) { warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT - ", %d) failed; error='%s' (errno=%d)", addr, size, exec, + ", %d) failed; error='%s' (errno=%d)", p2i(addr), size, exec, strerror(err), err); } @@ -2640,7 +2639,7 @@ static void warn_fail_commit_memory(char* addr, size_t size, size_t alignment_hint, bool exec, int err) { warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT - ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, size, + ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", p2i(addr), size, alignment_hint, exec, strerror(err), err); } @@ -2680,7 +2679,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, if (err != 0) { // the caller wants all commit errors to exit with the specified mesg: warn_fail_commit_memory(addr, size, exec, err); - vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "%s", mesg); } } @@ -2716,7 +2715,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, if (err != 0) { // the caller wants all commit errors to exit with the specified mesg: warn_fail_commit_memory(addr, size, alignment_hint, exec, err); - vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "%s", mesg); } } @@ -4278,8 +4277,8 @@ void os::Linux::set_signal_handler(int sig, bool set_installed) { // libjsig also interposes the sigaction() call below and saves the // old sigaction on it own. } else { - fatal(err_msg("Encountered unexpected pre-existing sigaction handler " - "%#lx for signal %d.", (long)oldhand, sig)); + fatal("Encountered unexpected pre-existing sigaction handler " + "%#lx for signal %d.", (long)oldhand, sig); } } @@ -4611,8 +4610,8 @@ void os::init(void) { Linux::set_page_size(sysconf(_SC_PAGESIZE)); if (Linux::page_size() == -1) { - fatal(err_msg("os_linux.cpp: os::init: sysconf failed (%s)", - strerror(errno))); + fatal("os_linux.cpp: os::init: sysconf failed (%s)", + strerror(errno)); } init_page_sizes((size_t) Linux::page_size()); @@ -4628,7 +4627,7 @@ void os::init(void) { int status; pthread_condattr_t* _condattr = os::Linux::condAttr(); if ((status = pthread_condattr_init(_condattr)) != 0) { - fatal(err_msg("pthread_condattr_init: %s", strerror(status))); + fatal("pthread_condattr_init: %s", strerror(status)); } // Only set the clock if CLOCK_MONOTONIC is available if (os::supports_monotonic_clock()) { @@ -4637,7 +4636,7 @@ void os::init(void) { warning("Unable to use monotonic clock with relative timed-waits" \ " - changes to the time-of-day clock may have adverse affects"); } else { - fatal(err_msg("pthread_condattr_setclock: %s", strerror(status))); + fatal("pthread_condattr_setclock: %s", strerror(status)); } } } @@ -4717,7 +4716,7 @@ jint os::init_2(void) { if (threadStackSizeInBytes != 0 && threadStackSizeInBytes < os::Linux::min_stack_allowed) { tty->print_cr("\nThe stack size specified is too small, " - "Specify at least %dk", + "Specify at least " SIZE_FORMAT "k", os::Linux::min_stack_allowed/ K); return JNI_ERR; } @@ -4918,12 +4917,12 @@ bool os::find(address addr, outputStream* st) { Dl_info dlinfo; memset(&dlinfo, 0, sizeof(dlinfo)); if (dladdr(addr, &dlinfo) != 0) { - st->print(PTR_FORMAT ": ", addr); + st->print(PTR_FORMAT ": ", p2i(addr)); if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) { - st->print("%s+%#x", dlinfo.dli_sname, - addr - (intptr_t)dlinfo.dli_saddr); + st->print("%s+" PTR_FORMAT, dlinfo.dli_sname, + p2i(addr) - p2i(dlinfo.dli_saddr)); } else if (dlinfo.dli_fbase != NULL) { - st->print("", addr - (intptr_t)dlinfo.dli_fbase); + st->print("", p2i(addr) - p2i(dlinfo.dli_fbase)); } else { st->print(""); } @@ -4931,7 +4930,7 @@ bool os::find(address addr, outputStream* st) { st->print(" in %s", dlinfo.dli_fname); } if (dlinfo.dli_fbase != NULL) { - st->print(" at " PTR_FORMAT, dlinfo.dli_fbase); + st->print(" at " PTR_FORMAT, p2i(dlinfo.dli_fbase)); } st->cr(); @@ -5323,7 +5322,7 @@ int os::loadavg(double loadavg[], int nelem) { void os::pause() { char filename[MAX_PATH]; if (PauseAtStartupFile && PauseAtStartupFile[0]) { - jio_snprintf(filename, MAX_PATH, PauseAtStartupFile); + jio_snprintf(filename, MAX_PATH, "%s", PauseAtStartupFile); } else { jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id()); } @@ -5959,7 +5958,7 @@ int os::get_core_path(char* buffer, size_t bufferSize) { int written; if (core_pattern[0] == '/') { - written = jio_snprintf(buffer, bufferSize, core_pattern); + written = jio_snprintf(buffer, bufferSize, "%s", core_pattern); } else { char cwd[PATH_MAX]; @@ -6095,7 +6094,7 @@ class TestReserveMemorySpecial : AllStatic { for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) { char* p = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, NULL, false); test_log(SIZE_FORMAT_HEX " " SIZE_FORMAT_HEX " -> " PTR_FORMAT " %s", - size, alignment, p, (p != NULL ? "" : "(failed)")); + size, alignment, p2i(p), (p != NULL ? "" : "(failed)")); if (p != NULL) { assert(is_ptr_aligned(p, alignment), "must be"); small_page_write(p, size); @@ -6114,8 +6113,8 @@ class TestReserveMemorySpecial : AllStatic { char* const req_addr = (char*) align_ptr_up(mapping1, alignment); char* p = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, req_addr, false); test_log(SIZE_FORMAT_HEX " " SIZE_FORMAT_HEX " " PTR_FORMAT " -> " PTR_FORMAT " %s", - size, alignment, req_addr, p, - ((p != NULL ? (p == req_addr ? "(exact match)" : "") : "(failed)"))); + size, alignment, p2i(req_addr), p2i(p), + ((p != NULL ? (p == req_addr ? "(exact match)" : "") : "(failed)"))); if (p != NULL) { assert(p == req_addr, "must be"); small_page_write(p, size); @@ -6134,8 +6133,7 @@ class TestReserveMemorySpecial : AllStatic { char* const req_addr = (char*) align_ptr_up(mapping2, alignment); char* p = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, req_addr, false); test_log(SIZE_FORMAT_HEX " " SIZE_FORMAT_HEX " " PTR_FORMAT " -> " PTR_FORMAT " %s", - size, alignment, req_addr, p, - ((p != NULL ? "" : "(failed)"))); + size, alignment, p2i(req_addr), p2i(p), ((p != NULL ? "" : "(failed)"))); // as the area around req_addr contains already existing mappings, the API should always // return NULL (as per contract, it cannot return another address) assert(p == NULL, "must be"); diff --git a/hotspot/src/os/linux/vm/vmError_linux.cpp b/hotspot/src/os/linux/vm/vmError_linux.cpp index f1d8e56b83c..4d684db2c8e 100644 --- a/hotspot/src/os/linux/vm/vmError_linux.cpp +++ b/hotspot/src/os/linux/vm/vmError_linux.cpp @@ -121,8 +121,7 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { return; } - VMError err(NULL, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(NULL, sig, pc, info, ucVoid); } void VMError::reset_signal_handlers() { diff --git a/hotspot/src/os/linux/vm/vmStructs_linux.hpp b/hotspot/src/os/linux/vm/vmStructs_linux.hpp new file mode 100644 index 00000000000..d9ac4dc9ec8 --- /dev/null +++ b/hotspot/src/os/linux/vm/vmStructs_linux.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_LINUX_VM_VMSTRUCTS_LINUX_HPP +#define OS_LINUX_VM_VMSTRUCTS_LINUX_HPP + +#include + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ + declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) + +#endif // OS_LINUX_VM_VMSTRUCTS_LINUX_HPP diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index 075c8f58cea..e30554cb10d 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -38,8 +38,6 @@ #include #include -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Todo: provide a os::get_max_process_id() or similar. Number of processes // may have been configured, can be read more accurately from proc fs etc. #ifndef MAX_PID @@ -194,30 +192,30 @@ void os::Posix::print_rlimit_info(outputStream* st) { st->print(" STACK "); getrlimit(RLIMIT_STACK, &rlim); if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity"); - else st->print("%uk", rlim.rlim_cur >> 10); + else st->print("%luk", rlim.rlim_cur >> 10); st->print(", CORE "); getrlimit(RLIMIT_CORE, &rlim); if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity"); - else st->print("%uk", rlim.rlim_cur >> 10); + else st->print("%luk", rlim.rlim_cur >> 10); // Isn't there on solaris #if !defined(TARGET_OS_FAMILY_solaris) && !defined(TARGET_OS_FAMILY_aix) st->print(", NPROC "); getrlimit(RLIMIT_NPROC, &rlim); if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity"); - else st->print("%d", rlim.rlim_cur); + else st->print("%lu", rlim.rlim_cur); #endif st->print(", NOFILE "); getrlimit(RLIMIT_NOFILE, &rlim); if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity"); - else st->print("%d", rlim.rlim_cur); + else st->print("%lu", rlim.rlim_cur); st->print(", AS "); getrlimit(RLIMIT_AS, &rlim); if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity"); - else st->print("%uk", rlim.rlim_cur >> 10); + else st->print("%luk", rlim.rlim_cur >> 10); st->cr(); } @@ -961,7 +959,7 @@ void os::Posix::print_siginfo_brief(outputStream* os, const siginfo_t* si) { } } else if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGTRAP || sig == SIGFPE) { - os->print(", si_addr: " PTR_FORMAT, si->si_addr); + os->print(", si_addr: " PTR_FORMAT, p2i(si->si_addr)); #ifdef SIGPOLL } else if (sig == SIGPOLL) { os->print(", si_band: " PTR64_FORMAT, (uint64_t)si->si_band); @@ -1027,10 +1025,10 @@ void os::WatcherThreadCrashProtection::check_crash_protection(int sig, } } -#define check_with_errno(check_type, cond, msg) \ - do { \ - int err = errno; \ - check_type(cond, err_msg("%s; error='%s' (errno=%d)", msg, strerror(err), err)); \ +#define check_with_errno(check_type, cond, msg) \ + do { \ + int err = errno; \ + check_type(cond, "%s; error='%s' (errno=%d)", msg, strerror(err), err); \ } while (false) #define assert_with_errno(cond, msg) check_with_errno(assert, cond, msg) diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index e5b68dafb15..2f5172da6b8 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1118,8 +1118,7 @@ sigset_t* os::Solaris::allowdebug_blocked_signals() { void _handle_uncaught_cxx_exception() { - VMError err("An uncaught C++ exception"); - err.report_and_die(); + VMError::report_and_die("An uncaught C++ exception"); } @@ -1330,7 +1329,7 @@ jlong getTimeMillis() { jlong os::javaTimeMillis() { timeval t; if (gettimeofday(&t, NULL) == -1) { - fatal(err_msg("os::javaTimeMillis: gettimeofday (%s)", strerror(errno))); + fatal("os::javaTimeMillis: gettimeofday (%s)", strerror(errno)); } return jlong(t.tv_sec) * 1000 + jlong(t.tv_usec) / 1000; } @@ -1338,7 +1337,7 @@ jlong os::javaTimeMillis() { void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { timeval t; if (gettimeofday(&t, NULL) == -1) { - fatal(err_msg("os::javaTimeSystemUTC: gettimeofday (%s)", strerror(errno))); + fatal("os::javaTimeSystemUTC: gettimeofday (%s)", strerror(errno)); } seconds = jlong(t.tv_sec); nanos = jlong(t.tv_usec) * 1000; @@ -2392,14 +2391,14 @@ void os::pd_commit_memory_or_exit(char* addr, size_t bytes, bool exec, if (err != 0) { // the caller wants all commit errors to exit with the specified mesg: warn_fail_commit_memory(addr, bytes, exec, err); - vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg); } } size_t os::Solaris::page_size_for_alignment(size_t alignment) { assert(is_size_aligned(alignment, (size_t) vm_page_size()), - err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, - alignment, (size_t) vm_page_size())); + SIZE_FORMAT " is not aligned to " SIZE_FORMAT, + alignment, (size_t) vm_page_size()); for (int i = 0; _page_sizes[i] != 0; i++) { if (is_size_aligned(alignment, _page_sizes[i])) { @@ -2415,7 +2414,7 @@ int os::Solaris::commit_memory_impl(char* addr, size_t bytes, int err = Solaris::commit_memory_impl(addr, bytes, exec); if (err == 0 && UseLargePages && alignment_hint > 0) { assert(is_size_aligned(bytes, alignment_hint), - err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint)); + SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint); // The syscall memcntl requires an exact page size (see man memcntl for details). size_t page_size = page_size_for_alignment(alignment_hint); @@ -2439,7 +2438,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t bytes, if (err != 0) { // the caller wants all commit errors to exit with the specified mesg: warn_fail_commit_memory(addr, bytes, alignment_hint, exec, err); - vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg); } } @@ -2969,11 +2968,11 @@ bool os::Solaris::is_valid_page_size(size_t bytes) { } bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) { - assert(is_valid_page_size(align), err_msg(SIZE_FORMAT " is not a valid page size", align)); + assert(is_valid_page_size(align), SIZE_FORMAT " is not a valid page size", align); assert(is_ptr_aligned((void*) start, align), - err_msg(PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align)); + PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align); assert(is_size_aligned(bytes, align), - err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align)); + SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align); // Signal to OS that we want large pages for addresses // from addr, addr + bytes @@ -3956,8 +3955,8 @@ void os::Solaris::set_signal_handler(int sig, bool set_installed, // libjsig also interposes the sigaction() call below and saves the // old sigaction on it own. } else { - fatal(err_msg("Encountered unexpected pre-existing sigaction handler " - "%#lx for signal %d.", (long)oldhand, sig)); + fatal("Encountered unexpected pre-existing sigaction handler " + "%#lx for signal %d.", (long)oldhand, sig); } } @@ -4403,8 +4402,7 @@ void os::init(void) { page_size = sysconf(_SC_PAGESIZE); if (page_size == -1) { - fatal(err_msg("os_solaris.cpp: os::init: sysconf failed (%s)", - strerror(errno))); + fatal("os_solaris.cpp: os::init: sysconf failed (%s)", strerror(errno)); } init_page_sizes((size_t) page_size); @@ -4416,7 +4414,7 @@ void os::init(void) { int fd = ::open("/dev/zero", O_RDWR); if (fd < 0) { - fatal(err_msg("os::init: cannot open /dev/zero (%s)", strerror(errno))); + fatal("os::init: cannot open /dev/zero (%s)", strerror(errno)); } else { Solaris::set_dev_zero_fd(fd); diff --git a/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp b/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp index b87e7b45c29..509c845636a 100644 --- a/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp +++ b/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp @@ -48,8 +48,8 @@ ThreadCritical::ThreadCritical() { thread_t owner = thr_self(); if (global_mut_owner != owner) { if (os::Solaris::mutex_lock(&global_mut)) - fatal(err_msg("ThreadCritical::ThreadCritical: mutex_lock failed (%s)", - strerror(errno))); + fatal("ThreadCritical::ThreadCritical: mutex_lock failed (%s)", + strerror(errno)); assert(global_mut_count == 0, "must have clean count"); assert(global_mut_owner == -1, "must have clean owner"); } @@ -68,8 +68,7 @@ ThreadCritical::~ThreadCritical() { if (global_mut_count == 0) { global_mut_owner = -1; if (os::Solaris::mutex_unlock(&global_mut)) - fatal(err_msg("ThreadCritical::~ThreadCritical: mutex_unlock failed " - "(%s)", strerror(errno))); + fatal("ThreadCritical::~ThreadCritical: mutex_unlock failed (%s)", strerror(errno)); } } else { assert (Threads::number_of_threads() == 0, "valid only during initialization"); diff --git a/hotspot/src/os/solaris/vm/vmError_solaris.cpp b/hotspot/src/os/solaris/vm/vmError_solaris.cpp index 57a3e1d84eb..8358801854e 100644 --- a/hotspot/src/os/solaris/vm/vmError_solaris.cpp +++ b/hotspot/src/os/solaris/vm/vmError_solaris.cpp @@ -117,8 +117,7 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { return; } - VMError err(NULL, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(NULL, sig, pc, info, ucVoid); } void VMError::reset_signal_handlers() { diff --git a/hotspot/src/os/solaris/vm/vmStructs_solaris.hpp b/hotspot/src/os/solaris/vm/vmStructs_solaris.hpp new file mode 100644 index 00000000000..c8ba51b502f --- /dev/null +++ b/hotspot/src/os/solaris/vm/vmStructs_solaris.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_SOLARIS_VM_VMSTRUCTS_SOLARIS_HPP +#define OS_SOLARIS_VM_VMSTRUCTS_SOLARIS_HPP + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + declare_unsigned_integer_type(OSThread::thread_id_t) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) + +#endif // OS_SOLARIS_VM_VMSTRUCTS_SOLARIS_HPP diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index b193f3c3eee..697b5bebdaf 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -823,7 +823,7 @@ jlong offset() { java_origin.wMilliseconds = 0; FILETIME jot; if (!SystemTimeToFileTime(&java_origin, &jot)) { - fatal(err_msg("Error = %d\nWindows error", GetLastError())); + fatal("Error = %d\nWindows error", GetLastError()); } _calculated_offset = jlong_from(jot.dwHighDateTime, jot.dwLowDateTime); _has_calculated_offset = 1; @@ -1936,7 +1936,7 @@ int os::get_last_error() { WindowsSemaphore::WindowsSemaphore(uint value) { _semaphore = ::CreateSemaphore(NULL, value, LONG_MAX, NULL); - guarantee(_semaphore != NULL, err_msg("CreateSemaphore failed with error code: %lu", GetLastError())); + guarantee(_semaphore != NULL, "CreateSemaphore failed with error code: %lu", GetLastError()); } WindowsSemaphore::~WindowsSemaphore() { @@ -1947,14 +1947,14 @@ void WindowsSemaphore::signal(uint count) { if (count > 0) { BOOL ret = ::ReleaseSemaphore(_semaphore, count, NULL); - assert(ret != 0, err_msg("ReleaseSemaphore failed with error code: %lu", GetLastError())); + assert(ret != 0, "ReleaseSemaphore failed with error code: %lu", GetLastError()); } } void WindowsSemaphore::wait() { DWORD ret = ::WaitForSingleObject(_semaphore, INFINITE); - assert(ret != WAIT_FAILED, err_msg("WaitForSingleObject failed with error code: %lu", GetLastError())); - assert(ret == WAIT_OBJECT_0, err_msg("WaitForSingleObject failed with return value: %lu", ret)); + assert(ret != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + assert(ret == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", ret); } // sun.misc.Signal @@ -2272,12 +2272,17 @@ LONG Handle_IDiv_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { #ifdef _M_AMD64 PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Rip; - assert(pc[0] == 0xF7, "not an idiv opcode"); - assert((pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); - assert(ctx->Rax == min_jint, "unexpected idiv exception"); - // set correct result values and continue after idiv instruction - ctx->Rip = (DWORD)pc + 2; // idiv reg, reg is 2 bytes - ctx->Rax = (DWORD)min_jint; // result + assert(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && pc[1] == 0xF7 || pc[0] == 0xF7, "not an idiv opcode"); + assert(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && (pc[2] & ~0x7) == 0xF8 || (pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); + if (pc[0] == 0xF7) { + // set correct result values and continue after idiv instruction + ctx->Rip = (DWORD64)pc + 2; // idiv reg, reg is 2 bytes + } else { + ctx->Rip = (DWORD64)pc + 3; // REX idiv reg, reg is 3 bytes + } + // Do not set ctx->Rax as it already contains the correct value (either 32 or 64 bit, depending on the operation) + // this is the case because the exception only happens for -MinValue/-1 and -MinValue is always in rax because of the + // idiv opcode (0xF7). ctx->Rdx = (DWORD)0; // remainder // Continue the execution #else @@ -2344,8 +2349,7 @@ LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { static inline void report_error(Thread* t, DWORD exception_code, address addr, void* siginfo, void* context) { - VMError err(t, exception_code, addr, siginfo, context); - err.report_and_die(); + VMError::report_and_die(t, exception_code, addr, siginfo, context); // If UseOsErrorReporting, this will return here and save the error file // somewhere where we can find it in the minidump. @@ -3325,7 +3329,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, assert(mesg != NULL, "mesg must be specified"); if (!pd_commit_memory(addr, size, exec)) { warn_fail_commit_memory(addr, size, exec); - vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "%s", mesg); } } @@ -5259,7 +5263,7 @@ bool os::check_heap(bool force) { } DWORD err = GetLastError(); if (err != ERROR_NO_MORE_ITEMS && err != ERROR_CALL_NOT_IMPLEMENTED) { - fatal(err_msg("heap walk aborted with error %d", err)); + fatal("heap walk aborted with error %d", err); } HeapUnlock(heap); } @@ -5978,8 +5982,8 @@ void TestReserveMemorySpecial_test() { os::release_memory_special(actual_location, expected_allocation_size); // only now check, after releasing any memory to avoid any leaks. assert(actual_location == expected_location, - err_msg("Failed to allocate memory at requested location " PTR_FORMAT " of size " SIZE_FORMAT ", is " PTR_FORMAT " instead", - expected_location, expected_allocation_size, actual_location)); + "Failed to allocate memory at requested location " PTR_FORMAT " of size " SIZE_FORMAT ", is " PTR_FORMAT " instead", + expected_location, expected_allocation_size, actual_location); } } diff --git a/hotspot/src/os/windows/vm/vmError_windows.cpp b/hotspot/src/os/windows/vm/vmError_windows.cpp index 7a4b96b2a47..44be12294bd 100644 --- a/hotspot/src/os/windows/vm/vmError_windows.cpp +++ b/hotspot/src/os/windows/vm/vmError_windows.cpp @@ -70,9 +70,8 @@ address VMError::get_resetted_sighandler(int sig) { LONG WINAPI crash_handler(struct _EXCEPTION_POINTERS* exceptionInfo) { DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode; - VMError err(NULL, exception_code, NULL, - exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord); - err.report_and_die(); + VMError::report_and_die(NULL, exception_code, NULL, exceptionInfo->ExceptionRecord, + exceptionInfo->ContextRecord); return EXCEPTION_CONTINUE_SEARCH; } diff --git a/hotspot/src/os/windows/vm/vmStructs_windows.hpp b/hotspot/src/os/windows/vm/vmStructs_windows.hpp new file mode 100644 index 00000000000..6133261f07e --- /dev/null +++ b/hotspot/src/os/windows/vm/vmStructs_windows.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_WINDOWS_VM_VMSTRUCTS_WINDOWS_HPP +#define OS_WINDOWS_VM_VMSTRUCTS_WINDOWS_HPP + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) + +#endif // OS_WINDOWS_VM_VMSTRUCTS_WINDOWS_HPP diff --git a/hotspot/src/os_cpu/aix_ppc/vm/globals_aix_ppc.hpp b/hotspot/src/os_cpu/aix_ppc/vm/globals_aix_ppc.hpp index eeb6c15239f..d705c869a16 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/globals_aix_ppc.hpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/globals_aix_ppc.hpp @@ -42,10 +42,6 @@ define_pd_global(intx, CompilerThreadStackSize, 4096); // Allow extra space in DEBUG builds for asserts. define_pd_global(size_t, JVMInvokeMethodSlack, 8192); -define_pd_global(intx, StackYellowPages, 6); -define_pd_global(intx, StackRedPages, 1); -define_pd_global(intx, StackShadowPages, 6 DEBUG_ONLY(+2)); - // Only used on 64 bit platforms define_pd_global(size_t, HeapBaseMinAddress, 2*G); diff --git a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp index d8829b51c6f..f0b867e88da 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp @@ -468,8 +468,7 @@ report_and_die: sigaddset(&newset, sig); sigthreadmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return 0; diff --git a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp index 423fea33748..ba2c97185a6 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp @@ -276,8 +276,6 @@ # endif #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - address os::current_stack_pointer() { #if defined(__clang__) || defined(__llvm__) register void *esp; @@ -731,8 +729,7 @@ JVM_handle_bsd_signal(int sig, sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return false; @@ -865,7 +862,7 @@ static void current_stack_region(address * bottom, size_t * size) { int rslt = pthread_stackseg_np(pthread_self(), &ss); if (rslt != 0) - fatal(err_msg("pthread_stackseg_np failed with err = %d", rslt)); + fatal("pthread_stackseg_np failed with err = %d", rslt); *bottom = (address)((char *)ss.ss_sp - ss.ss_size); *size = ss.ss_size; @@ -876,12 +873,12 @@ static void current_stack_region(address * bottom, size_t * size) { // JVM needs to know exact stack location, abort if it fails if (rslt != 0) - fatal(err_msg("pthread_attr_init failed with err = %d", rslt)); + fatal("pthread_attr_init failed with err = %d", rslt); rslt = pthread_attr_get_np(pthread_self(), &attr); if (rslt != 0) - fatal(err_msg("pthread_attr_get_np failed with err = %d", rslt)); + fatal("pthread_attr_get_np failed with err = %d", rslt); if (pthread_attr_getstackaddr(&attr, (void **)bottom) != 0 || pthread_attr_getstacksize(&attr, size) != 0) { diff --git a/hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp index 8d167adaf5a..c4f991aa650 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp @@ -66,8 +66,8 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { -#ifdef COMPILER2 - // C2 uses ebp as a general register see if NULL fp helps +#if defined(COMPILER2) || INCLUDE_JVMCI + // C2 and JVMCI use ebp as a general register see if NULL fp helps frame ret_frame2(ret_sp, NULL, addr.pc()); if (!ret_frame2.safe_for_sender(jt)) { // nothing else to try if the frame isn't good @@ -77,7 +77,7 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) #else // nothing else to try if the frame isn't good return false; -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ } *fr_addr = ret_frame; return true; diff --git a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp index 9b2db238c0e..40a455688f5 100644 --- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp +++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp @@ -320,8 +320,7 @@ static void current_stack_region(address *bottom, size_t *size) { int rslt = pthread_stackseg_np(pthread_self(), &ss); if (rslt != 0) - fatal(err_msg("pthread_stackseg_np failed with err = " INT32_FORMAT, - rslt)); + fatal("pthread_stackseg_np failed with err = " INT32_FORMAT, rslt); stack_top = (address) ss.ss_sp; stack_bytes = ss.ss_size; @@ -333,13 +332,12 @@ static void current_stack_region(address *bottom, size_t *size) { // JVM needs to know exact stack location, abort if it fails if (rslt != 0) - fatal(err_msg("pthread_attr_init failed with err = " INT32_FORMAT, rslt)); + fatal("pthread_attr_init failed with err = " INT32_FORMAT, rslt); rslt = pthread_attr_get_np(pthread_self(), &attr); if (rslt != 0) - fatal(err_msg("pthread_attr_get_np failed with err = " INT32_FORMAT, - rslt)); + fatal("pthread_attr_get_np failed with err = " INT32_FORMAT, rslt); if (pthread_attr_getstackaddr(&attr, (void **) &stack_bottom) != 0 || pthread_attr_getstacksize(&attr, &stack_bytes) != 0) { diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp index 3a3ffd9fb30..7ae7e616052 100644 --- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp +++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp @@ -464,8 +464,7 @@ JVM_handle_linux_signal(int sig, sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return true; // Mute compiler @@ -558,7 +557,7 @@ static void current_stack_region(address * bottom, size_t * size) { if (rslt == ENOMEM) { vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np"); } else { - fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt)); + fatal("pthread_getattr_np failed with errno = %d", rslt); } } diff --git a/hotspot/src/os_cpu/linux_ppc/vm/globals_linux_ppc.hpp b/hotspot/src/os_cpu/linux_ppc/vm/globals_linux_ppc.hpp index d9240d230b0..50174b66d1c 100644 --- a/hotspot/src/os_cpu/linux_ppc/vm/globals_linux_ppc.hpp +++ b/hotspot/src/os_cpu/linux_ppc/vm/globals_linux_ppc.hpp @@ -42,10 +42,6 @@ define_pd_global(intx, CompilerThreadStackSize, 4096); // Allow extra space in DEBUG builds for asserts. define_pd_global(size_t, JVMInvokeMethodSlack, 8192); -define_pd_global(intx, StackYellowPages, 6); -define_pd_global(intx, StackRedPages, 1); -define_pd_global(intx, StackShadowPages, 6 DEBUG_ONLY(+2)); - // Only used on 64 bit platforms define_pd_global(size_t, HeapBaseMinAddress, 2*G); diff --git a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp index ebf67a09f3a..1c42912c4a7 100644 --- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp +++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp @@ -439,8 +439,7 @@ report_and_die: sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return false; @@ -531,7 +530,7 @@ static void current_stack_region(address * bottom, size_t * size) { if (rslt == ENOMEM) { vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np"); } else { - fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt)); + fatal("pthread_getattr_np failed with errno = %d", rslt); } } diff --git a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp index 0c1c6263586..16457399fca 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp @@ -172,7 +172,7 @@ static void current_stack_region(address* bottom, size_t* size) { if (rslt == ENOMEM) { vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np"); } else { - fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt)); + fatal("pthread_getattr_np failed with errno = %d", rslt); } } @@ -692,8 +692,7 @@ JVM_handle_linux_signal(int sig, sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); } diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index decb51ea74f..fe1c4c59068 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -89,8 +89,6 @@ #define SPELL_REG_FP "ebp" #endif // AMD64 -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - address os::current_stack_pointer() { #ifdef SPARC_WORKS register void *esp; @@ -542,8 +540,7 @@ JVM_handle_linux_signal(int sig, sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return true; // Mute compiler @@ -689,7 +686,7 @@ static void current_stack_region(address * bottom, size_t * size) { if (rslt == ENOMEM) { vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np"); } else { - fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt)); + fatal("pthread_getattr_np failed with errno = %d", rslt); } } @@ -728,32 +725,32 @@ void os::print_context(outputStream *st, void *context) { ucontext_t *uc = (ucontext_t*)context; st->print_cr("Registers:"); #ifdef AMD64 - st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); - st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); - st->print(", RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]); - st->print(", RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]); + st->print( "RAX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RAX]); + st->print(", RBX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RBX]); + st->print(", RCX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RCX]); + st->print(", RDX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RDX]); st->cr(); - st->print( "RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]); - st->print(", RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]); - st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); - st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); + st->print( "RSP=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RSP]); + st->print(", RBP=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RBP]); + st->print(", RSI=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RSI]); + st->print(", RDI=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RDI]); st->cr(); - st->print( "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); - st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); - st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); - st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); + st->print( "R8 =" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R8]); + st->print(", R9 =" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R9]); + st->print(", R10=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R10]); + st->print(", R11=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R11]); st->cr(); - st->print( "R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]); - st->print(", R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]); - st->print(", R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]); - st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); + st->print( "R12=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R12]); + st->print(", R13=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R13]); + st->print(", R14=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R14]); + st->print(", R15=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R15]); st->cr(); - st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]); - st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); - st->print(", CSGSFS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_CSGSFS]); - st->print(", ERR=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ERR]); + st->print( "RIP=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RIP]); + st->print(", EFLAGS=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_EFL]); + st->print(", CSGSFS=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_CSGSFS]); + st->print(", ERR=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_ERR]); st->cr(); - st->print(" TRAPNO=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_TRAPNO]); + st->print(" TRAPNO=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_TRAPNO]); #else st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]); st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]); @@ -767,13 +764,13 @@ void os::print_context(outputStream *st, void *context) { st->cr(); st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EIP]); st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); - st->print(", CR2=" INTPTR_FORMAT, uc->uc_mcontext.cr2); + st->print(", CR2=" PTR64_FORMAT, (uint64_t)uc->uc_mcontext.cr2); #endif // AMD64 st->cr(); st->cr(); intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); - st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); + st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", p2i(sp)); print_hex_dump(st, (address)sp, (address)(sp + 8*sizeof(intptr_t)), sizeof(intptr_t)); st->cr(); @@ -781,7 +778,7 @@ void os::print_context(outputStream *st, void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Linux::ucontext_get_pc(uc); - st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); + st->print_cr("Instructions: (pc=" PTR_FORMAT ")", p2i(pc)); print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); } diff --git a/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp index 77affdd52e6..55e5bbac4e2 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp @@ -67,8 +67,8 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { -#ifdef COMPILER2 - // C2 uses ebp as a general register see if NULL fp helps +#if defined(COMPILER2) || INCLUDE_JVMCI + // C2 and JVMCI use ebp as a general register see if NULL fp helps frame ret_frame2(ret_sp, NULL, addr.pc()); if (!ret_frame2.safe_for_sender(jt)) { // nothing else to try if the frame isn't good @@ -78,7 +78,7 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) #else // nothing else to try if the frame isn't good return false; -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ } *fr_addr = ret_frame; return true; diff --git a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp index 5473f8aa44d..b17d58e60b0 100644 --- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp +++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp @@ -328,7 +328,7 @@ static void current_stack_region(address *bottom, size_t *size) { vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np"); } else { - fatal(err_msg("pthread_getattr_np failed with errno = %d", res)); + fatal("pthread_getattr_np failed with errno = %d", res); } } @@ -336,7 +336,7 @@ static void current_stack_region(address *bottom, size_t *size) { size_t stack_bytes; res = pthread_attr_getstack(&attr, (void **) &stack_bottom, &stack_bytes); if (res != 0) { - fatal(err_msg("pthread_attr_getstack failed with errno = %d", res)); + fatal("pthread_attr_getstack failed with errno = %d", res); } address stack_top = stack_bottom + stack_bytes; @@ -348,7 +348,7 @@ static void current_stack_region(address *bottom, size_t *size) { size_t guard_bytes; res = pthread_attr_getguardsize(&attr, &guard_bytes); if (res != 0) { - fatal(err_msg("pthread_attr_getguardsize failed with errno = %d", res)); + fatal("pthread_attr_getguardsize failed with errno = %d", res); } int guard_pages = align_size_up(guard_bytes, page_bytes) / page_bytes; assert(guard_bytes == guard_pages * page_bytes, "unaligned guard"); diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp index a41a2cc881b..ab54a71185b 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp @@ -24,6 +24,7 @@ // no precompiled headers #include "asm/macroAssembler.hpp" +#include "macroAssembler_sparc.hpp" #include "classfile/classLoader.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -549,8 +550,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack."); } - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); } diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp index 08a5fb3980a..a01e18dd0fc 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp @@ -30,29 +30,11 @@ // referenced by vmStructs.cpp. #define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Solaris Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) + nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ - \ - /************************/ \ - /* JavaThread constants */ \ - /************************/ \ - \ declare_constant(JavaFrameAnchor::flushed) #define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp index 5f885d4caf4..fdc17b596ad 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp @@ -707,8 +707,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack."); } - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return false; diff --git a/hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp b/hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp index 9304bb7242e..dc8b8b9b16a 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp @@ -29,21 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Solaris Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp index 7180fe1d9fd..08afec24834 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp @@ -74,8 +74,8 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { -#ifdef COMPILER2 - // C2 uses ebp as a general register see if NULL fp helps +#if defined(COMPILER2) || INCLUDE_JVMCI + // C2 and JVMCI use ebp as a general register see if NULL fp helps frame ret_frame2(ret_sp, NULL, addr.pc()); if (!ret_frame2.safe_for_sender(jt)) { // nothing else to try if the frame isn't good @@ -85,7 +85,7 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) #else // nothing else to try if the frame isn't good return false; -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ } *fr_addr = ret_frame; return true; diff --git a/hotspot/src/share/vm/Xusage.txt b/hotspot/src/share/vm/Xusage.txt index acd829b449f..8b3d4650a72 100644 --- a/hotspot/src/share/vm/Xusage.txt +++ b/hotspot/src/share/vm/Xusage.txt @@ -7,6 +7,7 @@ -Xbootclasspath/p: prepend in front of bootstrap class path -Xnoclassgc disable class garbage collection + -Xlog: control JVM logging, use -Xlog:help for details -Xloggc: log GC status to a file with time stamps -Xbatch disable background compilation -Xms set initial Java heap size diff --git a/hotspot/src/share/vm/adlc/formsopt.cpp b/hotspot/src/share/vm/adlc/formsopt.cpp index ac8ffff2960..90ec7c898ca 100644 --- a/hotspot/src/share/vm/adlc/formsopt.cpp +++ b/hotspot/src/share/vm/adlc/formsopt.cpp @@ -234,7 +234,6 @@ RegClass::RegClass(const char* classid) : _stack_or_reg(false), _classid(classid } RegClass::~RegClass() { - delete _classid; } // record a register in this class diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index 141f7c08c70..a31252f4eae 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -4006,7 +4006,6 @@ int MatchRule::is_expensive() const { strcmp(opType,"DivD")==0 || strcmp(opType,"DivF")==0 || strcmp(opType,"DivI")==0 || - strcmp(opType,"ExpD")==0 || strcmp(opType,"LogD")==0 || strcmp(opType,"Log10D")==0 || strcmp(opType,"ModD")==0 || @@ -4143,6 +4142,8 @@ bool MatchRule::is_vector() const { "SubVB","SubVS","SubVI","SubVL","SubVF","SubVD", "MulVS","MulVI","MulVL","MulVF","MulVD", "DivVF","DivVD", + "AbsVF","AbsVD", + "NegVF","NegVD", "SqrtVD", "AndV" ,"XorV" ,"OrV", "AddReductionVI", "AddReductionVL", diff --git a/hotspot/src/share/vm/asm/assembler.cpp b/hotspot/src/share/vm/asm/assembler.cpp index 2141d93b0da..bc8610875c1 100644 --- a/hotspot/src/share/vm/asm/assembler.cpp +++ b/hotspot/src/share/vm/asm/assembler.cpp @@ -43,8 +43,7 @@ AbstractAssembler::AbstractAssembler(CodeBuffer* code) { CodeSection* cs = code->insts(); cs->clear_mark(); // new assembler kills old mark if (cs->start() == NULL) { - vm_exit_out_of_memory(0, OOM_MMAP_ERROR, err_msg("CodeCache: no room for %s", - code->name())); + vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "CodeCache: no room for %s", code->name()); } _code_section = cs; _oop_recorder= code->oop_recorder(); diff --git a/hotspot/src/share/vm/asm/codeBuffer.cpp b/hotspot/src/share/vm/asm/codeBuffer.cpp index 93f388f8f4a..1ab5a5d6d8d 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.cpp +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp @@ -602,21 +602,19 @@ csize_t CodeBuffer::total_relocation_size() const { return (csize_t) align_size_up(total, HeapWordSize); } -csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const { - address buf = NULL; +csize_t CodeBuffer::copy_relocations_to(address buf, csize_t buf_limit, bool only_inst) const { csize_t buf_offset = 0; - csize_t buf_limit = 0; - if (dest != NULL) { - buf = (address)dest->relocation_begin(); - buf_limit = (address)dest->relocation_end() - buf; - assert((uintptr_t)buf % HeapWordSize == 0, "buf must be fully aligned"); - assert(buf_limit % HeapWordSize == 0, "buf must be evenly sized"); - } - // if dest == NULL, this is just the sizing pass - csize_t code_end_so_far = 0; csize_t code_point_so_far = 0; + + assert((uintptr_t)buf % HeapWordSize == 0, "buf must be fully aligned"); + assert(buf_limit % HeapWordSize == 0, "buf must be evenly sized"); + for (int n = (int) SECT_FIRST; n < (int)SECT_LIMIT; n++) { + if (only_inst && (n != (int)SECT_INSTS)) { + // Need only relocation info for code. + continue; + } // pull relocs out of each section const CodeSection* cs = code_section(n); assert(!(cs->is_empty() && cs->locs_count() > 0), "sanity"); @@ -683,7 +681,23 @@ csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const { buf_offset += sizeof(relocInfo); } - assert(code_end_so_far == total_content_size(), "sanity"); + assert(only_inst || code_end_so_far == total_content_size(), "sanity"); + + return buf_offset; +} + +csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const { + address buf = NULL; + csize_t buf_offset = 0; + csize_t buf_limit = 0; + + if (dest != NULL) { + buf = (address)dest->relocation_begin(); + buf_limit = (address)dest->relocation_end() - buf; + } + // if dest == NULL, this is just the sizing pass + // + buf_offset = copy_relocations_to(buf, buf_limit, false); // Account for index: if (buf != NULL) { @@ -1126,7 +1140,8 @@ void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) con while (c && c->offset() == offset) { stream->bol(); stream->print("%s", _prefix); - stream->print_cr("%s", c->string()); + // Don't interpret as format strings since it could contain % + stream->print_raw_cr(c->string()); c = c->next_comment(); } } diff --git a/hotspot/src/share/vm/asm/codeBuffer.hpp b/hotspot/src/share/vm/asm/codeBuffer.hpp index 0972d75b318..50b699c5e3e 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.hpp +++ b/hotspot/src/share/vm/asm/codeBuffer.hpp @@ -173,7 +173,7 @@ class CodeSection VALUE_OBJ_CLASS_SPEC { bool allocates(address pc) const { return pc >= _start && pc < _limit; } bool allocates2(address pc) const { return pc >= _start && pc <= _limit; } - void set_end(address pc) { assert(allocates2(pc), err_msg("not in CodeBuffer memory: " INTPTR_FORMAT " <= " INTPTR_FORMAT " <= " INTPTR_FORMAT, p2i(_start), p2i(pc), p2i(_limit))); _end = pc; } + void set_end(address pc) { assert(allocates2(pc), "not in CodeBuffer memory: " INTPTR_FORMAT " <= " INTPTR_FORMAT " <= " INTPTR_FORMAT, p2i(_start), p2i(pc), p2i(_limit)); _end = pc; } void set_mark(address pc) { assert(contains2(pc), "not in codeBuffer"); _mark = pc; } void set_mark_off(int offset) { assert(contains2(offset+_start),"not in codeBuffer"); @@ -375,6 +375,8 @@ class CodeBuffer: public StackObj { OopRecorder _default_oop_recorder; // override with initialize_oop_recorder Arena* _overflow_arena; + address _last_membar; // used to merge consecutive memory barriers + address _decode_begin; // start address for decode address decode_begin(); @@ -388,6 +390,7 @@ class CodeBuffer: public StackObj { _decode_begin = NULL; _overflow_arena = NULL; _code_strings = CodeStrings(); + _last_membar = NULL; } void initialize(address code_start, csize_t code_size) { @@ -452,7 +455,6 @@ class CodeBuffer: public StackObj { initialize_misc(name); } - // (4) code buffer allocating codeBlob memory for code & relocation // info. The name must be something informative and code_size must // include both code and stubs sizes. @@ -553,6 +555,8 @@ class CodeBuffer: public StackObj { // allocated size of all relocation data, including index, rounded up csize_t total_relocation_size() const; + csize_t copy_relocations_to(address buf, csize_t buf_limit, bool only_inst) const; + // allocated size of any and all recorded oops csize_t total_oop_size() const { OopRecorder* recorder = oop_recorder(); @@ -576,6 +580,10 @@ class CodeBuffer: public StackObj { OopRecorder* oop_recorder() const { return _oop_recorder; } CodeStrings& strings() { return _code_strings; } + address last_membar() const { return _last_membar; } + void set_last_membar(address a) { _last_membar = a; } + void clear_last_membar() { set_last_membar(NULL); } + void free_strings() { if (!_code_strings.is_null()) { _code_strings.free(); // sets _strings Null as a side-effect. diff --git a/hotspot/src/share/vm/asm/register.hpp b/hotspot/src/share/vm/asm/register.hpp index c500890181a..5e43cfa68fd 100644 --- a/hotspot/src/share/vm/asm/register.hpp +++ b/hotspot/src/share/vm/asm/register.hpp @@ -121,8 +121,7 @@ inline void assert_different_registers( ) { assert( a != b, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT "", - p2i(a), p2i(b)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT "", p2i(a), p2i(b) ); } @@ -135,9 +134,9 @@ inline void assert_different_registers( assert( a != b && a != c && b != c, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c) ); } @@ -152,9 +151,9 @@ inline void assert_different_registers( a != b && a != c && a != d && b != c && b != d && c != d, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d) ); } @@ -171,9 +170,9 @@ inline void assert_different_registers( && b != c && b != d && b != e && c != d && c != e && d != e, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e) ); } @@ -192,10 +191,10 @@ inline void assert_different_registers( && c != d && c != e && c != f && d != e && d != f && e != f, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f) ); } @@ -216,10 +215,10 @@ inline void assert_different_registers( && d != e && d != f && d != g && e != f && e != g && f != g, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g) ); } @@ -242,10 +241,10 @@ inline void assert_different_registers( && e != f && e != g && e != h && f != g && f != h && g != h, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h) ); } @@ -270,11 +269,11 @@ inline void assert_different_registers( && f != g && f != h && f != i && g != h && g != i && h != i, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT - ", i=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i) ); } @@ -300,11 +299,11 @@ inline void assert_different_registers( && g != h && g != i && g != j && h != i && h != j && i != j, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT - ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j) ); } @@ -332,11 +331,11 @@ inline void assert_different_registers( && h != i && h != j && h !=k && i != j && i !=k && j !=k, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT - ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k) ); } @@ -366,12 +365,12 @@ inline void assert_different_registers( && i != j && i !=k && i !=l && j !=k && j !=l && k !=l, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT - ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT - ", l=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k), p2i(l)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT + ", l=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k), p2i(l) ); } diff --git a/hotspot/src/share/vm/c1/c1_Compilation.cpp b/hotspot/src/share/vm/c1/c1_Compilation.cpp index 26b2d601ffc..58255ba27e0 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.cpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp @@ -325,7 +325,8 @@ bool Compilation::setup_code_buffer(CodeBuffer* code, int call_stub_estimate) { locs_buffer_size / sizeof(relocInfo)); code->initialize_consts_size(Compilation::desired_max_constant_size()); // Call stubs + two deopt handlers (regular and MH) + exception handler - int stub_size = (call_stub_estimate * LIR_Assembler::call_stub_size) + + int call_stub_size = LIR_Assembler::call_stub_size; + int stub_size = (call_stub_estimate * call_stub_size) + LIR_Assembler::exception_handler_size + (2 * LIR_Assembler::deopt_handler_size); if (stub_size >= code->insts_capacity()) return false; diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index 723face6b03..7144a6d5837 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -3363,11 +3363,9 @@ const char* GraphBuilder::check_can_parse(ciMethod* callee) const { return NULL; } - // negative filter: should callee NOT be inlined? returns NULL, ok to inline, or rejection msg const char* GraphBuilder::should_not_inline(ciMethod* callee) const { - if ( callee->should_exclude()) return "excluded by CompilerOracle"; - if ( callee->should_not_inline()) return "disallowed by CompilerOracle"; + if ( callee->should_not_inline()) return "disallowed by CompileCommand"; if ( callee->dont_inline()) return "don't inline by annotation"; return NULL; } @@ -3698,7 +3696,7 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode const char* msg = ""; if (callee->force_inline()) msg = "force inline by annotation"; - if (callee->should_inline()) msg = "force inline by CompileOracle"; + if (callee->should_inline()) msg = "force inline by CompileCommand"; print_inlining(callee, msg); } else { // use heuristic controls on inlining @@ -4020,7 +4018,7 @@ bool GraphBuilder::try_method_handle_inline(ciMethod* callee) { break; default: - fatal(err_msg("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } set_state(state_before); diff --git a/hotspot/src/share/vm/c1/c1_IR.hpp b/hotspot/src/share/vm/c1/c1_IR.hpp index 910ce06406d..e3dc4ba1950 100644 --- a/hotspot/src/share/vm/c1/c1_IR.hpp +++ b/hotspot/src/share/vm/c1/c1_IR.hpp @@ -244,7 +244,8 @@ class IRScopeDebugInfo: public CompilationResourceObj { // reexecute allowed only for the topmost frame bool reexecute = topmost ? should_reexecute() : false; bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis. - recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, return_oop, locvals, expvals, monvals); + bool rethrow_exception = false; + recorder->describe_scope(pc_offset, methodHandle(), scope()->method(), bci(), reexecute, rethrow_exception, is_method_handle_invoke, return_oop, locvals, expvals, monvals); } }; diff --git a/hotspot/src/share/vm/c1/c1_LIR.cpp b/hotspot/src/share/vm/c1/c1_LIR.cpp index 7d2b4f3e883..0319f02a66c 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.cpp +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp @@ -732,8 +732,7 @@ void LIR_OpVisitState::visit(LIR_Op* op) { case lir_sin: case lir_cos: case lir_log: - case lir_log10: - case lir_exp: { + case lir_log10: { assert(op->as_Op2() != NULL, "must be"); LIR_Op2* op2 = (LIR_Op2*)op; @@ -743,9 +742,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) { // overlap with the input. assert(op2->_info == NULL, "not used"); assert(op2->_tmp5->is_illegal(), "not used"); - assert(op2->_tmp2->is_valid() == (op->code() == lir_exp), "not used"); - assert(op2->_tmp3->is_valid() == (op->code() == lir_exp), "not used"); - assert(op2->_tmp4->is_valid() == (op->code() == lir_exp), "not used"); assert(op2->_opr1->is_valid(), "used"); do_input(op2->_opr1); do_temp(op2->_opr1); @@ -1775,7 +1771,6 @@ const char * LIR_Op::name() const { case lir_tan: s = "tan"; break; case lir_log: s = "log"; break; case lir_log10: s = "log10"; break; - case lir_exp: s = "exp"; break; case lir_pow: s = "pow"; break; case lir_logic_and: s = "logic_and"; break; case lir_logic_or: s = "logic_or"; break; diff --git a/hotspot/src/share/vm/c1/c1_LIR.hpp b/hotspot/src/share/vm/c1/c1_LIR.hpp index 4affbfb0826..d59550aa037 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.hpp +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp @@ -961,7 +961,6 @@ enum LIR_Code { , lir_tan , lir_log , lir_log10 - , lir_exp , lir_pow , lir_logic_and , lir_logic_or @@ -2199,7 +2198,6 @@ class LIR_List: public CompilationResourceObj { void sin (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_sin , from, tmp1, to, tmp2)); } void cos (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_cos , from, tmp1, to, tmp2)); } void tan (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_tan , from, tmp1, to, tmp2)); } - void exp (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, LIR_Opr tmp4, LIR_Opr tmp5) { append(new LIR_Op2(lir_exp , from, tmp1, to, tmp2, tmp3, tmp4, tmp5)); } void pow (LIR_Opr arg1, LIR_Opr arg2, LIR_Opr res, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, LIR_Opr tmp4, LIR_Opr tmp5) { append(new LIR_Op2(lir_pow, arg1, arg2, res, tmp1, tmp2, tmp3, tmp4, tmp5)); } void add (LIR_Opr left, LIR_Opr right, LIR_Opr res) { append(new LIR_Op2(lir_add, left, right, res)); } diff --git a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp index 94ef3a2bbd6..6a88526f885 100644 --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp @@ -405,7 +405,8 @@ void LIR_Assembler::record_non_safepoint_debug_info() { if (s == NULL) break; IRScope* scope = s->scope(); //Always pass false for reexecute since these ScopeDescs are never used for deopt - debug_info->describe_scope(pc_offset, scope->method(), s->bci(), false/*reexecute*/); + methodHandle null_mh; + debug_info->describe_scope(pc_offset, null_mh, scope->method(), s->bci(), false/*reexecute*/); } debug_info->end_non_safepoint(pc_offset); @@ -462,7 +463,7 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) { vtable_call(op); break; default: - fatal(err_msg_res("unexpected op code: %s", op->name())); + fatal("unexpected op code: %s", op->name()); break; } @@ -739,7 +740,6 @@ void LIR_Assembler::emit_op2(LIR_Op2* op) { case lir_cos: case lir_log: case lir_log10: - case lir_exp: case lir_pow: intrinsic_op(op->code(), op->in_opr1(), op->in_opr2(), op->result_opr(), op); break; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index d9360d9c75e..f188dfb942d 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -920,7 +920,7 @@ LIR_Opr LIRGenerator::round_item(LIR_Opr opr) { LIR_Opr LIRGenerator::force_to_spill(LIR_Opr value, BasicType t) { assert(type2size[t] == type2size[value->type()], - err_msg_res("size mismatch: t=%s, value->type()=%s", type2name(t), type2name(value->type()))); + "size mismatch: t=%s, value->type()=%s", type2name(t), type2name(value->type())); if (!value->is_register()) { // force into a register LIR_Opr r = new_register(value->type()); @@ -1630,6 +1630,9 @@ void LIRGenerator::CardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* __ move(dirty, card_addr); __ branch_destination(L_already_dirty->label()); } else { + if (UseConcMarkSweepGC && CMSPrecleaningEnabled) { + __ membar_storestore(); + } __ move(dirty, card_addr); } #endif @@ -2829,7 +2832,7 @@ void LIRGenerator::do_OsrEntry(OsrEntry* x) { void LIRGenerator::invoke_load_arguments(Invoke* x, LIRItemList* args, const LIR_OprList* arg_list) { assert(args->length() == arg_list->length(), - err_msg_res("args=%d, arg_list=%d", args->length(), arg_list->length())); + "args=%d, arg_list=%d", args->length(), arg_list->length()); for (int i = x->has_receiver() ? 1 : 0; i < args->length(); i++) { LIRItem* param = args->at(i); LIR_Opr loc = arg_list->at(i); @@ -2973,7 +2976,7 @@ void LIRGenerator::do_Invoke(Invoke* x) { break; } default: - fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(x->code()))); + fatal("unexpected bytecode: %s", Bytecodes::name(x->code())); break; } diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp index 7f8d45f81da..1009235d4dc 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp @@ -244,6 +244,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void do_getClass(Intrinsic* x); void do_currentThread(Intrinsic* x); void do_MathIntrinsic(Intrinsic* x); + void do_ExpIntrinsic(Intrinsic* x); void do_ArrayCopy(Intrinsic* x); void do_CompareAndSwap(Intrinsic* x, ValueType* type); void do_NIOCheckIndex(Intrinsic* x); diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index 1d91f180af9..7d03fb1c7dd 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -6588,7 +6588,6 @@ void LinearScanStatistic::collect(LinearScan* allocator) { case lir_log10: case lir_log: case lir_pow: - case lir_exp: case lir_logic_and: case lir_logic_or: case lir_logic_xor: diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 50fc0c47f46..ad4e8160921 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -317,6 +317,7 @@ const char* Runtime1::name_for_address(address entry) { FUNCTION_CASE(entry, TRACE_TIME_METHOD); #endif FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32()); + FUNCTION_CASE(entry, StubRoutines::dexp()); #undef FUNCTION_CASE @@ -553,7 +554,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t exception->print_value_string(), p2i((address)exception()), nm->method()->print_value_string(), p2i(pc), p2i(thread)); } // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort(exception)); + Exceptions::debug_check_abort(exception); // Clear out the exception oop and pc since looking up an // exception handler can cause class loading, which might throw an diff --git a/hotspot/src/share/vm/c1/c1_globals.hpp b/hotspot/src/share/vm/c1/c1_globals.hpp index deda96233c2..3cdcfc2ed38 100644 --- a/hotspot/src/share/vm/c1/c1_globals.hpp +++ b/hotspot/src/share/vm/c1/c1_globals.hpp @@ -152,6 +152,7 @@ \ product(intx, ValueMapMaxLoopSize, 8, \ "maximum size of a loop optimized by global value numbering") \ + range(0, 128) \ \ develop(bool, EliminateBlocks, true, \ "Eliminate unneccessary basic blocks") \ @@ -220,6 +221,7 @@ \ develop(intx, TraceLinearScanLevel, 0, \ "Debug levels for the linear scan allocator") \ + range(0, 4) \ \ develop(bool, StressLinearScan, false, \ "scramble block order used by LinearScan (stress test)") \ @@ -294,6 +296,7 @@ \ develop(intx, NMethodSizeLimit, (64*K)*wordSize, \ "Maximum size of a compiled method.") \ + range(0, max_jint) \ \ develop(bool, TraceFPUStack, false, \ "Trace emulation of the FPU stack (intel only)") \ @@ -309,6 +312,7 @@ \ develop(intx, InstructionCountCutoff, 37000, \ "If GraphBuilder adds this many instructions, bails out") \ + range(0, max_jint) \ \ develop(bool, ComputeExactFPURegisterUsage, true, \ "Compute additional live set for fpu registers to simplify fpu stack merge (Intel only)") \ diff --git a/hotspot/src/share/vm/ci/ciKlass.cpp b/hotspot/src/share/vm/ci/ciKlass.cpp index 2c3dd19d244..75c3c140a8e 100644 --- a/hotspot/src/share/vm/ci/ciKlass.cpp +++ b/hotspot/src/share/vm/ci/ciKlass.cpp @@ -66,8 +66,8 @@ ciKlass::ciKlass(ciSymbol* name, BasicType bt) : ciType(bt) { // ------------------------------------------------------------------ // ciKlass::is_subtype_of bool ciKlass::is_subtype_of(ciKlass* that) { - assert(this->is_loaded(), err_msg("must be loaded: %s", this->name()->as_quoted_ascii())); - assert(that->is_loaded(), err_msg("must be loaded: %s", that->name()->as_quoted_ascii())); + assert(this->is_loaded(), "must be loaded: %s", this->name()->as_quoted_ascii()); + assert(that->is_loaded(), "must be loaded: %s", that->name()->as_quoted_ascii()); // Check to see if the klasses are identical. if (this == that) { @@ -85,8 +85,8 @@ bool ciKlass::is_subtype_of(ciKlass* that) { // ------------------------------------------------------------------ // ciKlass::is_subclass_of bool ciKlass::is_subclass_of(ciKlass* that) { - assert(this->is_loaded(), err_msg("must be loaded: %s", this->name()->as_quoted_ascii())); - assert(that->is_loaded(), err_msg("must be loaded: %s", that->name()->as_quoted_ascii())); + assert(this->is_loaded(), "must be loaded: %s", this->name()->as_quoted_ascii()); + assert(that->is_loaded(), "must be loaded: %s", that->name()->as_quoted_ascii()); VM_ENTRY_MARK; Klass* this_klass = get_Klass(); diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 8bc5b319f4a..a0e184fa9ed 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -576,13 +576,13 @@ void ciCallProfile::add_receiver(ciKlass* receiver, int receiver_count) { void ciMethod::assert_virtual_call_type_ok(int bci) { assert(java_code_at_bci(bci) == Bytecodes::_invokevirtual || - java_code_at_bci(bci) == Bytecodes::_invokeinterface, err_msg("unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci)))); + java_code_at_bci(bci) == Bytecodes::_invokeinterface, "unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci))); } void ciMethod::assert_call_type_ok(int bci) { assert(java_code_at_bci(bci) == Bytecodes::_invokestatic || java_code_at_bci(bci) == Bytecodes::_invokespecial || - java_code_at_bci(bci) == Bytecodes::_invokedynamic, err_msg("unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci)))); + java_code_at_bci(bci) == Bytecodes::_invokedynamic, "unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci))); } /** @@ -1043,18 +1043,6 @@ MethodCounters* ciMethod::ensure_method_counters() { return method_counters; } -// ------------------------------------------------------------------ -// ciMethod::should_exclude -// -// Should this method be excluded from compilation? -bool ciMethod::should_exclude() { - check_is_loaded(); - VM_ENTRY_MARK; - methodHandle mh(THREAD, get_Method()); - bool ignore; - return CompilerOracle::should_exclude(mh, ignore); -} - // ------------------------------------------------------------------ // ciMethod::should_inline // diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 7ce61952341..d2268703098 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -266,7 +266,6 @@ class ciMethod : public ciMetadata { int resolve_vtable_index(ciKlass* caller, ciKlass* receiver); // Compilation directives - bool should_exclude(); bool should_inline(); bool should_not_inline(); bool should_print_assembly(); diff --git a/hotspot/src/share/vm/ci/ciMethodData.cpp b/hotspot/src/share/vm/ci/ciMethodData.cpp index 08ce7963963..7aaf9bdf2c4 100644 --- a/hotspot/src/share/vm/ci/ciMethodData.cpp +++ b/hotspot/src/share/vm/ci/ciMethodData.cpp @@ -122,7 +122,7 @@ void ciMethodData::load_extra_data() { // An empty slot or ArgInfoData entry marks the end of the trap data return; default: - fatal(err_msg("bad tag = %d", dp_dst->tag())); + fatal("bad tag = %d", dp_dst->tag()); } } } @@ -289,7 +289,7 @@ ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_f break; } default: - fatal(err_msg("bad tag = %d", dp->tag())); + fatal("bad tag = %d", dp->tag()); } } return NULL; @@ -578,7 +578,7 @@ void ciMethodData::dump_replay_data_extra_data_helper(outputStream* out, int rou break; } default: - fatal(err_msg("bad tag = %d", dp->tag())); + fatal("bad tag = %d", dp->tag()); } } } @@ -690,7 +690,7 @@ void ciMethodData::print_data_on(outputStream* st) { data = new ciSpeculativeTrapData(dp); break; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } st->print("%d", dp_to_di(data->dp())); st->fill_to(6); diff --git a/hotspot/src/share/vm/ci/ciReplay.cpp b/hotspot/src/share/vm/ci/ciReplay.cpp index ffaa0861164..3e22b50d2c4 100644 --- a/hotspot/src/share/vm/ci/ciReplay.cpp +++ b/hotspot/src/share/vm/ci/ciReplay.cpp @@ -730,7 +730,7 @@ class CompileReplay : public StackObj { if (parsed_two_word == i) continue; default: - fatal(err_msg_res("Unexpected tag: %d", cp->tag_at(i).value())); + fatal("Unexpected tag: %d", cp->tag_at(i).value()); break; } diff --git a/hotspot/src/share/vm/ci/ciTypeFlow.cpp b/hotspot/src/share/vm/ci/ciTypeFlow.cpp index 48f4d9fead0..8a5ad392bed 100644 --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp @@ -1964,7 +1964,7 @@ ciTypeFlow::ciTypeFlow(ciEnv* env, ciMethod* method, int osr_bci) { _has_irreducible_entry = false; _osr_bci = osr_bci; _failure_reason = NULL; - assert(0 <= start_bci() && start_bci() < code_size() , err_msg("correct osr_bci argument: 0 <= %d < %d", start_bci(), code_size())); + assert(0 <= start_bci() && start_bci() < code_size() , "correct osr_bci argument: 0 <= %d < %d", start_bci(), code_size()); _work_list = NULL; _ciblock_count = _methodBlocks->num_blocks(); diff --git a/hotspot/src/share/vm/classfile/altHashing.cpp b/hotspot/src/share/vm/classfile/altHashing.cpp index 91eb5bec152..efa3edb2ca9 100644 --- a/hotspot/src/share/vm/classfile/altHashing.cpp +++ b/hotspot/src/share/vm/classfile/altHashing.cpp @@ -262,10 +262,9 @@ void AltHashing::testMurmur3_32_ByteArray() { juint final_hash = murmur3_32(hashes, 4*256); assert (MURMUR3_32_X86_CHECK_VALUE == final_hash, - err_msg( - "Calculated hash result not as expected. Expected %08X got %08X\n", - MURMUR3_32_X86_CHECK_VALUE, - final_hash)); + "Calculated hash result not as expected. Expected %08X got %08X\n", + MURMUR3_32_X86_CHECK_VALUE, + final_hash); } void AltHashing::testEquivalentHashes() { @@ -276,24 +275,24 @@ void AltHashing::testEquivalentHashes() { jbytes = murmur3_32(TWO_BYTE, 2); jchars = murmur3_32(ONE_CHAR, 1); assert (jbytes == jchars, - err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars)); + "Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars); jbytes = murmur3_32(FOUR_BYTE, 4); jchars = murmur3_32(TWO_CHAR, 2); ints = murmur3_32(ONE_INT, 1); assert ((jbytes == jchars) && (jbytes == ints), - err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints)); + "Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints); jbytes = murmur3_32(SIX_BYTE, 6); jchars = murmur3_32(THREE_CHAR, 3); assert (jbytes == jchars, - err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars)); + "Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars); jbytes = murmur3_32(EIGHT_BYTE, 8); jchars = murmur3_32(FOUR_CHAR, 4); ints = murmur3_32(TWO_INT, 2); assert ((jbytes == jchars) && (jbytes == ints), - err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints)); + "Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints); } // Returns true if the alternate hashcode is correct diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 5f17e00415f..3e1f13de4ea 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -319,12 +319,12 @@ PRAGMA_DIAG_PUSH PRAGMA_FORMAT_NONLITERAL_IGNORED void ClassFileParser::report_assert_property_failure(const char* msg, TRAPS) { ResourceMark rm(THREAD); - fatal(err_msg(msg, _class_name->as_C_string())); + fatal(msg, _class_name->as_C_string()); } void ClassFileParser::report_assert_property_failure(const char* msg, int index, TRAPS) { ResourceMark rm(THREAD); - fatal(err_msg(msg, index, _class_name->as_C_string())); + fatal(msg, index, _class_name->as_C_string()); } PRAGMA_DIAG_POP @@ -492,8 +492,7 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { break; } default: - fatal(err_msg("bad constant pool tag value %u", - cp->tag_at(index).value())); + fatal("bad constant pool tag value %u", cp->tag_at(index).value()); ShouldNotReachHere(); break; } // end of switch @@ -1755,6 +1754,12 @@ ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_d if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_HotSpotIntrinsicCandidate; +#if INCLUDE_JVMCI + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_vm_ci_hotspot_Stable_signature): + if (_location != _in_field) break; // only allow for fields + if (!privileged) break; // only allow in privileged code + return _field_Stable; +#endif case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature): if (_location != _in_field) break; // only allow for fields if (!privileged) break; // only allow in privileged code @@ -1998,6 +2003,10 @@ methodHandle ClassFileParser::parse_method(bool is_interface, verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle)); } + if (name == vmSymbols::object_initializer_name() && is_interface) { + classfile_parse_error("Interface cannot have a method named , class file %s", CHECK_(nullHandle)); + } + int args_size = -1; // only used when _need_verify is true if (_need_verify) { args_size = ((flags & JVM_ACC_STATIC) ? 0 : 1) + diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 5e56b96721b..d1ff1c3cbab 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -913,7 +913,7 @@ Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() { } // Nothing more for the iterator to hand out. - assert(head == NULL, err_msg("head is " PTR_FORMAT ", expected not null:", p2i(head))); + assert(head == NULL, "head is " PTR_FORMAT ", expected not null:", p2i(head)); return NULL; } diff --git a/hotspot/src/share/vm/classfile/dictionary.cpp b/hotspot/src/share/vm/classfile/dictionary.cpp index 5260a62fbc6..3621af33f83 100644 --- a/hotspot/src/share/vm/classfile/dictionary.cpp +++ b/hotspot/src/share/vm/classfile/dictionary.cpp @@ -31,8 +31,6 @@ #include "runtime/orderAccess.inline.hpp" #include "utilities/hashtable.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - DictionaryEntry* Dictionary::_current_class_entry = NULL; int Dictionary::_current_class_index = 0; @@ -558,7 +556,7 @@ void ProtectionDomainCacheTable::print() { void ProtectionDomainCacheEntry::print() { tty->print_cr("entry " PTR_FORMAT " value " PTR_FORMAT " strongly_reachable %d next " PTR_FORMAT, - this, (void*)literal(), _strongly_reachable, next()); + p2i(this), p2i(literal()), _strongly_reachable, p2i(next())); } #endif diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index 9c0077e6dd2..fcdb0e0c6e5 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -53,7 +53,9 @@ #include "runtime/vframe.hpp" #include "utilities/preserveException.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif #define INJECTED_FIELD_COMPUTE_OFFSET(klass, name, signature, may_be_java) \ klass::_##name##_offset = JavaClasses::compute_injected_offset(JavaClasses::klass##_##name##_enum); @@ -1579,7 +1581,7 @@ void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) { while (h_throwable.not_null()) { objArrayHandle result (THREAD, objArrayOop(backtrace(h_throwable()))); if (result.is_null()) { - st->print_cr("%s", no_stack_trace_message()); + st->print_raw_cr(no_stack_trace_message()); return; } diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index ebdce8dae31..4199d350bee 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -157,7 +157,12 @@ class java_lang_String : AllStatic { if (count_offset > 0) { return java_string->int_field(count_offset); } else { - return ((typeArrayOop)java_string->obj_field(value_offset))->length(); + typeArrayOop value_array = ((typeArrayOop)java_string->obj_field(value_offset)); + if (value_array == NULL) { + return 0; + } else { + return value_array->length(); + } } } static int utf8_length(oop java_string); diff --git a/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp b/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp index b137da767c7..6df2d434ccf 100644 --- a/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp +++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp @@ -32,6 +32,9 @@ #include "runtime/thread.hpp" #include "services/threadService.hpp" #include "utilities/chunkedList.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#endif MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL; @@ -57,6 +60,9 @@ MetadataOnStackMark::MetadataOnStackMark(bool redefinition_walk) { CompileBroker::mark_on_stack(); JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack); ThreadService::metadata_do(Metadata::mark_on_stack); +#if INCLUDE_JVMCI + JVMCIRuntime::metadata_do(Metadata::mark_on_stack); +#endif } } @@ -119,7 +125,7 @@ MetadataOnStackBuffer* MetadataOnStackMark::allocate_buffer() { allocated = new MetadataOnStackBuffer(); } - assert(!allocated->is_full(), err_msg("Should not be full: " PTR_FORMAT, p2i(allocated))); + assert(!allocated->is_full(), "Should not be full: " PTR_FORMAT, p2i(allocated)); return allocated; } diff --git a/hotspot/src/share/vm/classfile/stackMapTable.cpp b/hotspot/src/share/vm/classfile/stackMapTable.cpp index f74adbe3172..1c92b61e5fe 100644 --- a/hotspot/src/share/vm/classfile/stackMapTable.cpp +++ b/hotspot/src/share/vm/classfile/stackMapTable.cpp @@ -186,7 +186,6 @@ VerificationType StackMapReader::parse_verification_type(u1* flags, TRAPS) { u2 offset = _stream->get_u2(THREAD); if (offset >= _code_length || _code_data[offset] != ClassVerifier::NEW_OFFSET) { - ResourceMark rm(THREAD); _verifier->class_format_error( "StackMapTable format error: bad offset for Uninitialized"); return VerificationType::bogus_type(); diff --git a/hotspot/src/share/vm/classfile/stringTable.cpp b/hotspot/src/share/vm/classfile/stringTable.cpp index 3640025956f..c14cd9e036a 100644 --- a/hotspot/src/share/vm/classfile/stringTable.cpp +++ b/hotspot/src/share/vm/classfile/stringTable.cpp @@ -43,8 +43,6 @@ #include "gc/g1/g1StringDedup.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // the number of buckets a thread claims const int ClaimChunkSize = 32; @@ -312,12 +310,12 @@ void StringTable::buckets_oops_do(OopClosure* f, int start_idx, int end_idx) { const int limit = the_table()->table_size(); assert(0 <= start_idx && start_idx <= limit, - err_msg("start_idx (%d) is out of bounds", start_idx)); + "start_idx (%d) is out of bounds", start_idx); assert(0 <= end_idx && end_idx <= limit, - err_msg("end_idx (%d) is out of bounds", end_idx)); + "end_idx (%d) is out of bounds", end_idx); assert(start_idx <= end_idx, - err_msg("Index ordering: start_idx=%d, end_idx=%d", - start_idx, end_idx)); + "Index ordering: start_idx=%d, end_idx=%d", + start_idx, end_idx); for (int i = start_idx; i < end_idx; i += 1) { HashtableEntry* entry = the_table()->bucket(i); @@ -335,12 +333,12 @@ void StringTable::buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClos const int limit = the_table()->table_size(); assert(0 <= start_idx && start_idx <= limit, - err_msg("start_idx (%d) is out of bounds", start_idx)); + "start_idx (%d) is out of bounds", start_idx); assert(0 <= end_idx && end_idx <= limit, - err_msg("end_idx (%d) is out of bounds", end_idx)); + "end_idx (%d) is out of bounds", end_idx); assert(start_idx <= end_idx, - err_msg("Index ordering: start_idx=%d, end_idx=%d", - start_idx, end_idx)); + "Index ordering: start_idx=%d, end_idx=%d", + start_idx, end_idx); for (int i = start_idx; i < end_idx; ++i) { HashtableEntry** p = the_table()->bucket_addr(i); @@ -445,7 +443,7 @@ StringTable::VerifyRetTypes StringTable::compare_entries( if (str1 == str2) { tty->print_cr("ERROR: identical oop values (0x" PTR_FORMAT ") " "in entry @ bucket[%d][%d] and entry @ bucket[%d][%d]", - (void *)str1, bkt1, e_cnt1, bkt2, e_cnt2); + p2i(str1), bkt1, e_cnt1, bkt2, e_cnt2); return _verify_fail_continue; } diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index faef8d12d0d..b5c3a157e12 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -37,8 +37,6 @@ #include "runtime/mutexLocker.hpp" #include "utilities/hashtable.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // -------------------------------------------------------------------------- // the number of buckets a thread claims const int ClaimChunkSize = 32; @@ -623,8 +621,8 @@ void SymbolTable::print_histogram() { ((float)_symbols_removed/(float)_symbols_counted)* 100); } tty->print_cr(" Reference counts %7d", Symbol::_total_count); - tty->print_cr(" Symbol arena used %7dK", arena()->used()/1024); - tty->print_cr(" Symbol arena size %7dK", arena()->size_in_bytes()/1024); + tty->print_cr(" Symbol arena used " SIZE_FORMAT_W(7) "K", arena()->used()/1024); + tty->print_cr(" Symbol arena size " SIZE_FORMAT_W(7) "K", arena()->size_in_bytes()/1024); tty->print_cr(" Total symbol length %7d", total_length); tty->print_cr(" Maximum symbol length %7d", max_length); tty->print_cr(" Average symbol length %7.2f", ((float) total_length / (float) total_count)); @@ -645,7 +643,7 @@ void SymbolTable::print() { HashtableEntry* entry = the_table()->bucket(i); if (entry != NULL) { while (entry != NULL) { - tty->print(PTR_FORMAT " ", entry->literal()); + tty->print(PTR_FORMAT " ", p2i(entry->literal())); entry->literal()->print(); tty->print(" %d", entry->literal()->refcount()); p = entry->next_addr(); diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 34d96ad07d1..bfae05db988 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -66,6 +66,9 @@ #include "classfile/sharedClassUtil.hpp" #include "classfile/systemDictionaryShared.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#endif #if INCLUDE_TRACE #include "trace/tracing.hpp" #endif @@ -228,10 +231,10 @@ Klass* SystemDictionary::resolve_or_fail(Symbol* class_name, // Forwards to resolve_instance_class_or_null Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) { - assert(!THREAD->is_Compiler_thread(), - err_msg("can not load classes with compiler thread: class=%s, classloader=%s", - class_name->as_C_string(), - class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string())); + assert(THREAD->can_call_java(), + "can not load classes with compiler thread: class=%s, classloader=%s", + class_name->as_C_string(), + class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string()); if (FieldType::is_array(class_name)) { return resolve_array_class_or_null(class_name, class_loader, protection_domain, THREAD); } else if (FieldType::is_obj(class_name)) { @@ -1917,7 +1920,7 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { WKID jsr292_group_end = WK_KLASS_ENUM_NAME(VolatileCallSite_klass); initialize_wk_klasses_until(jsr292_group_start, scan, CHECK); initialize_wk_klasses_through(jsr292_group_end, scan, CHECK); - initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK); + initialize_wk_klasses_until(NOT_JVMCI(WKID_LIMIT) JVMCI_ONLY(FIRST_JVMCI_WKID), scan, CHECK); _box_klasses[T_BOOLEAN] = WK_KLASS(Boolean_klass); _box_klasses[T_CHAR] = WK_KLASS(Character_klass); @@ -2264,7 +2267,7 @@ methodHandle SystemDictionary::find_method_handle_intrinsic(vmIntrinsics::ID iid assert(MethodHandles::is_signature_polymorphic(iid) && MethodHandles::is_signature_polymorphic_intrinsic(iid) && iid != vmIntrinsics::_invokeGeneric, - err_msg("must be a known MH intrinsic iid=%d: %s", iid, vmIntrinsics::name_at(iid))); + "must be a known MH intrinsic iid=%d: %s", iid, vmIntrinsics::name_at(iid)); unsigned int hash = invoke_method_table()->compute_hash(signature, iid); int index = invoke_method_table()->hash_to_index(hash); @@ -2343,7 +2346,7 @@ methodHandle SystemDictionary::find_method_handle_invoker(Symbol* name, Handle *method_type_result, TRAPS) { methodHandle empty; - assert(!THREAD->is_Compiler_thread(), ""); + assert(THREAD->can_call_java() ,""); Handle method_type = SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_(empty)); @@ -2390,7 +2393,7 @@ static bool is_always_visible_class(oop mirror) { if (klass->oop_is_typeArray()) { return true; // primitive array } - assert(klass->oop_is_instance(), klass->external_name()); + assert(klass->oop_is_instance(), "%s", klass->external_name()); return klass->is_public() && (InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::Object_klass()) || // java.lang InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::MethodHandle_klass())); // java.lang.invoke @@ -2411,7 +2414,7 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature, if (spe != NULL && spe->method_type() != NULL) { assert(java_lang_invoke_MethodType::is_instance(spe->method_type()), ""); return Handle(THREAD, spe->method_type()); - } else if (THREAD->is_Compiler_thread()) { + } else if (!THREAD->can_call_java()) { warning("SystemDictionary::find_method_handle_type called from compiler thread"); // FIXME return Handle(); // do not attempt from within compiler, unless it was cached } @@ -2443,7 +2446,7 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature, mirror = ss.as_java_mirror(class_loader, protection_domain, SignatureStream::NCDFError, CHECK_(empty)); } - assert(!oopDesc::is_null(mirror), ss.as_symbol(THREAD)->as_C_string()); + assert(!oopDesc::is_null(mirror), "%s", ss.as_symbol(THREAD)->as_C_string()); if (ss.at_return_type()) rt = Handle(THREAD, mirror); else diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index 9d7d88114e2..4eb39c59e9b 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -33,6 +33,7 @@ #include "runtime/reflectionUtils.hpp" #include "utilities/hashtable.hpp" #include "utilities/hashtable.inline.hpp" +#include "jvmci/systemDictionary_jvmci.hpp" // The system dictionary stores all loaded classes and maps: @@ -192,6 +193,10 @@ class Ticks; do_klass(Short_klass, java_lang_Short, Pre ) \ do_klass(Integer_klass, java_lang_Integer, Pre ) \ do_klass(Long_klass, java_lang_Long, Pre ) \ + \ + /* JVMCI classes. These are loaded on-demand. */ \ + JVMCI_WK_KLASSES_DO(do_klass) \ + /*end*/ @@ -209,6 +214,11 @@ class SystemDictionary : AllStatic { WKID_LIMIT, +#if INCLUDE_JVMCI + FIRST_JVMCI_WKID = WK_KLASS_ENUM_NAME(HotSpotCompiledCode_klass), + LAST_JVMCI_WKID = WK_KLASS_ENUM_NAME(Value_klass), +#endif + FIRST_WKID = NO_WKID + 1 }; @@ -219,6 +229,9 @@ class SystemDictionary : AllStatic { // Options after this point will use resolve_or_null instead. Opt, // preload tried; NULL if not present +#if INCLUDE_JVMCI + Jvmci, // preload tried; error if not present, use only with JVMCI +#endif OPTION_LIMIT, CEIL_LG_OPTION_LIMIT = 2 // OPTION_LIMIT <= (1<. Note that "" methods in interfaces are just - // normal methods. Interfaces cannot have ctors. + // . if (_method->name() == vmSymbols::object_initializer_name() && - current_frame.flag_this_uninit() && - !current_class()->is_interface()) { + current_frame.flag_this_uninit()) { verify_error(ErrorContext::bad_code(bci), "Constructor must call super() or this() " "before return"); diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 6ff63c981fc..b3ca0886f65 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -28,6 +28,7 @@ #include "oops/symbol.hpp" #include "memory/iterator.hpp" #include "trace/traceMacros.hpp" +#include "jvmci/vmSymbols_jvmci.hpp" // The class vmSymbols is a name space for fast lookup of // symbols commonly used in the VM. @@ -44,7 +45,6 @@ #define VM_SYMBOL_IGNORE(id, name) /*ignored*/ #define VM_ALIAS_IGNORE(id, id2) /*ignored*/ - // Mapping function names to values. New entries should be added below. #define VM_SYMBOLS_DO(template, do_alias) \ @@ -300,6 +300,9 @@ template(DEFAULT_CONTEXT_name, "DEFAULT_CONTEXT") \ NOT_LP64( do_alias(intptr_signature, int_signature) ) \ LP64_ONLY( do_alias(intptr_signature, long_signature) ) \ + \ + /* Support for JVMCI */ \ + JVMCI_VM_SYMBOLS_DO(template, do_alias) \ \ /* common method and field names */ \ template(object_initializer_name, "") \ @@ -382,6 +385,7 @@ template(bitCount_name, "bitCount") \ template(profile_name, "profile") \ template(equals_name, "equals") \ + template(length_name, "length") \ template(target_name, "target") \ template(toString_name, "toString") \ template(values_name, "values") \ @@ -432,6 +436,7 @@ template(void_long_signature, "()J") \ template(void_float_signature, "()F") \ template(void_double_signature, "()D") \ + template(bool_void_signature, "(Z)V") \ template(int_void_signature, "(I)V") \ template(int_int_signature, "(I)I") \ template(char_char_signature, "(C)C") \ diff --git a/hotspot/src/share/vm/code/codeBlob.hpp b/hotspot/src/share/vm/code/codeBlob.hpp index 6c64785d01b..cf846940b60 100644 --- a/hotspot/src/share/vm/code/codeBlob.hpp +++ b/hotspot/src/share/vm/code/codeBlob.hpp @@ -120,6 +120,7 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC { virtual bool is_compiled_by_c2() const { return false; } virtual bool is_compiled_by_c1() const { return false; } + virtual bool is_compiled_by_jvmci() const { return false; } // Casting nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; } @@ -380,6 +381,12 @@ class DeoptimizationBlob: public SingletonBlob { int _unpack_with_exception_in_tls; +#if INCLUDE_JVMCI + // Offsets when JVMCI calls uncommon_trap. + int _uncommon_trap_offset; + int _implicit_exception_uncommon_trap_offset; +#endif + // Creation support DeoptimizationBlob( CodeBuffer* cb, @@ -429,6 +436,21 @@ class DeoptimizationBlob: public SingletonBlob { assert(code_contains(code_begin() + _unpack_with_exception_in_tls), "must be PC inside codeblob"); } address unpack_with_exception_in_tls() const { return code_begin() + _unpack_with_exception_in_tls; } + +#if INCLUDE_JVMCI + // Offsets when JVMCI calls uncommon_trap. + void set_uncommon_trap_offset(int offset) { + _uncommon_trap_offset = offset; + assert(contains(code_begin() + _uncommon_trap_offset), "must be PC inside codeblob"); + } + address uncommon_trap() const { return code_begin() + _uncommon_trap_offset; } + + void set_implicit_exception_uncommon_trap_offset(int offset) { + _implicit_exception_uncommon_trap_offset = offset; + assert(contains(code_begin() + _implicit_exception_uncommon_trap_offset), "must be PC inside codeblob"); + } + address implicit_exception_uncommon_trap() const { return code_begin() + _implicit_exception_uncommon_trap_offset; } +#endif // INCLUDE_JVMCI }; diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index 8f1190ee5c5..94552fa7872 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -365,7 +365,7 @@ CodeBlob* CodeCache::allocate(int size, int code_blob_type, bool strict) { // Possibly wakes up the sweeper thread. NMethodSweeper::notify(code_blob_type); assert_locked_or_safepoint(CodeCache_lock); - assert(size > 0, err_msg_res("Code cache allocation request must be > 0 but is %d", size)); + assert(size > 0, "Code cache allocation request must be > 0 but is %d", size); if (size <= 0) { return NULL; } @@ -817,7 +817,7 @@ double CodeCache::reverse_free_ratio(int code_blob_type) { double max_capacity = (double)heap->max_capacity(); double result = max_capacity / unallocated_capacity; assert (max_capacity >= unallocated_capacity, "Must be"); - assert (result >= 1.0, err_msg_res("reverse_free_ratio must be at least 1. It is %f", result)); + assert (result >= 1.0, "reverse_free_ratio must be at least 1. It is %f", result); return result; } diff --git a/hotspot/src/share/vm/code/compiledIC.cpp b/hotspot/src/share/vm/code/compiledIC.cpp index 478a6cf58d0..3184e2ee86c 100644 --- a/hotspot/src/share/vm/code/compiledIC.cpp +++ b/hotspot/src/share/vm/code/compiledIC.cpp @@ -280,11 +280,13 @@ bool CompiledIC::is_call_to_compiled() const { bool is_monomorphic = (cb != NULL && cb->is_nmethod()); // Check that the cached_value is a klass for non-optimized monomorphic calls // This assertion is invalid for compiler1: a call that does not look optimized (no static stub) can be used - // for calling directly to vep without using the inline cache (i.e., cached_value == NULL) + // for calling directly to vep without using the inline cache (i.e., cached_value == NULL). + // For JVMCI this occurs because CHA is only used to improve inlining so call sites which could be optimized + // virtuals because there are no currently loaded subclasses of a type are left as virtual call sites. #ifdef ASSERT CodeBlob* caller = CodeCache::find_blob_unsafe(instruction_address()); - bool is_c1_method = caller->is_compiled_by_c1(); - assert( is_c1_method || + bool is_c1_or_jvmci_method = caller->is_compiled_by_c1() || caller->is_compiled_by_jvmci(); + assert( is_c1_or_jvmci_method || !is_monomorphic || is_optimized() || !caller->is_alive() || diff --git a/hotspot/src/share/vm/code/compiledIC.hpp b/hotspot/src/share/vm/code/compiledIC.hpp index c6f61c47f5e..d4d946e8336 100644 --- a/hotspot/src/share/vm/code/compiledIC.hpp +++ b/hotspot/src/share/vm/code/compiledIC.hpp @@ -306,7 +306,7 @@ class CompiledStaticCall: public NativeCall { friend CompiledStaticCall* compiledStaticCall_at(Relocation* call_site); // Code - static address emit_to_interp_stub(CodeBuffer &cbuf); + static address emit_to_interp_stub(CodeBuffer &cbuf, address mark = NULL); static int to_interp_stub_size(); static int reloc_to_interp_stub(); diff --git a/hotspot/src/share/vm/code/debugInfo.cpp b/hotspot/src/share/vm/code/debugInfo.cpp index 6ad7cc36b27..1cb13d7491c 100644 --- a/hotspot/src/share/vm/code/debugInfo.cpp +++ b/hotspot/src/share/vm/code/debugInfo.cpp @@ -29,8 +29,6 @@ #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Constructors DebugInfoWriteStream::DebugInfoWriteStream(DebugInformationRecorder* recorder, int initial_size) @@ -59,7 +57,7 @@ ScopeValue* DebugInfoReadStream::read_object_value() { #ifdef ASSERT assert(_obj_pool != NULL, "object pool does not exist"); for (int i = _obj_pool->length() - 1; i >= 0; i--) { - assert(((ObjectValue*) _obj_pool->at(i))->id() != id, "should not be read twice"); + assert(_obj_pool->at(i)->as_ObjectValue()->id() != id, "should not be read twice"); } #endif ObjectValue* result = new ObjectValue(id); @@ -73,7 +71,7 @@ ScopeValue* DebugInfoReadStream::get_cached_object() { int id = read_int(); assert(_obj_pool != NULL, "object pool does not exist"); for (int i = _obj_pool->length() - 1; i >= 0; i--) { - ObjectValue* ov = (ObjectValue*) _obj_pool->at(i); + ObjectValue* ov = _obj_pool->at(i)->as_ObjectValue(); if (ov->id() == id) { return ov; } diff --git a/hotspot/src/share/vm/code/debugInfo.hpp b/hotspot/src/share/vm/code/debugInfo.hpp index d79e101620a..7a1b666e5e0 100644 --- a/hotspot/src/share/vm/code/debugInfo.hpp +++ b/hotspot/src/share/vm/code/debugInfo.hpp @@ -41,6 +41,7 @@ // - ConstantValue describes a constant class ConstantOopReadValue; +class ObjectValue; class ScopeValue: public ResourceObj { public: @@ -58,6 +59,11 @@ class ScopeValue: public ResourceObj { return (ConstantOopReadValue*) this; } + ObjectValue* as_ObjectValue() { + assert(is_object(), "must be"); + return (ObjectValue*)this; + } + // Serialization of debugging information virtual void write_on(DebugInfoWriteStream* stream) = 0; static ScopeValue* read_from(DebugInfoReadStream* stream); diff --git a/hotspot/src/share/vm/code/debugInfoRec.cpp b/hotspot/src/share/vm/code/debugInfoRec.cpp index fa0cb70fc94..f1cbf02223f 100644 --- a/hotspot/src/share/vm/code/debugInfoRec.cpp +++ b/hotspot/src/share/vm/code/debugInfoRec.cpp @@ -37,6 +37,9 @@ class DIR_Chunk { int _offset; // location in the stream of this scope int _length; // number of bytes in the stream int _hash; // hash of stream bytes (for quicker reuse) +#if INCLUDE_JVMCI + DebugInformationRecorder* _DIR; +#endif void* operator new(size_t ignore, DebugInformationRecorder* dir) throw() { assert(ignore == sizeof(DIR_Chunk), ""); @@ -51,6 +54,9 @@ class DIR_Chunk { DIR_Chunk(int offset, int length, DebugInformationRecorder* dir) { _offset = offset; _length = length; +#if INCLUDE_JVMCI + _DIR = dir; +#endif unsigned int hash = 0; address p = dir->stream()->buffer() + _offset; for (int i = 0; i < length; i++) { @@ -77,6 +83,25 @@ class DIR_Chunk { } return NULL; } + +#if INCLUDE_JVMCI + static int compare(DIR_Chunk* const & a, DIR_Chunk* const & b) { + if (b->_hash > a->_hash) { + return 1; + } + if (b->_hash < a->_hash) { + return -1; + } + if (b->_length > a->_length) { + return 1; + } + if (b->_length < a->_length) { + return -1; + } + address buf = a->_DIR->stream()->buffer(); + return memcmp(buf + b->_offset, buf + a->_offset, a->_length); + } +#endif }; static inline bool compute_recording_non_safepoints() { @@ -113,7 +138,9 @@ DebugInformationRecorder::DebugInformationRecorder(OopRecorder* oop_recorder) _oop_recorder = oop_recorder; _all_chunks = new GrowableArray(300); +#if !INCLUDE_JVMCI _shared_chunks = new GrowableArray(30); +#endif _next_chunk = _next_chunk_limit = NULL; add_new_pc_offset(PcDesc::lower_offset_limit); // sentinel record @@ -235,10 +262,13 @@ struct dir_stats_struct { int DebugInformationRecorder::find_sharable_decode_offset(int stream_offset) { +#if !INCLUDE_JVMCI // Only pull this trick if non-safepoint recording // is enabled, for now. - if (!recording_non_safepoints()) + if (!recording_non_safepoints()) { return serialized_null; + } +#endif // INCLUDE_JVMCI NOT_PRODUCT(++dir_stats.chunks_queried); int stream_length = stream()->position() - stream_offset; @@ -247,6 +277,19 @@ int DebugInformationRecorder::find_sharable_decode_offset(int stream_offset) { DIR_Chunk* ns = new(this) DIR_Chunk(stream_offset, stream_length, this); +#if INCLUDE_JVMCI + DIR_Chunk* match = _all_chunks->insert_sorted(ns); + if (match != ns) { + // Found an existing chunk + NOT_PRODUCT(++dir_stats.chunks_shared); + assert(ns+1 == _next_chunk, ""); + _next_chunk = ns; + return match->_offset; + } else { + // Inserted this chunk, so nothing to do + return serialized_null; + } +#else // INCLUDE_JVMCI // Look in previously shared scopes first: DIR_Chunk* ms = ns->find_match(_shared_chunks, 0, this); if (ms != NULL) { @@ -274,15 +317,18 @@ int DebugInformationRecorder::find_sharable_decode_offset(int stream_offset) { // No match. Add this guy to the list, in hopes of future shares. _all_chunks->append(ns); return serialized_null; +#endif // INCLUDE_JVMCI } // must call add_safepoint before: it sets PcDesc and this routine uses // the last PcDesc set void DebugInformationRecorder::describe_scope(int pc_offset, + methodHandle methodH, ciMethod* method, int bci, bool reexecute, + bool rethrow_exception, bool is_method_handle_invoke, bool return_oop, DebugToken* locals, @@ -298,6 +344,7 @@ void DebugInformationRecorder::describe_scope(int pc_offset, // Record flags into pcDesc. last_pd->set_should_reexecute(reexecute); + last_pd->set_rethrow_exception(rethrow_exception); last_pd->set_is_method_handle_invoke(is_method_handle_invoke); last_pd->set_return_oop(return_oop); @@ -305,8 +352,16 @@ void DebugInformationRecorder::describe_scope(int pc_offset, stream()->write_int(sender_stream_offset); // serialize scope - Metadata* method_enc = (method == NULL)? NULL: method->constant_encoding(); - stream()->write_int(oop_recorder()->find_index(method_enc)); + Metadata* method_enc; + if (method != NULL) { + method_enc = method->constant_encoding(); + } else if (methodH.not_null()) { + method_enc = methodH(); + } else { + method_enc = NULL; + } + int method_enc_index = oop_recorder()->find_index(method_enc); + stream()->write_int(method_enc_index); stream()->write_bci(bci); assert(method == NULL || (method->is_native() && bci == 0) || @@ -338,7 +393,7 @@ void DebugInformationRecorder::dump_object_pool(GrowableArray* obje PcDesc* last_pd = &_pcs[_pcs_length-1]; if (objects != NULL) { for (int i = objects->length() - 1; i >= 0; i--) { - ((ObjectValue*) objects->at(i))->set_visited(false); + objects->at(i)->as_ObjectValue()->set_visited(false); } } int offset = serialize_scope_values(objects); diff --git a/hotspot/src/share/vm/code/debugInfoRec.hpp b/hotspot/src/share/vm/code/debugInfoRec.hpp index df056e2d5b9..62930adbc79 100644 --- a/hotspot/src/share/vm/code/debugInfoRec.hpp +++ b/hotspot/src/share/vm/code/debugInfoRec.hpp @@ -98,9 +98,11 @@ class DebugInformationRecorder: public ResourceObj { // by add_non_safepoint, and the locals, expressions, and monitors // must all be null. void describe_scope(int pc_offset, + methodHandle methodH, ciMethod* method, int bci, bool reexecute, + bool rethrow_exception = false, bool is_method_handle_invoke = false, bool return_oop = false, DebugToken* locals = NULL, @@ -143,6 +145,12 @@ class DebugInformationRecorder: public ResourceObj { bool recording_non_safepoints() { return _recording_non_safepoints; } + PcDesc* pcs() const { return _pcs; } + int pcs_length() const { return _pcs_length; } + + DebugInfoWriteStream* stream() const { return _stream; } + + private: friend class ScopeDesc; friend class vframeStreamCommon; @@ -155,13 +163,13 @@ class DebugInformationRecorder: public ResourceObj { DebugInfoWriteStream* _stream; - DebugInfoWriteStream* stream() const { return _stream; } - OopRecorder* _oop_recorder; // Scopes that have been described so far. GrowableArray* _all_chunks; +#if !INCLUDE_JVMCI GrowableArray* _shared_chunks; +#endif DIR_Chunk* _next_chunk; DIR_Chunk* _next_chunk_limit; diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp index 132bc162d42..ed77e17b7f5 100644 --- a/hotspot/src/share/vm/code/dependencies.cpp +++ b/hotspot/src/share/vm/code/dependencies.cpp @@ -31,6 +31,7 @@ #include "code/dependencies.hpp" #include "compiler/compileLog.hpp" #include "oops/oop.inline.hpp" +#include "oops/objArrayKlass.hpp" #include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/thread.inline.hpp" @@ -52,6 +53,9 @@ void Dependencies::initialize(ciEnv* env) { _oop_recorder = env->oop_recorder(); _log = env->log(); _dep_seen = new(arena) GrowableArray(arena, 500, 0, 0); +#if INCLUDE_JVMCI + _using_dep_values = false; +#endif DEBUG_ONLY(_deps[end_marker] = NULL); for (int i = (int)FIRST_TYPE; i < (int)TYPE_LIMIT; i++) { _deps[i] = new(arena) GrowableArray(arena, 10, 0, 0); @@ -120,6 +124,66 @@ void Dependencies::assert_call_site_target_value(ciCallSite* call_site, ciMethod assert_common_2(call_site_target_value, call_site, method_handle); } +#if INCLUDE_JVMCI + +Dependencies::Dependencies(Arena* arena, OopRecorder* oop_recorder, CompileLog* log) { + _oop_recorder = oop_recorder; + _log = log; + _dep_seen = new(arena) GrowableArray(arena, 500, 0, 0); + _using_dep_values = true; + DEBUG_ONLY(_dep_values[end_marker] = NULL); + for (int i = (int)FIRST_TYPE; i < (int)TYPE_LIMIT; i++) { + _dep_values[i] = new(arena) GrowableArray(arena, 10, 0, DepValue()); + } + _content_bytes = NULL; + _size_in_bytes = (size_t)-1; + + assert(TYPE_LIMIT <= (1<oop_is_array()) { + // As a special case, support this assertion on an array type, + // which reduces to an assertion on its element type. + // Note that this cannot be done with assertions that + // relate to concreteness or abstractness. + BasicType elemt = ArrayKlass::cast(ctxk)->element_type(); + if (is_java_primitive(elemt)) return; // Ex: int[][] + ctxk = ObjArrayKlass::cast(ctxk)->bottom_klass(); + //if (ctxk->is_final()) return; // Ex: String[][] + } + check_ctxk(ctxk); + assert_common_1(leaf_type, DepValue(_oop_recorder, ctxk)); +} + +void Dependencies::assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Klass* conck) { + check_ctxk_abstract(ctxk); + DepValue ctxk_dv(_oop_recorder, ctxk); + DepValue conck_dv(_oop_recorder, conck, &ctxk_dv); + assert_common_2(abstract_with_unique_concrete_subtype, ctxk_dv, conck_dv); +} + +void Dependencies::assert_unique_concrete_method(Klass* ctxk, Method* uniqm) { + check_ctxk(ctxk); + assert_common_2(unique_concrete_method, DepValue(_oop_recorder, ctxk), DepValue(_oop_recorder, uniqm)); +} + +void Dependencies::assert_call_site_target_value(oop call_site, oop method_handle) { + assert_common_2(call_site_target_value, DepValue(_oop_recorder, JNIHandles::make_local(call_site)), DepValue(_oop_recorder, JNIHandles::make_local(method_handle))); +} + +#endif // INCLUDE_JVMCI + + // Helper function. If we are adding a new dep. under ctxk2, // try to find an old dep. under a broader* ctxk1. If there is // @@ -230,6 +294,78 @@ void Dependencies::assert_common_3(DepType dept, deps->append(x2); } +#if INCLUDE_JVMCI +bool Dependencies::maybe_merge_ctxk(GrowableArray* deps, + int ctxk_i, DepValue ctxk2_dv) { + Klass* ctxk1 = deps->at(ctxk_i).as_klass(_oop_recorder); + Klass* ctxk2 = ctxk2_dv.as_klass(_oop_recorder); + if (ctxk2->is_subtype_of(ctxk1)) { + return true; // success, and no need to change + } else if (ctxk1->is_subtype_of(ctxk2)) { + // new context class fully subsumes previous one + deps->at_put(ctxk_i, ctxk2_dv); + return true; + } else { + return false; + } +} + +void Dependencies::assert_common_1(DepType dept, DepValue x) { + assert(dep_args(dept) == 1, "sanity"); + //log_dependency(dept, x); + GrowableArray* deps = _dep_values[dept]; + + // see if the same (or a similar) dep is already recorded + if (note_dep_seen(dept, x)) { + assert(deps->find(x) >= 0, "sanity"); + } else { + deps->append(x); + } +} + +void Dependencies::assert_common_2(DepType dept, + DepValue x0, DepValue x1) { + assert(dep_args(dept) == 2, "sanity"); + //log_dependency(dept, x0, x1); + GrowableArray* deps = _dep_values[dept]; + + // see if the same (or a similar) dep is already recorded + bool has_ctxk = has_explicit_context_arg(dept); + if (has_ctxk) { + assert(dep_context_arg(dept) == 0, "sanity"); + if (note_dep_seen(dept, x1)) { + // look in this bucket for redundant assertions + const int stride = 2; + for (int i = deps->length(); (i -= stride) >= 0; ) { + DepValue y1 = deps->at(i+1); + if (x1 == y1) { // same subject; check the context + if (maybe_merge_ctxk(deps, i+0, x0)) { + return; + } + } + } + } + } else { + assert(dep_implicit_context_arg(dept) == 0, "sanity"); + if (note_dep_seen(dept, x0) && note_dep_seen(dept, x1)) { + // look in this bucket for redundant assertions + const int stride = 2; + for (int i = deps->length(); (i -= stride) >= 0; ) { + DepValue y0 = deps->at(i+0); + DepValue y1 = deps->at(i+1); + if (x0 == y0 && x1 == y1) { + return; + } + } + } + } + + // append the assertion in the correct bucket: + deps->append(x0); + deps->append(x1); +} +#endif // INCLUDE_JVMCI + /// Support for encoding dependencies into an nmethod: void Dependencies::copy_to(nmethod* nm) { @@ -256,7 +392,40 @@ static int sort_dep_arg_2(ciBaseObject** p1, ciBaseObject** p2) static int sort_dep_arg_3(ciBaseObject** p1, ciBaseObject** p2) { return sort_dep(p1, p2, 3); } +#if INCLUDE_JVMCI +// metadata deps are sorted before object deps +static int sort_dep_value(Dependencies::DepValue* p1, Dependencies::DepValue* p2, int narg) { + for (int i = 0; i < narg; i++) { + int diff = p1[i].sort_key() - p2[i].sort_key(); + if (diff != 0) return diff; + } + return 0; +} +static int sort_dep_value_arg_1(Dependencies::DepValue* p1, Dependencies::DepValue* p2) +{ return sort_dep_value(p1, p2, 1); } +static int sort_dep_value_arg_2(Dependencies::DepValue* p1, Dependencies::DepValue* p2) +{ return sort_dep_value(p1, p2, 2); } +static int sort_dep_value_arg_3(Dependencies::DepValue* p1, Dependencies::DepValue* p2) +{ return sort_dep_value(p1, p2, 3); } +#endif // INCLUDE_JVMCI + void Dependencies::sort_all_deps() { +#if INCLUDE_JVMCI + if (_using_dep_values) { + for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { + DepType dept = (DepType)deptv; + GrowableArray* deps = _dep_values[dept]; + if (deps->length() <= 1) continue; + switch (dep_args(dept)) { + case 1: deps->sort(sort_dep_value_arg_1, 1); break; + case 2: deps->sort(sort_dep_value_arg_2, 2); break; + case 3: deps->sort(sort_dep_value_arg_3, 3); break; + default: ShouldNotReachHere(); + } + } + return; + } +#endif // INCLUDE_JVMCI for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { DepType dept = (DepType)deptv; GrowableArray* deps = _deps[dept]; @@ -272,6 +441,16 @@ void Dependencies::sort_all_deps() { size_t Dependencies::estimate_size_in_bytes() { size_t est_size = 100; +#if INCLUDE_JVMCI + if (_using_dep_values) { + for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { + DepType dept = (DepType)deptv; + GrowableArray* deps = _dep_values[dept]; + est_size += deps->length() * 2; // tags and argument(s) + } + return est_size; + } +#endif // INCLUDE_JVMCI for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { DepType dept = (DepType)deptv; GrowableArray* deps = _deps[dept]; @@ -311,6 +490,37 @@ void Dependencies::encode_content_bytes() { // cast is safe, no deps can overflow INT_MAX CompressedWriteStream bytes((int)estimate_size_in_bytes()); +#if INCLUDE_JVMCI + if (_using_dep_values) { + for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { + DepType dept = (DepType)deptv; + GrowableArray* deps = _dep_values[dept]; + if (deps->length() == 0) continue; + int stride = dep_args(dept); + int ctxkj = dep_context_arg(dept); // -1 if no context arg + assert(stride > 0, "sanity"); + for (int i = 0; i < deps->length(); i += stride) { + jbyte code_byte = (jbyte)dept; + int skipj = -1; + if (ctxkj >= 0 && ctxkj+1 < stride) { + Klass* ctxk = deps->at(i+ctxkj+0).as_klass(_oop_recorder); + DepValue x = deps->at(i+ctxkj+1); // following argument + if (ctxk == ctxk_encoded_as_null(dept, x.as_metadata(_oop_recorder))) { + skipj = ctxkj; // we win: maybe one less oop to keep track of + code_byte |= default_context_type_bit; + } + } + bytes.write_byte(code_byte); + for (int j = 0; j < stride; j++) { + if (j == skipj) continue; + DepValue v = deps->at(i+j); + int idx = v.index(); + bytes.write_int(idx); + } + } + } + } else { +#endif // INCLUDE_JVMCI for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { DepType dept = (DepType)deptv; GrowableArray* deps = _deps[dept]; @@ -344,6 +554,9 @@ void Dependencies::encode_content_bytes() { } } } +#if INCLUDE_JVMCI + } +#endif // write a sentinel byte to mark the end bytes.write_byte(end_marker); @@ -400,7 +613,7 @@ int Dependencies::dep_args(Dependencies::DepType dept) { } void Dependencies::check_valid_dependency_type(DepType dept) { - guarantee(FIRST_TYPE <= dept && dept < TYPE_LIMIT, err_msg("invalid dependency type: %d", (int) dept)); + guarantee(FIRST_TYPE <= dept && dept < TYPE_LIMIT, "invalid dependency type: %d", (int) dept); } // for the sake of the compiler log, print out current dependencies: @@ -540,10 +753,10 @@ void Dependencies::write_dependency_to(xmlStream* xtty, } void Dependencies::print_dependency(DepType dept, GrowableArray* args, - Klass* witness) { + Klass* witness, outputStream* st) { ResourceMark rm; ttyLocker ttyl; // keep the following output all in one block - tty->print_cr("%s of type %s", + st->print_cr("%s of type %s", (witness == NULL)? "Dependency": "Failed dependency", dep_name(dept)); // print arguments @@ -565,22 +778,22 @@ void Dependencies::print_dependency(DepType dept, GrowableArray* ar } else { what = "object "; } - tty->print(" %s = %s", what, (put_star? "*": "")); + st->print(" %s = %s", what, (put_star? "*": "")); if (arg.is_klass()) { - tty->print("%s", ((Klass*)arg.metadata_value())->external_name()); + st->print("%s", ((Klass*)arg.metadata_value())->external_name()); } else if (arg.is_method()) { - ((Method*)arg.metadata_value())->print_value(); + ((Method*)arg.metadata_value())->print_value_on(st); } else if (arg.is_oop()) { - arg.oop_value()->print_value_on(tty); + arg.oop_value()->print_value_on(st); } else { ShouldNotReachHere(); // Provide impl for this type. } - tty->cr(); + st->cr(); } if (witness != NULL) { bool put_star = !Dependencies::is_concrete_klass(witness); - tty->print_cr(" witness = %s%s", + st->print_cr(" witness = %s%s", (put_star? "*": ""), witness->external_name()); } @@ -600,14 +813,19 @@ void Dependencies::DepStream::log_dependency(Klass* witness) { } int argslen = args->length(); if (_deps != NULL && _deps->log() != NULL) { - Dependencies::write_dependency_to(_deps->log(), type(), args, witness); + if (ciEnv::current() != NULL) { + Dependencies::write_dependency_to(_deps->log(), type(), args, witness); + } else { + // Treat the CompileLog as an xmlstream instead + Dependencies::write_dependency_to((xmlStream*)_deps->log(), type(), args, witness); + } } else { Dependencies::write_dependency_to(xtty, type(), args, witness); } guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope"); } -void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose) { +void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose, outputStream* st) { ResourceMark rm; int nargs = argument_count(); GrowableArray* args = new GrowableArray(nargs); @@ -619,12 +837,12 @@ void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose) { } } int argslen = args->length(); - Dependencies::print_dependency(type(), args, witness); + Dependencies::print_dependency(type(), args, witness, st); if (verbose) { if (_code != NULL) { - tty->print(" code: "); - _code->print_value_on(tty); - tty->cr(); + st->print(" code: "); + _code->print_value_on(st); + st->cr(); } } guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope"); diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp index 3129a2cb5de..a2ffeeb08d1 100644 --- a/hotspot/src/share/vm/code/dependencies.hpp +++ b/hotspot/src/share/vm/code/dependencies.hpp @@ -202,10 +202,59 @@ class Dependencies: public ResourceObj { static void check_valid_dependency_type(DepType dept); +#if INCLUDE_JVMCI + // A Metadata* or object value recorded in an OopRecorder + class DepValue VALUE_OBJ_CLASS_SPEC { + private: + // Unique identifier of the value within the associated OopRecorder that + // encodes both the category of the value (0: invalid, positive: metadata, negative: object) + // and the index within a category specific array (metadata: index + 1, object: -(index + 1)) + int _id; + + public: + DepValue() : _id(0) {} + DepValue(OopRecorder* rec, Metadata* metadata, DepValue* candidate = NULL) { + assert(candidate == NULL || candidate->is_metadata(), "oops"); + if (candidate != NULL && candidate->as_metadata(rec) == metadata) { + _id = candidate->_id; + } else { + _id = rec->find_index(metadata) + 1; + } + } + DepValue(OopRecorder* rec, jobject obj, DepValue* candidate = NULL) { + assert(candidate == NULL || candidate->is_object(), "oops"); + if (candidate != NULL && candidate->as_object(rec) == obj) { + _id = candidate->_id; + } else { + _id = -(rec->find_index(obj) + 1); + } + } + + // Used to sort values in ascending order of index() with metadata values preceding object values + int sort_key() const { return -_id; } + + bool operator == (const DepValue& other) const { return other._id == _id; } + + bool is_valid() const { return _id != 0; } + int index() const { assert(is_valid(), "oops"); return _id < 0 ? -(_id + 1) : _id - 1; } + bool is_metadata() const { assert(is_valid(), "oops"); return _id > 0; } + bool is_object() const { assert(is_valid(), "oops"); return _id < 0; } + + Metadata* as_metadata(OopRecorder* rec) const { assert(is_metadata(), "oops"); return rec->metadata_at(index()); } + Klass* as_klass(OopRecorder* rec) const { assert(as_metadata(rec)->is_klass(), "oops"); return (Klass*) as_metadata(rec); } + Method* as_method(OopRecorder* rec) const { assert(as_metadata(rec)->is_method(), "oops"); return (Method*) as_metadata(rec); } + jobject as_object(OopRecorder* rec) const { assert(is_object(), "oops"); return rec->oop_at(index()); } + }; +#endif // INCLUDE_JVMCI + private: // State for writing a new set of dependencies: GrowableArray* _dep_seen; // (seen[h->ident] & (1<* _deps[TYPE_LIMIT]; +#if INCLUDE_JVMCI + bool _using_dep_values; + GrowableArray* _dep_values[TYPE_LIMIT]; +#endif static const char* _dep_name[TYPE_LIMIT]; static int _dep_args[TYPE_LIMIT]; @@ -224,8 +273,25 @@ class Dependencies: public ResourceObj { return (seen & (1<at_grow(x_id, 0); + _dep_seen->at_put(x_id, seen | (1<* deps, int ctxk_i, ciKlass* ctxk); +#if INCLUDE_JVMCI + bool maybe_merge_ctxk(GrowableArray* deps, + int ctxk_i, DepValue ctxk); +#endif void sort_all_deps(); size_t estimate_size_in_bytes(); @@ -247,6 +313,9 @@ class Dependencies: public ResourceObj { Dependencies(ciEnv* env) { initialize(env); } +#if INCLUDE_JVMCI + Dependencies(Arena* arena, OopRecorder* oop_recorder, CompileLog* log); +#endif private: // Check for a valid context type. @@ -279,6 +348,27 @@ class Dependencies: public ResourceObj { void assert_has_no_finalizable_subclasses(ciKlass* ctxk); void assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle); +#if INCLUDE_JVMCI + private: + static void check_ctxk(Klass* ctxk) { + assert(ctxk->oop_is_instance(), "java types only"); + } + static void check_ctxk_abstract(Klass* ctxk) { + check_ctxk(ctxk); + assert(ctxk->is_abstract(), "must be abstract"); + } + void assert_common_1(DepType dept, DepValue x); + void assert_common_2(DepType dept, DepValue x0, DepValue x1); + + public: + void assert_evol_method(Method* m); + void assert_has_no_finalizable_subclasses(Klass* ctxk); + void assert_leaf_type(Klass* ctxk); + void assert_unique_concrete_method(Klass* ctxk, Method* uniqm); + void assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Klass* conck); + void assert_call_site_target_value(oop callSite, oop methodHandle); +#endif // INCLUDE_JVMCI + // Define whether a given method or type is concrete. // These methods define the term "concrete" as used in this module. // For this module, an "abstract" class is one which is non-concrete. @@ -422,7 +512,7 @@ class Dependencies: public ResourceObj { static void print_dependency(DepType dept, GrowableArray* args, - Klass* witness = NULL); + Klass* witness = NULL, outputStream* st = tty); private: // helper for encoding common context types as zero: @@ -534,7 +624,7 @@ class Dependencies: public ResourceObj { void log_dependency(Klass* witness = NULL); // Print the current dependency to tty. - void print_dependency(Klass* witness = NULL, bool verbose = false); + void print_dependency(Klass* witness = NULL, bool verbose = false, outputStream* st = tty); }; friend class Dependencies::DepStream; diff --git a/hotspot/src/share/vm/code/exceptionHandlerTable.cpp b/hotspot/src/share/vm/code/exceptionHandlerTable.cpp index 224e164deb4..b2247b89523 100644 --- a/hotspot/src/share/vm/code/exceptionHandlerTable.cpp +++ b/hotspot/src/share/vm/code/exceptionHandlerTable.cpp @@ -27,8 +27,6 @@ #include "code/nmethod.hpp" #include "memory/allocation.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void ExceptionHandlerTable::add_entry(HandlerTableEntry entry) { _nesting.check(); if (_length >= _size) { @@ -102,9 +100,12 @@ void ExceptionHandlerTable::add_subtable( void ExceptionHandlerTable::copy_to(nmethod* nm) { assert(size_in_bytes() == nm->handler_table_size(), "size of space allocated in nmethod incorrect"); - memmove(nm->handler_table_begin(), _table, size_in_bytes()); + copy_bytes_to(nm->handler_table_begin()); } +void ExceptionHandlerTable::copy_bytes_to(address addr) { + memmove(addr, _table, size_in_bytes()); +} HandlerTableEntry* ExceptionHandlerTable::entry_for(int catch_pco, int handler_bci, int scope_depth) const { HandlerTableEntry* t = subtable_for(catch_pco); @@ -186,7 +187,7 @@ uint ImplicitExceptionTable::at( uint exec_off ) const { void ImplicitExceptionTable::print(address base) const { tty->print("{"); for( uint i=0; iprint("< " INTPTR_FORMAT ", " INTPTR_FORMAT " > ",base + *adr(i), base + *(adr(i)+1)); + tty->print("< " INTPTR_FORMAT ", " INTPTR_FORMAT " > ", p2i(base + *adr(i)), p2i(base + *(adr(i)+1))); tty->print_cr("}"); } @@ -225,6 +226,6 @@ void ImplicitExceptionTable::verify(nmethod *nm) const { for (uint i = 0; i < len(); i++) { if ((*adr(i) > (unsigned int)nm->insts_size()) || (*(adr(i)+1) > (unsigned int)nm->insts_size())) - fatal(err_msg("Invalid offset in ImplicitExceptionTable at " PTR_FORMAT, _data)); + fatal("Invalid offset in ImplicitExceptionTable at " PTR_FORMAT, p2i(_data)); } } diff --git a/hotspot/src/share/vm/code/exceptionHandlerTable.hpp b/hotspot/src/share/vm/code/exceptionHandlerTable.hpp index fa14dbe4120..338e8d56800 100644 --- a/hotspot/src/share/vm/code/exceptionHandlerTable.hpp +++ b/hotspot/src/share/vm/code/exceptionHandlerTable.hpp @@ -89,11 +89,11 @@ class ExceptionHandlerTable VALUE_OBJ_CLASS_SPEC { int _size; // the number of allocated entries ReallocMark _nesting; // assertion check for reallocations + public: // add the entry & grow the table if needed void add_entry(HandlerTableEntry entry); HandlerTableEntry* subtable_for(int catch_pco) const; - public: // (compile-time) construction within compiler ExceptionHandlerTable(int initial_size = 8); @@ -116,6 +116,7 @@ class ExceptionHandlerTable VALUE_OBJ_CLASS_SPEC { // nmethod support int size_in_bytes() const { return round_to(_length * sizeof(HandlerTableEntry), oopSize); } void copy_to(nmethod* nm); + void copy_bytes_to(address addr); // lookup HandlerTableEntry* entry_for(int catch_pco, int handler_bci, int scope_depth) const; diff --git a/hotspot/src/share/vm/code/icBuffer.cpp b/hotspot/src/share/vm/code/icBuffer.cpp index a08e2e616ae..65ea0b83ccd 100644 --- a/hotspot/src/share/vm/code/icBuffer.cpp +++ b/hotspot/src/share/vm/code/icBuffer.cpp @@ -38,8 +38,6 @@ #include "runtime/mutexLocker.hpp" #include "runtime/stubRoutines.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - DEF_STUB_INTERFACE(ICStub); StubQueue* InlineCacheBuffer::_buffer = NULL; @@ -97,7 +95,7 @@ void ICStub::verify() { } void ICStub::print() { - tty->print_cr("ICStub: site: " INTPTR_FORMAT, _ic_site); + tty->print_cr("ICStub: site: " INTPTR_FORMAT, p2i(_ic_site)); } #endif @@ -175,7 +173,7 @@ void InlineCacheBuffer::create_transition_stub(CompiledIC *ic, void* cached_valu assert (CompiledIC_lock->is_locked(), ""); if (TraceICBuffer) { tty->print_cr(" create transition stub for " INTPTR_FORMAT " destination " INTPTR_FORMAT " cached value " INTPTR_FORMAT, - ic->instruction_address(), entry, cached_value); + p2i(ic->instruction_address()), p2i(entry), p2i(cached_value)); } // If an transition stub is already associate with the inline cache, then we remove the association. @@ -230,6 +228,6 @@ void InlineCacheBuffer::queue_for_release(CompiledICHolder* icholder) { _pending_released = icholder; _pending_count++; if (TraceICBuffer) { - tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed", icholder); + tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed", p2i(icholder)); } } diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 44a92b5163e..0c46606da6a 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -26,6 +26,7 @@ #include "code/codeCache.hpp" #include "code/compiledIC.hpp" #include "code/dependencies.hpp" +#include "code/nativeInst.hpp" #include "code/nmethod.hpp" #include "code/scopeDesc.hpp" #include "compiler/abstractCompiler.hpp" @@ -46,11 +47,27 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" +#ifdef TARGET_ARCH_x86 +# include "nativeInst_x86.hpp" +#endif +#ifdef TARGET_ARCH_sparc +# include "nativeInst_sparc.hpp" +#endif +#ifdef TARGET_ARCH_zero +# include "nativeInst_zero.hpp" +#endif +#ifdef TARGET_ARCH_arm +# include "nativeInst_arm.hpp" +#endif +#ifdef TARGET_ARCH_ppc +# include "nativeInst_ppc.hpp" +#endif #ifdef SHARK #include "shark/sharkCompiler.hpp" #endif - -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif unsigned char nmethod::_global_unloading_clock = 0; @@ -84,6 +101,11 @@ bool nmethod::is_compiled_by_c1() const { } return compiler()->is_c1(); } +bool nmethod::is_compiled_by_jvmci() const { + if (compiler() == NULL || method() == NULL) return false; // can happen during debug printing + if (is_native_method()) return false; + return compiler()->is_jvmci(); +} bool nmethod::is_compiled_by_c2() const { if (compiler() == NULL) { return false; @@ -108,8 +130,7 @@ bool nmethod::is_compiled_by_shark() const { #ifndef PRODUCT // These variables are put into one block to reduce relocations // and make it simpler to print from the debugger. -static -struct nmethod_stats_struct { +struct java_nmethod_stats_struct { int nmethod_count; int total_size; int relocation_size; @@ -122,6 +143,7 @@ struct nmethod_stats_struct { int handler_table_size; int nul_chk_table_size; int oops_size; + int metadata_size; void note_nmethod(nmethod* nm) { nmethod_count += 1; @@ -131,39 +153,46 @@ struct nmethod_stats_struct { insts_size += nm->insts_size(); stub_size += nm->stub_size(); oops_size += nm->oops_size(); + metadata_size += nm->metadata_size(); scopes_data_size += nm->scopes_data_size(); scopes_pcs_size += nm->scopes_pcs_size(); dependencies_size += nm->dependencies_size(); handler_table_size += nm->handler_table_size(); nul_chk_table_size += nm->nul_chk_table_size(); } - void print_nmethod_stats() { + void print_nmethod_stats(const char* name) { if (nmethod_count == 0) return; - tty->print_cr("Statistics for %d bytecoded nmethods:", nmethod_count); + tty->print_cr("Statistics for %d bytecoded nmethods for %s:", nmethod_count, name); if (total_size != 0) tty->print_cr(" total in heap = %d", total_size); + if (nmethod_count != 0) tty->print_cr(" header = " SIZE_FORMAT, nmethod_count * sizeof(nmethod)); if (relocation_size != 0) tty->print_cr(" relocation = %d", relocation_size); if (consts_size != 0) tty->print_cr(" constants = %d", consts_size); if (insts_size != 0) tty->print_cr(" main code = %d", insts_size); if (stub_size != 0) tty->print_cr(" stub code = %d", stub_size); if (oops_size != 0) tty->print_cr(" oops = %d", oops_size); + if (metadata_size != 0) tty->print_cr(" metadata = %d", metadata_size); if (scopes_data_size != 0) tty->print_cr(" scopes data = %d", scopes_data_size); if (scopes_pcs_size != 0) tty->print_cr(" scopes pcs = %d", scopes_pcs_size); if (dependencies_size != 0) tty->print_cr(" dependencies = %d", dependencies_size); if (handler_table_size != 0) tty->print_cr(" handler table = %d", handler_table_size); if (nul_chk_table_size != 0) tty->print_cr(" nul chk table = %d", nul_chk_table_size); } +}; +struct native_nmethod_stats_struct { int native_nmethod_count; int native_total_size; int native_relocation_size; int native_insts_size; int native_oops_size; + int native_metadata_size; void note_native_nmethod(nmethod* nm) { native_nmethod_count += 1; native_total_size += nm->size(); native_relocation_size += nm->relocation_size(); native_insts_size += nm->insts_size(); native_oops_size += nm->oops_size(); + native_metadata_size += nm->metadata_size(); } void print_native_nmethod_stats() { if (native_nmethod_count == 0) return; @@ -172,8 +201,11 @@ struct nmethod_stats_struct { if (native_relocation_size != 0) tty->print_cr(" N. relocation = %d", native_relocation_size); if (native_insts_size != 0) tty->print_cr(" N. main code = %d", native_insts_size); if (native_oops_size != 0) tty->print_cr(" N. oops = %d", native_oops_size); + if (native_metadata_size != 0) tty->print_cr(" N. metadata = %d", native_metadata_size); } +}; +struct pc_nmethod_stats_struct { int pc_desc_resets; // number of resets (= number of caches) int pc_desc_queries; // queries to nmethod::find_pc_desc int pc_desc_approx; // number of those which have approximate true @@ -194,9 +226,51 @@ struct nmethod_stats_struct { pc_desc_repeats, pc_desc_hits, pc_desc_tests, pc_desc_searches, pc_desc_adds); } -} nmethod_stats; -#endif //PRODUCT +}; +#ifdef COMPILER1 +static java_nmethod_stats_struct c1_java_nmethod_stats; +#endif +#ifdef COMPILER2 +static java_nmethod_stats_struct c2_java_nmethod_stats; +#endif +#if INCLUDE_JVMCI +static java_nmethod_stats_struct jvmci_java_nmethod_stats; +#endif +#ifdef SHARK +static java_nmethod_stats_struct shark_java_nmethod_stats; +#endif +static java_nmethod_stats_struct unknown_java_nmethod_stats; + +static native_nmethod_stats_struct native_nmethod_stats; +static pc_nmethod_stats_struct pc_nmethod_stats; + +static void note_java_nmethod(nmethod* nm) { +#ifdef COMPILER1 + if (nm->is_compiled_by_c1()) { + c1_java_nmethod_stats.note_nmethod(nm); + } else +#endif +#ifdef COMPILER2 + if (nm->is_compiled_by_c2()) { + c2_java_nmethod_stats.note_nmethod(nm); + } else +#endif +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci()) { + jvmci_java_nmethod_stats.note_nmethod(nm); + } else +#endif +#ifdef SHARK + if (nm->is_compiled_by_shark()) { + shark_java_nmethod_stats.note_nmethod(nm); + } else +#endif + { + unknown_java_nmethod_stats.note_nmethod(nm); + } +} +#endif // !PRODUCT //--------------------------------------------------------------------------------- @@ -276,7 +350,7 @@ ExceptionCache* nmethod::exception_cache_entry_for_exception(Handle exception) { // Helper used by both find_pc_desc methods. static inline bool match_desc(PcDesc* pc, int pc_offset, bool approximate) { - NOT_PRODUCT(++nmethod_stats.pc_desc_tests); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_tests); if (!approximate) return pc->pc_offset() == pc_offset; else @@ -288,7 +362,7 @@ void PcDescCache::reset_to(PcDesc* initial_pc_desc) { _pc_descs[0] = NULL; // native method; no PcDescs at all return; } - NOT_PRODUCT(++nmethod_stats.pc_desc_resets); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_resets); // reset the cache by filling it with benign (non-null) values assert(initial_pc_desc->pc_offset() < 0, "must be sentinel"); for (int i = 0; i < cache_size; i++) @@ -296,8 +370,8 @@ void PcDescCache::reset_to(PcDesc* initial_pc_desc) { } PcDesc* PcDescCache::find_pc_desc(int pc_offset, bool approximate) { - NOT_PRODUCT(++nmethod_stats.pc_desc_queries); - NOT_PRODUCT(if (approximate) ++nmethod_stats.pc_desc_approx); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_queries); + NOT_PRODUCT(if (approximate) ++pc_nmethod_stats.pc_desc_approx); // Note: one might think that caching the most recently // read value separately would be a win, but one would be @@ -313,7 +387,7 @@ PcDesc* PcDescCache::find_pc_desc(int pc_offset, bool approximate) { res = _pc_descs[0]; if (res == NULL) return NULL; // native method; no PcDescs at all if (match_desc(res, pc_offset, approximate)) { - NOT_PRODUCT(++nmethod_stats.pc_desc_repeats); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_repeats); return res; } @@ -322,7 +396,7 @@ PcDesc* PcDescCache::find_pc_desc(int pc_offset, bool approximate) { res = _pc_descs[i]; if (res->pc_offset() < 0) break; // optimization: skip empty cache if (match_desc(res, pc_offset, approximate)) { - NOT_PRODUCT(++nmethod_stats.pc_desc_hits); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_hits); return res; } } @@ -332,7 +406,7 @@ PcDesc* PcDescCache::find_pc_desc(int pc_offset, bool approximate) { } void PcDescCache::add_pc_desc(PcDesc* pc_desc) { - NOT_PRODUCT(++nmethod_stats.pc_desc_adds); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_adds); // Update the LRU cache by shifting pc_desc forward. for (int i = 0; i < cache_size; i++) { PcDesc* next = _pc_descs[i]; @@ -459,7 +533,7 @@ void nmethod::init_defaults() { _marked_for_deoptimization = 0; _lock_count = 0; _stack_traversal_mark = 0; - _unload_reported = false; // jvmti state + _unload_reported = false; // jvmti state #ifdef ASSERT _oops_are_stale = false; @@ -478,6 +552,10 @@ void nmethod::init_defaults() { #if INCLUDE_RTM_OPT _rtm_state = NoRTM; #endif +#if INCLUDE_JVMCI + _jvmci_installed_code = NULL; + _speculation_log = NULL; +#endif } nmethod* nmethod::new_native_nmethod(methodHandle method, @@ -503,7 +581,7 @@ nmethod* nmethod::new_native_nmethod(methodHandle method, code_buffer, frame_size, basic_lock_owner_sp_offset, basic_lock_sp_offset, oop_maps); - NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_native_nmethod(nm)); + NOT_PRODUCT(if (nm != NULL) native_nmethod_stats.note_native_nmethod(nm)); if ((PrintAssembly || CompilerOracle::should_print(method)) && nm != NULL) { Disassembler::decode(nm); } @@ -531,6 +609,10 @@ nmethod* nmethod::new_nmethod(methodHandle method, ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, int comp_level +#if INCLUDE_JVMCI + , Handle installed_code, + Handle speculationLog +#endif ) { assert(debug_info->oop_recorder() == code_buffer->oop_recorder(), "shared OR"); @@ -553,7 +635,12 @@ nmethod* nmethod::new_nmethod(methodHandle method, handler_table, nul_chk_table, compiler, - comp_level); + comp_level +#if INCLUDE_JVMCI + , installed_code, + speculationLog +#endif + ); if (nm != NULL) { // To make dependency checking during class loading fast, record @@ -578,7 +665,7 @@ nmethod* nmethod::new_nmethod(methodHandle method, InstanceKlass::cast(klass)->add_dependent_nmethod(nm); } } - NOT_PRODUCT(nmethod_stats.note_nmethod(nm)); + NOT_PRODUCT(if (nm != NULL) note_java_nmethod(nm)); if (PrintAssembly || CompilerOracle::has_option_string(method, "PrintAssembly")) { Disassembler::decode(nm); } @@ -593,7 +680,10 @@ nmethod* nmethod::new_nmethod(methodHandle method, return nm; } - +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4355) // warning C4355: 'this' : used in base member initializer list +#endif // For native wrappers nmethod::nmethod( Method* method, @@ -683,6 +773,10 @@ nmethod::nmethod( } } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw () { return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level)); } @@ -703,6 +797,10 @@ nmethod::nmethod( ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, int comp_level +#if INCLUDE_JVMCI + , Handle installed_code, + Handle speculation_log +#endif ) : CodeBlob("nmethod", code_buffer, sizeof(nmethod), nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps), @@ -727,15 +825,42 @@ nmethod::nmethod( _consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts()); _stub_offset = content_offset() + code_buffer->total_offset_of(code_buffer->stubs()); +#if INCLUDE_JVMCI + _jvmci_installed_code = installed_code(); + _speculation_log = (instanceOop)speculation_log(); + + if (compiler->is_jvmci()) { + // JVMCI might not produce any stub sections + if (offsets->value(CodeOffsets::Exceptions) != -1) { + _exception_offset = code_offset() + offsets->value(CodeOffsets::Exceptions); + } else { + _exception_offset = -1; + } + if (offsets->value(CodeOffsets::Deopt) != -1) { + _deoptimize_offset = code_offset() + offsets->value(CodeOffsets::Deopt); + } else { + _deoptimize_offset = -1; + } + if (offsets->value(CodeOffsets::DeoptMH) != -1) { + _deoptimize_mh_offset = code_offset() + offsets->value(CodeOffsets::DeoptMH); + } else { + _deoptimize_mh_offset = -1; + } + } else { +#endif // Exception handler and deopt handler are in the stub section assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set"); assert(offsets->value(CodeOffsets::Deopt ) != -1, "must be set"); + _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); _deoptimize_offset = _stub_offset + offsets->value(CodeOffsets::Deopt); if (offsets->value(CodeOffsets::DeoptMH) != -1) { _deoptimize_mh_offset = _stub_offset + offsets->value(CodeOffsets::DeoptMH); } else { _deoptimize_mh_offset = -1; +#if INCLUDE_JVMCI + } +#endif } if (offsets->value(CodeOffsets::UnwindHandler) != -1) { _unwind_handler_offset = code_offset() + offsets->value(CodeOffsets::UnwindHandler); @@ -779,12 +904,12 @@ nmethod::nmethod( // we use the information of entry points to find out if a method is // static or non static - assert(compiler->is_c2() || + assert(compiler->is_c2() || compiler->is_jvmci() || _method->is_static() == (entry_point() == _verified_entry_point), " entry points must be same for static methods and vice versa"); } - bool printnmethods = PrintNMethods + bool printnmethods = PrintNMethods || PrintNMethodsAtLevel == _comp_level || CompilerOracle::should_print(_method) || CompilerOracle::has_option_string(_method, "PrintNMethods"); if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { @@ -792,7 +917,6 @@ nmethod::nmethod( } } - // Print a short set of xml attributes to identify this nmethod. The // output should be embedded in some other element. void nmethod::log_identity(xmlStream* log) const { @@ -809,9 +933,9 @@ void nmethod::log_identity(xmlStream* log) const { #define LOG_OFFSET(log, name) \ - if ((intptr_t)name##_end() - (intptr_t)name##_begin()) \ - log->print(" " XSTR(name) "_offset='%d'" , \ - (intptr_t)name##_begin() - (intptr_t)this) + if (p2i(name##_end()) - p2i(name##_begin())) \ + log->print(" " XSTR(name) "_offset='" INTX_FORMAT "'" , \ + p2i(name##_begin()) - p2i(this)) void nmethod::log_new_nmethod() const { @@ -820,8 +944,8 @@ void nmethod::log_new_nmethod() const { HandleMark hm; xtty->begin_elem("nmethod"); log_identity(xtty); - xtty->print(" entry='" INTPTR_FORMAT "' size='%d'", code_begin(), size()); - xtty->print(" address='" INTPTR_FORMAT "'", (intptr_t) this); + xtty->print(" entry='" INTPTR_FORMAT "' size='%d'", p2i(code_begin()), size()); + xtty->print(" address='" INTPTR_FORMAT "'", p2i(this)); LOG_OFFSET(xtty, relocation); LOG_OFFSET(xtty, consts); @@ -833,6 +957,7 @@ void nmethod::log_new_nmethod() const { LOG_OFFSET(xtty, handler_table); LOG_OFFSET(xtty, nul_chk_table); LOG_OFFSET(xtty, oops); + LOG_OFFSET(xtty, metadata); xtty->method(method()); xtty->stamp(); @@ -849,7 +974,7 @@ void nmethod::print_on(outputStream* st, const char* msg) const { ttyLocker ttyl; if (WizardMode) { CompileTask::print(st, this, msg, /*short_form:*/ true); - st->print_cr(" (" INTPTR_FORMAT ")", this); + st->print_cr(" (" INTPTR_FORMAT ")", p2i(this)); } else { CompileTask::print(st, this, msg, /*short_form:*/ false); } @@ -874,13 +999,13 @@ void nmethod::print_nmethod(bool printmethod) { oop_maps()->print(); } } - if (PrintDebugInfo) { + if (PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) { print_scopes(); } - if (PrintRelocations) { + if (PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) { print_relocations(); } - if (PrintDependencies) { + if (PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) { print_dependencies(); } if (PrintExceptionHandlers) { @@ -990,7 +1115,7 @@ ScopeDesc* nmethod::scope_desc_at(address pc) { PcDesc* pd = pc_desc_at(pc); guarantee(pd != NULL, "scope must be present"); return new ScopeDesc(this, pd->scope_decode_offset(), - pd->obj_decode_offset(), pd->should_reexecute(), + pd->obj_decode_offset(), pd->should_reexecute(), pd->rethrow_exception(), pd->return_oop()); } @@ -1161,7 +1286,7 @@ bool nmethod::can_convert_to_zombie() { } void nmethod::inc_decompile_count() { - if (!is_compiled_by_c2()) return; + if (!is_compiled_by_c2() && !is_compiled_by_jvmci()) return; // Could be gated by ProfileTraps, but do not bother... Method* m = method(); if (m == NULL) return; @@ -1205,7 +1330,7 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { tty->print_cr("[Class unloading: Making nmethod " INTPTR_FORMAT " unloadable], Method*(" INTPTR_FORMAT "), cause(" INTPTR_FORMAT ")", - this, (address)_method, (address)cause); + p2i(this), p2i(_method), p2i(cause)); if (!Universe::heap()->is_gc_active()) cause->klass()->print(); } @@ -1225,6 +1350,7 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { } _method = NULL; // Clear the method of this dead nmethod } + // Make the class unloaded - i.e., change state and notify sweeper assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); if (is_in_use()) { @@ -1237,6 +1363,18 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { // Unregister must be done before the state change Universe::heap()->unregister_nmethod(this); +#if INCLUDE_JVMCI + // The method can only be unloaded after the pointer to the installed code + // Java wrapper is no longer alive. Here we need to clear out this weak + // reference to the dead object. Nulling out the reference has to happen + // after the method is unregistered since the original value may be still + // tracked by the rset. + if (_jvmci_installed_code != NULL) { + InstalledCode::set_address(_jvmci_installed_code, 0); + _jvmci_installed_code = NULL; + } +#endif + _state = unloaded; // Log the unloading. @@ -1400,9 +1538,16 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { } else { assert(state == not_entrant, "other cases may need to be handled differently"); } +#if INCLUDE_JVMCI + if (_jvmci_installed_code != NULL) { + // Break the link between nmethod and InstalledCode such that the nmethod can subsequently be flushed safely. + InstalledCode::set_address(_jvmci_installed_code, 0); + } +#endif if (TraceCreateZombies) { - tty->print_cr("nmethod <" INTPTR_FORMAT "> code made %s", this, (state == not_entrant) ? "not entrant" : "zombie"); + ResourceMark m; + tty->print_cr("nmethod <" INTPTR_FORMAT "> %s code made %s", p2i(this), this->method() ? this->method()->name_and_sig_as_C_string() : "null", (state == not_entrant) ? "not entrant" : "zombie"); } NMethodSweeper::report_state_change(this); @@ -1418,10 +1563,12 @@ void nmethod::flush() { assert_locked_or_safepoint(CodeCache_lock); // completely deallocate this method - Events::log(JavaThread::current(), "flushing nmethod " INTPTR_FORMAT, this); + Events::log(JavaThread::current(), "flushing nmethod " INTPTR_FORMAT, p2i(this)); if (PrintMethodFlushing) { - tty->print_cr("*flushing nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT "/Free CodeCache:" SIZE_FORMAT "Kb", - _compile_id, this, CodeCache::nof_blobs(), CodeCache::unallocated_capacity(CodeCache::get_code_blob_type(this))/1024); + tty->print_cr("*flushing nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT + "/Free CodeCache:" SIZE_FORMAT "Kb", + _compile_id, p2i(this), CodeCache::nof_blobs(), + CodeCache::unallocated_capacity(CodeCache::get_code_blob_type(this))/1024); } // We need to deallocate any ExceptionCache data. @@ -1690,6 +1837,33 @@ void nmethod::do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred) } } +#if INCLUDE_JVMCI + // Follow JVMCI method + BarrierSet* bs = Universe::heap()->barrier_set(); + if (_jvmci_installed_code != NULL) { + if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { + if (!is_alive->do_object_b(_jvmci_installed_code)) { + bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); + _jvmci_installed_code = NULL; + bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + } + } else { + if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { + return; + } + } + } + + if (_speculation_log != NULL) { + if (!is_alive->do_object_b(_speculation_log)) { + bs->write_ref_nmethod_pre(&_speculation_log, this); + _speculation_log = NULL; + bs->write_ref_nmethod_post(&_speculation_log, this); + } + } +#endif + + // Ensure that all metadata is still alive verify_metadata_loaders(low_boundary, is_alive); } @@ -1709,7 +1883,7 @@ static bool clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address add // Clean inline caches pointing to both zombie and not_entrant methods if (!nm->is_in_use() || (nm->method()->code() != nm)) { ic->set_to_clean(); - assert(ic->is_clean(), err_msg("nmethod " PTR_FORMAT "not clean %s", from, from->method()->name_and_sig_as_C_string())); + assert(ic->is_clean(), "nmethod " PTR_FORMAT "not clean %s", p2i(from), from->method()->name_and_sig_as_C_string()); } } @@ -1772,6 +1946,27 @@ bool nmethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_ unloading_occurred = true; } +#if INCLUDE_JVMCI + // Follow JVMCI method + if (_jvmci_installed_code != NULL) { + if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { + if (!is_alive->do_object_b(_jvmci_installed_code)) { + _jvmci_installed_code = NULL; + } + } else { + if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { + return false; + } + } + } + + if (_speculation_log != NULL) { + if (!is_alive->do_object_b(_speculation_log)) { + _speculation_log = NULL; + } + } +#endif + // Exception cache clean_exception_cache(is_alive); @@ -1829,6 +2024,32 @@ bool nmethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_ return postponed; } +#if INCLUDE_JVMCI + // Follow JVMCI method + BarrierSet* bs = Universe::heap()->barrier_set(); + if (_jvmci_installed_code != NULL) { + if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { + if (!is_alive->do_object_b(_jvmci_installed_code)) { + bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); + _jvmci_installed_code = NULL; + bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + } + } else { + if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { + is_unloaded = true; + } + } + } + + if (_speculation_log != NULL) { + if (!is_alive->do_object_b(_speculation_log)) { + bs->write_ref_nmethod_pre(&_speculation_log, this); + _speculation_log = NULL; + bs->write_ref_nmethod_post(&_speculation_log, this); + } + } +#endif + // Ensure that all metadata is still alive verify_metadata_loaders(low_boundary, is_alive); @@ -2013,6 +2234,15 @@ void nmethod::oops_do(OopClosure* f, bool allow_zombie) { // (See comment above.) } +#if INCLUDE_JVMCI + if (_jvmci_installed_code != NULL) { + f->do_oop((oop*) &_jvmci_installed_code); + } + if (_speculation_log != NULL) { + f->do_oop((oop*) &_speculation_log); + } +#endif + RelocIterator iter(this, low_boundary); while (iter.next()) { @@ -2119,8 +2349,8 @@ public: if (_print_nm == NULL) return; if (!_detected_scavenge_root) _print_nm->print_on(tty, "new scavenge root"); tty->print_cr("" PTR_FORMAT "[offset=%d] detected scavengable oop " PTR_FORMAT " (found at " PTR_FORMAT ")", - _print_nm, (int)((intptr_t)p - (intptr_t)_print_nm), - (void *)(*p), (intptr_t)p); + p2i(_print_nm), (int)((intptr_t)p - (intptr_t)_print_nm), + p2i(*p), p2i(p)); (*p)->print(); } #endif //PRODUCT @@ -2137,7 +2367,7 @@ bool nmethod::detect_scavenge_root_oops() { // called with a frame corresponding to a Java invoke void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { #ifndef SHARK - if (!method()->is_native()) { + if (method() != NULL && !method()->is_native()) { SimpleScopeDesc ssd(this, fr.pc()); Bytecode_invoke call(ssd.method(), ssd.bci()); bool has_receiver = call.has_receiver(); @@ -2203,6 +2433,14 @@ void nmethod::copy_scopes_data(u_char* buffer, int size) { memcpy(scopes_data_begin(), buffer, size); } +// When using JVMCI the address might be off by the size of a call instruction. +bool nmethod::is_deopt_entry(address pc) { + return pc == deopt_handler_begin() +#if INCLUDE_JVMCI + || pc == (deopt_handler_begin() + NativeCall::instruction_size) +#endif + ; +} #ifdef ASSERT static PcDesc* linear_search(nmethod* nm, int pc_offset, bool approximate) { @@ -2211,7 +2449,7 @@ static PcDesc* linear_search(nmethod* nm, int pc_offset, bool approximate) { lower += 1; // exclude initial sentinel PcDesc* res = NULL; for (PcDesc* p = lower; p < upper; p++) { - NOT_PRODUCT(--nmethod_stats.pc_desc_tests); // don't count this call to match_desc + NOT_PRODUCT(--pc_nmethod_stats.pc_desc_tests); // don't count this call to match_desc if (match_desc(p, pc_offset, approximate)) { if (res == NULL) res = p; @@ -2258,7 +2496,7 @@ PcDesc* nmethod::find_pc_desc_internal(address pc, bool approximate) { // Use the last successful return as a split point. PcDesc* mid = _pc_desc_cache.last_pc_desc(); - NOT_PRODUCT(++nmethod_stats.pc_desc_searches); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_searches); if (mid->pc_offset() < pc_offset) { lower = mid; } else { @@ -2271,7 +2509,7 @@ PcDesc* nmethod::find_pc_desc_internal(address pc, bool approximate) { for (int step = (1 << (LOG2_RADIX*3)); step > 1; step >>= LOG2_RADIX) { while ((mid = lower + step) < upper) { assert_LU_OK; - NOT_PRODUCT(++nmethod_stats.pc_desc_searches); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_searches); if (mid->pc_offset() < pc_offset) { lower = mid; } else { @@ -2286,7 +2524,7 @@ PcDesc* nmethod::find_pc_desc_internal(address pc, bool approximate) { while (true) { assert_LU_OK; mid = lower + 1; - NOT_PRODUCT(++nmethod_stats.pc_desc_searches); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_searches); if (mid->pc_offset() < pc_offset) { lower = mid; } else { @@ -2426,7 +2664,7 @@ address nmethod::continuation_for_implicit_exception(address pc) { ResourceMark rm(thread); CodeBlob* cb = CodeCache::find_blob(pc); assert(cb != NULL && cb == this, ""); - tty->print_cr("implicit exception happened at " INTPTR_FORMAT, pc); + tty->print_cr("implicit exception happened at " INTPTR_FORMAT, p2i(pc)); print(); method()->print_codes(); print_code(); @@ -2473,7 +2711,6 @@ void nmethodLocker::unlock_nmethod(nmethod* nm) { assert(nm->_lock_count >= 0, "unmatched nmethod lock/unlock"); } - // ----------------------------------------------------------------------------- // nmethod::get_deopt_original_pc // @@ -2519,7 +2756,7 @@ public: _ok = false; } tty->print_cr("*** non-oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)", - (void *)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); + p2i(*p), p2i(p), (int)((intptr_t)p - (intptr_t)_nm)); } virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } }; @@ -2540,7 +2777,7 @@ void nmethod::verify() { ResourceMark rm; if (!CodeCache::contains(this)) { - fatal(err_msg("nmethod at " INTPTR_FORMAT " not in zone", this)); + fatal("nmethod at " INTPTR_FORMAT " not in zone", p2i(this)); } if(is_native_method() ) @@ -2548,13 +2785,12 @@ void nmethod::verify() { nmethod* nm = CodeCache::find_nmethod(verified_entry_point()); if (nm != this) { - fatal(err_msg("findNMethod did not find this nmethod (" INTPTR_FORMAT ")", - this)); + fatal("findNMethod did not find this nmethod (" INTPTR_FORMAT ")", p2i(this)); } for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) { if (! p->verify(this)) { - tty->print_cr("\t\tin nmethod at " INTPTR_FORMAT " (pcs)", this); + tty->print_cr("\t\tin nmethod at " INTPTR_FORMAT " (pcs)", p2i(this)); } } @@ -2587,7 +2823,7 @@ void nmethod::verify_interrupt_point(address call_site) { PcDesc* pd = pc_desc_at(nativeCall_at(call_site)->return_address()); assert(pd != NULL, "PcDesc must exist"); for (ScopeDesc* sd = new ScopeDesc(this, pd->scope_decode_offset(), - pd->obj_decode_offset(), pd->should_reexecute(), + pd->obj_decode_offset(), pd->should_reexecute(), pd->rethrow_exception(), pd->return_oop()); !sd->is_top(); sd = sd->sender()) { sd->verify(); @@ -2643,7 +2879,7 @@ public: _ok = false; } tty->print_cr("*** scavengable oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)", - (void *)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); + p2i(*p), p2i(p), (int)((intptr_t)p - (intptr_t)_nm)); (*p)->print(); } virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } @@ -2680,6 +2916,8 @@ void nmethod::print() const { tty->print("(c2) "); } else if (is_compiled_by_shark()) { tty->print("(shark) "); + } else if (is_compiled_by_jvmci()) { + tty->print("(JVMCI) "); } else { tty->print("(nm) "); } @@ -2687,8 +2925,8 @@ void nmethod::print() const { print_on(tty, NULL); if (WizardMode) { - tty->print("((nmethod*) " INTPTR_FORMAT ") ", this); - tty->print(" for method " INTPTR_FORMAT , (address)method()); + tty->print("((nmethod*) " INTPTR_FORMAT ") ", p2i(this)); + tty->print(" for method " INTPTR_FORMAT , p2i(method())); tty->print(" { "); if (is_in_use()) tty->print("in_use "); if (is_not_entrant()) tty->print("not_entrant "); @@ -2698,52 +2936,52 @@ void nmethod::print() const { tty->print_cr("}:"); } if (size () > 0) tty->print_cr(" total in heap [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - (address)this, - (address)this + size(), + p2i(this), + p2i(this) + size(), size()); if (relocation_size () > 0) tty->print_cr(" relocation [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - relocation_begin(), - relocation_end(), + p2i(relocation_begin()), + p2i(relocation_end()), relocation_size()); if (consts_size () > 0) tty->print_cr(" constants [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - consts_begin(), - consts_end(), + p2i(consts_begin()), + p2i(consts_end()), consts_size()); if (insts_size () > 0) tty->print_cr(" main code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - insts_begin(), - insts_end(), + p2i(insts_begin()), + p2i(insts_end()), insts_size()); if (stub_size () > 0) tty->print_cr(" stub code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - stub_begin(), - stub_end(), + p2i(stub_begin()), + p2i(stub_end()), stub_size()); if (oops_size () > 0) tty->print_cr(" oops [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - oops_begin(), - oops_end(), + p2i(oops_begin()), + p2i(oops_end()), oops_size()); if (metadata_size () > 0) tty->print_cr(" metadata [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - metadata_begin(), - metadata_end(), + p2i(metadata_begin()), + p2i(metadata_end()), metadata_size()); if (scopes_data_size () > 0) tty->print_cr(" scopes data [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - scopes_data_begin(), - scopes_data_end(), + p2i(scopes_data_begin()), + p2i(scopes_data_end()), scopes_data_size()); if (scopes_pcs_size () > 0) tty->print_cr(" scopes pcs [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - scopes_pcs_begin(), - scopes_pcs_end(), + p2i(scopes_pcs_begin()), + p2i(scopes_pcs_end()), scopes_pcs_size()); if (dependencies_size () > 0) tty->print_cr(" dependencies [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - dependencies_begin(), - dependencies_end(), + p2i(dependencies_begin()), + p2i(dependencies_end()), dependencies_size()); if (handler_table_size() > 0) tty->print_cr(" handler table [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - handler_table_begin(), - handler_table_end(), + p2i(handler_table_begin()), + p2i(handler_table_end()), handler_table_size()); if (nul_chk_table_size() > 0) tty->print_cr(" nul chk table [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - nul_chk_table_begin(), - nul_chk_table_end(), + p2i(nul_chk_table_begin()), + p2i(nul_chk_table_end()), nul_chk_table_size()); } @@ -2764,7 +3002,10 @@ void nmethod::print_scopes() { continue; ScopeDesc* sd = scope_desc_at(p->real_pc(this)); - sd->print_on(tty, p); + while (sd != NULL) { + sd->print_on(tty, p); + sd = sd->sender(); + } } } @@ -2794,20 +3035,20 @@ void nmethod::print_relocations() { jint* index_end = (jint*)relocation_end() - 1; jint index_size = *index_end; jint* index_start = (jint*)( (address)index_end - index_size ); - tty->print_cr(" index @" INTPTR_FORMAT ": index_size=%d", index_start, index_size); + tty->print_cr(" index @" INTPTR_FORMAT ": index_size=%d", p2i(index_start), index_size); if (index_size > 0) { jint* ip; for (ip = index_start; ip+2 <= index_end; ip += 2) tty->print_cr(" (%d %d) addr=" INTPTR_FORMAT " @" INTPTR_FORMAT, ip[0], ip[1], - header_end()+ip[0], - relocation_begin()-1+ip[1]); + p2i(header_end()+ip[0]), + p2i(relocation_begin()-1+ip[1])); for (; ip < index_end; ip++) tty->print_cr(" (%d ?)", ip[0]); - tty->print_cr(" @" INTPTR_FORMAT ": index_size=%d", ip, *ip); + tty->print_cr(" @" INTPTR_FORMAT ": index_size=%d", p2i(ip), *ip); ip++; - tty->print_cr("reloc_end @" INTPTR_FORMAT ":", ip); + tty->print_cr("reloc_end @" INTPTR_FORMAT ":", p2i(ip)); } } } @@ -2881,7 +3122,7 @@ ScopeDesc* nmethod::scope_desc_in(address begin, address end) { PcDesc* p = pc_desc_near(begin+1); if (p != NULL && p->real_pc(this) <= end) { return new ScopeDesc(this, p->scope_decode_offset(), - p->obj_decode_offset(), p->should_reexecute(), + p->obj_decode_offset(), p->should_reexecute(), p->rethrow_exception(), p->return_oop()); } return NULL; @@ -2890,9 +3131,9 @@ ScopeDesc* nmethod::scope_desc_in(address begin, address end) { void nmethod::print_nmethod_labels(outputStream* stream, address block_begin) const { if (block_begin == entry_point()) stream->print_cr("[Entry Point]"); if (block_begin == verified_entry_point()) stream->print_cr("[Verified Entry Point]"); - if (block_begin == exception_begin()) stream->print_cr("[Exception Handler]"); + if (JVMCI_ONLY(_exception_offset >= 0 &&) block_begin == exception_begin()) stream->print_cr("[Exception Handler]"); if (block_begin == stub_begin()) stream->print_cr("[Stub Code]"); - if (block_begin == deopt_handler_begin()) stream->print_cr("[Deopt Handler Code]"); + if (JVMCI_ONLY(_deoptimize_offset >= 0 &&) block_begin == deopt_handler_begin()) stream->print_cr("[Deopt Handler Code]"); if (has_method_handle_invokes()) if (block_begin == deopt_mh_handler_begin()) stream->print_cr("[Deopt MH Handler Code]"); @@ -3058,6 +3299,7 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, } } } + st->print(" {reexecute=%d rethrow=%d return_oop=%d}", sd->should_reexecute(), sd->rethrow_exception(), sd->return_oop()); } // Print all scopes @@ -3089,7 +3331,7 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, int cont_offset = ImplicitExceptionTable(this).at(begin - code_begin()); if (cont_offset != 0) { st->move_to(column); - st->print("; implicit exception: dispatches to " INTPTR_FORMAT, code_begin() + cont_offset); + st->print("; implicit exception: dispatches to " INTPTR_FORMAT, p2i(code_begin() + cont_offset)); } } @@ -3112,7 +3354,7 @@ void nmethod::print_calls(outputStream* st) { break; } case relocInfo::static_call_type: - st->print_cr("Static call at " INTPTR_FORMAT, iter.reloc()->addr()); + st->print_cr("Static call at " INTPTR_FORMAT, p2i(iter.reloc()->addr())); compiledStaticCall_at(iter.reloc())->print(); break; } @@ -3130,12 +3372,49 @@ void nmethod::print_nul_chk_table() { void nmethod::print_statistics() { ttyLocker ttyl; if (xtty != NULL) xtty->head("statistics type='nmethod'"); - nmethod_stats.print_native_nmethod_stats(); - nmethod_stats.print_nmethod_stats(); + native_nmethod_stats.print_native_nmethod_stats(); +#ifdef COMPILER1 + c1_java_nmethod_stats.print_nmethod_stats("C1"); +#endif +#ifdef COMPILER2 + c2_java_nmethod_stats.print_nmethod_stats("C2"); +#endif +#if INCLUDE_JVMCI + jvmci_java_nmethod_stats.print_nmethod_stats("JVMCI"); +#endif +#ifdef SHARK + shark_java_nmethod_stats.print_nmethod_stats("Shark"); +#endif + unknown_java_nmethod_stats.print_nmethod_stats("Unknown"); DebugInformationRecorder::print_statistics(); - nmethod_stats.print_pc_stats(); +#ifndef PRODUCT + pc_nmethod_stats.print_pc_stats(); +#endif Dependencies::print_statistics(); if (xtty != NULL) xtty->tail("statistics"); } -#endif // PRODUCT +#endif // !PRODUCT + +#if INCLUDE_JVMCI +char* nmethod::jvmci_installed_code_name(char* buf, size_t buflen) { + if (!this->is_compiled_by_jvmci()) { + return NULL; + } + oop installedCode = this->jvmci_installed_code(); + if (installedCode != NULL) { + oop installedCodeName = NULL; + if (installedCode->is_a(InstalledCode::klass())) { + installedCodeName = InstalledCode::name(installedCode); + } + if (installedCodeName != NULL) { + return java_lang_String::as_utf8_string(installedCodeName, buf, (int)buflen); + } else { + jio_snprintf(buf, buflen, "null"); + return buf; + } + } + jio_snprintf(buf, buflen, "noInstalledCode"); + return buf; +} +#endif diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 737c93df9bd..2125d9680bd 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -126,6 +126,12 @@ class nmethod : public CodeBlob { int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method jmethodID _jmethod_id; // Cache of method()->jmethod_id() +#if INCLUDE_JVMCI + // Needed to keep nmethods alive that are not the default nmethod for the associated Method. + oop _jvmci_installed_code; + oop _speculation_log; +#endif + // To support simple linked-list chaining of nmethods: nmethod* _osr_link; // from InstanceKlass::osr_nmethods_head @@ -273,7 +279,12 @@ class nmethod : public CodeBlob { ExceptionHandlerTable* handler_table, ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, - int comp_level); + int comp_level +#if INCLUDE_JVMCI + , Handle installed_code, + Handle speculation_log +#endif + ); // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); @@ -309,7 +320,12 @@ class nmethod : public CodeBlob { ExceptionHandlerTable* handler_table, ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, - int comp_level); + int comp_level +#if INCLUDE_JVMCI + , Handle installed_code = Handle(), + Handle speculation_log = Handle() +#endif + ); static nmethod* new_native_nmethod(methodHandle method, int compile_id, @@ -332,6 +348,7 @@ class nmethod : public CodeBlob { bool is_osr_method() const { return _entry_bci != InvocationEntryBci; } bool is_compiled_by_c1() const; + bool is_compiled_by_jvmci() const; bool is_compiled_by_c2() const; bool is_compiled_by_shark() const; @@ -582,6 +599,14 @@ public: // Evolution support. We make old (discarded) compiled methods point to new Method*s. void set_method(Method* method) { _method = method; } +#if INCLUDE_JVMCI + oop jvmci_installed_code() { return _jvmci_installed_code ; } + char* jvmci_installed_code_name(char* buf, size_t buflen); + void set_jvmci_installed_code(oop installed_code) { _jvmci_installed_code = installed_code; } + oop speculation_log() { return _speculation_log ; } + void set_speculation_log(oop speculation_log) { _speculation_log = speculation_log; } +#endif + // GC support void do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred); // The parallel versions are used by G1. @@ -639,7 +664,7 @@ public: // Deopt // Return true is the PC is one would expect if the frame is being deopted. bool is_deopt_pc (address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); } - bool is_deopt_entry (address pc) { return pc == deopt_handler_begin(); } + bool is_deopt_entry (address pc); bool is_deopt_mh_entry(address pc) { return pc == deopt_mh_handler_begin(); } // Accessor/mutator for the original pc of a frame before a frame was deopted. address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); } @@ -690,7 +715,7 @@ public: // Prints a comment for one native instruction (reloc info, pc desc) void print_code_comment_on(outputStream* st, int column, address begin, address end); - static void print_statistics() PRODUCT_RETURN; + static void print_statistics() PRODUCT_RETURN; // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, diff --git a/hotspot/src/share/vm/code/oopRecorder.cpp b/hotspot/src/share/vm/code/oopRecorder.cpp index e93e244c124..0e60c055f6d 100644 --- a/hotspot/src/share/vm/code/oopRecorder.cpp +++ b/hotspot/src/share/vm/code/oopRecorder.cpp @@ -157,3 +157,48 @@ template int ValueRecorder::maybe_find_index(T h) { // Explicitly instantiate these types template class ValueRecorder; template class ValueRecorder; + +oop ObjectLookup::ObjectEntry::oop_value() const { return JNIHandles::resolve(_value); } + +ObjectLookup::ObjectLookup(): _gc_count(Universe::heap()->total_collections()), _values(4) {} + +void ObjectLookup::maybe_resort() { + // The values are kept sorted by address which may be invalidated + // after a GC, so resort if a GC has occurred since last time. + if (_gc_count != Universe::heap()->total_collections()) { + _gc_count = Universe::heap()->total_collections(); + _values.sort(sort_by_address); + } +} + +int ObjectLookup::sort_by_address(oop a, oop b) { + if (b > a) return 1; + if (a > b) return -1; + return 0; +} + +int ObjectLookup::sort_by_address(ObjectEntry* a, ObjectEntry* b) { + return sort_by_address(a->oop_value(), b->oop_value()); +} + +int ObjectLookup::sort_oop_by_address(oop const& a, ObjectEntry const& b) { + return sort_by_address(a, b.oop_value()); +} + +int ObjectLookup::find_index(jobject handle, OopRecorder* oop_recorder) { + if (handle == NULL) { + return 0; + } + oop object = JNIHandles::resolve(handle); + maybe_resort(); + bool found; + int location = _values.find_sorted(object, found); + if (!found) { + jobject handle = JNIHandles::make_local(object); + ObjectEntry r(handle, oop_recorder->allocate_oop_index(handle)); + _values.insert_before(location, r); + return r.index(); + } + return _values.at(location).index(); +} + diff --git a/hotspot/src/share/vm/code/oopRecorder.hpp b/hotspot/src/share/vm/code/oopRecorder.hpp index 97651fedcbf..adb32cb5d97 100644 --- a/hotspot/src/share/vm/code/oopRecorder.hpp +++ b/hotspot/src/share/vm/code/oopRecorder.hpp @@ -146,18 +146,57 @@ template class ValueRecorder : public StackObj { #endif }; +class OopRecorder; + +class ObjectLookup : public ResourceObj { + private: + class ObjectEntry { + private: + jobject _value; + int _index; + + public: + ObjectEntry(jobject value, int index) : _value(value), _index(index) {} + ObjectEntry() : _value(NULL), _index(0) {} + oop oop_value() const; + int index() { return _index; } + }; + + GrowableArray _values; + unsigned int _gc_count; + + // Utility sort functions + static int sort_by_address(oop a, oop b); + static int sort_by_address(ObjectEntry* a, ObjectEntry* b); + static int sort_oop_by_address(oop const& a, ObjectEntry const& b); + + public: + ObjectLookup(); + + // Resort list if a GC has occurred since the last sort + void maybe_resort(); + int find_index(jobject object, OopRecorder* oop_recorder); +}; + class OopRecorder : public ResourceObj { private: ValueRecorder _oops; ValueRecorder _metadata; + ObjectLookup* _object_lookup; public: - OopRecorder(Arena* arena = NULL): _oops(arena), _metadata(arena) {} + OopRecorder(Arena* arena = NULL, bool deduplicate = false): _oops(arena), _metadata(arena) { + if (deduplicate) { + _object_lookup = new ObjectLookup(); + } else { + _object_lookup = NULL; + } + } int allocate_oop_index(jobject h) { return _oops.allocate_index(h); } - int find_index(jobject h) { - return _oops.find_index(h); + virtual int find_index(jobject h) { + return _object_lookup != NULL ? _object_lookup->find_index(h, this) : _oops.find_index(h); } jobject oop_at(int index) { return _oops.at(index); @@ -175,7 +214,7 @@ class OopRecorder : public ResourceObj { int allocate_metadata_index(Metadata* oop) { return _metadata.allocate_index(oop); } - int find_index(Metadata* h) { + virtual int find_index(Metadata* h) { return _metadata.find_index(h); } Metadata* metadata_at(int index) { diff --git a/hotspot/src/share/vm/code/pcDesc.cpp b/hotspot/src/share/vm/code/pcDesc.cpp index 5f7ba80f07c..a860b5b804d 100644 --- a/hotspot/src/share/vm/code/pcDesc.cpp +++ b/hotspot/src/share/vm/code/pcDesc.cpp @@ -29,8 +29,6 @@ #include "code/scopeDesc.hpp" #include "memory/resourceArea.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - PcDesc::PcDesc(int pc_offset, int scope_decode_offset, int obj_decode_offset) { _pc_offset = pc_offset; _scope_decode_offset = scope_decode_offset; @@ -45,7 +43,7 @@ address PcDesc::real_pc(const nmethod* code) const { void PcDesc::print(nmethod* code) { #ifndef PRODUCT ResourceMark rm; - tty->print_cr("PcDesc(pc=0x%lx offset=%x bits=%x):", real_pc(code), pc_offset(), _flags); + tty->print_cr("PcDesc(pc=" PTR_FORMAT " offset=%x bits=%x):", p2i(real_pc(code)), pc_offset(), _flags); if (scope_decode_offset() == DebugInformationRecorder::serialized_null) { return; diff --git a/hotspot/src/share/vm/code/pcDesc.hpp b/hotspot/src/share/vm/code/pcDesc.hpp index 83ec92149de..83734c8f0b8 100644 --- a/hotspot/src/share/vm/code/pcDesc.hpp +++ b/hotspot/src/share/vm/code/pcDesc.hpp @@ -42,7 +42,8 @@ class PcDesc VALUE_OBJ_CLASS_SPEC { enum { PCDESC_reexecute = 1 << 0, PCDESC_is_method_handle_invoke = 1 << 1, - PCDESC_return_oop = 1 << 2 + PCDESC_return_oop = 1 << 2, + PCDESC_rethrow_exception = 1 << 3 }; int _flags; @@ -71,6 +72,8 @@ class PcDesc VALUE_OBJ_CLASS_SPEC { }; // Flags + bool rethrow_exception() const { return (_flags & PCDESC_rethrow_exception) != 0; } + void set_rethrow_exception(bool z) { set_flag(PCDESC_rethrow_exception, z); } bool should_reexecute() const { return (_flags & PCDESC_reexecute) != 0; } void set_should_reexecute(bool z) { set_flag(PCDESC_reexecute, z); } diff --git a/hotspot/src/share/vm/code/relocInfo.cpp b/hotspot/src/share/vm/code/relocInfo.cpp index 174a615deaf..4ae8099a384 100644 --- a/hotspot/src/share/vm/code/relocInfo.cpp +++ b/hotspot/src/share/vm/code/relocInfo.cpp @@ -30,8 +30,7 @@ #include "memory/resourceArea.hpp" #include "runtime/stubCodeGenerator.hpp" #include "utilities/copy.hpp" - -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +#include "oops/oop.inline.hpp" const RelocationHolder RelocationHolder::none; // its type is relocInfo::none @@ -424,6 +423,30 @@ void Relocation::set_value(address x) { ShouldNotReachHere(); } +void Relocation::const_set_data_value(address x) { +#ifdef _LP64 + if (format() == relocInfo::narrow_oop_in_const) { + *(narrowOop*)addr() = oopDesc::encode_heap_oop((oop) x); + } else { +#endif + *(address*)addr() = x; +#ifdef _LP64 + } +#endif +} + +void Relocation::const_verify_data_value(address x) { +#ifdef _LP64 + if (format() == relocInfo::narrow_oop_in_const) { + assert(*(narrowOop*)addr() == oopDesc::encode_heap_oop((oop) x), "must agree"); + } else { +#endif + assert(*(address*)addr() == x, "must agree"); +#ifdef _LP64 + } +#endif +} + RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { if (rtype == relocInfo::none) return RelocationHolder::none; @@ -447,7 +470,7 @@ int32_t Relocation::runtime_address_to_index(address runtime_address) { // Known "miscellaneous" non-stub pointers: // os::get_polling_page(), SafepointSynchronize::address_of_state() if (PrintRelocations) { - tty->print_cr("random unregistered address in relocInfo: " INTPTR_FORMAT, runtime_address); + tty->print_cr("random unregistered address in relocInfo: " INTPTR_FORMAT, p2i(runtime_address)); } #ifndef _LP64 return (int32_t) (intptr_t)runtime_address; @@ -580,7 +603,8 @@ void static_stub_Relocation::pack_data_to(CodeSection* dest) { void static_stub_Relocation::unpack_data() { address base = binding()->section_start(CodeBuffer::SECT_INSTS); - _static_call = address_from_scaled_offset(unpack_1_int(), base); + jint offset = unpack_1_int(); + _static_call = address_from_scaled_offset(offset, base); } void trampoline_stub_Relocation::pack_data_to(CodeSection* dest ) { @@ -794,7 +818,8 @@ address opt_virtual_call_Relocation::static_stub() { RelocIterator iter(code()); while (iter.next()) { if (iter.type() == relocInfo::static_stub_type) { - if (iter.static_stub_reloc()->static_call() == static_call_addr) { + static_stub_Relocation* stub_reloc = iter.static_stub_reloc(); + if (stub_reloc->static_call() == static_call_addr) { return iter.addr(); } } @@ -816,7 +841,8 @@ address static_call_Relocation::static_stub() { RelocIterator iter(code()); while (iter.next()) { if (iter.type() == relocInfo::static_stub_type) { - if (iter.static_stub_reloc()->static_call() == static_call_addr) { + static_stub_Relocation* stub_reloc = iter.static_stub_reloc(); + if (stub_reloc->static_call() == static_call_addr) { return iter.addr(); } } @@ -925,7 +951,7 @@ void RelocIterator::print_current() { return; } tty->print("relocInfo@" INTPTR_FORMAT " [type=%d(%s) addr=" INTPTR_FORMAT " offset=%d", - _current, type(), reloc_type_string((relocInfo::relocType) type()), _addr, _current->addr_offset()); + p2i(_current), type(), reloc_type_string((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset()); if (current()->format() != 0) tty->print(" format=%d", current()->format()); if (datalen() == 1) { @@ -951,11 +977,11 @@ void RelocIterator::print_current() { oop_value = r->oop_value(); } tty->print(" | [oop_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT " offset=%d]", - oop_addr, (address)raw_oop, r->offset()); + p2i(oop_addr), p2i(raw_oop), r->offset()); // Do not print the oop by default--we want this routine to // work even during GC or other inconvenient times. if (WizardMode && oop_value != NULL) { - tty->print("oop_value=" INTPTR_FORMAT ": ", (address)oop_value); + tty->print("oop_value=" INTPTR_FORMAT ": ", p2i(oop_value)); oop_value->print_value_on(tty); } break; @@ -972,9 +998,9 @@ void RelocIterator::print_current() { metadata_value = r->metadata_value(); } tty->print(" | [metadata_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT " offset=%d]", - metadata_addr, (address)raw_metadata, r->offset()); + p2i(metadata_addr), p2i(raw_metadata), r->offset()); if (metadata_value != NULL) { - tty->print("metadata_value=" INTPTR_FORMAT ": ", (address)metadata_value); + tty->print("metadata_value=" INTPTR_FORMAT ": ", p2i(metadata_value)); metadata_value->print_value_on(tty); } break; @@ -984,33 +1010,33 @@ void RelocIterator::print_current() { case relocInfo::section_word_type: { DataRelocation* r = (DataRelocation*) reloc(); - tty->print(" | [target=" INTPTR_FORMAT "]", r->value()); //value==target + tty->print(" | [target=" INTPTR_FORMAT "]", p2i(r->value())); //value==target break; } case relocInfo::static_call_type: case relocInfo::runtime_call_type: { CallRelocation* r = (CallRelocation*) reloc(); - tty->print(" | [destination=" INTPTR_FORMAT "]", r->destination()); + tty->print(" | [destination=" INTPTR_FORMAT "]", p2i(r->destination())); break; } case relocInfo::virtual_call_type: { virtual_call_Relocation* r = (virtual_call_Relocation*) reloc(); tty->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT "]", - r->destination(), r->cached_value()); + p2i(r->destination()), p2i(r->cached_value())); break; } case relocInfo::static_stub_type: { static_stub_Relocation* r = (static_stub_Relocation*) reloc(); - tty->print(" | [static_call=" INTPTR_FORMAT "]", r->static_call()); + tty->print(" | [static_call=" INTPTR_FORMAT "]", p2i(r->static_call())); break; } case relocInfo::trampoline_stub_type: { trampoline_stub_Relocation* r = (trampoline_stub_Relocation*) reloc(); - tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", r->owner()); + tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", p2i(r->owner())); break; } } @@ -1029,7 +1055,7 @@ void RelocIterator::print() { got_next = (skip_next || next()); skip_next = false; - tty->print(" @" INTPTR_FORMAT ": ", scan); + tty->print(" @" INTPTR_FORMAT ": ", p2i(scan)); relocInfo* newscan = _current+1; if (!has_current()) newscan -= 1; // nothing to scan here! while (scan < newscan) { diff --git a/hotspot/src/share/vm/code/relocInfo.hpp b/hotspot/src/share/vm/code/relocInfo.hpp index c92bfb4b053..dc9b11bbcfe 100644 --- a/hotspot/src/share/vm/code/relocInfo.hpp +++ b/hotspot/src/share/vm/code/relocInfo.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -210,6 +210,11 @@ class NativeMovConstReg; // See [About Offsets] below. // //%note reloc_2 // +// relocInfo::poll_[return_]type -- a safepoint poll +// Value: none +// Instruction types: memory load or test +// Data: none +// // For example: // // INSTRUCTIONS RELOC: TYPE PREFIX DATA @@ -443,6 +448,11 @@ class relocInfo VALUE_OBJ_CLASS_SPEC { }; public: enum { +#ifdef _LP64 + // for use in format + // format_width must be at least 1 on _LP64 + narrow_oop_in_const = 1, +#endif // Conservatively large estimate of maximum length (in shorts) // of any relocation record. // Extended format is length prefix, data words, and tag/offset suffix. @@ -525,19 +535,19 @@ class RelocIterator : public StackObj { typedef relocInfo::relocType relocType; private: - address _limit; // stop producing relocations after this _addr - relocInfo* _current; // the current relocation information - relocInfo* _end; // end marker; we're done iterating when _current == _end - nmethod* _code; // compiled method containing _addr - address _addr; // instruction to which the relocation applies - short _databuf; // spare buffer for compressed data - short* _data; // pointer to the relocation's data - short _datalen; // number of halfwords in _data - char _format; // position within the instruction + address _limit; // stop producing relocations after this _addr + relocInfo* _current; // the current relocation information + relocInfo* _end; // end marker; we're done iterating when _current == _end + nmethod* _code; // compiled method containing _addr + address _addr; // instruction to which the relocation applies + short _databuf; // spare buffer for compressed data + short* _data; // pointer to the relocation's data + short _datalen; // number of halfwords in _data + char _format; // position within the instruction // Base addresses needed to compute targets of section_word_type relocs. - address _section_start[SECT_LIMIT]; - address _section_end [SECT_LIMIT]; + address _section_start[SECT_LIMIT]; + address _section_end [SECT_LIMIT]; void set_has_current(bool b) { _datalen = !b ? -1 : 0; @@ -565,7 +575,7 @@ class RelocIterator : public StackObj { public: // constructor - RelocIterator(nmethod* nm, address begin = NULL, address limit = NULL); + RelocIterator(nmethod* nm, address begin = NULL, address limit = NULL); RelocIterator(CodeSection* cb, address begin = NULL, address limit = NULL); // get next reloc info, return !eos @@ -762,6 +772,9 @@ class Relocation VALUE_OBJ_CLASS_SPEC { } protected: + // platform-independent utility for patching constant section + void const_set_data_value (address x); + void const_verify_data_value (address x); // platform-dependent utilities for decoding and patching instructions void pd_set_data_value (address x, intptr_t off, bool verify_only = false); // a set or mem-ref void pd_verify_data_value (address x, intptr_t off) { pd_set_data_value(x, off, true); } @@ -872,13 +885,13 @@ class DataRelocation : public Relocation { void set_value(address x) { set_value(x, offset()); } void set_value(address x, intptr_t o) { if (addr_in_const()) - *(address*)addr() = x; + const_set_data_value(x); else pd_set_data_value(x, o); } void verify_value(address x) { if (addr_in_const()) - assert(*(address*)addr() == x, "must agree"); + const_verify_data_value(x); else pd_verify_data_value(x, offset()); } @@ -1117,7 +1130,7 @@ class static_stub_Relocation : public Relocation { } private: - address _static_call; // location of corresponding static_call + address _static_call; // location of corresponding static_call static_stub_Relocation(address static_call) { _static_call = static_call; @@ -1318,10 +1331,8 @@ class poll_Relocation : public Relocation { void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); }; -class poll_return_Relocation : public Relocation { - bool is_data() { return true; } +class poll_return_Relocation : public poll_Relocation { relocInfo::relocType type() { return relocInfo::poll_return_type; } - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); }; // We know all the xxx_Relocation classes, so now we can define these: diff --git a/hotspot/src/share/vm/code/scopeDesc.cpp b/hotspot/src/share/vm/code/scopeDesc.cpp index 6f19c3ab869..55d4eb9830e 100644 --- a/hotspot/src/share/vm/code/scopeDesc.cpp +++ b/hotspot/src/share/vm/code/scopeDesc.cpp @@ -30,22 +30,22 @@ #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - -ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool return_oop) { +ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) { _code = code; _decode_offset = decode_offset; _objects = decode_object_values(obj_decode_offset); _reexecute = reexecute; + _rethrow_exception = rethrow_exception; _return_oop = return_oop; decode_body(); } -ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool return_oop) { +ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) { _code = code; _decode_offset = decode_offset; _objects = decode_object_values(DebugInformationRecorder::serialized_null); _reexecute = reexecute; + _rethrow_exception = rethrow_exception; _return_oop = return_oop; decode_body(); } @@ -56,6 +56,7 @@ ScopeDesc::ScopeDesc(const ScopeDesc* parent) { _decode_offset = parent->_sender_decode_offset; _objects = parent->_objects; _reexecute = false; //reexecute only applies to the first scope + _rethrow_exception = false; _return_oop = false; decode_body(); } @@ -178,13 +179,13 @@ void ScopeDesc::print_on(outputStream* st) const { void ScopeDesc::print_on(outputStream* st, PcDesc* pd) const { // header if (pd != NULL) { - st->print_cr("ScopeDesc(pc=" PTR_FORMAT " offset=%x):", pd->real_pc(_code), pd->pc_offset()); + st->print_cr("ScopeDesc(pc=" PTR_FORMAT " offset=%x):", p2i(pd->real_pc(_code)), pd->pc_offset()); } print_value_on(st); // decode offsets if (WizardMode) { - st->print("ScopeDesc[%d]@" PTR_FORMAT " ", _decode_offset, _code->content_begin()); + st->print("ScopeDesc[%d]@" PTR_FORMAT " ", _decode_offset, p2i(_code->content_begin())); st->print_cr(" offset: %d", _decode_offset); st->print_cr(" bci: %d", bci()); st->print_cr(" reexecute: %s", should_reexecute() ? "true" : "false"); @@ -227,17 +228,18 @@ void ScopeDesc::print_on(outputStream* st, PcDesc* pd) const { } } -#ifdef COMPILER2 - if (DoEscapeAnalysis && is_top() && _objects != NULL) { +#if defined(COMPILER2) || INCLUDE_JVMCI + if (NOT_JVMCI(DoEscapeAnalysis &&) is_top() && _objects != NULL) { st->print_cr(" Objects"); for (int i = 0; i < _objects->length(); i++) { ObjectValue* sv = (ObjectValue*) _objects->at(i); st->print(" - %d: ", sv->id()); + st->print("%s ", java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())->external_name()); sv->print_fields_on(st); st->cr(); } } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI } #endif diff --git a/hotspot/src/share/vm/code/scopeDesc.hpp b/hotspot/src/share/vm/code/scopeDesc.hpp index 7330f6edbd6..57082c08350 100644 --- a/hotspot/src/share/vm/code/scopeDesc.hpp +++ b/hotspot/src/share/vm/code/scopeDesc.hpp @@ -41,7 +41,7 @@ class SimpleScopeDesc : public StackObj { int _bci; public: - SimpleScopeDesc(nmethod* code,address pc) { + SimpleScopeDesc(nmethod* code, address pc) { PcDesc* pc_desc = code->pc_desc_at(pc); assert(pc_desc != NULL, "Must be able to find matching PcDesc"); DebugInfoReadStream buffer(code, pc_desc->scope_decode_offset()); @@ -60,17 +60,18 @@ class SimpleScopeDesc : public StackObj { class ScopeDesc : public ResourceObj { public: // Constructor - ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool return_oop); + ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop); // Calls above, giving default value of "serialized_null" to the // "obj_decode_offset" argument. (We don't use a default argument to // avoid a .hpp-.hpp dependency.) - ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool return_oop); + ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop); // JVM state Method* method() const { return _method; } int bci() const { return _bci; } bool should_reexecute() const { return _reexecute; } + bool rethrow_exception() const { return _rethrow_exception; } bool return_oop() const { return _return_oop; } GrowableArray* locals(); @@ -95,6 +96,7 @@ class ScopeDesc : public ResourceObj { Method* _method; int _bci; bool _reexecute; + bool _rethrow_exception; bool _return_oop; // Decoding offsets diff --git a/hotspot/src/share/vm/code/stubs.cpp b/hotspot/src/share/vm/code/stubs.cpp index 8243e5ba5c3..73a39247c71 100644 --- a/hotspot/src/share/vm/code/stubs.cpp +++ b/hotspot/src/share/vm/code/stubs.cpp @@ -67,7 +67,7 @@ StubQueue::StubQueue(StubInterface* stub_interface, int buffer_size, intptr_t size = round_to(buffer_size, 2*BytesPerWord); BufferBlob* blob = BufferBlob::create(name, size); if( blob == NULL) { - vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, err_msg("CodeCache: no room for %s", name)); + vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "CodeCache: no room for %s", name); } _stub_interface = stub_interface; _buffer_size = blob->content_size(); diff --git a/hotspot/src/share/vm/code/vtableStubs.cpp b/hotspot/src/share/vm/code/vtableStubs.cpp index c6262988265..eff1a269721 100644 --- a/hotspot/src/share/vm/code/vtableStubs.cpp +++ b/hotspot/src/share/vm/code/vtableStubs.cpp @@ -40,8 +40,6 @@ #include "opto/matcher.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // ----------------------------------------------------------------------------------------- // Implementation of VtableStub @@ -79,8 +77,8 @@ void* VtableStub::operator new(size_t size, int code_size) throw() { void VtableStub::print_on(outputStream* st) const { - st->print("vtable stub (index = %d, receiver_location = %d, code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "[)", - index(), receiver_location(), code_begin(), code_end()); + st->print("vtable stub (index = %d, receiver_location = " INTX_FORMAT ", code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "[)", + index(), p2i(receiver_location()), p2i(code_begin()), p2i(code_end())); } @@ -126,8 +124,8 @@ address VtableStubs::find_stub(bool is_vtable_stub, int vtable_index) { enter(is_vtable_stub, vtable_index, s); if (PrintAdapterHandlers) { - tty->print_cr("Decoding VtableStub %s[%d]@%d", - is_vtable_stub? "vtbl": "itbl", vtable_index, VtableStub::receiver_location()); + tty->print_cr("Decoding VtableStub %s[%d]@" INTX_FORMAT, + is_vtable_stub? "vtbl": "itbl", vtable_index, p2i(VtableStub::receiver_location())); Disassembler::decode(s->code_begin(), s->code_end()); } // Notify JVMTI about this stub. The event will be recorded by the enclosing @@ -222,9 +220,9 @@ extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int InstanceKlass* ik = InstanceKlass::cast(klass); klassVtable* vt = ik->vtable(); ik->print(); - fatal(err_msg("bad compiled vtable dispatch: receiver " INTPTR_FORMAT ", " - "index %d (vtable length %d)", - (address)receiver, index, vt->length())); + fatal("bad compiled vtable dispatch: receiver " INTPTR_FORMAT ", " + "index %d (vtable length %d)", + p2i(receiver), index, vt->length()); } -#endif // Product +#endif // PRODUCT diff --git a/hotspot/src/share/vm/compiler/abstractCompiler.cpp b/hotspot/src/share/vm/compiler/abstractCompiler.cpp index 0e9c3cf16ee..fa866adba4f 100644 --- a/hotspot/src/share/vm/compiler/abstractCompiler.cpp +++ b/hotspot/src/share/vm/compiler/abstractCompiler.cpp @@ -58,7 +58,7 @@ bool AbstractCompiler::should_perform_shutdown() { } void AbstractCompiler::set_state(int state) { - // Ensure that ste is only set by one thread at a time + // Ensure that state is only set by one thread at a time MutexLocker only_one(CompileThread_lock); _compiler_state = state; CompileThread_lock->notify_all(); diff --git a/hotspot/src/share/vm/compiler/abstractCompiler.hpp b/hotspot/src/share/vm/compiler/abstractCompiler.hpp index 41c155d09a3..96dfbd45b58 100644 --- a/hotspot/src/share/vm/compiler/abstractCompiler.hpp +++ b/hotspot/src/share/vm/compiler/abstractCompiler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,47 @@ #include "ci/compilerInterface.hpp" +typedef void (*initializer)(void); + +#if INCLUDE_JVMCI +// Per-compiler statistics +class CompilerStatistics VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + + class Data VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + public: + elapsedTimer _time; // time spent compiling + int _bytes; // number of bytecodes compiled, including inlined bytecodes + int _count; // number of compilations + Data() : _bytes(0), _count(0) {} + void update(elapsedTimer time, int bytes) { + _time.add(time); + _bytes += bytes; + _count++; + } + void reset() { + _time.reset(); + } + }; + + public: + Data _standard; // stats for non-OSR compilations + Data _osr; // stats for OSR compilations + int _nmethods_size; // + int _nmethods_code_size; + int bytes_per_second() { + int bytes = _standard._bytes + _osr._bytes; + if (bytes == 0) { + return 0; + } + double seconds = _standard._time.seconds() + _osr._time.seconds(); + return seconds == 0.0 ? 0 : (int) (bytes / seconds); + } + CompilerStatistics() : _nmethods_size(0), _nmethods_code_size(0) {} +}; +#endif // INCLUDE_JVMCI + class AbstractCompiler : public CHeapObj { private: volatile int _num_compiler_threads; @@ -45,12 +86,17 @@ class AbstractCompiler : public CHeapObj { none, c1, c2, + jvmci, shark }; private: Type _type; +#if INCLUDE_JVMCI + CompilerStatistics _stats; +#endif + public: AbstractCompiler(Type type) : _type(type), _compiler_state(uninitialized), _num_compiler_threads(0) {} @@ -115,6 +161,7 @@ class AbstractCompiler : public CHeapObj { // Compiler type queries. bool is_c1() { return _type == c1; } bool is_c2() { return _type == c2; } + bool is_jvmci() { return _type == jvmci; } bool is_shark() { return _type == shark; } // Customization @@ -138,6 +185,10 @@ class AbstractCompiler : public CHeapObj { virtual void print_timers() { ShouldNotReachHere(); } + +#if INCLUDE_JVMCI + CompilerStatistics* stats() { return &_stats; } +#endif }; #endif // SHARE_VM_COMPILER_ABSTRACTCOMPILER_HPP diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 1a2bef47e81..89d969e4f94 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -51,6 +51,11 @@ #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "runtime/vframe.hpp" +#endif #ifdef COMPILER2 #include "opto/c2compiler.hpp" #endif @@ -453,41 +458,9 @@ void CompileQueue::print_tty() { print(tty); } -CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) { - +CompilerCounters::CompilerCounters() { _current_method[0] = '\0'; _compile_type = CompileBroker::no_compile; - - if (UsePerfData) { - ResourceMark rm; - - // create the thread instance name space string - don't create an - // instance subspace if instance is -1 - keeps the adapterThread - // counters from having a ".0" namespace. - const char* thread_i = (instance == -1) ? thread_name : - PerfDataManager::name_space(thread_name, instance); - - - char* name = PerfDataManager::counter_name(thread_i, "method"); - _perf_current_method = - PerfDataManager::create_string_variable(SUN_CI, name, - cmname_buffer_length, - _current_method, CHECK); - - name = PerfDataManager::counter_name(thread_i, "type"); - _perf_compile_type = PerfDataManager::create_variable(SUN_CI, name, - PerfData::U_None, - (jlong)_compile_type, - CHECK); - - name = PerfDataManager::counter_name(thread_i, "time"); - _perf_time = PerfDataManager::create_counter(SUN_CI, name, - PerfData::U_Ticks, CHECK); - - name = PerfDataManager::counter_name(thread_i, "compiles"); - _perf_compiles = PerfDataManager::create_counter(SUN_CI, name, - PerfData::U_Events, CHECK); - } } // ------------------------------------------------------------------ @@ -505,6 +478,30 @@ void CompileBroker::compilation_init() { // Set the interface to the current compiler(s). int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple); int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization); + +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // This is creating a JVMCICompiler singleton. + JVMCICompiler* jvmci = new JVMCICompiler(); + + if (UseJVMCICompiler) { + _compilers[1] = jvmci; + if (FLAG_IS_DEFAULT(JVMCIThreads)) { + if (BootstrapJVMCI) { + // JVMCI will bootstrap so give it more threads + c2_count = MIN2(32, os::active_processor_count()); + } + } else { + c2_count = JVMCIThreads; + } + if (FLAG_IS_DEFAULT(JVMCIHostThreads)) { + } else { + c1_count = JVMCIHostThreads; + } + } + } +#endif // INCLUDE_JVMCI + #ifdef COMPILER1 if (c1_count > 0) { _compilers[0] = new Compiler(); @@ -512,8 +509,10 @@ void CompileBroker::compilation_init() { #endif // COMPILER1 #ifdef COMPILER2 - if (c2_count > 0) { - _compilers[1] = new C2Compiler(); + if (true JVMCI_ONLY( && !UseJVMCICompiler)) { + if (c2_count > 0) { + _compilers[1] = new C2Compiler(); + } } #endif // COMPILER2 @@ -733,8 +732,8 @@ void CompileBroker::init_compiler_sweeper_threads(int c1_compiler_count, int c2_ const bool compiler_thread = true; for (int i = 0; i < c2_compiler_count; i++) { // Create a name for our thread. - sprintf(name_buffer, "C2 CompilerThread%d", i); - CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); + sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i); + CompilerCounters* counters = new CompilerCounters(); // Shark and C2 make_thread(name_buffer, _c2_compile_queue, counters, _compilers[1], compiler_thread, CHECK); } @@ -742,7 +741,7 @@ void CompileBroker::init_compiler_sweeper_threads(int c1_compiler_count, int c2_ for (int i = c2_compiler_count; i < compiler_count; i++) { // Create a name for our thread. sprintf(name_buffer, "C1 CompilerThread%d", i); - CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); + CompilerCounters* counters = new CompilerCounters(); // C1 make_thread(name_buffer, _c1_compile_queue, counters, _compilers[0], compiler_thread, CHECK); } @@ -803,7 +802,7 @@ void CompileBroker::compile_method_base(methodHandle method, if (osr_bci != InvocationEntryBci) { tty->print(" osr_bci: %d", osr_bci); } - tty->print(" comment: %s count: %d", comment, hot_count); + tty->print(" level: %d comment: %s count: %d", comp_level, comment, hot_count); if (!hot_method.is_null()) { tty->print(" hot: "); if (hot_method() != method()) { @@ -895,6 +894,41 @@ void CompileBroker::compile_method_base(methodHandle method, // Should this thread wait for completion of the compile? blocking = is_compile_blocking(); +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + if (blocking) { + // Don't allow blocking compiles for requests triggered by JVMCI. + if (thread->is_Compiler_thread()) { + blocking = false; + } + + // Don't allow blocking compiles if inside a class initializer or while performing class loading + vframeStream vfst((JavaThread*) thread); + for (; !vfst.at_end(); vfst.next()) { + if (vfst.method()->is_static_initializer() || + (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) && + vfst.method()->name() == vmSymbols::loadClass_name())) { + blocking = false; + break; + } + } + + // Don't allow blocking compilation requests to JVMCI + // if JVMCI itself is not yet initialized + if (!JVMCIRuntime::is_HotSpotJVMCIRuntime_initialized() && compiler(comp_level)->is_jvmci()) { + blocking = false; + } + + // Don't allow blocking compilation requests if we are in JVMCIRuntime::shutdown + // to avoid deadlock between compiler thread(s) and threads run at shutdown + // such as the DestroyJavaVM thread. + if (JVMCIRuntime::shutdown_called()) { + blocking = false; + } + } + } +#endif // INCLUDE_JVMCI + // We will enter the compilation in the queue. // 14012000: Note that this sets the queued_for_compile bits in // the target method. We can now reason that a method cannot be @@ -1076,7 +1110,10 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, // return requested nmethod // We accept a higher level osr method - return osr_bci == InvocationEntryBci ? method->code() : method->lookup_osr_nmethod_for(osr_bci, comp_level, false); + if (osr_bci == InvocationEntryBci) { + return method->code(); + } + return method->lookup_osr_nmethod_for(osr_bci, comp_level, false); } @@ -1157,7 +1194,7 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, method->print_short_name(tty); tty->cr(); } - method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompilerOracle"); + method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompileCommand"); } return false; @@ -1199,6 +1236,15 @@ int CompileBroker::assign_compile_id(methodHandle method, int osr_bci) { #endif } +// ------------------------------------------------------------------ +// CompileBroker::assign_compile_id_unlocked +// +// Public wrapper for assign_compile_id that acquires the needed locks +uint CompileBroker::assign_compile_id_unlocked(Thread* thread, methodHandle method, int osr_bci) { + MutexLocker locker(MethodCompileQueue_lock, thread); + return assign_compile_id(method, osr_bci); +} + /** * Should the current thread block until this compilation request * has been fulfilled? @@ -1436,10 +1482,6 @@ void CompileBroker::compiler_thread_loop() { os::hint_no_preempt(); } - // trace per thread time and compile statistics - CompilerCounters* counters = ((CompilerThread*)thread)->counters(); - PerfTraceTimedEvent(counters->time_counter(), counters->compile_counter()); - // Assign the task to the current thread. Mark this compilation // thread as active for the profiler. CompileTaskWrapper ctw(task); @@ -1558,6 +1600,35 @@ static void codecache_print(bool detailed) tty->print("%s", s.as_string()); } +void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env) { + + if (success) { + task->mark_success(); + if (ci_env != NULL) { + task->set_num_inlined_bytecodes(ci_env->num_inlined_bytecodes()); + } + if (_compilation_log != NULL) { + nmethod* code = task->code(); + if (code != NULL) { + _compilation_log->log_nmethod(thread, code); + } + } + } + + // simulate crash during compilation + assert(task->compile_id() != CICrashAt, "just as planned"); + if (event.should_commit()) { + event.set_method(task->method()); + event.set_compileID(task->compile_id()); + event.set_compileLevel(task->comp_level()); + event.set_succeded(task->is_success()); + event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci); + event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size()); + event.set_inlinedBytes(task->num_inlined_bytecodes()); + event.commit(); + } +} + // ------------------------------------------------------------------ // CompileBroker::invoke_compiler_on_method // @@ -1606,12 +1677,27 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { push_jni_handle_block(); Method* target_handle = task->method(); int compilable = ciEnv::MethodCompilable; + AbstractCompiler *comp = compiler(task_level); + + int system_dictionary_modification_counter; + { + MutexLocker locker(Compile_lock, thread); + system_dictionary_modification_counter = SystemDictionary::number_of_modifications(); + } +#if INCLUDE_JVMCI + if (UseJVMCICompiler && comp != NULL && comp->is_jvmci()) { + JVMCICompiler* jvmci = (JVMCICompiler*) comp; + + TraceTime t1("compilation", &time); + EventCompilation event; + + JVMCIEnv env(task, system_dictionary_modification_counter); + jvmci->compile_method(target_handle, osr_bci, &env); + + post_compile(thread, task, event, task->code() != NULL, NULL); + } else +#endif // INCLUDE_JVMCI { - int system_dictionary_modification_counter; - { - MutexLocker locker(Compile_lock, thread); - system_dictionary_modification_counter = SystemDictionary::number_of_modifications(); - } NoHandleMark nhm; ThreadToNativeFromVM ttn(thread); @@ -1637,7 +1723,6 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { TraceTime t1("compilation", &time); EventCompilation event; - AbstractCompiler *comp = compiler(task_level); if (comp == NULL) { ci_env.record_method_not_compilable("no compiler", !TieredCompilation); } else { @@ -1669,32 +1754,13 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { } if (PrintCompilation) { FormatBufferResource msg = retry_message != NULL ? - err_msg_res("COMPILE SKIPPED: %s (%s)", ci_env.failure_reason(), retry_message) : - err_msg_res("COMPILE SKIPPED: %s", ci_env.failure_reason()); + FormatBufferResource("COMPILE SKIPPED: %s (%s)", ci_env.failure_reason(), retry_message) : + FormatBufferResource("COMPILE SKIPPED: %s", ci_env.failure_reason()); task->print(tty, msg); } - } else { - task->mark_success(); - task->set_num_inlined_bytecodes(ci_env.num_inlined_bytecodes()); - if (_compilation_log != NULL) { - nmethod* code = task->code(); - if (code != NULL) { - _compilation_log->log_nmethod(thread, code); - } - } - } - // simulate crash during compilation - assert(task->compile_id() != CICrashAt, "just as planned"); - if (event.should_commit()) { - event.set_method(target->get_Method()); - event.set_compileID(compile_id); - event.set_compileLevel(task->comp_level()); - event.set_succeded(task->is_success()); - event.set_isOsr(is_osr); - event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size()); - event.set_inlinedBytes(task->num_inlined_bytecodes()); - event.commit(); } + + post_compile(thread, task, event, !ci_env.failing(), &ci_env); } pop_jni_handle_block(); @@ -1945,13 +2011,19 @@ void CompileBroker::collect_statistics(CompilerThread* thread, elapsedTimer time _peak_compilation_time = time.milliseconds() > _peak_compilation_time ? time.milliseconds() : _peak_compilation_time; if (CITime) { + int bytes_compiled = method->code_size() + task->num_inlined_bytecodes(); + JVMCI_ONLY(CompilerStatistics* stats = compiler(task->comp_level())->stats();) if (is_osr) { _t_osr_compilation.add(time); - _sum_osr_bytes_compiled += method->code_size() + task->num_inlined_bytecodes(); + _sum_osr_bytes_compiled += bytes_compiled; + JVMCI_ONLY(stats->_osr.update(time, bytes_compiled);) } else { _t_standard_compilation.add(time); _sum_standard_bytes_compiled += method->code_size() + task->num_inlined_bytecodes(); + JVMCI_ONLY(stats->_standard.update(time, bytes_compiled);) } + JVMCI_ONLY(stats->_nmethods_size += code->total_size();) + JVMCI_ONLY(stats->_nmethods_code_size += code->insts_size();) } if (UsePerfData) { @@ -2007,22 +2079,106 @@ const char* CompileBroker::compiler_name(int comp_level) { } } -void CompileBroker::print_times() { +#if INCLUDE_JVMCI +void CompileBroker::print_times(AbstractCompiler* comp) { + CompilerStatistics* stats = comp->stats(); + tty->print_cr(" %s {speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}", + comp->name(), stats->bytes_per_second(), + stats->_standard._time.seconds(), stats->_standard._bytes, stats->_standard._count, + stats->_osr._time.seconds(), stats->_osr._bytes, stats->_osr._count, + stats->_nmethods_size, stats->_nmethods_code_size); + comp->print_timers(); +} +#endif // INCLUDE_JVMCI + +void CompileBroker::print_times(bool per_compiler, bool aggregate) { +#if INCLUDE_JVMCI + elapsedTimer standard_compilation; + elapsedTimer total_compilation; + elapsedTimer osr_compilation; + + int standard_bytes_compiled = 0; + int osr_bytes_compiled = 0; + + int standard_compile_count = 0; + int osr_compile_count = 0; + int total_compile_count = 0; + + int nmethods_size = 0; + int nmethods_code_size = 0; + bool printedHeader = false; + + for (unsigned int i = 0; i < sizeof(_compilers) / sizeof(AbstractCompiler*); i++) { + AbstractCompiler* comp = _compilers[i]; + if (comp != NULL) { + if (per_compiler && aggregate && !printedHeader) { + printedHeader = true; + tty->cr(); + tty->print_cr("Individual compiler times (for compiled methods only)"); + tty->print_cr("------------------------------------------------"); + tty->cr(); + } + CompilerStatistics* stats = comp->stats(); + + standard_compilation.add(stats->_standard._time); + osr_compilation.add(stats->_osr._time); + + standard_bytes_compiled += stats->_standard._bytes; + osr_bytes_compiled += stats->_osr._bytes; + + standard_compile_count += stats->_standard._count; + osr_compile_count += stats->_osr._count; + + nmethods_size += stats->_nmethods_size; + nmethods_code_size += stats->_nmethods_code_size; + + if (per_compiler) { + print_times(comp); + } + } + } + total_compile_count = osr_compile_count + standard_compile_count; + total_compilation.add(osr_compilation); + total_compilation.add(standard_compilation); + + // In hosted mode, print the JVMCI compiler specific counters manually. + if (!UseJVMCICompiler) { + JVMCICompiler::print_compilation_timers(); + } +#else // INCLUDE_JVMCI + elapsedTimer standard_compilation = CompileBroker::_t_standard_compilation; + elapsedTimer osr_compilation = CompileBroker::_t_osr_compilation; + elapsedTimer total_compilation = CompileBroker::_t_total_compilation; + + int standard_bytes_compiled = CompileBroker::_sum_standard_bytes_compiled; + int osr_bytes_compiled = CompileBroker::_sum_osr_bytes_compiled; + + int standard_compile_count = CompileBroker::_total_standard_compile_count; + int osr_compile_count = CompileBroker::_total_osr_compile_count; + int total_compile_count = CompileBroker::_total_compile_count; + + int nmethods_size = CompileBroker::_sum_nmethod_code_size; + int nmethods_code_size = CompileBroker::_sum_nmethod_size; +#endif // INCLUDE_JVMCI + + if (!aggregate) { + return; + } tty->cr(); tty->print_cr("Accumulated compiler times"); tty->print_cr("----------------------------------------------------------"); //0000000000111111111122222222223333333333444444444455555555556666666666 //0123456789012345678901234567890123456789012345678901234567890123456789 - tty->print_cr(" Total compilation time : %7.3f s", CompileBroker::_t_total_compilation.seconds()); + tty->print_cr(" Total compilation time : %7.3f s", total_compilation.seconds()); tty->print_cr(" Standard compilation : %7.3f s, Average : %2.3f s", - CompileBroker::_t_standard_compilation.seconds(), - CompileBroker::_t_standard_compilation.seconds() / CompileBroker::_total_standard_compile_count); + standard_compilation.seconds(), + standard_compilation.seconds() / standard_compile_count); tty->print_cr(" Bailed out compilation : %7.3f s, Average : %2.3f s", CompileBroker::_t_bailedout_compilation.seconds(), CompileBroker::_t_bailedout_compilation.seconds() / CompileBroker::_total_bailout_count); tty->print_cr(" On stack replacement : %7.3f s, Average : %2.3f s", - CompileBroker::_t_osr_compilation.seconds(), - CompileBroker::_t_osr_compilation.seconds() / CompileBroker::_total_osr_compile_count); + osr_compilation.seconds(), + osr_compilation.seconds() / osr_compile_count); tty->print_cr(" Invalidated : %7.3f s, Average : %2.3f s", CompileBroker::_t_invalidated_compilation.seconds(), CompileBroker::_t_invalidated_compilation.seconds() / CompileBroker::_total_invalidated_count); @@ -2038,18 +2194,19 @@ void CompileBroker::print_times() { comp->print_timers(); } tty->cr(); - tty->print_cr(" Total compiled methods : %8d methods", CompileBroker::_total_compile_count); - tty->print_cr(" Standard compilation : %8d methods", CompileBroker::_total_standard_compile_count); - tty->print_cr(" On stack replacement : %8d methods", CompileBroker::_total_osr_compile_count); - int tcb = CompileBroker::_sum_osr_bytes_compiled + CompileBroker::_sum_standard_bytes_compiled; + tty->print_cr(" Total compiled methods : %8d methods", total_compile_count); + tty->print_cr(" Standard compilation : %8d methods", standard_compile_count); + tty->print_cr(" On stack replacement : %8d methods", osr_compile_count); + int tcb = osr_bytes_compiled + standard_bytes_compiled; tty->print_cr(" Total compiled bytecodes : %8d bytes", tcb); - tty->print_cr(" Standard compilation : %8d bytes", CompileBroker::_sum_standard_bytes_compiled); - tty->print_cr(" On stack replacement : %8d bytes", CompileBroker::_sum_osr_bytes_compiled); - int bps = (int)(tcb / CompileBroker::_t_total_compilation.seconds()); + tty->print_cr(" Standard compilation : %8d bytes", standard_bytes_compiled); + tty->print_cr(" On stack replacement : %8d bytes", osr_bytes_compiled); + double tcs = total_compilation.seconds(); + int bps = tcs == 0.0 ? 0 : (int)(tcb / tcs); tty->print_cr(" Average compilation speed : %8d bytes/s", bps); tty->cr(); - tty->print_cr(" nmethod code size : %8d bytes", CompileBroker::_sum_nmethod_code_size); - tty->print_cr(" nmethod total size : %8d bytes", CompileBroker::_sum_nmethod_size); + tty->print_cr(" nmethod code size : %8d bytes", nmethods_code_size); + tty->print_cr(" nmethod total size : %8d bytes", nmethods_size); } // Debugging output for failure diff --git a/hotspot/src/share/vm/compiler/compileBroker.hpp b/hotspot/src/share/vm/compiler/compileBroker.hpp index 2a4f9ab3d5c..3363db9d25c 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.hpp +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp @@ -29,6 +29,7 @@ #include "compiler/abstractCompiler.hpp" #include "compiler/compileTask.hpp" #include "runtime/perfData.hpp" +#include "trace/tracing.hpp" class nmethod; class nmethodLocker; @@ -47,36 +48,26 @@ class CompilerCounters : public CHeapObj { private: char _current_method[cmname_buffer_length]; - PerfStringVariable* _perf_current_method; - int _compile_type; - PerfVariable* _perf_compile_type; - - PerfCounter* _perf_time; - PerfCounter* _perf_compiles; public: - CompilerCounters(const char* name, int instance, TRAPS); + CompilerCounters(); // these methods should be called in a thread safe context void set_current_method(const char* method) { strncpy(_current_method, method, (size_t)cmname_buffer_length-1); _current_method[cmname_buffer_length-1] = '\0'; - if (UsePerfData) _perf_current_method->set_value(method); } char* current_method() { return _current_method; } void set_compile_type(int compile_type) { _compile_type = compile_type; - if (UsePerfData) _perf_compile_type->set_value((jlong)compile_type); } int compile_type() { return _compile_type; } - PerfCounter* time_counter() { return _perf_time; } - PerfCounter* compile_counter() { return _perf_compiles; } }; // CompileQueue @@ -243,6 +234,7 @@ class CompileBroker: AllStatic { static void wait_for_completion(CompileTask* task); static void invoke_compiler_on_method(CompileTask* task); + static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env); static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level); static void push_jni_handle_block(); static void pop_jni_handle_block(); @@ -288,6 +280,9 @@ class CompileBroker: AllStatic { int hot_count, const char* comment, Thread* thread); + // Acquire any needed locks and assign a compile id + static uint assign_compile_id_unlocked(Thread* thread, methodHandle method, int osr_bci); + static void compiler_thread_loop(); static uint get_compilation_id() { return _compilation_id; } @@ -336,8 +331,13 @@ class CompileBroker: AllStatic { // Redefine Classes support static void mark_on_stack(); +#if INCLUDE_JVMCI + // Print curent compilation time stats for a given compiler + static void print_times(AbstractCompiler* comp); +#endif + // Print a detailed accounting of compilation time - static void print_times(); + static void print_times(bool per_compiler = true, bool aggregate = true); // Debugging output for failure static void print_last_compile(); diff --git a/hotspot/src/share/vm/compiler/compileTask.cpp b/hotspot/src/share/vm/compiler/compileTask.cpp index d7620736d9e..0dcc95d23c8 100644 --- a/hotspot/src/share/vm/compiler/compileTask.cpp +++ b/hotspot/src/share/vm/compiler/compileTask.cpp @@ -183,6 +183,10 @@ void CompileTask::print_impl(outputStream* st, Method* method, int compile_id, i if (!short_form) { st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp } + // print compiler name if requested + if (CIPrintCompilerName) { + st->print("%s:", CompileBroker::compiler_name(comp_level)); + } st->print("%4d ", compile_id); // print compilation number // For unloaded methods the transition to zombie occurs after the @@ -271,7 +275,8 @@ void CompileTask::log_task(xmlStream* log) { if (_osr_bci != CompileBroker::standard_entry_bci) { log->print(" osr_bci='%d'", _osr_bci); } - if (_comp_level != CompLevel_highest_tier) { + // Always print the level in tiered. + if (_comp_level != CompLevel_highest_tier || TieredCompilation) { log->print(" level='%d'", _comp_level); } if (_is_blocking) { @@ -306,6 +311,24 @@ void CompileTask::log_task_queued() { } +// ------------------------------------------------------------------ +// CompileTask::log_task_dequeued +void CompileTask::log_task_dequeued(const char* comment) { + if (LogCompilation && xtty != NULL) { + Thread* thread = Thread::current(); + ttyLocker ttyl; + ResourceMark rm(thread); + + xtty->begin_elem("task_dequeued"); + log_task(xtty); + if (comment != NULL) { + xtty->print(" comment='%s'", comment); + } + xtty->end_elem(); + } +} + + // ------------------------------------------------------------------ // CompileTask::log_task_start void CompileTask::log_task_start(CompileLog* log) { diff --git a/hotspot/src/share/vm/compiler/compileTask.hpp b/hotspot/src/share/vm/compiler/compileTask.hpp index 1eb73c13df4..68c93386187 100644 --- a/hotspot/src/share/vm/compiler/compileTask.hpp +++ b/hotspot/src/share/vm/compiler/compileTask.hpp @@ -133,6 +133,7 @@ public: void log_task(xmlStream* log); void log_task_queued(); + void log_task_dequeued(const char* comment); void log_task_start(CompileLog* log); void log_task_done(CompileLog* log); diff --git a/hotspot/src/share/vm/compiler/compilerOracle.cpp b/hotspot/src/share/vm/compiler/compilerOracle.cpp index 382debbe8ea..4e90f6ad679 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp @@ -24,149 +24,17 @@ #include "precompiled.hpp" #include "compiler/compilerOracle.hpp" +#include "compiler/methodMatcher.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/klass.hpp" #include "oops/method.hpp" -#include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" #include "runtime/os.hpp" -class MethodMatcher : public CHeapObj { - public: - enum Mode { - Exact, - Prefix = 1, - Suffix = 2, - Substring = Prefix | Suffix, - Any, - Unknown = -1 - }; - - protected: - Symbol* _class_name; - Symbol* _method_name; - Symbol* _signature; - Mode _class_mode; - Mode _method_mode; - MethodMatcher* _next; - - static bool match(Symbol* candidate, Symbol* match, Mode match_mode); - - Symbol* class_name() const { return _class_name; } - Symbol* method_name() const { return _method_name; } - Symbol* signature() const { return _signature; } - - public: - MethodMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, MethodMatcher* next); - MethodMatcher(Symbol* class_name, Symbol* method_name, MethodMatcher* next); - - // utility method - MethodMatcher* find(methodHandle method) { - Symbol* class_name = method->method_holder()->name(); - Symbol* method_name = method->name(); - for (MethodMatcher* current = this; current != NULL; current = current->_next) { - if (match(class_name, current->class_name(), current->_class_mode) && - match(method_name, current->method_name(), current->_method_mode) && - (current->signature() == NULL || current->signature() == method->signature())) { - return current; - } - } - return NULL; - } - - bool match(methodHandle method) { - return find(method) != NULL; - } - - MethodMatcher* next() const { return _next; } - - static void print_symbol(Symbol* h, Mode mode) { - ResourceMark rm; - - if (mode == Suffix || mode == Substring || mode == Any) { - tty->print("*"); - } - if (mode != Any) { - h->print_symbol_on(tty); - } - if (mode == Prefix || mode == Substring) { - tty->print("*"); - } - } - - void print_base() { - print_symbol(class_name(), _class_mode); - tty->print("."); - print_symbol(method_name(), _method_mode); - if (signature() != NULL) { - signature()->print_symbol_on(tty); - } - } - - virtual void print() { - print_base(); - tty->cr(); - } -}; - -MethodMatcher::MethodMatcher(Symbol* class_name, Symbol* method_name, MethodMatcher* next) { - _class_name = class_name; - _method_name = method_name; - _next = next; - _class_mode = MethodMatcher::Exact; - _method_mode = MethodMatcher::Exact; - _signature = NULL; -} - - -MethodMatcher::MethodMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, MethodMatcher* next): - _class_mode(class_mode) - , _method_mode(method_mode) - , _next(next) - , _class_name(class_name) - , _method_name(method_name) - , _signature(signature) { -} - -bool MethodMatcher::match(Symbol* candidate, Symbol* match, Mode match_mode) { - if (match_mode == Any) { - return true; - } - - if (match_mode == Exact) { - return candidate == match; - } - - ResourceMark rm; - const char * candidate_string = candidate->as_C_string(); - const char * match_string = match->as_C_string(); - - switch (match_mode) { - case Prefix: - return strstr(candidate_string, match_string) == candidate_string; - - case Suffix: { - size_t clen = strlen(candidate_string); - size_t mlen = strlen(match_string); - return clen >= mlen && strcmp(candidate_string + clen - mlen, match_string) == 0; - } - - case Substring: - return strstr(candidate_string, match_string) != NULL; - - default: - return false; - } -} - enum OptionType { IntxType, UintxType, @@ -202,114 +70,6 @@ template<> OptionType get_type_for() { return DoubleType; } -template -static const T copy_value(const T value) { - return value; -} - -template<> const ccstr copy_value(const ccstr value) { - return (const ccstr)os::strdup_check_oom(value); -} - -template -class TypedMethodOptionMatcher : public MethodMatcher { - const char* _option; - OptionType _type; - const T _value; - -public: - TypedMethodOptionMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, const char* opt, - const T value, MethodMatcher* next) : - MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next), - _type(get_type_for()), _value(copy_value(value)) { - _option = os::strdup_check_oom(opt); - } - - ~TypedMethodOptionMatcher() { - os::free((void*)_option); - } - - TypedMethodOptionMatcher* match(methodHandle method, const char* opt) { - TypedMethodOptionMatcher* current = this; - while (current != NULL) { - current = (TypedMethodOptionMatcher*)current->find(method); - if (current == NULL) { - return NULL; - } - if (strcmp(current->_option, opt) == 0) { - return current; - } - current = current->next(); - } - return NULL; - } - - TypedMethodOptionMatcher* next() { - return (TypedMethodOptionMatcher*)_next; - } - - OptionType get_type(void) { - return _type; - }; - - T value() { return _value; } - - void print() { - ttyLocker ttyl; - print_base(); - tty->print(" %s", _option); - tty->print(" "); - tty->cr(); - } -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" intx %s", _option); - tty->print(" = " INTX_FORMAT, _value); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" uintx %s", _option); - tty->print(" = " UINTX_FORMAT, _value); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" bool %s", _option); - tty->print(" = %s", _value ? "true" : "false"); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" const char* %s", _option); - tty->print(" = '%s'", _value); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" double %s", _option); - tty->print(" = %f", _value); - tty->cr(); -}; - // this must parallel the command_names below enum OracleCommand { UnknownCommand = -1, @@ -342,8 +102,198 @@ static const char * command_names[] = { }; class MethodMatcher; -static MethodMatcher* lists[OracleCommandCount] = { 0, }; +class TypedMethodOptionMatcher; +static BasicMatcher* lists[OracleCommandCount] = { 0, }; +static TypedMethodOptionMatcher* option_list = NULL; + +class TypedMethodOptionMatcher : public MethodMatcher { + private: + TypedMethodOptionMatcher* _next; + const char* _option; + OptionType _type; + public: + + union { + bool bool_value; + intx intx_value; + uintx uintx_value; + double double_value; + ccstr ccstr_value; + } _u; + + TypedMethodOptionMatcher() : MethodMatcher(), + _next(NULL), + _type(UnknownType) { + _option = NULL; + memset(&_u, 0, sizeof(_u)); + } + + static TypedMethodOptionMatcher* parse_method_pattern(char*& line, const char*& error_msg); + TypedMethodOptionMatcher* match(methodHandle method, const char* opt, OptionType type); + + void init(const char* opt, OptionType type, TypedMethodOptionMatcher* next) { + _next = next; + _type = type; + _option = os::strdup_check_oom(opt); + } + + void set_next(TypedMethodOptionMatcher* next) {_next = next; } + TypedMethodOptionMatcher* next() { return _next; } + OptionType type() { return _type; } + template T value(); + template void set_value(T value); + void print(); + void print_all(); + TypedMethodOptionMatcher* clone(); + ~TypedMethodOptionMatcher(); +}; + +// A few templated accessors instead of a full template class. +template<> intx TypedMethodOptionMatcher::value() { + return _u.intx_value; +} + +template<> uintx TypedMethodOptionMatcher::value() { + return _u.uintx_value; +} + +template<> bool TypedMethodOptionMatcher::value() { + return _u.bool_value; +} + +template<> double TypedMethodOptionMatcher::value() { + return _u.double_value; +} + +template<> ccstr TypedMethodOptionMatcher::value() { + return _u.ccstr_value; +} + +template<> void TypedMethodOptionMatcher::set_value(intx value) { + _u.intx_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(uintx value) { + _u.uintx_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(double value) { + _u.double_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(bool value) { + _u.bool_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(ccstr value) { + _u.ccstr_value = (const ccstr)os::strdup_check_oom(value); +} + +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(tty); + switch (_type) { + case IntxType: + tty->print_cr(" intx %s = " INTX_FORMAT, _option, value()); + break; + case UintxType: + tty->print_cr(" uintx %s = " UINTX_FORMAT, _option, value()); + break; + case BoolType: + tty->print_cr(" bool %s = %s", _option, value() ? "true" : "false"); + break; + case DoubleType: + tty->print_cr(" double %s = %f", _option, value()); + break; + case CcstrType: + tty->print_cr(" const char* %s = '%s'", _option, value()); + break; + default: + ShouldNotReachHere(); + } +} + +void TypedMethodOptionMatcher::print_all() { + print(); + if (_next != NULL) { + tty->print(" "); + _next->print_all(); + } + } + +TypedMethodOptionMatcher* TypedMethodOptionMatcher::clone() { + TypedMethodOptionMatcher* m = new TypedMethodOptionMatcher(); + m->_class_mode = _class_mode; + m->_class_name = _class_name; + m->_method_mode = _method_mode; + m->_method_name = _method_name; + m->_signature = _signature; + // Need to ref count the symbols + if (_class_name != NULL) { + _class_name->increment_refcount(); + } + if (_method_name != NULL) { + _method_name->increment_refcount(); + } + if (_signature != NULL) { + _signature->increment_refcount(); + } + return m; +} + +TypedMethodOptionMatcher::~TypedMethodOptionMatcher() { + if (_option != NULL) { + os::free((void*)_option); + } + if (_class_name != NULL) { + _class_name->decrement_refcount(); + } + if (_method_name != NULL) { + _method_name->decrement_refcount(); + } + if (_signature != NULL) { + _signature->decrement_refcount(); + } +} + +TypedMethodOptionMatcher* TypedMethodOptionMatcher::parse_method_pattern(char*& line, const char*& error_msg) { + assert(error_msg == NULL, "Dont call here with error_msg already set"); + TypedMethodOptionMatcher* tom = new TypedMethodOptionMatcher(); + MethodMatcher::parse_method_pattern(line, error_msg, tom); + if (error_msg != NULL) { + delete tom; + return NULL; + } + return tom; +} + +TypedMethodOptionMatcher* TypedMethodOptionMatcher::match(methodHandle method, const char* opt, OptionType type) { + TypedMethodOptionMatcher* current = this; + while (current != NULL) { + // Fastest compare first. + if (current->type() == type) { + if (strcmp(current->_option, opt) == 0) { + if (current->matches(method)) { + return current; + } + } + } + current = current->next(); + } + return NULL; +} + +template +static void add_option_string(TypedMethodOptionMatcher* matcher, + const char* option, + T value) { + assert(matcher != option_list, "No circular lists please"); + matcher->init(option, get_type_for(), option_list); + matcher->set_value(value); + option_list = matcher; + return; +} static bool check_predicate(OracleCommand command, methodHandle method) { return ((lists[command] != NULL) && @@ -351,51 +301,27 @@ static bool check_predicate(OracleCommand command, methodHandle method) { lists[command]->match(method)); } - -static MethodMatcher* add_predicate(OracleCommand command, - Symbol* class_name, MethodMatcher::Mode c_mode, - Symbol* method_name, MethodMatcher::Mode m_mode, - Symbol* signature) { +static void add_predicate(OracleCommand command, BasicMatcher* bm) { assert(command != OptionCommand, "must use add_option_string"); - if (command == LogCommand && !LogCompilation && lists[LogCommand] == NULL) + if (command == LogCommand && !LogCompilation && lists[LogCommand] == NULL) { tty->print_cr("Warning: +LogCompilation must be enabled in order for individual methods to be logged."); - lists[command] = new MethodMatcher(class_name, c_mode, method_name, m_mode, signature, lists[command]); - return lists[command]; -} + } + bm->set_next(lists[command]); + lists[command] = bm; -template -static MethodMatcher* add_option_string(Symbol* class_name, MethodMatcher::Mode c_mode, - Symbol* method_name, MethodMatcher::Mode m_mode, - Symbol* signature, - const char* option, - T value) { - lists[OptionCommand] = new TypedMethodOptionMatcher(class_name, c_mode, method_name, m_mode, - signature, option, value, lists[OptionCommand]); - return lists[OptionCommand]; -} - -template -static bool get_option_value(methodHandle method, const char* option, T& value) { - TypedMethodOptionMatcher* m; - if (lists[OptionCommand] != NULL - && (m = ((TypedMethodOptionMatcher*)lists[OptionCommand])->match(method, option)) != NULL - && m->get_type() == get_type_for()) { - value = m->value(); - return true; - } else { - return false; - } -} - -bool CompilerOracle::has_option_string(methodHandle method, const char* option) { - bool value = false; - get_option_value(method, option, value); - return value; + return; } template bool CompilerOracle::has_option_value(methodHandle method, const char* option, T& value) { - return ::get_option_value(method, option, value); + if (option_list != NULL) { + TypedMethodOptionMatcher* m = option_list->match(method, option, get_type_for()); + if (m != NULL) { + value = m->value(); + return true; + } + } + return false; } // Explicit instantiation for all OptionTypes supported. @@ -405,6 +331,12 @@ template bool CompilerOracle::has_option_value(methodHandle method, const template bool CompilerOracle::has_option_value(methodHandle method, const char* option, ccstr& value); template bool CompilerOracle::has_option_value(methodHandle method, const char* option, double& value); +bool CompilerOracle::has_option_string(methodHandle method, const char* option) { + bool value = false; + has_option_value(method, option, value); + return value; +} + bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) { quietly = true; if (lists[ExcludeCommand] != NULL) { @@ -420,19 +352,18 @@ bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) { return false; } - bool CompilerOracle::should_inline(methodHandle method) { return (check_predicate(InlineCommand, method)); } - +// Check both DontInlineCommand and ExcludeCommand here +// - consistent behavior for all compilers bool CompilerOracle::should_not_inline(methodHandle method) { - return (check_predicate(DontInlineCommand, method)); + return check_predicate(DontInlineCommand, method) || check_predicate(ExcludeCommand, method); } - bool CompilerOracle::should_print(methodHandle method) { - return (check_predicate(PrintCommand, method)); + return check_predicate(PrintCommand, method); } bool CompilerOracle::should_print_methods() { @@ -445,12 +376,10 @@ bool CompilerOracle::should_log(methodHandle method) { return (check_predicate(LogCommand, method)); } - bool CompilerOracle::should_break_at(methodHandle method) { return check_predicate(BreakCommand, method); } - static OracleCommand parse_command_name(const char * line, int* bytes_read) { assert(ARRAY_SIZE(command_names) == OracleCommandCount, "command_names size mismatch"); @@ -516,84 +445,12 @@ static void usage() { tty->cr(); }; -// The JVM specification defines the allowed characters. -// Tokens that are disallowed by the JVM specification can have -// a meaning to the parser so we need to include them here. -// The parser does not enforce all rules of the JVMS - a successful parse -// does not mean that it is an allowed name. Illegal names will -// be ignored since they never can match a class or method. -// -// '\0' and 0xf0-0xff are disallowed in constant string values -// 0x20 ' ', 0x09 '\t' and, 0x2c ',' are used in the matching -// 0x5b '[' and 0x5d ']' can not be used because of the matcher -// 0x28 '(' and 0x29 ')' are used for the signature -// 0x2e '.' is always replaced before the matching -// 0x2f '/' is only used in the class name as package separator - -#define RANGEBASE "\x1\x2\x3\x4\x5\x6\x7\x8\xa\xb\xc\xd\xe\xf" \ - "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ - "\x21\x22\x23\x24\x25\x26\x27\x2a\x2b\x2c\x2d" \ - "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ - "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ - "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5c\x5e\x5f" \ - "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ - "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" \ - "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \ - "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \ - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \ - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \ - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" \ - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \ - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" - -#define RANGE0 "[*" RANGEBASE "]" -#define RANGESLASH "[*" RANGEBASE "/]" - -static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) { - int match = MethodMatcher::Exact; - while (name[0] == '*') { - match |= MethodMatcher::Suffix; - // Copy remaining string plus NUL to the beginning - memmove(name, name + 1, strlen(name + 1) + 1); - } - - if (strcmp(name, "*") == 0) return MethodMatcher::Any; - - size_t len = strlen(name); - while (len > 0 && name[len - 1] == '*') { - match |= MethodMatcher::Prefix; - name[--len] = '\0'; - } - - if (strstr(name, "*") != NULL) { - error_msg = " Embedded * not allowed"; - return MethodMatcher::Unknown; - } - return (MethodMatcher::Mode)match; -} - -static bool scan_line(const char * line, - char class_name[], MethodMatcher::Mode* c_mode, - char method_name[], MethodMatcher::Mode* m_mode, - int* bytes_read, const char*& error_msg) { - *bytes_read = 0; - error_msg = NULL; - if (2 == sscanf(line, "%*[ \t]%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, bytes_read)) { - *c_mode = check_mode(class_name, error_msg); - *m_mode = check_mode(method_name, error_msg); - return *c_mode != MethodMatcher::Unknown && *m_mode != MethodMatcher::Unknown; - } - return false; -} - // Scan next flag and value in line, return MethodMatcher object on success, NULL on failure. // On failure, error_msg contains description for the first error. // For future extensions: set error_msg on first error. -static MethodMatcher* scan_flag_and_value(const char* type, const char* line, int& total_bytes_read, - Symbol* c_name, MethodMatcher::Mode c_match, - Symbol* m_name, MethodMatcher::Mode m_match, - Symbol* signature, - char* errorbuf, const int buf_size) { +static void scan_flag_and_value(const char* type, const char* line, int& total_bytes_read, + TypedMethodOptionMatcher* matcher, + char* errorbuf, const int buf_size) { total_bytes_read = 0; int bytes_read = 0; char flag[256]; @@ -608,7 +465,8 @@ static MethodMatcher* scan_flag_and_value(const char* type, const char* line, in intx value; if (sscanf(line, "%*[ \t]" INTX_FORMAT "%n", &value, &bytes_read) == 1) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value); + add_option_string(matcher, flag, value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s ", flag, type); } @@ -616,7 +474,8 @@ static MethodMatcher* scan_flag_and_value(const char* type, const char* line, in uintx value; if (sscanf(line, "%*[ \t]" UINTX_FORMAT "%n", &value, &bytes_read) == 1) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value); + add_option_string(matcher, flag, value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -625,7 +484,8 @@ static MethodMatcher* scan_flag_and_value(const char* type, const char* line, in char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value); + add_option_string(matcher, flag, (ccstr)value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -646,7 +506,8 @@ static MethodMatcher* scan_flag_and_value(const char* type, const char* line, in next_value += bytes_read; end_value = next_value-1; } - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value); + add_option_string(matcher, flag, (ccstr)value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -655,10 +516,12 @@ static MethodMatcher* scan_flag_and_value(const char* type, const char* line, in if (sscanf(line, "%*[ \t]%255[a-zA-Z]%n", value, &bytes_read) == 1) { if (strcmp(value, "true") == 0) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, true); + add_option_string(matcher, flag, true); + return; } else if (strcmp(value, "false") == 0) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, false); + add_option_string(matcher, flag, false); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -673,7 +536,8 @@ static MethodMatcher* scan_flag_and_value(const char* type, const char* line, in char value[512] = ""; jio_snprintf(value, sizeof(value), "%s.%s", buffer[0], buffer[1]); total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, atof(value)); + add_option_string(matcher, flag, atof(value)); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -683,7 +547,7 @@ static MethodMatcher* scan_flag_and_value(const char* type, const char* line, in } else { jio_snprintf(errorbuf, buf_size, " Flag name for type %s should be alphanumeric ", type); } - return NULL; + return; } int skip_whitespace(char* line) { @@ -693,31 +557,20 @@ int skip_whitespace(char* line) { return whitespace_read; } +void CompilerOracle::print_parse_error(const char*& error_msg, char* original_line) { + assert(error_msg != NULL, "Must have error_message"); + + ttyLocker ttyl; + tty->print_cr("CompileCommand: An error occurred during parsing"); + tty->print_cr("Line: %s", original_line); + tty->print_cr("Error: %s", error_msg); + CompilerOracle::print_tip(); +} + void CompilerOracle::parse_from_line(char* line) { if (line[0] == '\0') return; if (line[0] == '#') return; - bool have_colon = (strstr(line, "::") != NULL); - for (char* lp = line; *lp != '\0'; lp++) { - // Allow '.' to separate the class name from the method name. - // This is the preferred spelling of methods: - // exclude java/lang/String.indexOf(I)I - // Allow ',' for spaces (eases command line quoting). - // exclude,java/lang/String.indexOf - // For backward compatibility, allow space as separator also. - // exclude java/lang/String indexOf - // exclude,java/lang/String,indexOf - // For easy cut-and-paste of method names, allow VM output format - // as produced by Method::print_short_name: - // exclude java.lang.String::indexOf - // For simple implementation convenience here, convert them all to space. - if (have_colon) { - if (*lp == '.') *lp = '/'; // dots build the package prefix - if (*lp == ':') *lp = ' '; - } - if (*lp == ',' || *lp == '.') *lp = ' '; - } - char* original_line = line; int bytes_read; OracleCommand command = parse_command_name(line, &bytes_read); @@ -742,109 +595,86 @@ void CompilerOracle::parse_from_line(char* line) { return; } - MethodMatcher::Mode c_match = MethodMatcher::Exact; - MethodMatcher::Mode m_match = MethodMatcher::Exact; - char class_name[256]; - char method_name[256]; - char sig[1024]; - char errorbuf[1024]; - const char* error_msg = NULL; // description of first error that appears - MethodMatcher* match = NULL; + const char* error_msg = NULL; + if (command == OptionCommand) { + // Look for trailing options. + // + // Two types of trailing options are + // supported: + // + // (1) CompileCommand=option,Klass::method,flag + // (2) CompileCommand=option,Klass::method,type,flag,value + // + // Type (1) is used to enable a boolean flag for a method. + // + // Type (2) is used to support options with a value. Values can have the + // the following types: intx, uintx, bool, ccstr, ccstrlist, and double. + // + // For future extensions: extend scan_flag_and_value() - if (scan_line(line, class_name, &c_match, method_name, &m_match, &bytes_read, error_msg)) { - EXCEPTION_MARK; - Symbol* c_name = SymbolTable::new_symbol(class_name, CHECK); - Symbol* m_name = SymbolTable::new_symbol(method_name, CHECK); - Symbol* signature = NULL; - - line += bytes_read; - - // there might be a signature following the method. - // signatures always begin with ( so match that by hand - line += skip_whitespace(line); - if (1 == sscanf(line, "(%254[[);/" RANGEBASE "]%n", sig + 1, &bytes_read)) { - sig[0] = '('; - line += bytes_read; - signature = SymbolTable::new_symbol(sig, CHECK); + char option[256]; // stores flag for Type (1) and type of Type (2) + line++; // skip the ',' + TypedMethodOptionMatcher* archetype = TypedMethodOptionMatcher::parse_method_pattern(line, error_msg); + if (archetype == NULL) { + assert(error_msg != NULL, "Must have error_message"); + print_parse_error(error_msg, original_line); + return; } - if (command == OptionCommand) { - // Look for trailing options. - // - // Two types of trailing options are - // supported: - // - // (1) CompileCommand=option,Klass::method,flag - // (2) CompileCommand=option,Klass::method,type,flag,value - // - // Type (1) is used to enable a boolean flag for a method. - // - // Type (2) is used to support options with a value. Values can have the - // the following types: intx, uintx, bool, ccstr, ccstrlist, and double. - // - // For future extensions: extend scan_flag_and_value() - char option[256]; // stores flag for Type (1) and type of Type (2) + line += skip_whitespace(line); - line += skip_whitespace(line); - while (sscanf(line, "%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) { - if (match != NULL && !_quiet) { - // Print out the last match added - ttyLocker ttyl; - tty->print("CompileCommand: %s ", command_names[command]); - match->print(); + // This is unnecessarily complex. Should retire multi-option lines and skip while loop + while (sscanf(line, "%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) { + line += bytes_read; + + // typed_matcher is used as a blueprint for each option, deleted at the end + TypedMethodOptionMatcher* typed_matcher = archetype->clone(); + if (strcmp(option, "intx") == 0 + || strcmp(option, "uintx") == 0 + || strcmp(option, "bool") == 0 + || strcmp(option, "ccstr") == 0 + || strcmp(option, "ccstrlist") == 0 + || strcmp(option, "double") == 0 + ) { + char errorbuf[1024] = {0}; + // Type (2) option: parse flag name and value. + scan_flag_and_value(option, line, bytes_read, typed_matcher, errorbuf, sizeof(errorbuf)); + if (*errorbuf != '\0') { + error_msg = errorbuf; + print_parse_error(error_msg, original_line); + return; } line += bytes_read; + } else { + // Type (1) option + add_option_string(typed_matcher, option, true); + } + if (typed_matcher != NULL && !_quiet) { + // Print out the last match added + assert(error_msg == NULL, "No error here"); + ttyLocker ttyl; + tty->print("CompileCommand: %s ", command_names[command]); + typed_matcher->print(); + } + line += skip_whitespace(line); + } // while( + delete archetype; + } else { // not an OptionCommand) + assert(error_msg == NULL, "Don't call here with error_msg already set"); - if (strcmp(option, "intx") == 0 - || strcmp(option, "uintx") == 0 - || strcmp(option, "bool") == 0 - || strcmp(option, "ccstr") == 0 - || strcmp(option, "ccstrlist") == 0 - || strcmp(option, "double") == 0 - ) { - - // Type (2) option: parse flag name and value. - match = scan_flag_and_value(option, line, bytes_read, - c_name, c_match, m_name, m_match, signature, - errorbuf, sizeof(errorbuf)); - if (match == NULL) { - error_msg = errorbuf; - break; - } - line += bytes_read; - } else { - // Type (1) option - match = add_option_string(c_name, c_match, m_name, m_match, signature, option, true); - } - line += skip_whitespace(line); - } // while( - } else { - match = add_predicate(command, c_name, c_match, m_name, m_match, signature); - } - } - - ttyLocker ttyl; - if (error_msg != NULL) { - // an error has happened - tty->print_cr("CompileCommand: An error occured during parsing"); - tty->print_cr(" \"%s\"", original_line); + BasicMatcher* matcher = BasicMatcher::parse_method_pattern(line, error_msg); if (error_msg != NULL) { - tty->print_cr("%s", error_msg); + assert(matcher == NULL, "consistency"); + print_parse_error(error_msg, original_line); + return; } - CompilerOracle::print_tip(); - } else { - // check for remaining characters - bytes_read = 0; - sscanf(line, "%*[ \t]%n", &bytes_read); - if (line[bytes_read] != '\0') { - tty->print_cr("CompileCommand: Bad pattern"); - tty->print_cr(" \"%s\"", original_line); - tty->print_cr(" Unrecognized text %s after command ", line); - CompilerOracle::print_tip(); - } else if (match != NULL && !_quiet) { + add_predicate(command, matcher); + if (!_quiet) { + ttyLocker ttyl; tty->print("CompileCommand: %s ", command_names[command]); - match->print(); + matcher->print(tty); + tty->cr(); } } } @@ -1045,10 +875,12 @@ void CompilerOracle::parse_compile_only(char * line) { Symbol* m_name = SymbolTable::new_symbol(methodName, CHECK); Symbol* signature = NULL; - add_predicate(CompileOnlyCommand, c_name, c_match, m_name, m_match, signature); + BasicMatcher* bm = new BasicMatcher(); + bm->init(c_name, c_match, m_name, m_match, signature); + add_predicate(CompileOnlyCommand, bm); if (PrintVMOptions) { tty->print("CompileOnly: compileonly "); - lists[CompileOnlyCommand]->print(); + lists[CompileOnlyCommand]->print_all(tty); } className = NULL; diff --git a/hotspot/src/share/vm/compiler/compilerOracle.hpp b/hotspot/src/share/vm/compiler/compilerOracle.hpp index b4b2974ce21..e369e84e888 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.hpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.hpp @@ -35,6 +35,7 @@ class CompilerOracle : AllStatic { private: static bool _quiet; static void print_tip(); + static void print_parse_error(const char*& error_msg, char* original_line); public: diff --git a/hotspot/src/share/vm/compiler/disassembler.cpp b/hotspot/src/share/vm/compiler/disassembler.cpp index 378fb67c16c..82b0291f2d6 100644 --- a/hotspot/src/share/vm/compiler/disassembler.cpp +++ b/hotspot/src/share/vm/compiler/disassembler.cpp @@ -56,8 +56,6 @@ #include "shark/sharkEntry.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void* Disassembler::_library = NULL; bool Disassembler::_tried_to_load_library = false; @@ -330,16 +328,19 @@ void decode_env::print_address(address adr) { if (Universe::is_fully_initialized()) { if (StubRoutines::contains(adr)) { StubCodeDesc* desc = StubCodeDesc::desc_for(adr); - if (desc == NULL) + if (desc == NULL) { desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset); + } if (desc != NULL) { st->print("Stub::%s", desc->name()); - if (desc->begin() != adr) - st->print("%+d 0x%p",adr - desc->begin(), adr); - else if (WizardMode) st->print(" " PTR_FORMAT, adr); + if (desc->begin() != adr) { + st->print(INTX_FORMAT_W(+) " " PTR_FORMAT, adr - desc->begin(), p2i(adr)); + } else if (WizardMode) { + st->print(" " PTR_FORMAT, p2i(adr)); + } return; } - st->print("Stub:: " PTR_FORMAT, adr); + st->print("Stub:: " PTR_FORMAT, p2i(adr)); return; } @@ -347,13 +348,13 @@ void decode_env::print_address(address adr) { if (bs->is_a(BarrierSet::CardTableModRef) && adr == (address)(barrier_set_cast(bs)->byte_map_base)) { st->print("word_map_base"); - if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr); + if (WizardMode) st->print(" " INTPTR_FORMAT, p2i(adr)); return; } } // Fall through to a simple (hexadecimal) numeral. - st->print(PTR_FORMAT, adr); + st->print(PTR_FORMAT, p2i(adr)); } void decode_env::print_insn_labels() { @@ -365,7 +366,7 @@ void decode_env::print_insn_labels() { } _strings.print_block_comment(st, (intptr_t)(p - _start)); if (_print_pc) { - st->print(" " PTR_FORMAT ": ", p); + st->print(" " PTR_FORMAT ": ", p2i(p)); } } @@ -386,13 +387,16 @@ void decode_env::print_insn_bytes(address pc, address pc_limit) { address pc1 = pc + perline; if (pc1 > pc_limit) pc1 = pc_limit; for (; pc < pc1; pc += incr) { - if (pc == pc0) + if (pc == pc0) { st->print(BYTES_COMMENT); - else if ((uint)(pc - pc0) % sizeof(int) == 0) + } else if ((uint)(pc - pc0) % sizeof(int) == 0) { st->print(" "); // put out a space on word boundaries - if (incr == sizeof(int)) - st->print("%08lx", *(int*)pc); - else st->print("%02x", (*pc)&0xFF); + } + if (incr == sizeof(int)) { + st->print("%08x", *(int*)pc); + } else { + st->print("%02x", (*pc)&0xFF); + } } st->cr(); } @@ -487,8 +491,14 @@ address decode_env::decode_instructions(address start, address end) { void Disassembler::decode(CodeBlob* cb, outputStream* st) { if (!load_library()) return; + if (cb->is_nmethod()) { + decode((nmethod*)cb, st); + return; + } decode_env env(cb, st); - env.output()->print_cr("Decoding CodeBlob " PTR_FORMAT, cb); + env.output()->print_cr("----------------------------------------------------------------------"); + env.output()->print_cr("%s", cb->name()); + env.output()->print_cr(" at [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(cb->code_begin()), p2i(cb->code_end()), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*)); env.decode_instructions(cb->code_begin(), cb->code_end()); } @@ -501,8 +511,7 @@ void Disassembler::decode(address start, address end, outputStream* st, CodeStri void Disassembler::decode(nmethod* nm, outputStream* st) { if (!load_library()) return; decode_env env(nm, st); - env.output()->print_cr("Decoding compiled method " PTR_FORMAT ":", nm); - env.output()->print_cr("Code:"); + env.output()->print_cr("----------------------------------------------------------------------"); #ifdef SHARK SharkEntry* entry = (SharkEntry *) nm->code_begin(); @@ -513,6 +522,21 @@ void Disassembler::decode(nmethod* nm, outputStream* st) { unsigned char* end = nm->code_end(); #endif // SHARK + nm->method()->method_holder()->name()->print_symbol_on(env.output()); + env.output()->print("."); + nm->method()->name()->print_symbol_on(env.output()); + nm->method()->signature()->print_symbol_on(env.output()); +#if INCLUDE_JVMCI + { + char buffer[O_BUFLEN]; + char* jvmciName = nm->jvmci_installed_code_name(buffer, O_BUFLEN); + if (jvmciName != NULL) { + env.output()->print(" (%s)", jvmciName); + } + } +#endif + env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(p), p2i(end), ((jlong)(end - p))); + // If there has been profiling, print the buckets. if (FlatProfiler::bucket_start_for(p) != NULL) { unsigned char* p1 = p; @@ -533,9 +557,9 @@ void Disassembler::decode(nmethod* nm, outputStream* st) { int offset = 0; for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) { if ((offset % 8) == 0) { - env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, p, offset, *((int32_t*) p), *((int64_t*) p)); + env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, p2i(p), offset, *((int32_t*) p), *((int64_t*) p)); } else { - env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT, p, offset, *((int32_t*) p)); + env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT, p2i(p), offset, *((int32_t*) p)); } } } diff --git a/hotspot/src/share/vm/compiler/methodLiveness.cpp b/hotspot/src/share/vm/compiler/methodLiveness.cpp index eda1ab156b3..d3a3f4b13e4 100644 --- a/hotspot/src/share/vm/compiler/methodLiveness.cpp +++ b/hotspot/src/share/vm/compiler/methodLiveness.cpp @@ -32,8 +32,6 @@ #include "memory/allocation.inline.hpp" #include "utilities/bitMap.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // The MethodLiveness class performs a simple liveness analysis on a method // in order to decide which locals are live (that is, will be used again) at // a particular bytecode index (bci). @@ -540,7 +538,7 @@ void MethodLiveness::print_times() { _time_flow.seconds() * 100 / _time_total.seconds()); tty->print_cr (" Query : %3.3f sec. (%2.2f%%)", _time_query.seconds(), _time_query.seconds() * 100 / _time_total.seconds()); - tty->print_cr (" #bytes : %8d (%3.0f bytes per sec)", + tty->print_cr (" #bytes : %8ld (%3.0f bytes per sec)", _total_bytes, _total_bytes / _time_total.seconds()); tty->print_cr (" #methods : %8d (%3.0f methods per sec)", @@ -554,7 +552,7 @@ void MethodLiveness::print_times() { _max_method_blocks); tty->print_cr (" avg bytes : %3.3f", (float)_total_bytes / _total_methods); - tty->print_cr (" #blocks : %8d", + tty->print_cr (" #blocks : %8ld", _total_blocks); tty->print_cr (" avg normal predecessors : %3.3f max normal predecessors : %3d", (float)_total_edges / _total_blocks, @@ -564,7 +562,7 @@ void MethodLiveness::print_times() { _max_block_exc_edges); tty->print_cr (" avg visits : %3.3f", (float)_total_visits / _total_blocks); - tty->print_cr (" #locals queried : %8d #live : %8d %%live : %2.2f%%", + tty->print_cr (" #locals queried : %8ld #live : %8ld %%live : %2.2f%%", _total_locals_queried, _total_live_locals_queried, 100.0 * _total_live_locals_queried / _total_locals_queried); diff --git a/hotspot/src/share/vm/compiler/methodMatcher.cpp b/hotspot/src/share/vm/compiler/methodMatcher.cpp new file mode 100644 index 00000000000..d48c8944bd9 --- /dev/null +++ b/hotspot/src/share/vm/compiler/methodMatcher.cpp @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "compiler/methodMatcher.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" + +// The JVM specification defines the allowed characters. +// Tokens that are disallowed by the JVM specification can have +// a meaning to the parser so we need to include them here. +// The parser does not enforce all rules of the JVMS - a successful parse +// does not mean that it is an allowed name. Illegal names will +// be ignored since they never can match a class or method. +// +// '\0' and 0xf0-0xff are disallowed in constant string values +// 0x20 ' ', 0x09 '\t' and, 0x2c ',' are used in the matching +// 0x5b '[' and 0x5d ']' can not be used because of the matcher +// 0x28 '(' and 0x29 ')' are used for the signature +// 0x2e '.' is always replaced before the matching +// 0x2f '/' is only used in the class name as package separator + +#define RANGEBASE "\x1\x2\x3\x4\x5\x6\x7\x8\xa\xb\xc\xd\xe\xf" \ + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ + "\x21\x22\x23\x24\x25\x26\x27\x2a\x2b\x2c\x2d" \ + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ + "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5c\x5e\x5f" \ + "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" \ + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \ + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \ + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \ + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \ + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" \ + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \ + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + +#define RANGE0 "[*" RANGEBASE "]" +#define RANGESLASH "[*" RANGEBASE "/]" + +MethodMatcher::MethodMatcher(): + _class_mode(Exact) + , _method_mode(Exact) + , _class_name(NULL) + , _method_name(NULL) + , _signature(NULL) { +} + +MethodMatcher::~MethodMatcher() { + if (_class_name != NULL) { + _class_name->decrement_refcount(); + } + if (_method_name != NULL) { + _method_name->decrement_refcount(); + } + if (_signature != NULL) { + _signature->decrement_refcount(); + } +} + +void MethodMatcher::init(Symbol* class_name, Mode class_mode, + Symbol* method_name, Mode method_mode, + Symbol* signature) { + _class_mode = class_mode; + _method_mode = method_mode; + _class_name = class_name; + _method_name = method_name; + _signature = signature; +} + +bool MethodMatcher::canonicalize(char * line, const char *& error_msg) { + char* colon = strstr(line, "::"); + bool have_colon = (colon != NULL); + if (have_colon) { + // Don't allow multiple '::' + if (colon + 2 != '\0') { + if (strstr(colon+2, "::")) { + error_msg = "Method pattern only allows one '::' allowed"; + return false; + } + } + + bool in_signature = false; + char* pos = line; + if (pos != NULL) { + for (char* lp = pos + 1; *lp != '\0'; lp++) { + if (*lp == '(') { + break; + } + + if (*lp == '/') { + error_msg = "Method pattern uses '/' together with '::'"; + return false; + } + } + } + } else { + // Don't allow mixed package separators + char* pos = strchr(line, '.'); + bool in_signature = false; + if (pos != NULL) { + for (char* lp = pos + 1; *lp != '\0'; lp++) { + if (*lp == '(') { + in_signature = true; + } + + // After any comma the method pattern has ended + if (*lp == ',') { + break; + } + + if (!in_signature && (*lp == '/')) { + error_msg = "Method pattern uses mixed '/' and '.' package separators"; + return false; + } + + if (*lp == '.') { + error_msg = "Method pattern uses multiple '.' in pattern"; + return false; + } + } + } + } + + for (char* lp = line; *lp != '\0'; lp++) { + // Allow '.' to separate the class name from the method name. + // This is the preferred spelling of methods: + // exclude java/lang/String.indexOf(I)I + // Allow ',' for spaces (eases command line quoting). + // exclude,java/lang/String.indexOf + // For backward compatibility, allow space as separator also. + // exclude java/lang/String indexOf + // exclude,java/lang/String,indexOf + // For easy cut-and-paste of method names, allow VM output format + // as produced by Method::print_short_name: + // exclude java.lang.String::indexOf + // For simple implementation convenience here, convert them all to space. + + if (have_colon) { + if (*lp == '.') *lp = '/'; // dots build the package prefix + if (*lp == ':') *lp = ' '; + } + if (*lp == ',' || *lp == '.') *lp = ' '; + } + return true; +} + +bool MethodMatcher::match(Symbol* candidate, Symbol* match, Mode match_mode) const { + if (match_mode == Any) { + return true; + } + + if (match_mode == Exact) { + return candidate == match; + } + + ResourceMark rm; + const char * candidate_string = candidate->as_C_string(); + const char * match_string = match->as_C_string(); + + switch (match_mode) { + case Prefix: + return strstr(candidate_string, match_string) == candidate_string; + + case Suffix: { + size_t clen = strlen(candidate_string); + size_t mlen = strlen(match_string); + return clen >= mlen && strcmp(candidate_string + clen - mlen, match_string) == 0; + } + + case Substring: + return strstr(candidate_string, match_string) != NULL; + + default: + return false; + } +} + +static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) { + int match = MethodMatcher::Exact; + if (name[0] == '*') { + if (strlen(name) == 1) { + return MethodMatcher::Any; + } + match |= MethodMatcher::Suffix; + memmove(name, name + 1, strlen(name + 1) + 1); + } + + size_t len = strlen(name); + if (len > 0 && name[len - 1] == '*') { + match |= MethodMatcher::Prefix; + name[--len] = '\0'; + } + + if (strlen(name) == 0) { + error_msg = "** Not a valid pattern"; + return MethodMatcher::Any; + } + + if (strstr(name, "*") != NULL) { + error_msg = " Embedded * not allowed"; + return MethodMatcher::Unknown; + } + return (MethodMatcher::Mode)match; +} + +// Skip any leading spaces +void skip_leading_spaces(char*& line, int* total_bytes_read ) { + int bytes_read = 0; + sscanf(line, "%*[ \t]%n", &bytes_read); + if (bytes_read > 0) { + line += bytes_read; + *total_bytes_read += bytes_read; + } +} + +void MethodMatcher::parse_method_pattern(char*& line, const char*& error_msg, MethodMatcher* matcher) { + MethodMatcher::Mode c_match; + MethodMatcher::Mode m_match; + char class_name[256] = {0}; + char method_name[256] = {0}; + char sig[1024] = {0}; + int bytes_read = 0; + int total_bytes_read = 0; + + assert(error_msg == NULL, "Dont call here with error_msg already set"); + + if (!MethodMatcher::canonicalize(line, error_msg)) { + assert(error_msg != NULL, "Message must be set if parsing failed"); + return; + } + + skip_leading_spaces(line, &total_bytes_read); + + if (2 == sscanf(line, "%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, &bytes_read)) { + c_match = check_mode(class_name, error_msg); + m_match = check_mode(method_name, error_msg); + + if ((strchr(class_name, '<') != NULL) || (strchr(class_name, '>') != NULL)) { + error_msg = "Chars '<' and '>' not allowed in class name"; + return; + } + if ((strchr(method_name, '<') != NULL) || (strchr(method_name, '>') != NULL)) { + if ((strncmp("", method_name, 255) != 0) && (strncmp("", method_name, 255) != 0)) { + error_msg = "Chars '<' and '>' only allowed in and "; + return; + } + } + + if (c_match == MethodMatcher::Unknown || m_match == MethodMatcher::Unknown) { + assert(error_msg != NULL, "Must have been set by check_mode()"); + return; + } + + EXCEPTION_MARK; + Symbol* signature = NULL; + line += bytes_read; + bytes_read = 0; + + skip_leading_spaces(line, &total_bytes_read); + + // there might be a signature following the method. + // signatures always begin with ( so match that by hand + if (line[0] == '(') { + line++; + sig[0] = '('; + // scan the rest + if (1 == sscanf(line, "%254[[);/" RANGEBASE "]%n", sig+1, &bytes_read)) { + if (strchr(sig, '*') != NULL) { + error_msg = " Wildcard * not allowed in signature"; + return; + } + line += bytes_read; + } + signature = SymbolTable::new_symbol(sig, CHECK); + } + Symbol* c_name = SymbolTable::new_symbol(class_name, CHECK); + Symbol* m_name = SymbolTable::new_symbol(method_name, CHECK); + + matcher->init(c_name, c_match, m_name, m_match, signature); + return; + } else { + error_msg = "Could not parse method pattern"; + } +} + +bool MethodMatcher::matches(methodHandle method) const { + Symbol* class_name = method->method_holder()->name(); + Symbol* method_name = method->name(); + Symbol* signature = method->signature(); + + if (match(class_name, this->class_name(), _class_mode) && + match(method_name, this->method_name(), _method_mode) && + ((this->signature() == NULL) || match(signature, this->signature(), Prefix))) { + return true; + } + return false; +} + +void MethodMatcher::print_symbol(outputStream* st, Symbol* h, Mode mode) { + ResourceMark rm; + + if (mode == Suffix || mode == Substring || mode == Any) { + st->print("*"); + } + if (mode != Any) { + h->print_symbol_on(st); + } + if (mode == Prefix || mode == Substring) { + st->print("*"); + } +} + +void MethodMatcher::print_base(outputStream* st) { + print_symbol(st, class_name(), _class_mode); + st->print("."); + print_symbol(st, method_name(), _method_mode); + if (signature() != NULL) { + signature()->print_symbol_on(st); + } +} + + + + diff --git a/hotspot/src/share/vm/compiler/methodMatcher.hpp b/hotspot/src/share/vm/compiler/methodMatcher.hpp new file mode 100644 index 00000000000..aba72726224 --- /dev/null +++ b/hotspot/src/share/vm/compiler/methodMatcher.hpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_COMPILER_METHODMATCHER_HPP +#define SHARE_VM_COMPILER_METHODMATCHER_HPP + +#include "memory/allocation.inline.hpp" +#include "runtime/handles.inline.hpp" +#include "memory/resourceArea.hpp" + +class MethodMatcher : public CHeapObj { + public: + enum Mode { + Exact, + Prefix = 1, + Suffix = 2, + Substring = Prefix | Suffix, + Any, + Unknown = -1 + }; + + protected: + Symbol* _class_name; + Symbol* _method_name; + Symbol* _signature; + Mode _class_mode; + Mode _method_mode; + + public: + Symbol* class_name() const { return _class_name; } + Mode class_mode() const { return _class_mode; } + Symbol* method_name() const { return _method_name; } + Mode method_mode() const { return _method_mode; } + Symbol* signature() const { return _signature; } + + MethodMatcher(); + ~MethodMatcher(); + + void init(Symbol* class_name, Mode class_mode, Symbol* method_name, Mode method_mode, Symbol* signature); + static void parse_method_pattern(char*& line, const char*& error_msg, MethodMatcher* m); + static void print_symbol(outputStream* st, Symbol* h, Mode mode); + bool matches(methodHandle method) const; + void print_base(outputStream* st); + + private: + static bool canonicalize(char * line, const char *& error_msg); + bool match(Symbol* candidate, Symbol* match, Mode match_mode) const; +}; + +class BasicMatcher : public MethodMatcher { +private: + BasicMatcher* _next; +public: + + BasicMatcher() : MethodMatcher(), + _next(NULL) { + } + + BasicMatcher(BasicMatcher* next) : + _next(next) { + } + + static BasicMatcher* parse_method_pattern(char* line, const char*& error_msg) { + assert(error_msg == NULL, "Dont call here with error_msg already set"); + BasicMatcher* bm = new BasicMatcher(); + MethodMatcher::parse_method_pattern(line, error_msg, bm); + if (error_msg != NULL) { + delete bm; + return NULL; + } + + // check for bad trailing characters + int bytes_read = 0; + sscanf(line, "%*[ \t]%n", &bytes_read); + if (line[bytes_read] != '\0') { + error_msg = "Unrecognized trailing text after method pattern"; + delete bm; + return NULL; + } + return bm; + } + + bool match(methodHandle method) { + for (BasicMatcher* current = this; current != NULL; current = current->next()) { + if (current->matches(method)) { + return true; + } + } + return false; + } + + void set_next(BasicMatcher* next) { _next = next; } + BasicMatcher* next() { return _next; } + + void print(outputStream* st) { print_base(st); } + void print_all(outputStream* st) { + print_base(st); + if (_next != NULL) { + _next->print_all(st); + } + } +}; + +#endif // SHARE_VM_COMPILER_METHODMATCHER_HPP + diff --git a/hotspot/src/share/vm/compiler/oopMap.cpp b/hotspot/src/share/vm/compiler/oopMap.cpp index cb5dfc7ef83..197324a4ac4 100644 --- a/hotspot/src/share/vm/compiler/oopMap.cpp +++ b/hotspot/src/share/vm/compiler/oopMap.cpp @@ -39,6 +39,9 @@ #ifdef COMPILER2 #include "opto/optoreg.hpp" #endif +#ifdef SPARC +#include "vmreg_sparc.inline.hpp" +#endif // OopMapStream @@ -58,7 +61,6 @@ OopMapStream::OopMapStream(const ImmutableOopMap* oop_map, int oop_types_mask) { _valid_omv = false; } - void OopMapStream::find_next() { while(_position++ < _size) { _omv.read_from(_stream); @@ -156,9 +158,7 @@ void OopMap::set_oop(VMReg reg) { void OopMap::set_value(VMReg reg) { - // At this time, we only need value entries in our OopMap when ZapDeadCompiledLocals is active. - if (ZapDeadCompiledLocals) - set_xxx(reg, OopMapValue::value_value, VMRegImpl::Bad()); + // At this time, we don't need value entries in our OopMap. } @@ -199,7 +199,6 @@ void OopMapSet::grow_om_data() { set_om_data(new_data); } - void OopMapSet::add_gc_map(int pc_offset, OopMap *map ) { assert(om_size() != -1,"Cannot grow a fixed OopMapSet"); @@ -276,10 +275,15 @@ static DoNothingClosure do_nothing; static void add_derived_oop(oop* base, oop* derived) { #ifndef TIERED COMPILER1_PRESENT(ShouldNotReachHere();) +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + ShouldNotReachHere(); + } +#endif #endif // TIERED -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI DerivedPointerTable::add(derived, base); -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI } @@ -288,7 +292,7 @@ static void trace_codeblob_maps(const frame *fr, const RegisterMap *reg_map) { // Print oopmap and regmap tty->print_cr("------ "); CodeBlob* cb = fr->cb(); - ImmutableOopMapSet* maps = cb->oop_maps(); + const ImmutableOopMapSet* maps = cb->oop_maps(); const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc()); map->print(); if( cb->is_nmethod() ) { @@ -325,7 +329,7 @@ void OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map, NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);) - ImmutableOopMapSet* maps = cb->oop_maps(); + const ImmutableOopMapSet* maps = cb->oop_maps(); const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc()); assert(map != NULL, "no ptr map found"); @@ -337,6 +341,11 @@ void OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map, if (!oms.is_done()) { #ifndef TIERED COMPILER1_PRESENT(ShouldNotReachHere();) +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + ShouldNotReachHere(); + } +#endif #endif // !TIERED // Protect the operation on the derived pointers. This // protects the addition of derived pointers to the shared @@ -345,72 +354,73 @@ void OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map, do { omv = oms.current(); oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); - if ( loc != NULL ) { - oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map); - oop *derived_loc = loc; - oop val = *base_loc; - if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { - // Ignore NULL oops and decoded NULL narrow oops which - // equal to Universe::narrow_oop_base when a narrow oop - // implicit null check is used in compiled code. - // The narrow_oop_base could be NULL or be the address - // of the page below heap depending on compressed oops mode. - } else - derived_oop_fn(base_loc, derived_loc); + guarantee(loc != NULL, "missing saved register"); + oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map); + oop *derived_loc = loc; + oop val = *base_loc; + if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { + // Ignore NULL oops and decoded NULL narrow oops which + // equal to Universe::narrow_oop_base when a narrow oop + // implicit null check is used in compiled code. + // The narrow_oop_base could be NULL or be the address + // of the page below heap depending on compressed oops mode. + } else { + derived_oop_fn(base_loc, derived_loc); } oms.next(); } while (!oms.is_done()); } } - // We want coop, value and oop oop_types - int mask = OopMapValue::oop_value | OopMapValue::value_value | OopMapValue::narrowoop_value; + // We want coop and oop oop_types + int mask = OopMapValue::oop_value | OopMapValue::narrowoop_value; { for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) { omv = oms.current(); oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); - if ( loc != NULL ) { - if ( omv.type() == OopMapValue::oop_value ) { - oop val = *loc; - if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { - // Ignore NULL oops and decoded NULL narrow oops which - // equal to Universe::narrow_oop_base when a narrow oop - // implicit null check is used in compiled code. - // The narrow_oop_base could be NULL or be the address - // of the page below heap depending on compressed oops mode. - continue; - } -#ifdef ASSERT - if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) || - !Universe::heap()->is_in_or_null(*loc)) { - tty->print_cr("# Found non oop pointer. Dumping state at failure"); - // try to dump out some helpful debugging information - trace_codeblob_maps(fr, reg_map); - omv.print(); - tty->print_cr("register r"); - omv.reg()->print(); - tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc); - // do the real assert. - assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer"); - } -#endif // ASSERT - oop_fn->do_oop(loc); - } else if ( omv.type() == OopMapValue::value_value ) { - assert((*loc) == (oop)NULL || !Universe::is_narrow_oop_base(*loc), - "found invalid value pointer"); - value_fn->do_oop(loc); - } else if ( omv.type() == OopMapValue::narrowoop_value ) { - narrowOop *nl = (narrowOop*)loc; -#ifndef VM_LITTLE_ENDIAN - if (!omv.reg()->is_stack()) { - // compressed oops in registers only take up 4 bytes of an - // 8 byte register but they are in the wrong part of the - // word so adjust loc to point at the right place. - nl = (narrowOop*)((address)nl + 4); - } -#endif - oop_fn->do_oop(nl); + // It should be an error if no location can be found for a + // register mentioned as contained an oop of some kind. Maybe + // this was allowed previously because value_value items might + // be missing? + guarantee(loc != NULL, "missing saved register"); + if ( omv.type() == OopMapValue::oop_value ) { + oop val = *loc; + if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { + // Ignore NULL oops and decoded NULL narrow oops which + // equal to Universe::narrow_oop_base when a narrow oop + // implicit null check is used in compiled code. + // The narrow_oop_base could be NULL or be the address + // of the page below heap depending on compressed oops mode. + continue; } +#ifdef ASSERT + if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) || + !Universe::heap()->is_in_or_null(*loc)) { + tty->print_cr("# Found non oop pointer. Dumping state at failure"); + // try to dump out some helpful debugging information + trace_codeblob_maps(fr, reg_map); + omv.print(); + tty->print_cr("register r"); + omv.reg()->print(); + tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc); + // do the real assert. + assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer"); + } +#endif // ASSERT + oop_fn->do_oop(loc); + } else if ( omv.type() == OopMapValue::narrowoop_value ) { + narrowOop *nl = (narrowOop*)loc; +#ifndef VM_LITTLE_ENDIAN + VMReg vmReg = omv.reg(); + // Don't do this on SPARC float registers as they can be individually addressed + if (!vmReg->is_stack() SPARC_ONLY(&& !vmReg->is_FloatRegister())) { + // compressed oops in registers only take up 4 bytes of an + // 8 byte register but they are in the wrong part of the + // word so adjust loc to point at the right place. + nl = (narrowOop*)((address)nl + 4); + } +#endif + oop_fn->do_oop(nl); } } } @@ -451,7 +461,7 @@ void OopMapSet::update_register_map(const frame *fr, RegisterMap *reg_map) { // Check that runtime stubs save all callee-saved registers #ifdef COMPILER2 - assert(cb->is_compiled_by_c1() || !cb->is_runtime_stub() || + assert(cb->is_compiled_by_c1() || cb->is_compiled_by_jvmci() || !cb->is_runtime_stub() || (nof_callee >= SAVED_ON_ENTRY_REG_COUNT || nof_callee >= C_SAVED_ON_ENTRY_REG_COUNT), "must save all"); #endif // COMPILER2 @@ -465,13 +475,18 @@ void OopMapSet::update_register_map(const frame *fr, RegisterMap *reg_map) { bool ImmutableOopMap::has_derived_pointer() const { #ifndef TIERED COMPILER1_PRESENT(return false); +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + return false; + } +#endif #endif // !TIERED -#ifdef COMPILER2 - OopMapStream oms((OopMap*)this,OopMapValue::derived_oop_value); +#if defined(COMPILER2) || INCLUDE_JVMCI + OopMapStream oms(this,OopMapValue::derived_oop_value); return oms.is_done(); #else return false; -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI } #endif //PRODUCT @@ -485,9 +500,6 @@ void print_register_type(OopMapValue::oop_types x, VMReg optional, case OopMapValue::oop_value: st->print("Oop"); break; - case OopMapValue::value_value: - st->print("Value"); - break; case OopMapValue::narrowoop_value: st->print("NarrowOop"); break; @@ -607,74 +619,9 @@ int ImmutableOopMap::nr_of_bytes() const { } #endif -class ImmutableOopMapBuilder { -private: - class Mapping; - -private: - const OopMapSet* _set; - const OopMap* _empty; - const OopMap* _last; - int _empty_offset; - int _last_offset; - int _offset; - Mapping* _mapping; - ImmutableOopMapSet* _new_set; - - /* Used for bookkeeping when building ImmutableOopMaps */ - class Mapping : public ResourceObj { - public: - enum kind_t { OOPMAP_UNKNOWN = 0, OOPMAP_NEW = 1, OOPMAP_EMPTY = 2, OOPMAP_DUPLICATE = 3 }; - - kind_t _kind; - int _offset; - int _size; - const OopMap* _map; - const OopMap* _other; - - Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(NULL) {} - - void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) { - _kind = kind; - _offset = offset; - _size = size; - _map = map; - _other = other; - } - }; - -public: - ImmutableOopMapBuilder(const OopMapSet* set) : _set(set), _new_set(NULL), _empty(NULL), _last(NULL), _empty_offset(-1), _last_offset(-1), _offset(0) { - _mapping = NEW_RESOURCE_ARRAY(Mapping, _set->size()); - } - - int heap_size(); - ImmutableOopMapSet* build(); -private: - bool is_empty(const OopMap* map) const { - return map->count() == 0; - } - - bool is_last_duplicate(const OopMap* map) { - if (_last != NULL && _last->count() > 0 && _last->equals(map)) { - return true; - } - return false; - } - -#ifdef ASSERT - void verify(address buffer, int size, const ImmutableOopMapSet* set); -#endif - - bool has_empty() const { - return _empty_offset != -1; - } - - int size_for(const OopMap* map) const; - void fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); - int fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); - void fill(ImmutableOopMapSet* set, int size); -}; +ImmutableOopMapBuilder::ImmutableOopMapBuilder(const OopMapSet* set) : _set(set), _new_set(NULL), _empty(NULL), _last(NULL), _empty_offset(-1), _last_offset(-1), _offset(0), _required(-1) { + _mapping = NEW_RESOURCE_ARRAY(Mapping, _set->size()); +} int ImmutableOopMapBuilder::size_for(const OopMap* map) const { return align_size_up(sizeof(ImmutableOopMap) + map->data_size(), 8); @@ -719,6 +666,7 @@ int ImmutableOopMapBuilder::heap_size() { int total = base + pairs + _offset; DEBUG_ONLY(total += 8); + _required = total; return total; } @@ -770,21 +718,25 @@ void ImmutableOopMapBuilder::verify(address buffer, int size, const ImmutableOop } #endif -ImmutableOopMapSet* ImmutableOopMapBuilder::build() { - int required = heap_size(); +ImmutableOopMapSet* ImmutableOopMapBuilder::generate_into(address buffer) { + DEBUG_ONLY(memset(&buffer[_required-8], 0xff, 8)); - // We need to allocate a chunk big enough to hold the ImmutableOopMapSet and all of its ImmutableOopMaps - address buffer = (address) NEW_C_HEAP_ARRAY(unsigned char, required, mtCode); - DEBUG_ONLY(memset(&buffer[required-8], 0xff, 8)); + _new_set = new (buffer) ImmutableOopMapSet(_set, _required); + fill(_new_set, _required); - _new_set = new (buffer) ImmutableOopMapSet(_set, required); - fill(_new_set, required); - - DEBUG_ONLY(verify(buffer, required, _new_set)); + DEBUG_ONLY(verify(buffer, _required, _new_set)); return _new_set; } +ImmutableOopMapSet* ImmutableOopMapBuilder::build() { + _required = heap_size(); + + // We need to allocate a chunk big enough to hold the ImmutableOopMapSet and all of its ImmutableOopMaps + address buffer = (address) NEW_C_HEAP_ARRAY(unsigned char, _required, mtCode); + return generate_into(buffer); +} + ImmutableOopMapSet* ImmutableOopMapSet::build_from(const OopMapSet* oopmap_set) { ResourceMark mark; ImmutableOopMapBuilder builder(oopmap_set); @@ -794,7 +746,7 @@ ImmutableOopMapSet* ImmutableOopMapSet::build_from(const OopMapSet* oopmap_set) //------------------------------DerivedPointerTable--------------------------- -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI class DerivedPointerEntry : public CHeapObj { private: @@ -887,4 +839,4 @@ void DerivedPointerTable::update_pointers() { _active = false; } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI diff --git a/hotspot/src/share/vm/compiler/oopMap.hpp b/hotspot/src/share/vm/compiler/oopMap.hpp index f2639c8ae6a..080f80d4825 100644 --- a/hotspot/src/share/vm/compiler/oopMap.hpp +++ b/hotspot/src/share/vm/compiler/oopMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ // Interface for generating the frame map for compiled code. A frame map // describes for a specific pc whether each register and frame stack slot is: // Oop - A GC root for current frame -// Value - Live non-oop, non-float value: int, either half of double // Dead - Dead; can be Zapped for debugging // CalleeXX - Callee saved; also describes which caller register is saved // DerivedXX - A derived oop; original oop is described. @@ -54,7 +53,7 @@ private: public: // Constants - enum { type_bits = 5, + enum { type_bits = 4, register_bits = BitsPerShort - type_bits }; enum { type_shift = 0, @@ -68,10 +67,9 @@ public: enum oop_types { // must fit in type_bits unused_value =0, // powers of 2, for masking OopMapStream oop_value = 1, - value_value = 2, - narrowoop_value = 4, - callee_saved_value = 8, - derived_oop_value= 16 }; + narrowoop_value = 2, + callee_saved_value = 4, + derived_oop_value= 8 }; // Constructors OopMapValue () { set_value(0); set_content_reg(VMRegImpl::Bad()); } @@ -96,13 +94,11 @@ public: // Querying bool is_oop() { return mask_bits(value(), type_mask_in_place) == oop_value; } - bool is_value() { return mask_bits(value(), type_mask_in_place) == value_value; } bool is_narrowoop() { return mask_bits(value(), type_mask_in_place) == narrowoop_value; } bool is_callee_saved() { return mask_bits(value(), type_mask_in_place) == callee_saved_value; } bool is_derived_oop() { return mask_bits(value(), type_mask_in_place) == derived_oop_value; } void set_oop() { set_value((value() & register_mask_in_place) | oop_value); } - void set_value() { set_value((value() & register_mask_in_place) | value_value); } void set_narrowoop() { set_value((value() & register_mask_in_place) | narrowoop_value); } void set_callee_saved() { set_value((value() & register_mask_in_place) | callee_saved_value); } void set_derived_oop() { set_value((value() & register_mask_in_place) | derived_oop_value); } @@ -188,6 +184,8 @@ class OopMap: public ResourceObj { void copy_data_to(address addr) const; OopMap* deep_copy(); + bool has_derived_pointer() const PRODUCT_RETURN0; + bool legal_vm_reg_name(VMReg local) { return OopMapValue::legal_vm_reg_name(local); } @@ -354,13 +352,82 @@ class OopMapStream : public StackObj { #endif }; +class ImmutableOopMapBuilder { +private: + class Mapping; + +private: + const OopMapSet* _set; + const OopMap* _empty; + const OopMap* _last; + int _empty_offset; + int _last_offset; + int _offset; + int _required; + Mapping* _mapping; + ImmutableOopMapSet* _new_set; + + /* Used for bookkeeping when building ImmutableOopMaps */ + class Mapping : public ResourceObj { + public: + enum kind_t { OOPMAP_UNKNOWN = 0, OOPMAP_NEW = 1, OOPMAP_EMPTY = 2, OOPMAP_DUPLICATE = 3 }; + + kind_t _kind; + int _offset; + int _size; + const OopMap* _map; + const OopMap* _other; + + Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(NULL) {} + + void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) { + _kind = kind; + _offset = offset; + _size = size; + _map = map; + _other = other; + } + }; + +public: + ImmutableOopMapBuilder(const OopMapSet* set); + + int heap_size(); + ImmutableOopMapSet* build(); + ImmutableOopMapSet* generate_into(address buffer); +private: + bool is_empty(const OopMap* map) const { + return map->count() == 0; + } + + bool is_last_duplicate(const OopMap* map) { + if (_last != NULL && _last->count() > 0 && _last->equals(map)) { + return true; + } + return false; + } + +#ifdef ASSERT + void verify(address buffer, int size, const ImmutableOopMapSet* set); +#endif + + bool has_empty() const { + return _empty_offset != -1; + } + + int size_for(const OopMap* map) const; + void fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); + int fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); + void fill(ImmutableOopMapSet* set, int size); +}; + // Derived pointer support. This table keeps track of all derived points on a // stack. It is cleared before each scavenge/GC. During the traversal of all // oops, it is filled in with references to all locations that contains a // derived oop (assumed to be very few). When the GC is complete, the derived // pointers are updated based on their base pointers new value and an offset. -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI class DerivedPointerTable : public AllStatic { friend class VMStructs; private: @@ -396,6 +463,6 @@ class DerivedPointerTableDeactivate: public StackObj { } } }; -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI #endif // SHARE_VM_COMPILER_OOPMAP_HPP diff --git a/hotspot/src/share/vm/gc/cms/adaptiveFreeList.cpp b/hotspot/src/share/vm/gc/cms/adaptiveFreeList.cpp index 6a37dd01f8b..a406c747f21 100644 --- a/hotspot/src/share/vm/gc/cms/adaptiveFreeList.cpp +++ b/hotspot/src/share/vm/gc/cms/adaptiveFreeList.cpp @@ -133,17 +133,17 @@ void AdaptiveFreeList::verify_stats() const { + _allocation_stats.coal_births() + 1) // Total Production Stock + 1 >= (_allocation_stats.split_deaths() + _allocation_stats.coal_deaths() + (ssize_t)count()), // Total Current Stock + depletion - err_msg("FreeList " PTR_FORMAT " of size " SIZE_FORMAT - " violates Conservation Principle: " - "prev_sweep(" SIZE_FORMAT ")" - " + split_births(" SIZE_FORMAT ")" - " + coal_births(" SIZE_FORMAT ") + 1 >= " - " split_deaths(" SIZE_FORMAT ")" - " coal_deaths(" SIZE_FORMAT ")" - " + count(" SSIZE_FORMAT ")", - p2i(this), size(), _allocation_stats.prev_sweep(), _allocation_stats.split_births(), - _allocation_stats.coal_births(), _allocation_stats.split_deaths(), - _allocation_stats.coal_deaths(), count())); + "FreeList " PTR_FORMAT " of size " SIZE_FORMAT + " violates Conservation Principle: " + "prev_sweep(" SIZE_FORMAT ")" + " + split_births(" SIZE_FORMAT ")" + " + coal_births(" SIZE_FORMAT ") + 1 >= " + " split_deaths(" SIZE_FORMAT ")" + " coal_deaths(" SIZE_FORMAT ")" + " + count(" SSIZE_FORMAT ")", + p2i(this), size(), _allocation_stats.prev_sweep(), _allocation_stats.split_births(), + _allocation_stats.coal_births(), _allocation_stats.split_deaths(), + _allocation_stats.coal_deaths(), count()); } #endif diff --git a/hotspot/src/share/vm/gc/cms/allocationStats.hpp b/hotspot/src/share/vm/gc/cms/allocationStats.hpp index 71ba6149144..a2259276fe3 100644 --- a/hotspot/src/share/vm/gc/cms/allocationStats.hpp +++ b/hotspot/src/share/vm/gc/cms/allocationStats.hpp @@ -105,9 +105,9 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { ssize_t demand = prev_sweep() - (ssize_t)count + split_births() + coal_births() - split_deaths() - coal_deaths(); assert(demand >= 0, - err_msg("Demand (" SSIZE_FORMAT ") should be non-negative for " - PTR_FORMAT " (size=" SIZE_FORMAT ")", - demand, p2i(this), count)); + "Demand (" SSIZE_FORMAT ") should be non-negative for " + PTR_FORMAT " (size=" SIZE_FORMAT ")", + demand, p2i(this), count); // Defensive: adjust for imprecision in event counting if (demand < 0) { demand = 0; diff --git a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp index 9d1044b4098..d924ed27baf 100644 --- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp @@ -1959,9 +1959,9 @@ void CompactibleFreeListSpace::save_marks() { MemRegion ur = used_region(); MemRegion urasm = used_region_at_save_marks(); assert(ur.contains(urasm), - err_msg(" Error at save_marks(): [" PTR_FORMAT "," PTR_FORMAT ")" - " should contain [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(ur.start()), p2i(ur.end()), p2i(urasm.start()), p2i(urasm.end()))); + " Error at save_marks(): [" PTR_FORMAT "," PTR_FORMAT ")" + " should contain [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(ur.start()), p2i(ur.end()), p2i(urasm.start()), p2i(urasm.end())); #endif // inform allocator that promotions should be tracked. assert(_promoInfo.noPromotions(), "_promoInfo inconsistency"); @@ -2875,9 +2875,9 @@ FreeChunk* CompactibleFreeListSpace::get_n_way_chunk_to_split(size_t word_sz, si smallSplitBirth(rem); } assert(n * word_sz == fc->size(), - err_msg("Chunk size " SIZE_FORMAT " is not exactly splittable by " - SIZE_FORMAT " sized chunks of size " SIZE_FORMAT, - fc->size(), n, word_sz)); + "Chunk size " SIZE_FORMAT " is not exactly splittable by " + SIZE_FORMAT " sized chunks of size " SIZE_FORMAT, + fc->size(), n, word_sz); return fc; } diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp index 9806a5e59c5..d29415817b5 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp @@ -1593,7 +1593,7 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer(); gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start()); - GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL, gc_tracer->gc_id()); + GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL); // Temporarily widen the span of the weak reference processing to // the entire heap. @@ -1654,7 +1654,7 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { _collectorState = Resetting; assert(_restart_addr == NULL, "Should have been NULL'd before baton was passed"); - reset(false /* == !concurrent */); + reset_stw(); _cmsGen->reset_after_compaction(); _concurrent_cycles_since_last_unload = 0; @@ -1934,7 +1934,7 @@ void CMSCollector::collect_in_background(GCCause::Cause cause) { } case Resetting: // CMS heap resizing has been completed - reset(true); + reset_concurrent(); assert(_collectorState == Idling, "Collector state should " "have changed"); @@ -2367,7 +2367,9 @@ bool CMSCollector::verify_after_remark(bool silent) { // way with the marking information used by GC. NoRefDiscovery no_discovery(ref_processor()); - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;) +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif // Clear any marks from a previous round verification_mark_bm()->clear_all(); @@ -2825,7 +2827,6 @@ class CMSPhaseAccounting: public StackObj { public: CMSPhaseAccounting(CMSCollector *collector, const char *phase, - const GCId gc_id, bool print_cr = true); ~CMSPhaseAccounting(); @@ -2834,7 +2835,6 @@ class CMSPhaseAccounting: public StackObj { const char *_phase; elapsedTimer _wallclock; bool _print_cr; - const GCId _gc_id; public: // Not MT-safe; so do not pass around these StackObj's @@ -2850,15 +2850,14 @@ class CMSPhaseAccounting: public StackObj { CMSPhaseAccounting::CMSPhaseAccounting(CMSCollector *collector, const char *phase, - const GCId gc_id, bool print_cr) : - _collector(collector), _phase(phase), _print_cr(print_cr), _gc_id(gc_id) { + _collector(collector), _phase(phase), _print_cr(print_cr) { if (PrintCMSStatistics != 0) { _collector->resetYields(); } if (PrintGCDetails) { - gclog_or_tty->gclog_stamp(_gc_id); + gclog_or_tty->gclog_stamp(); gclog_or_tty->print_cr("[%s-concurrent-%s-start]", _collector->cmsGen()->short_name(), _phase); } @@ -2872,7 +2871,7 @@ CMSPhaseAccounting::~CMSPhaseAccounting() { _collector->stopTimer(); _wallclock.stop(); if (PrintGCDetails) { - gclog_or_tty->gclog_stamp(_gc_id); + gclog_or_tty->gclog_stamp(); gclog_or_tty->print("[%s-concurrent-%s: %3.3f/%3.3f secs]", _collector->cmsGen()->short_name(), _phase, _collector->timerValue(), _wallclock.seconds()); @@ -2951,7 +2950,7 @@ void CMSCollector::checkpointRootsInitialWork() { setup_cms_unloading_and_verification_state(); NOT_PRODUCT(GCTraceTime t("\ncheckpointRootsInitialWork", - PrintGCDetails && Verbose, true, _gc_timer_cm, _gc_tracer_cm->gc_id());) + PrintGCDetails && Verbose, true, _gc_timer_cm);) // Reset all the PLAB chunk arrays if necessary. if (_survivor_plab_array != NULL && !CMSPLABRecordAlways) { @@ -2987,7 +2986,9 @@ void CMSCollector::checkpointRootsInitialWork() { } { - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;) +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif if (CMSParallelInitialMarkEnabled) { // The parallel version. WorkGang* workers = gch->workers(); @@ -3054,7 +3055,7 @@ bool CMSCollector::markFromRoots() { CMSTokenSyncWithLocks ts(true, bitMapLock()); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "mark", _gc_tracer_cm->gc_id(), !PrintGCDetails); + CMSPhaseAccounting pa(this, "mark", !PrintGCDetails); bool res = markFromRootsWork(); if (res) { _collectorState = Precleaning; @@ -3476,7 +3477,7 @@ class Par_ConcMarkingClosure: public MetadataAwareOopClosure { // been published), so we do not need to check for // uninitialized objects before pushing here. void Par_ConcMarkingClosure::do_oop(oop obj) { - assert(obj->is_oop_or_null(true), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; // Check if oop points into the CMS generation // and is not marked @@ -3751,7 +3752,7 @@ void CMSCollector::preclean() { _start_sampling = false; } TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "preclean", _gc_tracer_cm->gc_id(), !PrintGCDetails); + CMSPhaseAccounting pa(this, "preclean", !PrintGCDetails); preclean_work(CMSPrecleanRefLists1, CMSPrecleanSurvivors1); } CMSTokenSync x(true); // is cms thread @@ -3780,7 +3781,7 @@ void CMSCollector::abortable_preclean() { // we will never do an actual abortable preclean cycle. if (get_eden_used() > CMSScheduleRemarkEdenSizeThreshold) { TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "abortable-preclean", _gc_tracer_cm->gc_id(), !PrintGCDetails); + CMSPhaseAccounting pa(this, "abortable-preclean", !PrintGCDetails); // We need more smarts in the abortable preclean // loop below to deal with cases where allocation // in young gen is very very slow, and our precleaning @@ -3925,7 +3926,7 @@ size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) { GCTimer *gc_timer = NULL; // Currently not tracing concurrent phases rp->preclean_discovered_references( rp->is_alive_non_header(), &keep_alive, &complete_trace, &yield_cl, - gc_timer, _gc_tracer_cm->gc_id()); + gc_timer); } if (clean_survivor) { // preclean the active survivor space(s) @@ -4261,7 +4262,7 @@ void CMSCollector::checkpointRootsFinal() { // expect it to be false and set to true FlagSetting fl(gch->_is_gc_active, false); NOT_PRODUCT(GCTraceTime t("Scavenge-Before-Remark", - PrintGCDetails && Verbose, true, _gc_timer_cm, _gc_tracer_cm->gc_id());) + PrintGCDetails && Verbose, true, _gc_timer_cm);) gch->do_collection(true, // full (i.e. force, see below) false, // !clear_all_soft_refs 0, // size @@ -4279,7 +4280,7 @@ void CMSCollector::checkpointRootsFinal() { } void CMSCollector::checkpointRootsFinalWork() { - NOT_PRODUCT(GCTraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id());) + NOT_PRODUCT(GCTraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, _gc_timer_cm);) assert(haveFreelistLocks(), "must have free list locks"); assert_lock_strong(bitMapLock()); @@ -4316,7 +4317,9 @@ void CMSCollector::checkpointRootsFinalWork() { } { - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;) +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif // Note on the role of the mod union table: // Since the marker in "markFromRoots" marks concurrently with @@ -4329,11 +4332,10 @@ void CMSCollector::checkpointRootsFinalWork() { // the most recent young generation GC, minus those cleaned up by the // concurrent precleaning. if (CMSParallelRemarkEnabled) { - GCTraceTime t("Rescan (parallel) ", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("Rescan (parallel) ", PrintGCDetails, false, _gc_timer_cm); do_remark_parallel(); } else { - GCTraceTime t("Rescan (non-parallel) ", PrintGCDetails, false, - _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("Rescan (non-parallel) ", PrintGCDetails, false, _gc_timer_cm); do_remark_non_parallel(); } } @@ -4341,7 +4343,7 @@ void CMSCollector::checkpointRootsFinalWork() { verify_overflow_empty(); { - NOT_PRODUCT(GCTraceTime ts("refProcessingWork", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id());) + NOT_PRODUCT(GCTraceTime ts("refProcessingWork", PrintGCDetails, false, _gc_timer_cm);) refProcessingWork(); } verify_work_stacks_empty(); @@ -5116,7 +5118,7 @@ void CMSCollector::do_remark_non_parallel() { NULL, // space is set further below &_markBitMap, &_markStack, &mrias_cl); { - GCTraceTime t("grey object rescan", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("grey object rescan", PrintGCDetails, false, _gc_timer_cm); // Iterate over the dirty cards, setting the corresponding bits in the // mod union table. { @@ -5153,7 +5155,7 @@ void CMSCollector::do_remark_non_parallel() { Universe::verify(); } { - GCTraceTime t("root rescan", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("root rescan", PrintGCDetails, false, _gc_timer_cm); verify_work_stacks_empty(); @@ -5175,7 +5177,7 @@ void CMSCollector::do_remark_non_parallel() { } { - GCTraceTime t("visit unhandled CLDs", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("visit unhandled CLDs", PrintGCDetails, false, _gc_timer_cm); verify_work_stacks_empty(); @@ -5194,7 +5196,7 @@ void CMSCollector::do_remark_non_parallel() { } { - GCTraceTime t("dirty klass scan", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("dirty klass scan", PrintGCDetails, false, _gc_timer_cm); verify_work_stacks_empty(); @@ -5403,7 +5405,7 @@ void CMSCollector::refProcessingWork() { _span, &_markBitMap, &_markStack, &cmsKeepAliveClosure, false /* !preclean */); { - GCTraceTime t("weak refs processing", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("weak refs processing", PrintGCDetails, false, _gc_timer_cm); ReferenceProcessorStats stats; if (rp->processing_is_mt()) { @@ -5428,15 +5430,13 @@ void CMSCollector::refProcessingWork() { &cmsKeepAliveClosure, &cmsDrainMarkingStackClosure, &task_executor, - _gc_timer_cm, - _gc_tracer_cm->gc_id()); + _gc_timer_cm); } else { stats = rp->process_discovered_references(&_is_alive_closure, &cmsKeepAliveClosure, &cmsDrainMarkingStackClosure, NULL, - _gc_timer_cm, - _gc_tracer_cm->gc_id()); + _gc_timer_cm); } _gc_tracer_cm->report_gc_reference_stats(stats); @@ -5447,7 +5447,7 @@ void CMSCollector::refProcessingWork() { if (should_unload_classes()) { { - GCTraceTime t("class unloading", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("class unloading", PrintGCDetails, false, _gc_timer_cm); // Unload classes and purge the SystemDictionary. bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure); @@ -5460,13 +5460,13 @@ void CMSCollector::refProcessingWork() { } { - GCTraceTime t("scrub symbol table", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("scrub symbol table", PrintGCDetails, false, _gc_timer_cm); // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); } { - GCTraceTime t("scrub string table", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("scrub string table", PrintGCDetails, false, _gc_timer_cm); // Delete entries for dead interned strings. StringTable::unlink(&_is_alive_closure); } @@ -5534,7 +5534,7 @@ void CMSCollector::sweep() { _intra_sweep_timer.start(); { TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "sweep", _gc_tracer_cm->gc_id(), !PrintGCDetails); + CMSPhaseAccounting pa(this, "sweep", !PrintGCDetails); // First sweep the old gen { CMSTokenSyncWithLocks ts(true, _cmsGen->freelistLock(), @@ -5704,74 +5704,77 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* old_gen) { // Reset CMS data structures (for now just the marking bit map) // preparatory for the next cycle. -void CMSCollector::reset(bool concurrent) { - if (concurrent) { - CMSTokenSyncWithLocks ts(true, bitMapLock()); +void CMSCollector::reset_concurrent() { + CMSTokenSyncWithLocks ts(true, bitMapLock()); - // If the state is not "Resetting", the foreground thread - // has done a collection and the resetting. - if (_collectorState != Resetting) { - assert(_collectorState == Idling, "The state should only change" - " because the foreground collector has finished the collection"); - return; - } - - // Clear the mark bitmap (no grey objects to start with) - // for the next cycle. - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting cmspa(this, "reset", _gc_tracer_cm->gc_id(), !PrintGCDetails); - - HeapWord* curAddr = _markBitMap.startWord(); - while (curAddr < _markBitMap.endWord()) { - size_t remaining = pointer_delta(_markBitMap.endWord(), curAddr); - MemRegion chunk(curAddr, MIN2(CMSBitMapYieldQuantum, remaining)); - _markBitMap.clear_large_range(chunk); - if (ConcurrentMarkSweepThread::should_yield() && - !foregroundGCIsActive() && - CMSYield) { - assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(), - "CMS thread should hold CMS token"); - assert_lock_strong(bitMapLock()); - bitMapLock()->unlock(); - ConcurrentMarkSweepThread::desynchronize(true); - stopTimer(); - if (PrintCMSStatistics != 0) { - incrementYields(); - } - - // See the comment in coordinator_yield() - for (unsigned i = 0; i < CMSYieldSleepCount && - ConcurrentMarkSweepThread::should_yield() && - !CMSCollector::foregroundGCIsActive(); ++i) { - os::sleep(Thread::current(), 1, false); - } - - ConcurrentMarkSweepThread::synchronize(true); - bitMapLock()->lock_without_safepoint_check(); - startTimer(); - } - curAddr = chunk.end(); - } - // A successful mostly concurrent collection has been done. - // Because only the full (i.e., concurrent mode failure) collections - // are being measured for gc overhead limits, clean the "near" flag - // and count. - size_policy()->reset_gc_overhead_limit_count(); - _collectorState = Idling; - } else { - // already have the lock - assert(_collectorState == Resetting, "just checking"); - assert_lock_strong(bitMapLock()); - _markBitMap.clear_all(); - _collectorState = Idling; + // If the state is not "Resetting", the foreground thread + // has done a collection and the resetting. + if (_collectorState != Resetting) { + assert(_collectorState == Idling, "The state should only change" + " because the foreground collector has finished the collection"); + return; } + // Clear the mark bitmap (no grey objects to start with) + // for the next cycle. + TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); + CMSPhaseAccounting cmspa(this, "reset", !PrintGCDetails); + + HeapWord* curAddr = _markBitMap.startWord(); + while (curAddr < _markBitMap.endWord()) { + size_t remaining = pointer_delta(_markBitMap.endWord(), curAddr); + MemRegion chunk(curAddr, MIN2(CMSBitMapYieldQuantum, remaining)); + _markBitMap.clear_large_range(chunk); + if (ConcurrentMarkSweepThread::should_yield() && + !foregroundGCIsActive() && + CMSYield) { + assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(), + "CMS thread should hold CMS token"); + assert_lock_strong(bitMapLock()); + bitMapLock()->unlock(); + ConcurrentMarkSweepThread::desynchronize(true); + stopTimer(); + if (PrintCMSStatistics != 0) { + incrementYields(); + } + + // See the comment in coordinator_yield() + for (unsigned i = 0; i < CMSYieldSleepCount && + ConcurrentMarkSweepThread::should_yield() && + !CMSCollector::foregroundGCIsActive(); ++i) { + os::sleep(Thread::current(), 1, false); + } + + ConcurrentMarkSweepThread::synchronize(true); + bitMapLock()->lock_without_safepoint_check(); + startTimer(); + } + curAddr = chunk.end(); + } + // A successful mostly concurrent collection has been done. + // Because only the full (i.e., concurrent mode failure) collections + // are being measured for gc overhead limits, clean the "near" flag + // and count. + size_policy()->reset_gc_overhead_limit_count(); + _collectorState = Idling; + + register_gc_end(); +} + +// Same as above but for STW paths +void CMSCollector::reset_stw() { + // already have the lock + assert(_collectorState == Resetting, "just checking"); + assert_lock_strong(bitMapLock()); + GCIdMarkAndRestore gc_id_mark(_cmsThread->gc_id()); + _markBitMap.clear_all(); + _collectorState = Idling; register_gc_end(); } void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) { TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer_cm->gc_id()); + GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); switch (op) { @@ -6048,8 +6051,8 @@ MarkRefsIntoClosure::MarkRefsIntoClosure( _span(span), _bitMap(bitMap) { - assert(_ref_processor == NULL, "deliberately left NULL"); - assert(_bitMap->covers(_span), "_bitMap/_span mismatch"); + assert(ref_processor() == NULL, "deliberately left NULL"); + assert(_bitMap->covers(_span), "_bitMap/_span mismatch"); } void MarkRefsIntoClosure::do_oop(oop obj) { @@ -6070,8 +6073,8 @@ Par_MarkRefsIntoClosure::Par_MarkRefsIntoClosure( _span(span), _bitMap(bitMap) { - assert(_ref_processor == NULL, "deliberately left NULL"); - assert(_bitMap->covers(_span), "_bitMap/_span mismatch"); + assert(ref_processor() == NULL, "deliberately left NULL"); + assert(_bitMap->covers(_span), "_bitMap/_span mismatch"); } void Par_MarkRefsIntoClosure::do_oop(oop obj) { @@ -6094,8 +6097,8 @@ MarkRefsIntoVerifyClosure::MarkRefsIntoVerifyClosure( _verification_bm(verification_bm), _cms_bm(cms_bm) { - assert(_ref_processor == NULL, "deliberately left NULL"); - assert(_verification_bm->covers(_span), "_verification_bm/_span mismatch"); + assert(ref_processor() == NULL, "deliberately left NULL"); + assert(_verification_bm->covers(_span), "_verification_bm/_span mismatch"); } void MarkRefsIntoVerifyClosure::do_oop(oop obj) { @@ -6137,8 +6140,9 @@ MarkRefsIntoAndScanClosure::MarkRefsIntoAndScanClosure(MemRegion span, _concurrent_precleaning(concurrent_precleaning), _freelistLock(NULL) { - _ref_processor = rp; - assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL"); + // FIXME: Should initialize in base class constructor. + assert(rp != NULL, "ref_processor shouldn't be NULL"); + set_ref_processor_internal(rp); } // This closure is used to mark refs into the CMS generation at the @@ -6243,8 +6247,9 @@ Par_MarkRefsIntoAndScanClosure::Par_MarkRefsIntoAndScanClosure( ((uint)CMSWorkQueueDrainThreshold * ParallelGCThreads))), _par_pushAndMarkClosure(collector, span, rp, bit_map, work_queue) { - _ref_processor = rp; - assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL"); + // FIXME: Should initialize in base class constructor. + assert(rp != NULL, "ref_processor shouldn't be NULL"); + set_ref_processor_internal(rp); } // This closure is used to mark refs into the CMS generation at the @@ -6458,7 +6463,7 @@ void SurvivorSpacePrecleanClosure::do_yield_work() { // isMarked() query is "safe". bool ScanMarkedObjectsAgainClosure::do_object_bm(oop p, MemRegion mr) { // Ignore mark word because we are running concurrent with mutators - assert(p->is_oop_or_null(true), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(p))); + assert(p->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(p)); HeapWord* addr = (HeapWord*)p; assert(_span.contains(addr), "we are scanning the CMS generation"); bool is_obj_array = false; @@ -6893,7 +6898,7 @@ void PushAndMarkVerifyClosure::handle_stack_overflow(HeapWord* lost) { } void PushAndMarkVerifyClosure::do_oop(oop obj) { - assert(obj->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + assert(obj->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; if (_span.contains(addr) && !_verification_bm->isMarked(addr)) { // Oop lies in _span and isn't yet grey or black @@ -6991,7 +6996,7 @@ void Par_PushOrMarkClosure::handle_stack_overflow(HeapWord* lost) { void PushOrMarkClosure::do_oop(oop obj) { // Ignore mark word because we are running concurrent with mutators. - assert(obj->is_oop_or_null(true), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; if (_span.contains(addr) && !_bitMap->isMarked(addr)) { // Oop lies in _span and isn't yet grey or black @@ -7029,7 +7034,7 @@ void PushOrMarkClosure::do_oop(narrowOop* p) { PushOrMarkClosure::do_oop_work(p) void Par_PushOrMarkClosure::do_oop(oop obj) { // Ignore mark word because we are running concurrent with mutators. - assert(obj->is_oop_or_null(true), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; if (_whole_span.contains(addr) && !_bit_map->isMarked(addr)) { // Oop lies in _span and isn't yet grey or black @@ -7094,7 +7099,7 @@ PushAndMarkClosure::PushAndMarkClosure(CMSCollector* collector, _mark_stack(mark_stack), _concurrent_precleaning(concurrent_precleaning) { - assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL"); + assert(ref_processor() != NULL, "ref_processor shouldn't be NULL"); } // Grey object rescan during pre-cleaning and second checkpoint phases -- @@ -7106,7 +7111,7 @@ void PushAndMarkClosure::do_oop(oop obj) { // path and may be at the end of the global overflow list (so // the mark word may be NULL). assert(obj->is_oop_or_null(true /* ignore mark word */), - err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; // Check if oop points into the CMS generation // and is not marked @@ -7165,7 +7170,7 @@ Par_PushAndMarkClosure::Par_PushAndMarkClosure(CMSCollector* collector, _bit_map(bit_map), _work_queue(work_queue) { - assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL"); + assert(ref_processor() != NULL, "ref_processor shouldn't be NULL"); } void PushAndMarkClosure::do_oop(oop* p) { PushAndMarkClosure::do_oop_work(p); } @@ -7186,7 +7191,7 @@ void Par_PushAndMarkClosure::do_oop(oop obj) { // the debugger, is_oop_or_null(false) may subsequently start // to hold. assert(obj->is_oop_or_null(true), - err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; // Check if oop points into the CMS generation // and is not marked @@ -7423,7 +7428,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { // coalesced chunk to the appropriate free list. if (inFreeRange()) { assert(freeFinger() >= _sp->bottom() && freeFinger() < _limit, - err_msg("freeFinger() " PTR_FORMAT " is out-of-bounds", p2i(freeFinger()))); + "freeFinger() " PTR_FORMAT " is out-of-bounds", p2i(freeFinger())); flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger())); if (CMSTraceSweeper) { @@ -7825,10 +7830,10 @@ void SweepClosure::lookahead_and_flush(FreeChunk* fc, size_t chunk_size) { assert(inFreeRange(), "Should only be called if currently in a free range."); HeapWord* const eob = ((HeapWord*)fc) + chunk_size; assert(_sp->used_region().contains(eob - 1), - err_msg("eob = " PTR_FORMAT " eob-1 = " PTR_FORMAT " _limit = " PTR_FORMAT - " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")" - " when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")", - p2i(eob), p2i(eob-1), p2i(_limit), p2i(_sp->bottom()), p2i(_sp->end()), p2i(fc), chunk_size)); + "eob = " PTR_FORMAT " eob-1 = " PTR_FORMAT " _limit = " PTR_FORMAT + " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")" + " when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")", + p2i(eob), p2i(eob-1), p2i(_limit), p2i(_sp->bottom()), p2i(_sp->end()), p2i(fc), chunk_size); if (eob >= _limit) { assert(eob == _limit || fc->is_free(), "Only a free chunk should allow us to cross over the limit"); if (CMSTraceSweeper) { diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp index 82baa5eb1fc..c846cb48308 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp @@ -296,8 +296,8 @@ class ChunkArray: public CHeapObj { size_t end() { assert(_index <= capacity(), - err_msg("_index (" SIZE_FORMAT ") > _capacity (" SIZE_FORMAT "): out of bounds", - _index, _capacity)); + "_index (" SIZE_FORMAT ") > _capacity (" SIZE_FORMAT "): out of bounds", + _index, _capacity); return _index; } // exclusive @@ -322,9 +322,9 @@ class ChunkArray: public CHeapObj { } else { ++_overflows; assert(_index == _capacity, - err_msg("_index (" SIZE_FORMAT ") > _capacity (" SIZE_FORMAT - "): out of bounds at overflow#" SIZE_FORMAT, - _index, _capacity, _overflows)); + "_index (" SIZE_FORMAT ") > _capacity (" SIZE_FORMAT + "): out of bounds at overflow#" SIZE_FORMAT, + _index, _capacity, _overflows); } } }; @@ -799,8 +799,10 @@ class CMSCollector: public CHeapObj { // Concurrent sweeping work void sweepWork(ConcurrentMarkSweepGeneration* old_gen); - // (Concurrent) resetting of support data structures - void reset(bool concurrent); + // Concurrent resetting of support data structures + void reset_concurrent(); + // Resetting of support data structures from a STW full GC + void reset_stw(); // Clear _expansion_cause fields of constituent generations void clear_expansion_cause(); diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp index af75fbb91c3..8d19ad31278 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp @@ -26,6 +26,7 @@ #include "classfile/systemDictionary.hpp" #include "gc/cms/concurrentMarkSweepGeneration.inline.hpp" #include "gc/cms/concurrentMarkSweepThread.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/oop.inline.hpp" @@ -124,6 +125,7 @@ void ConcurrentMarkSweepThread::run() { while (!_should_terminate) { sleepBeforeNextCycle(); if (_should_terminate) break; + GCIdMark gc_id_mark; GCCause::Cause cause = _collector->_full_gc_requested ? _collector->_full_gc_cause : GCCause::_cms_concurrent_mark; _collector->collect_in_background(cause); diff --git a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp index fbadbec692d..35fa18f1d88 100644 --- a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp +++ b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp @@ -43,7 +43,7 @@ non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr, uint n_threads) { assert(n_threads > 0, "expected n_threads > 0"); assert(n_threads <= ParallelGCThreads, - err_msg("n_threads: %u > ParallelGCThreads: %u", n_threads, ParallelGCThreads)); + "n_threads: %u > ParallelGCThreads: %u", n_threads, ParallelGCThreads); // Make sure the LNC array is valid for the space. jbyte** lowest_non_clean; @@ -370,18 +370,18 @@ process_chunk_boundaries(Space* sp, - lowest_non_clean_base_chunk_index; if (last_chunk_index_to_check > last_chunk_index) { assert(last_block + last_block_size > used.end(), - err_msg("Inconsistency detected: last_block [" PTR_FORMAT "," PTR_FORMAT "]" - " does not exceed used.end() = " PTR_FORMAT "," - " yet last_chunk_index_to_check " INTPTR_FORMAT - " exceeds last_chunk_index " INTPTR_FORMAT, - p2i(last_block), p2i(last_block + last_block_size), - p2i(used.end()), - last_chunk_index_to_check, last_chunk_index)); + "Inconsistency detected: last_block [" PTR_FORMAT "," PTR_FORMAT "]" + " does not exceed used.end() = " PTR_FORMAT "," + " yet last_chunk_index_to_check " INTPTR_FORMAT + " exceeds last_chunk_index " INTPTR_FORMAT, + p2i(last_block), p2i(last_block + last_block_size), + p2i(used.end()), + last_chunk_index_to_check, last_chunk_index); assert(sp->used_region().end() > used.end(), - err_msg("Expansion did not happen: " - "[" PTR_FORMAT "," PTR_FORMAT ") -> [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(sp->used_region().start()), p2i(sp->used_region().end()), - p2i(used.start()), p2i(used.end()))); + "Expansion did not happen: " + "[" PTR_FORMAT "," PTR_FORMAT ") -> [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(sp->used_region().start()), p2i(sp->used_region().end()), + p2i(used.start()), p2i(used.end())); NOISY(tty->print_cr(" process_chunk_boundary: heap expanded; explicitly bounding last_chunk");) last_chunk_index_to_check = last_chunk_index; } diff --git a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp index 916ca41fb1e..e2ff84ab5f8 100644 --- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp @@ -896,7 +896,7 @@ void ParNewGeneration::collect(bool full, size_policy->minor_collection_begin(); } - GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL, _gc_tracer.gc_id()); + GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); // Capture heap used before collection (for printing). size_t gch_prev_used = gch->used(); @@ -959,15 +959,17 @@ void ParNewGeneration::collect(bool full, ParNewRefProcTaskExecutor task_executor(*this, *_old_gen, thread_state_set); stats = rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers, &task_executor, - _gc_timer, _gc_tracer.gc_id()); + _gc_timer); } else { thread_state_set.flush(); gch->save_marks(); stats = rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers, NULL, - _gc_timer, _gc_tracer.gc_id()); + _gc_timer); } _gc_tracer.report_gc_reference_stats(stats); + _gc_tracer.report_tenuring_threshold(tenuring_threshold()); + if (!promotion_failed()) { // Swap the survivor spaces. eden()->clear(SpaceDecorator::Mangle); @@ -1030,7 +1032,6 @@ void ParNewGeneration::collect(bool full, rp->verify_no_references_recorded(); gch->trace_heap_after_gc(gc_tracer()); - _gc_tracer.report_tenuring_threshold(tenuring_threshold()); _gc_timer->register_gc_end(); diff --git a/hotspot/src/share/vm/gc/cms/promotionInfo.hpp b/hotspot/src/share/vm/gc/cms/promotionInfo.hpp index a58bcb74038..c5a3f715c96 100644 --- a/hotspot/src/share/vm/gc/cms/promotionInfo.hpp +++ b/hotspot/src/share/vm/gc/cms/promotionInfo.hpp @@ -73,7 +73,7 @@ class PromotedObject VALUE_OBJ_CLASS_SPEC { } else { res = (PromotedObject*)(_next & next_mask); } - assert(oop(res)->is_oop_or_null(true /* ignore mark word */), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(oop(res)))); + assert(oop(res)->is_oop_or_null(true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(res))); return res; } inline void setNext(PromotedObject* x) { diff --git a/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp b/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp index 190483c84be..426c41e1d67 100644 --- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp +++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp @@ -58,7 +58,7 @@ void VM_CMS_Operation::release_and_notify_pending_list_lock() { void VM_CMS_Operation::verify_before_gc() { if (VerifyBeforeGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm, _collector->_gc_tracer_cm->gc_id()); + GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); @@ -70,7 +70,7 @@ void VM_CMS_Operation::verify_before_gc() { void VM_CMS_Operation::verify_after_gc() { if (VerifyAfterGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm, _collector->_gc_tracer_cm->gc_id()); + GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); @@ -134,6 +134,7 @@ void VM_CMS_Initial_Mark::doit() { return; } HS_PRIVATE_CMS_INITMARK_BEGIN(); + GCIdMark gc_id_mark(_gc_id); _collector->_gc_timer_cm->register_gc_pause_start("Initial Mark"); @@ -161,6 +162,7 @@ void VM_CMS_Final_Remark::doit() { return; } HS_PRIVATE_CMS_REMARK_BEGIN(); + GCIdMark gc_id_mark(_gc_id); _collector->_gc_timer_cm->register_gc_pause_start("Final Mark"); diff --git a/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp b/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp index da3ee8670f6..a0a62181e89 100644 --- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp +++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp @@ -27,6 +27,7 @@ #include "gc/cms/concurrentMarkSweepGeneration.hpp" #include "gc/shared/gcCause.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/vmGCOperations.hpp" #include "runtime/vm_operations.hpp" @@ -53,6 +54,7 @@ class VM_CMS_Operation: public VM_Operation { protected: CMSCollector* _collector; // associated collector bool _prologue_succeeded; // whether doit_prologue succeeded + uint _gc_id; bool lost_race() const; @@ -63,7 +65,8 @@ class VM_CMS_Operation: public VM_Operation { public: VM_CMS_Operation(CMSCollector* collector): _collector(collector), - _prologue_succeeded(false) {} + _prologue_succeeded(false), + _gc_id(GCId::current()) {} ~VM_CMS_Operation() {} // The legal collector state for executing this CMS op. diff --git a/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp b/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp index 6f2ac4c50a7..24ac4248dee 100644 --- a/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp +++ b/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/cms/yieldingWorkgroup.hpp" +#include "gc/shared/gcId.hpp" #include "utilities/macros.hpp" YieldingFlexibleGangWorker::YieldingFlexibleGangWorker(YieldingFlexibleWorkGang* gang, int id) @@ -340,6 +341,7 @@ void YieldingFlexibleGangWorker::loop() { // Now, release the gang mutex and do the work. { MutexUnlockerEx mul(gang_monitor, Mutex::_no_safepoint_check_flag); + GCIdMark gc_id_mark(data.task()->gc_id()); data.task()->work(id); // This might include yielding } // Reacquire monitor and note completion of this worker diff --git a/hotspot/src/share/vm/gc/g1/bufferingOopClosure.cpp b/hotspot/src/share/vm/gc/g1/bufferingOopClosure.cpp index 1985ee31cc0..cf1b182c57f 100644 --- a/hotspot/src/share/vm/gc/g1/bufferingOopClosure.cpp +++ b/hotspot/src/share/vm/gc/g1/bufferingOopClosure.cpp @@ -153,10 +153,10 @@ class TestBufferingOopClosure { boc.done(); - #define assert_testCount(got, expected) \ - assert((got) == (expected), \ - err_msg("Expected: %d, got: %d, when running testCount(%d, %d, %d)", \ - (got), (expected), num_narrow, num_full, do_oop_order)) + #define assert_testCount(got, expected) \ + assert((got) == (expected), \ + "Expected: %d, got: %d, when running testCount(%d, %d, %d)", \ + (got), (expected), num_narrow, num_full, do_oop_order) assert_testCount(num_narrow, coc.narrow_oop_count()); assert_testCount(num_full, coc.full_oop_count()); @@ -190,11 +190,11 @@ class TestBufferingOopClosure { fr.oops_do(&boc, 0); - #define assert_testIsBufferEmptyOrFull(got, expected) \ - assert((got) == (expected), \ - err_msg("Expected: %d, got: %d. testIsBufferEmptyOrFull(%d, %d, %s, %s)", \ - (got), (expected), num_narrow, num_full, \ - BOOL_TO_STR(expect_empty), BOOL_TO_STR(expect_full))) + #define assert_testIsBufferEmptyOrFull(got, expected) \ + assert((got) == (expected), \ + "Expected: %d, got: %d. testIsBufferEmptyOrFull(%d, %d, %s, %s)", \ + (got), (expected), num_narrow, num_full, \ + BOOL_TO_STR(expect_empty), BOOL_TO_STR(expect_full)) assert_testIsBufferEmptyOrFull(expect_empty, boc.is_buffer_empty()); assert_testIsBufferEmptyOrFull(expect_full, boc.is_buffer_full()); @@ -232,8 +232,8 @@ class TestBufferingOopClosure { boc.done(); assert(boc.is_buffer_empty(), - err_msg("Should be empty after call to done(). testEmptyAfterDone(%d, %d)", - num_narrow, num_full)); + "Should be empty after call to done(). testEmptyAfterDone(%d, %d)", + num_narrow, num_full); } static void testEmptyAfterDone() { diff --git a/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp index d3ad72b38ef..9ac0304a02b 100644 --- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp +++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp @@ -91,10 +91,8 @@ CollectionSetChooser::CollectionSetChooser() : #ifndef PRODUCT void CollectionSetChooser::verify() { - guarantee(_end <= regions_length(), - err_msg("_end: %u regions length: %u", _end, regions_length())); - guarantee(_front <= _end, - err_msg("_front: %u _end: %u", _front, _end)); + guarantee(_end <= regions_length(), "_end: %u regions length: %u", _end, regions_length()); + guarantee(_front <= _end, "_front: %u _end: %u", _front, _end); uint index = 0; size_t sum_of_reclaimable_bytes = 0; while (index < _front) { @@ -108,19 +106,19 @@ void CollectionSetChooser::verify() { guarantee(curr != NULL, "Regions in _regions array cannot be NULL"); guarantee(!curr->is_young(), "should not be young!"); guarantee(!curr->is_pinned(), - err_msg("Pinned region should not be in collection set (index %u)", curr->hrm_index())); + "Pinned region should not be in collection set (index %u)", curr->hrm_index()); if (prev != NULL) { guarantee(order_regions(prev, curr) != 1, - err_msg("GC eff prev: %1.4f GC eff curr: %1.4f", - prev->gc_efficiency(), curr->gc_efficiency())); + "GC eff prev: %1.4f GC eff curr: %1.4f", + prev->gc_efficiency(), curr->gc_efficiency()); } sum_of_reclaimable_bytes += curr->reclaimable_bytes(); prev = curr; } guarantee(sum_of_reclaimable_bytes == _remaining_reclaimable_bytes, - err_msg("reclaimable bytes inconsistent, " - "remaining: " SIZE_FORMAT " sum: " SIZE_FORMAT, - _remaining_reclaimable_bytes, sum_of_reclaimable_bytes)); + "reclaimable bytes inconsistent, " + "remaining: " SIZE_FORMAT " sum: " SIZE_FORMAT, + _remaining_reclaimable_bytes, sum_of_reclaimable_bytes); } #endif // !PRODUCT @@ -151,7 +149,7 @@ void CollectionSetChooser::sort_regions() { void CollectionSetChooser::add_region(HeapRegion* hr) { assert(!hr->is_pinned(), - err_msg("Pinned region shouldn't be added to the collection set (index %u)", hr->hrm_index())); + "Pinned region shouldn't be added to the collection set (index %u)", hr->hrm_index()); assert(!hr->is_young(), "should not be young!"); _regions.append(hr); _end++; diff --git a/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp b/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp index 011c4ef1f2e..e24e58ae4c8 100644 --- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp +++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp @@ -73,9 +73,7 @@ public: HeapRegion* res = NULL; if (_front < _end) { res = regions_at(_front); - assert(res != NULL, - err_msg("Unexpected NULL hr in _regions at index %u", - _front)); + assert(res != NULL, "Unexpected NULL hr in _regions at index %u", _front); } return res; } @@ -88,9 +86,9 @@ public: assert(_front < _end, "pre-condition"); regions_at_put(_front, NULL); assert(hr->reclaimable_bytes() <= _remaining_reclaimable_bytes, - err_msg("remaining reclaimable bytes inconsistent " - "from region: " SIZE_FORMAT " remaining: " SIZE_FORMAT, - hr->reclaimable_bytes(), _remaining_reclaimable_bytes)); + "remaining reclaimable bytes inconsistent " + "from region: " SIZE_FORMAT " remaining: " SIZE_FORMAT, + hr->reclaimable_bytes(), _remaining_reclaimable_bytes); _remaining_reclaimable_bytes -= hr->reclaimable_bytes(); _front += 1; return hr; diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp index ef8b7a58a62..b10aa68f53b 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp @@ -112,6 +112,8 @@ class ConcurrentG1Refine: public CHeapObj { int thread_threshold_step() const { return _thread_threshold_step; } G1HotCardCache* hot_card_cache() { return &_hot_card_cache; } + + static bool hot_card_cache_enabled() { return G1HotCardCache::default_use_cache(); } }; #endif // SHARE_VM_GC_G1_CONCURRENTG1REFINE_HPP diff --git a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp index 2d79ef7ed52..2eea03ad5b3 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp @@ -41,6 +41,7 @@ #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionSet.inline.hpp" #include "gc/g1/suspendibleThreadSet.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcTraceTime.hpp" @@ -245,10 +246,6 @@ MemRegion CMBitMap::getAndClearMarkedRegion(HeapWord* addr, CMMarkStack::CMMarkStack(ConcurrentMark* cm) : _base(NULL), _cm(cm) -#ifdef ASSERT - , _drain_in_progress(false) - , _drain_in_progress_yields(false) -#endif {} bool CMMarkStack::allocate(size_t capacity) { @@ -362,30 +359,6 @@ bool CMMarkStack::par_pop_arr(oop* ptr_arr, int max, int* n) { } } -template -bool CMMarkStack::drain(OopClosureClass* cl, CMBitMap* bm, bool yield_after) { - assert(!_drain_in_progress || !_drain_in_progress_yields || yield_after - || SafepointSynchronize::is_at_safepoint(), - "Drain recursion must be yield-safe."); - bool res = true; - debug_only(_drain_in_progress = true); - debug_only(_drain_in_progress_yields = yield_after); - while (!isEmpty()) { - oop newOop = pop(); - assert(G1CollectedHeap::heap()->is_in_reserved(newOop), "Bad pop"); - assert(newOop->is_oop(), "Expected an oop"); - assert(bm == NULL || bm->isMarked((HeapWord*)newOop), - "only grey objects on this stack"); - newOop->oop_iterate(cl); - if (yield_after && _cm->do_yield_check()) { - res = false; - break; - } - } - debug_only(_drain_in_progress = false); - return res; -} - void CMMarkStack::note_start_of_gc() { assert(_saved_index == -1, "note_start_of_gc()/end_of_gc() bracketed incorrectly"); @@ -399,7 +372,7 @@ void CMMarkStack::note_end_of_gc() { // only check this once per GC anyway, so it won't be a performance // issue in any way. guarantee(_saved_index == _index, - err_msg("saved index: %d index: %d", _saved_index, _index)); + "saved index: %d index: %d", _saved_index, _index); _saved_index = -1; } @@ -520,7 +493,6 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev _has_overflown(false), _concurrent(false), _has_aborted(false), - _aborted_gc_id(GCId::undefined()), _restart_for_overflow(false), _concurrent_marking_in_progress(false), @@ -794,8 +766,8 @@ void ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurren // in a STW phase. assert(!concurrent_marking_in_progress(), "invariant"); assert(out_of_regions(), - err_msg("only way to get here: _finger: " PTR_FORMAT ", _heap_end: " PTR_FORMAT, - p2i(_finger), p2i(_heap_end))); + "only way to get here: _finger: " PTR_FORMAT ", _heap_end: " PTR_FORMAT, + p2i(_finger), p2i(_heap_end)); } } @@ -991,7 +963,7 @@ void ConcurrentMark::enter_first_sync_barrier(uint worker_id) { force_overflow()->update(); if (G1Log::fine()) { - gclog_or_tty->gclog_stamp(concurrent_gc_id()); + gclog_or_tty->gclog_stamp(); gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]"); } } @@ -1181,7 +1153,7 @@ void ConcurrentMark::scanRootRegions() { // should not attempt to do any further work. if (root_regions()->scan_in_progress()) { if (G1Log::fine()) { - gclog_or_tty->gclog_stamp(concurrent_gc_id()); + gclog_or_tty->gclog_stamp(); gclog_or_tty->print_cr("[GC concurrent-root-region-scan-start]"); } @@ -1195,7 +1167,7 @@ void ConcurrentMark::scanRootRegions() { _parallel_workers->run_task(&task); if (G1Log::fine()) { - gclog_or_tty->gclog_stamp(concurrent_gc_id()); + gclog_or_tty->gclog_stamp(); gclog_or_tty->print_cr("[GC concurrent-root-region-scan-end, %1.7lf secs]", os::elapsedTime() - scan_start); } @@ -1235,7 +1207,8 @@ void ConcurrentMark::markFromRoots() { } // Helper class to get rid of some boilerplate code. -class G1CMTraceTime : public GCTraceTime { +class G1CMTraceTime : public StackObj { + GCTraceTimeImpl _gc_trace_time; static bool doit_and_prepend(bool doit) { if (doit) { gclog_or_tty->put(' '); @@ -1245,8 +1218,7 @@ class G1CMTraceTime : public GCTraceTime { public: G1CMTraceTime(const char* title, bool doit) - : GCTraceTime(title, doit_and_prepend(doit), false, G1CollectedHeap::heap()->gc_timer_cm(), - G1CollectedHeap::heap()->concurrent_mark()->concurrent_gc_id()) { + : _gc_trace_time(title, doit_and_prepend(doit), false, G1CollectedHeap::heap()->gc_timer_cm()) { } }; @@ -1415,9 +1387,9 @@ public: HeapWord* start = hr->bottom(); assert(start <= hr->end() && start <= ntams && ntams <= hr->end(), - err_msg("Preconditions not met - " - "start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT, - p2i(start), p2i(ntams), p2i(hr->end()))); + "Preconditions not met - " + "start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT, + p2i(start), p2i(ntams), p2i(hr->end())); // Find the first marked object at or after "start". start = _bm->getNextMarkedWordAddress(start, ntams); @@ -1717,11 +1689,11 @@ class FinalCountDataUpdateClosure: public CMCountDataClosureBase { } assert(end_idx <= _card_bm->size(), - err_msg("oob: end_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT, - end_idx, _card_bm->size())); + "oob: end_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT, + end_idx, _card_bm->size()); assert(start_idx < _card_bm->size(), - err_msg("oob: start_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT, - start_idx, _card_bm->size())); + "oob: start_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT, + start_idx, _card_bm->size()); _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */); } @@ -2391,8 +2363,7 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { &g1_keep_alive, &g1_drain_mark_stack, executor, - g1h->gc_timer_cm(), - concurrent_gc_id()); + g1h->gc_timer_cm()); g1h->gc_tracer_cm()->report_gc_reference_stats(stats); // The do_oop work routines of the keep_alive and drain_marking_stack @@ -2471,7 +2442,7 @@ private: // object; it could instead have been a stale reference. oop obj = static_cast(entry); assert(obj->is_oop(true /* ignore mark word */), - err_msg("Invalid oop in SATB buffer: " PTR_FORMAT, p2i(obj))); + "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(obj)); _task->make_reference_grey(obj, hr); } } @@ -2588,9 +2559,9 @@ void ConcurrentMark::checkpointRootsFinalWork() { SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); guarantee(has_overflown() || satb_mq_set.completed_buffers_num() == 0, - err_msg("Invariant: has_overflown = %s, num buffers = %d", - BOOL_TO_STR(has_overflown()), - satb_mq_set.completed_buffers_num())); + "Invariant: has_overflown = %s, num buffers = %d", + BOOL_TO_STR(has_overflown()), + satb_mq_set.completed_buffers_num()); print_stats(); } @@ -2724,11 +2695,11 @@ public: void operator()(oop obj) const { guarantee(obj->is_oop(), - err_msg("Non-oop " PTR_FORMAT ", phase: %s, info: %d", - p2i(obj), _phase, _info)); + "Non-oop " PTR_FORMAT ", phase: %s, info: %d", + p2i(obj), _phase, _info); guarantee(!_g1h->obj_in_cs(obj), - err_msg("obj: " PTR_FORMAT " in CSet, phase: %s, info: %d", - p2i(obj), _phase, _info)); + "obj: " PTR_FORMAT " in CSet, phase: %s, info: %d", + p2i(obj), _phase, _info); } }; @@ -2761,8 +2732,8 @@ void ConcurrentMark::verify_no_cset_oops() { // here. HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger); guarantee(global_hr == NULL || global_finger == global_hr->bottom(), - err_msg("global finger: " PTR_FORMAT " region: " HR_FORMAT, - p2i(global_finger), HR_FORMAT_PARAMS(global_hr))); + "global finger: " PTR_FORMAT " region: " HR_FORMAT, + p2i(global_finger), HR_FORMAT_PARAMS(global_hr)); } // Verify the task fingers @@ -2775,8 +2746,8 @@ void ConcurrentMark::verify_no_cset_oops() { HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger); guarantee(task_hr == NULL || task_finger == task_hr->bottom() || !task_hr->in_collection_set(), - err_msg("task finger: " PTR_FORMAT " region: " HR_FORMAT, - p2i(task_finger), HR_FORMAT_PARAMS(task_hr))); + "task finger: " PTR_FORMAT " region: " HR_FORMAT, + p2i(task_finger), HR_FORMAT_PARAMS(task_hr)); } } } @@ -2816,10 +2787,10 @@ class AggregateCountDataHRClosure: public HeapRegionClosure { HeapWord* end = hr->end(); assert(start <= limit && limit <= hr->top() && hr->top() <= hr->end(), - err_msg("Preconditions not met - " - "start: " PTR_FORMAT ", limit: " PTR_FORMAT ", " - "top: " PTR_FORMAT ", end: " PTR_FORMAT, - p2i(start), p2i(limit), p2i(hr->top()), p2i(hr->end()))); + "Preconditions not met - " + "start: " PTR_FORMAT ", limit: " PTR_FORMAT ", " + "top: " PTR_FORMAT ", end: " PTR_FORMAT, + p2i(start), p2i(limit), p2i(hr->top()), p2i(hr->end())); assert(hr->next_marked_bytes() == 0, "Precondition"); @@ -2988,8 +2959,6 @@ void ConcurrentMark::abort() { } _first_overflow_barrier_sync.abort(); _second_overflow_barrier_sync.abort(); - _aborted_gc_id = _g1h->gc_tracer_cm()->gc_id(); - assert(!_aborted_gc_id.is_undefined(), "ConcurrentMark::abort() executed more than once?"); _has_aborted = true; SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); @@ -3004,13 +2973,6 @@ void ConcurrentMark::abort() { _g1h->register_concurrent_cycle_end(); } -const GCId& ConcurrentMark::concurrent_gc_id() { - if (has_aborted()) { - return _aborted_gc_id; - } - return _g1h->gc_tracer_cm()->gc_id(); -} - static void print_ms_time_info(const char* prefix, const char* name, NumberSeq& ns) { gclog_or_tty->print_cr("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).", @@ -3122,17 +3084,21 @@ public: } }; +static ReferenceProcessor* get_cm_oop_closure_ref_processor(G1CollectedHeap* g1h) { + ReferenceProcessor* result = NULL; + if (G1UseConcMarkReferenceProcessing) { + result = g1h->ref_processor_cm(); + assert(result != NULL, "should not be NULL"); + } + return result; +} + G1CMOopClosure::G1CMOopClosure(G1CollectedHeap* g1h, ConcurrentMark* cm, CMTask* task) - : _g1h(g1h), _cm(cm), _task(task) { - assert(_ref_processor == NULL, "should be initialized to NULL"); - - if (G1UseConcMarkReferenceProcessing) { - _ref_processor = g1h->ref_processor_cm(); - assert(_ref_processor != NULL, "should not be NULL"); - } -} + : MetadataAwareOopClosure(get_cm_oop_closure_ref_processor(g1h)), + _g1h(g1h), _cm(cm), _task(task) +{ } void CMTask::setup_for_region(HeapRegion* hr) { assert(hr != NULL, @@ -3769,8 +3735,7 @@ void CMTask::do_marking_step(double time_target_ms, // and do_marking_step() is not being called serially. bool do_stealing = do_termination && !is_serial; - double diff_prediction_ms = - g1_policy->get_new_prediction(&_marking_step_diffs_ms); + double diff_prediction_ms = _g1h->g1_policy()->predictor().get_new_prediction(&_marking_step_diffs_ms); _time_target_ms = time_target_ms - diff_prediction_ms; // set up the variables that are used in the work-based scheme to diff --git a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc/g1/concurrentMark.hpp index 947dee852ff..9dc0e87093f 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.hpp @@ -28,7 +28,6 @@ #include "classfile/javaClasses.hpp" #include "gc/g1/g1RegionToSpaceMapper.hpp" #include "gc/g1/heapRegionSet.hpp" -#include "gc/shared/gcId.hpp" #include "gc/shared/taskqueue.hpp" class G1CollectedHeap; @@ -183,15 +182,6 @@ class CMMarkStack VALUE_OBJ_CLASS_SPEC { bool _overflow; bool _should_expand; - DEBUG_ONLY(bool _drain_in_progress;) - DEBUG_ONLY(bool _drain_in_progress_yields;) - - oop pop() { - if (!isEmpty()) { - return _base[--_index] ; - } - return NULL; - } public: CMMarkStack(ConcurrentMark* cm); @@ -213,17 +203,6 @@ class CMMarkStack VALUE_OBJ_CLASS_SPEC { // operations, which use the same locking strategy. bool par_pop_arr(oop* ptr_arr, int max, int* n); - // Drain the mark stack, applying the given closure to all fields of - // objects on the stack. (That is, continue until the stack is empty, - // even if closure applications add entries to the stack.) The "bm" - // argument, if non-null, may be used to verify that only marked objects - // are on the mark stack. If "yield_after" is "true", then the - // concurrent marker performing the drain offers to yield after - // processing each object. If a yield occurs, stops the drain operation - // and returns false. Otherwise, returns true. - template - bool drain(OopClosureClass* cl, CMBitMap* bm, bool yield_after = false); - bool isEmpty() { return _index == 0; } int maxElems() { return _capacity; } @@ -425,7 +404,6 @@ protected: volatile bool _concurrent; // Set at the end of a Full GC so that marking aborts volatile bool _has_aborted; - GCId _aborted_gc_id; // Used when remark aborts due to an overflow to indicate that // another concurrent marking phase should start @@ -768,8 +746,6 @@ public: bool has_aborted() { return _has_aborted; } - const GCId& concurrent_gc_id(); - // This prints the global/local fingers. It is used for debugging. NOT_PRODUCT(void print_finger();) diff --git a/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp b/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp index 8a93d5e8ca3..03bc56be7c5 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp @@ -197,9 +197,9 @@ inline bool CMBitMapRO::iterate(BitMapClosure* cl) { assert(_bmStartWord <= (addr) && (addr) < (_bmStartWord + _bmWordSize), \ "outside underlying space?"); \ assert(G1CollectedHeap::heap()->is_in_exact(addr), \ - err_msg("Trying to access not available bitmap " PTR_FORMAT \ - " corresponding to " PTR_FORMAT " (%u)", \ - p2i(this), p2i(addr), G1CollectedHeap::heap()->addr_to_region(addr))); + "Trying to access not available bitmap " PTR_FORMAT \ + " corresponding to " PTR_FORMAT " (%u)", \ + p2i(this), p2i(addr), G1CollectedHeap::heap()->addr_to_region(addr)); inline void CMBitMap::mark(HeapWord* addr) { check_mark(addr); @@ -225,8 +225,7 @@ inline bool CMBitMap::parClear(HeapWord* addr) { template inline void CMMarkStack::iterate(Fn fn) { - assert(_saved_index == _index, - err_msg("saved index: %d index: %d", _saved_index, _index)); + assert(_saved_index == _index, "saved index: %d index: %d", _saved_index, _index); for (int i = 0; i < _index; ++i) { fn(_base[i]); } @@ -385,7 +384,7 @@ inline void CMTask::deal_with_reference(oop obj) { increment_refs_reached(); HeapWord* objAddr = (HeapWord*) obj; - assert(obj->is_oop_or_null(true /* ignore mark word */), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + assert(obj->is_oop_or_null(true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); if (_g1h->is_in_g1_reserved(objAddr)) { assert(obj != NULL, "null check is implicit"); if (!_nextMarkBitMap->isMarked(objAddr)) { @@ -427,9 +426,9 @@ inline void ConcurrentMark::grayRoot(oop obj, size_t word_size, // assert that word_size is under an upper bound which is its // containing region's capacity. assert(word_size * HeapWordSize <= hr->capacity(), - err_msg("size: " SIZE_FORMAT " capacity: " SIZE_FORMAT " " HR_FORMAT, - word_size * HeapWordSize, hr->capacity(), - HR_FORMAT_PARAMS(hr))); + "size: " SIZE_FORMAT " capacity: " SIZE_FORMAT " " HR_FORMAT, + word_size * HeapWordSize, hr->capacity(), + HR_FORMAT_PARAMS(hr)); if (addr < hr->next_top_at_mark_start()) { if (!_nextMarkBitMap->isMarked(addr)) { diff --git a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp index 427b073cecb..36dd7fc29bb 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp @@ -30,6 +30,7 @@ #include "gc/g1/g1MMUTracker.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "gc/g1/vm_operations_g1.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcTrace.hpp" #include "memory/resourceArea.hpp" #include "runtime/vmThread.hpp" @@ -85,7 +86,7 @@ void ConcurrentMarkThread::cm_log(bool doit, bool join_sts, const char* fmt, ... SuspendibleThreadSetJoiner sts_joiner(join_sts); va_list args; va_start(args, fmt); - gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id()); + gclog_or_tty->gclog_stamp(); gclog_or_tty->vprint_cr(fmt, args); va_end(args); } @@ -108,6 +109,7 @@ void ConcurrentMarkThread::run() { break; } + assert(GCId::current() != GCId::undefined(), "GC id should have been set up by the initial mark GC."); { ResourceMark rm; HandleMark hm; @@ -194,7 +196,7 @@ void ConcurrentMarkThread::run() { // reclaimed by cleanup. double cleanup_start_sec = os::elapsedTime(); - cm_log(G1Log::fine(), true, "[GC concurrent-cleanup-start]"); + cm_log(G1Log::fine(), false, "[GC concurrent-cleanup-start]"); // Now do the concurrent cleanup operation. _cm->completeCleanup(); diff --git a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp index 7ec36bd94b4..9a61b0da769 100644 --- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp @@ -91,7 +91,7 @@ size_t G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region, } size_t G1AllocRegion::retire(bool fill_up) { - assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly")); + assert_alloc_region(_alloc_region != NULL, "not initialized properly"); size_t result = 0; @@ -101,15 +101,14 @@ size_t G1AllocRegion::retire(bool fill_up) { // We never have to check whether the active region is empty or not, // and potentially free it if it is, given that it's guaranteed that // it will never be empty. - assert(!alloc_region->is_empty(), - ar_ext_msg(this, "the alloc region should never be empty")); + assert_alloc_region(!alloc_region->is_empty(), + "the alloc region should never be empty"); if (fill_up) { result = fill_up_remaining_space(alloc_region, _bot_updates); } - assert(alloc_region->used() >= _used_bytes_before, - ar_ext_msg(this, "invariant")); + assert_alloc_region(alloc_region->used() >= _used_bytes_before, "invariant"); size_t allocated_bytes = alloc_region->used() - _used_bytes_before; retire_region(alloc_region, allocated_bytes); _used_bytes_before = 0; @@ -122,8 +121,8 @@ size_t G1AllocRegion::retire(bool fill_up) { HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size, bool force) { - assert(_alloc_region == _dummy_region, ar_ext_msg(this, "pre-condition")); - assert(_used_bytes_before == 0, ar_ext_msg(this, "pre-condition")); + assert_alloc_region(_alloc_region == _dummy_region, "pre-condition"); + assert_alloc_region(_used_bytes_before == 0, "pre-condition"); trace("attempting region allocation"); HeapRegion* new_alloc_region = allocate_new_region(word_size, force); @@ -132,7 +131,7 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size, // Need to do this before the allocation _used_bytes_before = new_alloc_region->used(); HeapWord* result = allocate(new_alloc_region, word_size, _bot_updates); - assert(result != NULL, ar_ext_msg(this, "the allocation should succeeded")); + assert_alloc_region(result != NULL, "the allocation should succeeded"); OrderAccess::storestore(); // Note that we first perform the allocation and then we store the @@ -148,17 +147,10 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size, ShouldNotReachHere(); } -void G1AllocRegion::fill_in_ext_msg(ar_ext_msg* msg, const char* message) { - msg->append("[%s] %s c: %u b: %s r: " PTR_FORMAT " u: " SIZE_FORMAT, - _name, message, _count, BOOL_TO_STR(_bot_updates), - p2i(_alloc_region), _used_bytes_before); -} - void G1AllocRegion::init() { trace("initializing"); - assert(_alloc_region == NULL && _used_bytes_before == 0, - ar_ext_msg(this, "pre-condition")); - assert(_dummy_region != NULL, ar_ext_msg(this, "should have been set")); + assert_alloc_region(_alloc_region == NULL && _used_bytes_before == 0, "pre-condition"); + assert_alloc_region(_dummy_region != NULL, "should have been set"); _alloc_region = _dummy_region; _count = 0; trace("initialized"); @@ -168,11 +160,10 @@ void G1AllocRegion::set(HeapRegion* alloc_region) { trace("setting"); // We explicitly check that the region is not empty to make sure we // maintain the "the alloc region cannot be empty" invariant. - assert(alloc_region != NULL && !alloc_region->is_empty(), - ar_ext_msg(this, "pre-condition")); - assert(_alloc_region == _dummy_region && - _used_bytes_before == 0 && _count == 0, - ar_ext_msg(this, "pre-condition")); + assert_alloc_region(alloc_region != NULL && !alloc_region->is_empty(), "pre-condition"); + assert_alloc_region(_alloc_region == _dummy_region && + _used_bytes_before == 0 && _count == 0, + "pre-condition"); _used_bytes_before = alloc_region->used(); _alloc_region = alloc_region; @@ -184,8 +175,7 @@ void G1AllocRegion::update_alloc_region(HeapRegion* alloc_region) { trace("update"); // We explicitly check that the region is not empty to make sure we // maintain the "the alloc region cannot be empty" invariant. - assert(alloc_region != NULL && !alloc_region->is_empty(), - ar_ext_msg(this, "pre-condition")); + assert_alloc_region(alloc_region != NULL && !alloc_region->is_empty(), "pre-condition"); _alloc_region = alloc_region; _alloc_region->set_allocation_context(allocation_context()); @@ -197,8 +187,7 @@ HeapRegion* G1AllocRegion::release() { trace("releasing"); HeapRegion* alloc_region = _alloc_region; retire(false /* fill_up */); - assert(_alloc_region == _dummy_region, - ar_ext_msg(this, "post-condition of retire()")); + assert_alloc_region(_alloc_region == _dummy_region, "post-condition of retire()"); _alloc_region = NULL; trace("released"); return (alloc_region == _dummy_region) ? NULL : alloc_region; diff --git a/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp b/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp index ace24dfc340..9feb295af4a 100644 --- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp +++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp @@ -34,8 +34,6 @@ class G1CollectedHeap; // 0 -> no tracing, 1 -> basic tracing, 2 -> basic + allocation tracing #define G1_ALLOC_REGION_TRACING 0 -class ar_ext_msg; - // A class that holds a region that is active in satisfying allocation // requests, potentially issued in parallel. When the active region is // full it will be retired and replaced with a new one. The @@ -44,7 +42,6 @@ class ar_ext_msg; // replaced. class G1AllocRegion VALUE_OBJ_CLASS_SPEC { - friend class ar_ext_msg; private: // The active allocating region we are currently allocating out @@ -131,8 +128,6 @@ private: // to allocate a new region even if the max has been reached. HeapWord* new_alloc_region_and_allocate(size_t word_size, bool force); - void fill_in_ext_msg(ar_ext_msg* msg, const char* message); - protected: // Retire the active allocating region. If fill_up is true then make // sure that the region is full before we retire it so that no one @@ -278,11 +273,4 @@ public: virtual HeapRegion* release(); }; -class ar_ext_msg : public err_msg { -public: - ar_ext_msg(G1AllocRegion* alloc_region, const char *message) : err_msg("%s", "") { - alloc_region->fill_in_ext_msg(this, message); - } -}; - #endif // SHARE_VM_GC_G1_G1ALLOCREGION_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1AllocRegion.inline.hpp b/hotspot/src/share/vm/gc/g1/g1AllocRegion.inline.hpp index 188775833b6..c9a4d4058e5 100644 --- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.inline.hpp @@ -28,10 +28,18 @@ #include "gc/g1/g1AllocRegion.hpp" #include "gc/g1/heapRegion.inline.hpp" +#define assert_alloc_region(p, message) \ + do { \ + assert((p), "[%s] %s c: %u b: %s r: " PTR_FORMAT " u: " SIZE_FORMAT, \ + _name, (message), _count, BOOL_TO_STR(_bot_updates), \ + p2i(_alloc_region), _used_bytes_before); \ + } while (0) + + inline HeapWord* G1AllocRegion::allocate(HeapRegion* alloc_region, size_t word_size, bool bot_updates) { - assert(alloc_region != NULL, err_msg("pre-condition")); + assert(alloc_region != NULL, "pre-condition"); if (!bot_updates) { return alloc_region->allocate_no_bot_updates(word_size); @@ -50,8 +58,8 @@ inline HeapWord* G1AllocRegion::par_allocate(HeapRegion* alloc_region, size_t desired_word_size, size_t* actual_word_size, bool bot_updates) { - assert(alloc_region != NULL, err_msg("pre-condition")); - assert(!alloc_region->is_empty(), err_msg("pre-condition")); + assert(alloc_region != NULL, "pre-condition"); + assert(!alloc_region->is_empty(), "pre-condition"); if (!bot_updates) { return alloc_region->par_allocate_no_bot_updates(min_word_size, desired_word_size, actual_word_size); @@ -69,10 +77,10 @@ inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size, bool bot_updates) { - assert(bot_updates == _bot_updates, ar_ext_msg(this, "pre-condition")); + assert_alloc_region(bot_updates == _bot_updates, "pre-condition"); HeapRegion* alloc_region = _alloc_region; - assert(alloc_region != NULL, ar_ext_msg(this, "not initialized properly")); + assert_alloc_region(alloc_region != NULL, "not initialized properly"); HeapWord* result = par_allocate(alloc_region, min_word_size, desired_word_size, actual_word_size, bot_updates); if (result != NULL) { @@ -113,8 +121,8 @@ inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t min_word_size, inline HeapWord* G1AllocRegion::attempt_allocation_force(size_t word_size, bool bot_updates) { - assert(bot_updates == _bot_updates, ar_ext_msg(this, "pre-condition")); - assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly")); + assert_alloc_region(bot_updates == _bot_updates, "pre-condition"); + assert_alloc_region(_alloc_region != NULL, "not initialized properly"); trace("forcing alloc", word_size, word_size); HeapWord* result = new_alloc_region_and_allocate(word_size, true /* force */); diff --git a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp index 97786e61b76..f298798430e 100644 --- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp @@ -54,7 +54,7 @@ void G1Allocator::reuse_retained_old_region(EvacuationInfo& evacuation_info, HeapRegion* retained_region = *retained_old; *retained_old = NULL; assert(retained_region == NULL || !retained_region->is_archive(), - err_msg("Archive region should not be alloc region (index %u)", retained_region->hrm_index())); + "Archive region should not be alloc region (index %u)", retained_region->hrm_index()); // We will discard the current GC alloc region if: // a) it's in the collection set (it can happen!), @@ -147,8 +147,8 @@ HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest, size_t temp = 0; HeapWord* result = par_allocate_during_gc(dest, word_size, word_size, &temp, context); assert(result == NULL || temp == word_size, - err_msg("Requested " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT, - word_size, temp, p2i(result))); + "Requested " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT, + word_size, temp, p2i(result)); return result; } @@ -276,16 +276,16 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(InCSetState dest, context); assert(buf == NULL || ((actual_plab_size >= required_in_plab) && (actual_plab_size <= plab_word_size)), - err_msg("Requested at minimum " SIZE_FORMAT ", desired " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT, - required_in_plab, plab_word_size, actual_plab_size, p2i(buf))); + "Requested at minimum " SIZE_FORMAT ", desired " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT, + required_in_plab, plab_word_size, actual_plab_size, p2i(buf)); if (buf != NULL) { alloc_buf->set_buf(buf, actual_plab_size); HeapWord* const obj = alloc_buf->allocate(word_sz); - assert(obj != NULL, err_msg("PLAB should have been big enough, tried to allocate " - SIZE_FORMAT " requiring " SIZE_FORMAT " PLAB size " SIZE_FORMAT, - word_sz, required_in_plab, plab_word_size)); + assert(obj != NULL, "PLAB should have been big enough, tried to allocate " + SIZE_FORMAT " requiring " SIZE_FORMAT " PLAB size " SIZE_FORMAT, + word_sz, required_in_plab, plab_word_size); return obj; } // Otherwise. @@ -354,7 +354,7 @@ bool G1ArchiveAllocator::alloc_new_region() { if (hr == NULL) { return false; } - assert(hr->is_empty(), err_msg("expected empty region (index %u)", hr->hrm_index())); + assert(hr->is_empty(), "expected empty region (index %u)", hr->hrm_index()); hr->set_archive(); _g1h->old_set_add(hr); _g1h->hr_printer()->alloc(hr, G1HRPrinter::Archive); @@ -383,15 +383,15 @@ HeapWord* G1ArchiveAllocator::archive_mem_allocate(size_t word_size) { } HeapWord* old_top = _allocation_region->top(); assert(_bottom >= _allocation_region->bottom(), - err_msg("inconsistent allocation state: " PTR_FORMAT " < " PTR_FORMAT, - p2i(_bottom), p2i(_allocation_region->bottom()))); + "inconsistent allocation state: " PTR_FORMAT " < " PTR_FORMAT, + p2i(_bottom), p2i(_allocation_region->bottom())); assert(_max <= _allocation_region->end(), - err_msg("inconsistent allocation state: " PTR_FORMAT " > " PTR_FORMAT, - p2i(_max), p2i(_allocation_region->end()))); + "inconsistent allocation state: " PTR_FORMAT " > " PTR_FORMAT, + p2i(_max), p2i(_allocation_region->end())); assert(_bottom <= old_top && old_top <= _max, - err_msg("inconsistent allocation state: expected " - PTR_FORMAT " <= " PTR_FORMAT " <= " PTR_FORMAT, - p2i(_bottom), p2i(old_top), p2i(_max))); + "inconsistent allocation state: expected " + PTR_FORMAT " <= " PTR_FORMAT " <= " PTR_FORMAT, + p2i(_bottom), p2i(old_top), p2i(_max)); // Allocate the next word_size words in the current allocation chunk. // If allocation would cross the _max boundary, insert a filler and begin @@ -430,9 +430,9 @@ HeapWord* G1ArchiveAllocator::archive_mem_allocate(size_t word_size) { void G1ArchiveAllocator::complete_archive(GrowableArray* ranges, size_t end_alignment_in_bytes) { assert((end_alignment_in_bytes >> LogHeapWordSize) < HeapRegion::min_region_size_in_words(), - err_msg("alignment " SIZE_FORMAT " too large", end_alignment_in_bytes)); + "alignment " SIZE_FORMAT " too large", end_alignment_in_bytes); assert(is_size_aligned(end_alignment_in_bytes, HeapWordSize), - err_msg("alignment " SIZE_FORMAT " is not HeapWord (%u) aligned", end_alignment_in_bytes, HeapWordSize)); + "alignment " SIZE_FORMAT " is not HeapWord (%u) aligned", end_alignment_in_bytes, HeapWordSize); // If we've allocated nothing, simply return. if (_allocation_region == NULL) { @@ -465,8 +465,8 @@ void G1ArchiveAllocator::complete_archive(GrowableArray* ranges, // MemRegions to the GrowableArray provided by the caller. int index = _allocated_regions.length() - 1; assert(_allocated_regions.at(index) == _allocation_region, - err_msg("expected region %u at end of array, found %u", - _allocation_region->hrm_index(), _allocated_regions.at(index)->hrm_index())); + "expected region %u at end of array, found %u", + _allocation_region->hrm_index(), _allocated_regions.at(index)->hrm_index()); HeapWord* base_address = _allocation_region->bottom(); HeapWord* top = base_address; @@ -482,7 +482,7 @@ void G1ArchiveAllocator::complete_archive(GrowableArray* ranges, index = index - 1; } - assert(top != base_address, err_msg("zero-sized range, address " PTR_FORMAT, p2i(base_address))); + assert(top != base_address, "zero-sized range, address " PTR_FORMAT, p2i(base_address)); ranges->append(MemRegion(base_address, pointer_delta(top, base_address))); _allocated_regions.clear(); _allocation_region = NULL; diff --git a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp index 4828d7e5dd9..f58b248bd4e 100644 --- a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp @@ -295,9 +295,9 @@ public: virtual G1PLAB* alloc_buffer(InCSetState dest, AllocationContext_t context) { assert(dest.is_valid(), - err_msg("Allocation buffer index out-of-bounds: " CSETSTATE_FORMAT, dest.value())); + "Allocation buffer index out-of-bounds: " CSETSTATE_FORMAT, dest.value()); assert(_alloc_buffers[dest.value()] != NULL, - err_msg("Allocation buffer is NULL: " CSETSTATE_FORMAT, dest.value())); + "Allocation buffer is NULL: " CSETSTATE_FORMAT, dest.value()); return _alloc_buffers[dest.value()]; } diff --git a/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp b/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp index 51ae3e64f13..3ca9451132a 100644 --- a/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp @@ -36,7 +36,7 @@ HeapWord* G1Allocator::attempt_allocation(size_t word_size, AllocationContext_t HeapWord* G1Allocator::attempt_allocation_locked(size_t word_size, AllocationContext_t context) { HeapWord* result = mutator_alloc_region(context)->attempt_allocation_locked(word_size, false /* bot_updates */); assert(result != NULL || mutator_alloc_region(context)->get() == NULL, - err_msg("Must not have a mutator alloc region if there is no memory, but is " PTR_FORMAT, p2i(mutator_alloc_region(context)->get()))); + "Must not have a mutator alloc region if there is no memory, but is " PTR_FORMAT, p2i(mutator_alloc_region(context)->get())); return result; } diff --git a/hotspot/src/share/vm/gc/g1/g1BiasedArray.cpp b/hotspot/src/share/vm/gc/g1/g1BiasedArray.cpp index adb573ba66e..002864dd64b 100644 --- a/hotspot/src/share/vm/gc/g1/g1BiasedArray.cpp +++ b/hotspot/src/share/vm/gc/g1/g1BiasedArray.cpp @@ -36,19 +36,21 @@ address G1BiasedMappedArrayBase::create_new_base_array(size_t length, size_t ele #ifndef PRODUCT void G1BiasedMappedArrayBase::verify_index(idx_t index) const { guarantee(_base != NULL, "Array not initialized"); - guarantee(index < length(), err_msg("Index out of bounds index: " SIZE_FORMAT " length: " SIZE_FORMAT, index, length())); + guarantee(index < length(), "Index out of bounds index: " SIZE_FORMAT " length: " SIZE_FORMAT, index, length()); } void G1BiasedMappedArrayBase::verify_biased_index(idx_t biased_index) const { guarantee(_biased_base != NULL, "Array not initialized"); guarantee(biased_index >= bias() && biased_index < (bias() + length()), - err_msg("Biased index out of bounds, index: " SIZE_FORMAT " bias: " SIZE_FORMAT " length: " SIZE_FORMAT, biased_index, bias(), length())); + "Biased index out of bounds, index: " SIZE_FORMAT " bias: " SIZE_FORMAT " length: " SIZE_FORMAT, + biased_index, bias(), length()); } void G1BiasedMappedArrayBase::verify_biased_index_inclusive_end(idx_t biased_index) const { guarantee(_biased_base != NULL, "Array not initialized"); guarantee(biased_index >= bias() && biased_index <= (bias() + length()), - err_msg("Biased index out of inclusive bounds, index: " SIZE_FORMAT " bias: " SIZE_FORMAT " length: " SIZE_FORMAT, biased_index, bias(), length())); + "Biased index out of inclusive bounds, index: " SIZE_FORMAT " bias: " SIZE_FORMAT " length: " SIZE_FORMAT, + biased_index, bias(), length()); } class TestMappedArray : public G1BiasedMappedArray { @@ -65,7 +67,7 @@ public: REGION_SIZE_IN_WORDS * HeapWordSize); // Check address calculation (bounds) assert(array.bottom_address_mapped() == fake_heap, - err_msg("bottom mapped address should be " PTR_FORMAT ", but is " PTR_FORMAT, p2i(fake_heap), p2i(array.bottom_address_mapped()))); + "bottom mapped address should be " PTR_FORMAT ", but is " PTR_FORMAT, p2i(fake_heap), p2i(array.bottom_address_mapped())); assert(array.end_address_mapped() == (fake_heap + REGION_SIZE_IN_WORDS * NUM_REGIONS), "must be"); int* bottom = array.address_mapped_to(fake_heap); diff --git a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp index a5effbcde2e..42069703b27 100644 --- a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp +++ b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp @@ -56,7 +56,7 @@ protected: void initialize_base(address base, size_t length, size_t bias, size_t elem_size, uint shift_by) { assert(base != NULL, "just checking"); assert(length > 0, "just checking"); - assert(shift_by < sizeof(uintptr_t) * 8, err_msg("Shifting by %u, larger than word size?", shift_by)); + assert(shift_by < sizeof(uintptr_t) * 8, "Shifting by %u, larger than word size?", shift_by); _base = base; _length = length; _biased_base = base - (bias * elem_size); @@ -69,13 +69,13 @@ protected: void initialize(HeapWord* bottom, HeapWord* end, size_t target_elem_size_in_bytes, size_t mapping_granularity_in_bytes) { assert(mapping_granularity_in_bytes > 0, "just checking"); assert(is_power_of_2(mapping_granularity_in_bytes), - err_msg("mapping granularity must be power of 2, is %zd", mapping_granularity_in_bytes)); + "mapping granularity must be power of 2, is %zd", mapping_granularity_in_bytes); assert((uintptr_t)bottom % mapping_granularity_in_bytes == 0, - err_msg("bottom mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, - mapping_granularity_in_bytes, p2i(bottom))); + "bottom mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, + mapping_granularity_in_bytes, p2i(bottom)); assert((uintptr_t)end % mapping_granularity_in_bytes == 0, - err_msg("end mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, - mapping_granularity_in_bytes, p2i(end))); + "end mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, + mapping_granularity_in_bytes, p2i(end)); size_t num_target_elems = pointer_delta(end, bottom, mapping_granularity_in_bytes); idx_t bias = (uintptr_t)bottom / mapping_granularity_in_bytes; address base = create_new_base_array(num_target_elems, target_elem_size_in_bytes); diff --git a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp index 3deaefdfe59..276260534c3 100644 --- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp +++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp @@ -69,14 +69,14 @@ bool G1BlockOffsetSharedArray::is_card_boundary(HeapWord* p) const { #ifdef ASSERT void G1BlockOffsetSharedArray::check_index(size_t index, const char* msg) const { assert((index) < (_reserved.word_size() >> LogN_words), - err_msg("%s - index: " SIZE_FORMAT ", _vs.committed_size: " SIZE_FORMAT, - msg, (index), (_reserved.word_size() >> LogN_words))); + "%s - index: " SIZE_FORMAT ", _vs.committed_size: " SIZE_FORMAT, + msg, (index), (_reserved.word_size() >> LogN_words)); assert(G1CollectedHeap::heap()->is_in_exact(address_for_index_raw(index)), - err_msg("Index " SIZE_FORMAT " corresponding to " PTR_FORMAT - " (%u) is not in committed area.", - (index), - p2i(address_for_index_raw(index)), - G1CollectedHeap::heap()->addr_to_region(address_for_index_raw(index)))); + "Index " SIZE_FORMAT " corresponding to " PTR_FORMAT + " (%u) is not in committed area.", + (index), + p2i(address_for_index_raw(index)), + G1CollectedHeap::heap()->addr_to_region(address_for_index_raw(index))); } #endif // ASSERT @@ -192,27 +192,27 @@ void G1BlockOffsetArray::check_all_cards(size_t start_card, size_t end_card) con u_char entry = _array->offset_array(c); if (c - start_card > BlockOffsetArray::power_to_cards_back(1)) { guarantee(entry > N_words, - err_msg("Should be in logarithmic region - " - "entry: %u, " - "_array->offset_array(c): %u, " - "N_words: %u", - (uint)entry, (uint)_array->offset_array(c), (uint)N_words)); + "Should be in logarithmic region - " + "entry: %u, " + "_array->offset_array(c): %u, " + "N_words: %u", + (uint)entry, (uint)_array->offset_array(c), (uint)N_words); } size_t backskip = BlockOffsetArray::entry_to_cards_back(entry); size_t landing_card = c - backskip; guarantee(landing_card >= (start_card - 1), "Inv"); if (landing_card >= start_card) { guarantee(_array->offset_array(landing_card) <= entry, - err_msg("Monotonicity - landing_card offset: %u, " - "entry: %u", - (uint)_array->offset_array(landing_card), (uint)entry)); + "Monotonicity - landing_card offset: %u, " + "entry: %u", + (uint)_array->offset_array(landing_card), (uint)entry); } else { guarantee(landing_card == start_card - 1, "Tautology"); // Note that N_words is the maximum offset value guarantee(_array->offset_array(landing_card) <= N_words, - err_msg("landing card offset: %u, " - "N_words: %u", - (uint)_array->offset_array(landing_card), (uint)N_words)); + "landing card offset: %u, " + "N_words: %u", + (uint)_array->offset_array(landing_card), (uint)N_words); } } } @@ -271,9 +271,9 @@ G1BlockOffsetArray::forward_to_block_containing_addr_slow(HeapWord* q, HeapWord* next_boundary = _array->address_for_index(n_index) + (n_index == next_index ? 0 : N_words); assert(next_boundary <= _array->_end, - err_msg("next_boundary is beyond the end of the covered region " - " next_boundary " PTR_FORMAT " _array->_end " PTR_FORMAT, - p2i(next_boundary), p2i(_array->_end))); + "next_boundary is beyond the end of the covered region " + " next_boundary " PTR_FORMAT " _array->_end " PTR_FORMAT, + p2i(next_boundary), p2i(_array->_end)); if (addr >= gsp()->top()) return gsp()->top(); while (next_boundary < addr) { while (n <= next_boundary) { @@ -361,25 +361,23 @@ void G1BlockOffsetArray::alloc_block_work2(HeapWord** threshold_, size_t* index_ // is checked by an assertion above. size_t start_index = _array->index_for(blk_start); HeapWord* boundary = _array->address_for_index(start_index); - assert((_array->offset_array(orig_index) == 0 && - blk_start == boundary) || - (_array->offset_array(orig_index) > 0 && - _array->offset_array(orig_index) <= N_words), - err_msg("offset array should have been set - " - "orig_index offset: %u, " - "blk_start: " PTR_FORMAT ", " - "boundary: " PTR_FORMAT, - (uint)_array->offset_array(orig_index), - p2i(blk_start), p2i(boundary))); + assert((_array->offset_array(orig_index) == 0 && blk_start == boundary) || + (_array->offset_array(orig_index) > 0 && _array->offset_array(orig_index) <= N_words), + "offset array should have been set - " + "orig_index offset: %u, " + "blk_start: " PTR_FORMAT ", " + "boundary: " PTR_FORMAT, + (uint)_array->offset_array(orig_index), + p2i(blk_start), p2i(boundary)); for (size_t j = orig_index + 1; j <= end_index; j++) { assert(_array->offset_array(j) > 0 && _array->offset_array(j) <= (u_char) (N_words+BlockOffsetArray::N_powers-1), - err_msg("offset array should have been set - " - "%u not > 0 OR %u not <= %u", - (uint) _array->offset_array(j), - (uint) _array->offset_array(j), - (uint) (N_words+BlockOffsetArray::N_powers-1))); + "offset array should have been set - " + "%u not > 0 OR %u not <= %u", + (uint) _array->offset_array(j), + (uint) _array->offset_array(j), + (uint) (N_words+BlockOffsetArray::N_powers-1)); } #endif } @@ -402,8 +400,8 @@ void G1BlockOffsetArray::verify() const { size_t obj_size = block_size(obj); obj_end = obj + obj_size; guarantee(obj_end > obj && obj_end <= gsp()->top(), - err_msg("Invalid object end. obj: " PTR_FORMAT " obj_size: " SIZE_FORMAT " obj_end: " PTR_FORMAT " top: " PTR_FORMAT, - p2i(obj), obj_size, p2i(obj_end), p2i(gsp()->top()))); + "Invalid object end. obj: " PTR_FORMAT " obj_size: " SIZE_FORMAT " obj_end: " PTR_FORMAT " top: " PTR_FORMAT, + p2i(obj), obj_size, p2i(obj_end), p2i(gsp()->top())); } } else { // Because we refine the BOT based on which cards are dirty there is not much we can verify here. @@ -414,13 +412,13 @@ void G1BlockOffsetArray::verify() const { size_t max_backskip = current_card - start_card; guarantee(backskip <= max_backskip, - err_msg("Going backwards beyond the start_card. start_card: " SIZE_FORMAT " current_card: " SIZE_FORMAT " backskip: " SIZE_FORMAT, - start_card, current_card, backskip)); + "Going backwards beyond the start_card. start_card: " SIZE_FORMAT " current_card: " SIZE_FORMAT " backskip: " SIZE_FORMAT, + start_card, current_card, backskip); HeapWord* backskip_address = _array->address_for_index(current_card - backskip); guarantee(backskip_address >= gsp()->bottom(), - err_msg("Going backwards beyond bottom of the region: bottom: " PTR_FORMAT ", backskip_address: " PTR_FORMAT, - p2i(gsp()->bottom()), p2i(backskip_address))); + "Going backwards beyond bottom of the region: bottom: " PTR_FORMAT ", backskip_address: " PTR_FORMAT, + p2i(gsp()->bottom()), p2i(backskip_address)); } } } diff --git a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp index 96f5a89d260..095054b376e 100644 --- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp +++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp @@ -80,8 +80,8 @@ public: virtual void set_bottom(HeapWord* new_bottom) { assert(new_bottom <= _end, - err_msg("new_bottom (" PTR_FORMAT ") > _end (" PTR_FORMAT ")", - p2i(new_bottom), p2i(_end))); + "new_bottom (" PTR_FORMAT ") > _end (" PTR_FORMAT ")", + p2i(new_bottom), p2i(_end)); _bottom = new_bottom; resize(pointer_delta(_end, _bottom)); } @@ -149,9 +149,8 @@ private: void check_offset(size_t offset, const char* msg) const { assert(offset <= N_words, - err_msg("%s - " - "offset: " SIZE_FORMAT ", N_words: %u", - msg, offset, (uint)N_words)); + "%s - offset: " SIZE_FORMAT ", N_words: %u", + msg, offset, (uint)N_words); } // Bounds checking accessors: diff --git a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp index c594fae33ec..ac854a4e70c 100644 --- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp @@ -81,8 +81,8 @@ inline size_t G1BlockOffsetSharedArray::index_for(const void* p) const { char* pc = (char*)p; assert(pc >= (char*)_reserved.start() && pc < (char*)_reserved.end(), - err_msg("p (" PTR_FORMAT ") not in reserved [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(p), p2i(_reserved.start()), p2i(_reserved.end()))); + "p (" PTR_FORMAT ") not in reserved [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(p), p2i(_reserved.start()), p2i(_reserved.end())); size_t result = index_for_raw(p); check_index(result, "bad index from address"); return result; @@ -93,10 +93,9 @@ G1BlockOffsetSharedArray::address_for_index(size_t index) const { check_index(index, "index out of range"); HeapWord* result = address_for_index_raw(index); assert(result >= _reserved.start() && result < _reserved.end(), - err_msg("bad address from index result " PTR_FORMAT - " _reserved.start() " PTR_FORMAT " _reserved.end() " - PTR_FORMAT, - p2i(result), p2i(_reserved.start()), p2i(_reserved.end()))); + "bad address from index result " PTR_FORMAT + " _reserved.start() " PTR_FORMAT " _reserved.end() " PTR_FORMAT, + p2i(result), p2i(_reserved.start()), p2i(_reserved.end())); return result; } diff --git a/hotspot/src/share/vm/gc/g1/g1CardCounts.cpp b/hotspot/src/share/vm/gc/g1/g1CardCounts.cpp index 90117ee1624..af078c2b9b8 100644 --- a/hotspot/src/share/vm/gc/g1/g1CardCounts.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CardCounts.cpp @@ -53,8 +53,8 @@ size_t G1CardCounts::heap_map_factor() { void G1CardCounts::clear_range(size_t from_card_num, size_t to_card_num) { if (has_count_table()) { assert(from_card_num < to_card_num, - err_msg("Wrong order? from: " SIZE_FORMAT ", to: " SIZE_FORMAT, - from_card_num, to_card_num)); + "Wrong order? from: " SIZE_FORMAT ", to: " SIZE_FORMAT, + from_card_num, to_card_num); Copy::fill_to_bytes(&_card_counts[from_card_num], (to_card_num - from_card_num)); } } @@ -96,8 +96,8 @@ uint G1CardCounts::add_card_count(jbyte* card_ptr) { if (has_count_table()) { size_t card_num = ptr_2_card_num(card_ptr); assert(card_num < _reserved_max_card_num, - err_msg("Card " SIZE_FORMAT " outside of card counts table (max size " SIZE_FORMAT ")", - card_num, _reserved_max_card_num)); + "Card " SIZE_FORMAT " outside of card counts table (max size " SIZE_FORMAT ")", + card_num, _reserved_max_card_num); count = (uint) _card_counts[card_num]; if (count < G1ConcRSHotCardLimit) { _card_counts[card_num] = diff --git a/hotspot/src/share/vm/gc/g1/g1CardCounts.hpp b/hotspot/src/share/vm/gc/g1/g1CardCounts.hpp index e23a2986d61..60b6f3dd2f5 100644 --- a/hotspot/src/share/vm/gc/g1/g1CardCounts.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CardCounts.hpp @@ -79,19 +79,19 @@ class G1CardCounts: public CHeapObj { size_t ptr_2_card_num(const jbyte* card_ptr) { assert(card_ptr >= _ct_bot, - err_msg("Invalid card pointer: " - "card_ptr: " PTR_FORMAT ", " - "_ct_bot: " PTR_FORMAT, - p2i(card_ptr), p2i(_ct_bot))); + "Invalid card pointer: " + "card_ptr: " PTR_FORMAT ", " + "_ct_bot: " PTR_FORMAT, + p2i(card_ptr), p2i(_ct_bot)); size_t card_num = pointer_delta(card_ptr, _ct_bot, sizeof(jbyte)); assert(card_num < _reserved_max_card_num, - err_msg("card pointer out of range: " PTR_FORMAT, p2i(card_ptr))); + "card pointer out of range: " PTR_FORMAT, p2i(card_ptr)); return card_num; } jbyte* card_num_2_ptr(size_t card_num) { assert(card_num < _reserved_max_card_num, - err_msg("card num out of range: " SIZE_FORMAT, card_num)); + "card num out of range: " SIZE_FORMAT, card_num); return (jbyte*) (_ct_bot + card_num); } diff --git a/hotspot/src/share/vm/gc/g1/g1CodeBlobClosure.hpp b/hotspot/src/share/vm/gc/g1/g1CodeBlobClosure.hpp index bdbf5835a79..e3c9c30d19f 100644 --- a/hotspot/src/share/vm/gc/g1/g1CodeBlobClosure.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CodeBlobClosure.hpp @@ -22,6 +22,9 @@ * */ +#ifndef SHARE_VM_GC_G1_G1CODEBLOBCLOSURE_HPP +#define SHARE_VM_GC_G1_G1CODEBLOBCLOSURE_HPP + #include "gc/g1/g1CollectedHeap.hpp" #include "memory/iterator.hpp" @@ -53,3 +56,6 @@ public: void do_code_blob(CodeBlob* cb); }; + +#endif // SHARE_VM_GC_G1_G1CODEBLOBCLOSURE_HPP + diff --git a/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp b/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp index 9eda0b888b8..4180191ea0d 100644 --- a/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp @@ -197,7 +197,9 @@ CodeRootSetTable* G1CodeRootSet::load_acquire_table() { } void G1CodeRootSet::allocate_small_table() { - _table = new CodeRootSetTable(SmallSize); + CodeRootSetTable* temp = new CodeRootSetTable(SmallSize); + + OrderAccess::release_store_ptr(&_table, temp); } void CodeRootSetTable::purge_list_append(CodeRootSetTable* table) { @@ -350,11 +352,11 @@ class G1CodeRootSetTest { assert(set1.is_empty(), "Code root set must be initially empty but is not."); assert(G1CodeRootSet::static_mem_size() == sizeof(void*), - err_msg("The code root set's static memory usage is incorrect, " SIZE_FORMAT " bytes", G1CodeRootSet::static_mem_size())); + "The code root set's static memory usage is incorrect, " SIZE_FORMAT " bytes", G1CodeRootSet::static_mem_size()); set1.add((nmethod*)1); - assert(set1.length() == 1, err_msg("Added exactly one element, but set contains " - SIZE_FORMAT " elements", set1.length())); + assert(set1.length() == 1, "Added exactly one element, but set contains " + SIZE_FORMAT " elements", set1.length()); const size_t num_to_add = (size_t)G1CodeRootSet::Threshold + 1; @@ -362,16 +364,16 @@ class G1CodeRootSetTest { set1.add((nmethod*)1); } assert(set1.length() == 1, - err_msg("Duplicate detection should not have increased the set size but " - "is " SIZE_FORMAT, set1.length())); + "Duplicate detection should not have increased the set size but " + "is " SIZE_FORMAT, set1.length()); for (size_t i = 2; i <= num_to_add; i++) { set1.add((nmethod*)(uintptr_t)(i)); } assert(set1.length() == num_to_add, - err_msg("After adding in total " SIZE_FORMAT " distinct code roots, they " - "need to be in the set, but there are only " SIZE_FORMAT, - num_to_add, set1.length())); + "After adding in total " SIZE_FORMAT " distinct code roots, they " + "need to be in the set, but there are only " SIZE_FORMAT, + num_to_add, set1.length()); assert(CodeRootSetTable::_purge_list != NULL, "should have grown to large hashtable"); @@ -385,8 +387,8 @@ class G1CodeRootSetTest { } } assert(num_popped == num_to_add, - err_msg("Managed to pop " SIZE_FORMAT " code roots, but only " SIZE_FORMAT " " - "were added", num_popped, num_to_add)); + "Managed to pop " SIZE_FORMAT " code roots, but only " SIZE_FORMAT " " + "were added", num_popped, num_to_add); assert(CodeRootSetTable::_purge_list != NULL, "should have grown to large hashtable"); G1CodeRootSet::purge(); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 2ba451f94d7..4b36a61ff68 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -44,6 +44,7 @@ #include "gc/g1/g1ParScanThreadState.inline.hpp" #include "gc/g1/g1RegionToSpaceMapper.hpp" #include "gc/g1/g1RemSet.inline.hpp" +#include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1RootProcessor.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/g1YCTypes.hpp" @@ -53,6 +54,7 @@ #include "gc/g1/suspendibleThreadSet.hpp" #include "gc/g1/vm_operations_g1.hpp" #include "gc/shared/gcHeapSummary.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" @@ -124,213 +126,6 @@ class RedirtyLoggedCardTableEntryClosure : public CardTableEntryClosure { size_t num_processed() const { return _num_processed; } }; -YoungList::YoungList(G1CollectedHeap* g1h) : - _g1h(g1h), _head(NULL), _length(0), _last_sampled_rs_lengths(0), - _survivor_head(NULL), _survivor_tail(NULL), _survivor_length(0) { - guarantee(check_list_empty(false), "just making sure..."); -} - -void YoungList::push_region(HeapRegion *hr) { - assert(!hr->is_young(), "should not already be young"); - assert(hr->get_next_young_region() == NULL, "cause it should!"); - - hr->set_next_young_region(_head); - _head = hr; - - _g1h->g1_policy()->set_region_eden(hr, (int) _length); - ++_length; -} - -void YoungList::add_survivor_region(HeapRegion* hr) { - assert(hr->is_survivor(), "should be flagged as survivor region"); - assert(hr->get_next_young_region() == NULL, "cause it should!"); - - hr->set_next_young_region(_survivor_head); - if (_survivor_head == NULL) { - _survivor_tail = hr; - } - _survivor_head = hr; - ++_survivor_length; -} - -void YoungList::empty_list(HeapRegion* list) { - while (list != NULL) { - HeapRegion* next = list->get_next_young_region(); - list->set_next_young_region(NULL); - list->uninstall_surv_rate_group(); - // This is called before a Full GC and all the non-empty / - // non-humongous regions at the end of the Full GC will end up as - // old anyway. - list->set_old(); - list = next; - } -} - -void YoungList::empty_list() { - assert(check_list_well_formed(), "young list should be well formed"); - - empty_list(_head); - _head = NULL; - _length = 0; - - empty_list(_survivor_head); - _survivor_head = NULL; - _survivor_tail = NULL; - _survivor_length = 0; - - _last_sampled_rs_lengths = 0; - - assert(check_list_empty(false), "just making sure..."); -} - -bool YoungList::check_list_well_formed() { - bool ret = true; - - uint length = 0; - HeapRegion* curr = _head; - HeapRegion* last = NULL; - while (curr != NULL) { - if (!curr->is_young()) { - gclog_or_tty->print_cr("### YOUNG REGION " PTR_FORMAT "-" PTR_FORMAT " " - "incorrectly tagged (y: %d, surv: %d)", - p2i(curr->bottom()), p2i(curr->end()), - curr->is_young(), curr->is_survivor()); - ret = false; - } - ++length; - last = curr; - curr = curr->get_next_young_region(); - } - ret = ret && (length == _length); - - if (!ret) { - gclog_or_tty->print_cr("### YOUNG LIST seems not well formed!"); - gclog_or_tty->print_cr("### list has %u entries, _length is %u", - length, _length); - } - - return ret; -} - -bool YoungList::check_list_empty(bool check_sample) { - bool ret = true; - - if (_length != 0) { - gclog_or_tty->print_cr("### YOUNG LIST should have 0 length, not %u", - _length); - ret = false; - } - if (check_sample && _last_sampled_rs_lengths != 0) { - gclog_or_tty->print_cr("### YOUNG LIST has non-zero last sampled RS lengths"); - ret = false; - } - if (_head != NULL) { - gclog_or_tty->print_cr("### YOUNG LIST does not have a NULL head"); - ret = false; - } - if (!ret) { - gclog_or_tty->print_cr("### YOUNG LIST does not seem empty"); - } - - return ret; -} - -void -YoungList::rs_length_sampling_init() { - _sampled_rs_lengths = 0; - _curr = _head; -} - -bool -YoungList::rs_length_sampling_more() { - return _curr != NULL; -} - -void -YoungList::rs_length_sampling_next() { - assert( _curr != NULL, "invariant" ); - size_t rs_length = _curr->rem_set()->occupied(); - - _sampled_rs_lengths += rs_length; - - // The current region may not yet have been added to the - // incremental collection set (it gets added when it is - // retired as the current allocation region). - if (_curr->in_collection_set()) { - // Update the collection set policy information for this region - _g1h->g1_policy()->update_incremental_cset_info(_curr, rs_length); - } - - _curr = _curr->get_next_young_region(); - if (_curr == NULL) { - _last_sampled_rs_lengths = _sampled_rs_lengths; - // gclog_or_tty->print_cr("last sampled RS lengths = %d", _last_sampled_rs_lengths); - } -} - -void -YoungList::reset_auxilary_lists() { - guarantee( is_empty(), "young list should be empty" ); - assert(check_list_well_formed(), "young list should be well formed"); - - // Add survivor regions to SurvRateGroup. - _g1h->g1_policy()->note_start_adding_survivor_regions(); - _g1h->g1_policy()->finished_recalculating_age_indexes(true /* is_survivors */); - - int young_index_in_cset = 0; - for (HeapRegion* curr = _survivor_head; - curr != NULL; - curr = curr->get_next_young_region()) { - _g1h->g1_policy()->set_region_survivor(curr, young_index_in_cset); - - // The region is a non-empty survivor so let's add it to - // the incremental collection set for the next evacuation - // pause. - _g1h->g1_policy()->add_region_to_incremental_cset_rhs(curr); - young_index_in_cset += 1; - } - assert((uint) young_index_in_cset == _survivor_length, "post-condition"); - _g1h->g1_policy()->note_stop_adding_survivor_regions(); - - _head = _survivor_head; - _length = _survivor_length; - if (_survivor_head != NULL) { - assert(_survivor_tail != NULL, "cause it shouldn't be"); - assert(_survivor_length > 0, "invariant"); - _survivor_tail->set_next_young_region(NULL); - } - - // Don't clear the survivor list handles until the start of - // the next evacuation pause - we need it in order to re-tag - // the survivor regions from this evacuation pause as 'young' - // at the start of the next. - - _g1h->g1_policy()->finished_recalculating_age_indexes(false /* is_survivors */); - - assert(check_list_well_formed(), "young list should be well formed"); -} - -void YoungList::print() { - HeapRegion* lists[] = {_head, _survivor_head}; - const char* names[] = {"YOUNG", "SURVIVOR"}; - - for (uint list = 0; list < ARRAY_SIZE(lists); ++list) { - gclog_or_tty->print_cr("%s LIST CONTENTS", names[list]); - HeapRegion *curr = lists[list]; - if (curr == NULL) - gclog_or_tty->print_cr(" empty"); - while (curr != NULL) { - gclog_or_tty->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT ", N: " PTR_FORMAT ", age: %4d", - HR_FORMAT_PARAMS(curr), - p2i(curr->prev_top_at_mark_start()), - p2i(curr->next_top_at_mark_start()), - curr->age_in_surv_rate_group_cond()); - curr = curr->get_next_young_region(); - } - } - - gclog_or_tty->cr(); -} void G1RegionMappingChangedListener::reset_from_card_cache(uint start_idx, size_t num_regions) { HeapRegionRemSet::invalidate_from_card_cache(start_idx, num_regions); @@ -971,11 +766,11 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) { size_t commits = 0; guarantee(reserved.contains(start_address) && reserved.contains(last_address), - err_msg("MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", - p2i(start_address), p2i(last_address))); + "MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", + p2i(start_address), p2i(last_address)); guarantee(start_address > prev_last_addr, - err_msg("Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , - p2i(start_address), p2i(prev_last_addr))); + "Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , + p2i(start_address), p2i(prev_last_addr)); prev_last_addr = last_address; // Check for ranges that start in the same G1 region in which the previous @@ -1017,7 +812,7 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) { while (curr_region != NULL) { assert(curr_region->is_empty() && !curr_region->is_pinned(), - err_msg("Region already in use (index %u)", curr_region->hrm_index())); + "Region already in use (index %u)", curr_region->hrm_index()); _hr_printer.alloc(curr_region, G1HRPrinter::Archive); curr_region->set_allocation_context(AllocationContext::system()); curr_region->set_archive(); @@ -1055,11 +850,11 @@ void G1CollectedHeap::fill_archive_regions(MemRegion* ranges, size_t count) { HeapWord* last_address = ranges[i].last(); assert(reserved.contains(start_address) && reserved.contains(last_address), - err_msg("MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", - p2i(start_address), p2i(last_address))); + "MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", + p2i(start_address), p2i(last_address)); assert(start_address > prev_last_addr, - err_msg("Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , - p2i(start_address), p2i(prev_last_addr))); + "Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , + p2i(start_address), p2i(prev_last_addr)); HeapRegion* start_region = _hrm.addr_to_region(start_address); HeapRegion* last_region = _hrm.addr_to_region(last_address); @@ -1076,7 +871,7 @@ void G1CollectedHeap::fill_archive_regions(MemRegion* ranges, size_t count) { HeapRegion* curr_region = start_region; while (curr_region != NULL) { guarantee(curr_region->is_archive(), - err_msg("Expected archive region at index %u", curr_region->hrm_index())); + "Expected archive region at index %u", curr_region->hrm_index()); if (curr_region != last_region) { curr_region = _hrm.next_region_in_heap(curr_region); } else { @@ -1139,11 +934,11 @@ void G1CollectedHeap::dealloc_archive_regions(MemRegion* ranges, size_t count) { HeapWord* last_address = ranges[i].last(); assert(reserved.contains(start_address) && reserved.contains(last_address), - err_msg("MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", - p2i(start_address), p2i(last_address))); + "MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", + p2i(start_address), p2i(last_address)); assert(start_address > prev_last_addr, - err_msg("Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , - p2i(start_address), p2i(prev_last_addr))); + "Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , + p2i(start_address), p2i(prev_last_addr)); size_used += ranges[i].byte_size(); prev_last_addr = last_address; @@ -1168,7 +963,7 @@ void G1CollectedHeap::dealloc_archive_regions(MemRegion* ranges, size_t count) { HeapRegion* curr_region = start_region; while (curr_region != NULL) { guarantee(curr_region->is_archive(), - err_msg("Expected archive region at index %u", curr_region->hrm_index())); + "Expected archive region at index %u", curr_region->hrm_index()); uint curr_index = curr_region->hrm_index(); _old_set.remove(curr_region); curr_region->set_free(); @@ -1450,6 +1245,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, gc_timer->register_gc_start(); SerialOldTracer* gc_tracer = G1MarkSweep::gc_tracer(); + GCIdMark gc_id_mark; gc_tracer->report_gc_start(gc_cause(), gc_timer->gc_start()); SvcGCMarker sgcm(SvcGCMarker::FULL); @@ -1476,7 +1272,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); { - GCTraceTime t(GCCauseString("Full GC", gc_cause()), G1Log::fine(), true, NULL, gc_tracer->gc_id()); + GCTraceTime t(GCCauseString("Full GC", gc_cause()), G1Log::fine(), true, NULL); TraceCollectorStats tcs(g1mm()->full_collection_counters()); TraceMemoryManagerStats tms(true /* fullGC */, gc_cause()); @@ -1507,7 +1303,9 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, check_bitmaps("Full GC Start"); pre_full_gc_dump(gc_timer); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif // Disable discovery and empty the discovered lists // for the CM ref processor. @@ -1567,7 +1365,9 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, // not been removed from the discovered lists. ref_processor_stw()->enqueue_discovered_references(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif MemoryService::track_memory_usage(); @@ -1755,9 +1555,9 @@ resize_if_necessary_after_full_collection(size_t word_size) { // This assert only makes sense here, before we adjust them // with respect to the min and max heap size. assert(minimum_desired_capacity <= maximum_desired_capacity, - err_msg("minimum_desired_capacity = " SIZE_FORMAT ", " - "maximum_desired_capacity = " SIZE_FORMAT, - minimum_desired_capacity, maximum_desired_capacity)); + "minimum_desired_capacity = " SIZE_FORMAT ", " + "maximum_desired_capacity = " SIZE_FORMAT, + minimum_desired_capacity, maximum_desired_capacity); // Should not be greater than the heap max size. No need to adjust // it with respect to the heap min size as it's a lower bound (i.e., @@ -1799,21 +1599,20 @@ resize_if_necessary_after_full_collection(size_t word_size) { } } - -HeapWord* -G1CollectedHeap::satisfy_failed_allocation(size_t word_size, - AllocationContext_t context, - bool* succeeded) { - assert_at_safepoint(true /* should_be_vm_thread */); - - *succeeded = true; +HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, + AllocationContext_t context, + bool do_gc, + bool clear_all_soft_refs, + bool expect_null_mutator_alloc_region, + bool* gc_succeeded) { + *gc_succeeded = true; // Let's attempt the allocation first. HeapWord* result = attempt_allocation_at_safepoint(word_size, context, - false /* expect_null_mutator_alloc_region */); + expect_null_mutator_alloc_region); if (result != NULL) { - assert(*succeeded, "sanity"); + assert(*gc_succeeded, "sanity"); return result; } @@ -1823,41 +1622,58 @@ G1CollectedHeap::satisfy_failed_allocation(size_t word_size, // do something smarter than full collection to satisfy a failed alloc.) result = expand_and_allocate(word_size, context); if (result != NULL) { - assert(*succeeded, "sanity"); + assert(*gc_succeeded, "sanity"); return result; } - // Expansion didn't work, we'll try to do a Full GC. - bool gc_succeeded = do_collection(false, /* explicit_gc */ - false, /* clear_all_soft_refs */ - word_size); - if (!gc_succeeded) { - *succeeded = false; - return NULL; + if (do_gc) { + // Expansion didn't work, we'll try to do a Full GC. + *gc_succeeded = do_collection(false, /* explicit_gc */ + clear_all_soft_refs, + word_size); } - // Retry the allocation - result = attempt_allocation_at_safepoint(word_size, - context, - true /* expect_null_mutator_alloc_region */); - if (result != NULL) { - assert(*succeeded, "sanity"); + return NULL; +} + +HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size, + AllocationContext_t context, + bool* succeeded) { + assert_at_safepoint(true /* should_be_vm_thread */); + + // Attempts to allocate followed by Full GC. + HeapWord* result = + satisfy_failed_allocation_helper(word_size, + context, + true, /* do_gc */ + false, /* clear_all_soft_refs */ + false, /* expect_null_mutator_alloc_region */ + succeeded); + + if (result != NULL || !*succeeded) { return result; } - // Then, try a Full GC that will collect all soft references. - gc_succeeded = do_collection(false, /* explicit_gc */ - true, /* clear_all_soft_refs */ - word_size); - if (!gc_succeeded) { - *succeeded = false; - return NULL; + // Attempts to allocate followed by Full GC that will collect all soft references. + result = satisfy_failed_allocation_helper(word_size, + context, + true, /* do_gc */ + true, /* clear_all_soft_refs */ + true, /* expect_null_mutator_alloc_region */ + succeeded); + + if (result != NULL || !*succeeded) { + return result; } - // Retry the allocation once more - result = attempt_allocation_at_safepoint(word_size, - context, - true /* expect_null_mutator_alloc_region */); + // Attempts to allocate, no GC + result = satisfy_failed_allocation_helper(word_size, + context, + false, /* do_gc */ + false, /* clear_all_soft_refs */ + true, /* expect_null_mutator_alloc_region */ + succeeded); + if (result != NULL) { assert(*succeeded, "sanity"); return result; @@ -2447,14 +2263,11 @@ void G1CollectedHeap::check_gc_time_stamps() { } #endif // PRODUCT -void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl, - DirtyCardQueue* into_cset_dcq, - bool concurrent, - uint worker_i) { - // Clean cards in the hot card cache - G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache(); - hot_card_cache->drain(worker_i, g1_rem_set(), into_cset_dcq); +void G1CollectedHeap::iterate_hcc_closure(CardTableEntryClosure* cl, uint worker_i) { + _cg1r->hot_card_cache()->drain(cl, worker_i); +} +void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl, uint worker_i) { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); size_t n_completed_buffers = 0; while (dcqs.apply_closure_to_completed_buffer(cl, worker_i, 0, true)) { @@ -2538,9 +2351,9 @@ void G1CollectedHeap::allocate_dummy_regions() { void G1CollectedHeap::increment_old_marking_cycles_started() { assert(_old_marking_cycles_started == _old_marking_cycles_completed || - _old_marking_cycles_started == _old_marking_cycles_completed + 1, - err_msg("Wrong marking cycle count (started: %d, completed: %d)", - _old_marking_cycles_started, _old_marking_cycles_completed)); + _old_marking_cycles_started == _old_marking_cycles_completed + 1, + "Wrong marking cycle count (started: %d, completed: %d)", + _old_marking_cycles_started, _old_marking_cycles_completed); _old_marking_cycles_started++; } @@ -2564,17 +2377,17 @@ void G1CollectedHeap::increment_old_marking_cycles_completed(bool concurrent) { assert(concurrent || (_old_marking_cycles_started == _old_marking_cycles_completed + 1) || (_old_marking_cycles_started == _old_marking_cycles_completed + 2), - err_msg("for inner caller (Full GC): _old_marking_cycles_started = %u " - "is inconsistent with _old_marking_cycles_completed = %u", - _old_marking_cycles_started, _old_marking_cycles_completed)); + "for inner caller (Full GC): _old_marking_cycles_started = %u " + "is inconsistent with _old_marking_cycles_completed = %u", + _old_marking_cycles_started, _old_marking_cycles_completed); // This is the case for the outer caller, i.e. the concurrent cycle. assert(!concurrent || (_old_marking_cycles_started == _old_marking_cycles_completed + 1), - err_msg("for outer caller (concurrent cycle): " - "_old_marking_cycles_started = %u " - "is inconsistent with _old_marking_cycles_completed = %u", - _old_marking_cycles_started, _old_marking_cycles_completed)); + "for outer caller (concurrent cycle): " + "_old_marking_cycles_started = %u " + "is inconsistent with _old_marking_cycles_completed = %u", + _old_marking_cycles_started, _old_marking_cycles_completed); _old_marking_cycles_completed += 1; @@ -2594,15 +2407,18 @@ void G1CollectedHeap::increment_old_marking_cycles_completed(bool concurrent) { } void G1CollectedHeap::register_concurrent_cycle_start(const Ticks& start_time) { + GCIdMarkAndRestore conc_gc_id_mark; collector_state()->set_concurrent_cycle_started(true); _gc_timer_cm->register_gc_start(start_time); _gc_tracer_cm->report_gc_start(gc_cause(), _gc_timer_cm->gc_start()); trace_heap_before_gc(_gc_tracer_cm); + _cmThread->set_gc_id(GCId::current()); } void G1CollectedHeap::register_concurrent_cycle_end() { if (collector_state()->concurrent_cycle_started()) { + GCIdMarkAndRestore conc_gc_id_mark(_cmThread->gc_id()); if (_cm->has_aborted()) { _gc_tracer_cm->report_concurrent_mode_failure(); } @@ -2625,6 +2441,7 @@ void G1CollectedHeap::trace_heap_after_concurrent_cycle() { // but before the concurrent cycle end has been registered. // Make sure that we only send the heap information once. if (!_heap_summary_sent) { + GCIdMarkAndRestore conc_gc_id_mark(_cmThread->gc_id()); trace_heap_after_gc(_gc_tracer_cm); _heap_summary_sent = true; } @@ -3124,7 +2941,7 @@ class VerifyKlassClosure: public KlassClosure { _young_ref_counter_closure.reset_count(); k->oops_do(&_young_ref_counter_closure); if (_young_ref_counter_closure.count() > 0) { - guarantee(k->has_modified_oops(), err_msg("Klass " PTR_FORMAT ", has young refs but is not dirty.", p2i(k))); + guarantee(k->has_modified_oops(), "Klass " PTR_FORMAT ", has young refs but is not dirty.", p2i(k)); } } }; @@ -3194,8 +3011,8 @@ public: template void do_oop_work(T *p) { oop obj = oopDesc::load_decode_heap_oop(p); guarantee(obj == NULL || G1MarkSweep::in_archive_range(obj), - err_msg("Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT, - p2i(p), p2i(obj))); + "Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT, + p2i(p), p2i(obj)); } }; @@ -3630,8 +3447,9 @@ void G1CollectedHeap::gc_epilogue(bool full) { // FIXME: what is this about? // I'm ignoring the "fill_newgen()" call if "alloc_event_enabled" // is set. - COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(), - "derived pointer present")); +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_empty(), "derived pointer present"); +#endif // always_do_update_barrier = true; resize_all_tlabs(); @@ -3894,7 +3712,7 @@ void G1CollectedHeap::log_gc_header() { return; } - gclog_or_tty->gclog_stamp(_gc_tracer_stw->gc_id()); + gclog_or_tty->gclog_stamp(); GCCauseString gc_cause_str = GCCauseString("GC pause", gc_cause()) .append(collector_state()->gcs_are_young() ? "(young)" : "(mixed)") @@ -3952,6 +3770,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { _gc_timer_stw->register_gc_start(); + GCIdMark gc_id_mark; _gc_tracer_stw->report_gc_start(gc_cause(), _gc_timer_stw->gc_start()); SvcGCMarker sgcm(SvcGCMarker::MINOR); @@ -4037,7 +3856,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { check_bitmaps("GC Start"); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif // Please see comment in g1CollectedHeap.hpp and // G1CollectedHeap::ref_processing_init() to see how @@ -4325,80 +4146,6 @@ void G1CollectedHeap::preserve_mark_during_evac_failure(uint worker_id, oop obj, } } -void G1ParCopyHelper::mark_object(oop obj) { - assert(!_g1->heap_region_containing(obj)->in_collection_set(), "should not mark objects in the CSet"); - - // We know that the object is not moving so it's safe to read its size. - _cm->grayRoot(obj, (size_t) obj->size(), _worker_id); -} - -void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) { - assert(from_obj->is_forwarded(), "from obj should be forwarded"); - assert(from_obj->forwardee() == to_obj, "to obj should be the forwardee"); - assert(from_obj != to_obj, "should not be self-forwarded"); - - assert(_g1->heap_region_containing(from_obj)->in_collection_set(), "from obj should be in the CSet"); - assert(!_g1->heap_region_containing(to_obj)->in_collection_set(), "should not mark objects in the CSet"); - - // The object might be in the process of being copied by another - // worker so we cannot trust that its to-space image is - // well-formed. So we have to read its size from its from-space - // image which we know should not be changing. - _cm->grayRoot(to_obj, (size_t) from_obj->size(), _worker_id); -} - -template -void G1ParCopyHelper::do_klass_barrier(T* p, oop new_obj) { - if (_g1->heap_region_containing_raw(new_obj)->is_young()) { - _scanned_klass->record_modified_oops(); - } -} - -template -template -void G1ParCopyClosure::do_oop_work(T* p) { - T heap_oop = oopDesc::load_heap_oop(p); - - if (oopDesc::is_null(heap_oop)) { - return; - } - - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - - assert(_worker_id == _par_scan_state->worker_id(), "sanity"); - - const InCSetState state = _g1->in_cset_state(obj); - if (state.is_in_cset()) { - oop forwardee; - markOop m = obj->mark(); - if (m->is_marked()) { - forwardee = (oop) m->decode_pointer(); - } else { - forwardee = _par_scan_state->copy_to_survivor_space(state, obj, m); - } - assert(forwardee != NULL, "forwardee should not be NULL"); - oopDesc::encode_store_heap_oop(p, forwardee); - if (do_mark_object != G1MarkNone && forwardee != obj) { - // If the object is self-forwarded we don't need to explicitly - // mark it, the evacuation failure protocol will do so. - mark_forwarded_object(obj, forwardee); - } - - if (barrier == G1BarrierKlass) { - do_klass_barrier(p, forwardee); - } - } else { - if (state.is_humongous()) { - _g1->set_humongous_is_live(obj); - } - // The object is not in collection set. If we're a root scanning - // closure during an initial mark pause then attempt to mark the object. - if (do_mark_object == G1MarkFromRoot) { - mark_object(obj); - } - } -} - class G1ParEvacuateFollowersClosure : public VoidClosure { private: double _start_term; @@ -4451,32 +4198,6 @@ void G1ParEvacuateFollowersClosure::do_void() { } while (!offer_termination()); } -class G1KlassScanClosure : public KlassClosure { - G1ParCopyHelper* _closure; - bool _process_only_dirty; - int _count; - public: - G1KlassScanClosure(G1ParCopyHelper* closure, bool process_only_dirty) - : _process_only_dirty(process_only_dirty), _closure(closure), _count(0) {} - void do_klass(Klass* klass) { - // If the klass has not been dirtied we know that there's - // no references into the young gen and we can skip it. - if (!_process_only_dirty || klass->has_modified_oops()) { - // Clean the klass since we're going to scavenge all the metadata. - klass->clear_modified_oops(); - - // Tell the closure that this klass is the Klass to scavenge - // and is the one to dirty if oops are left pointing into the young gen. - _closure->set_scanned_klass(klass); - - klass->oops_do(_closure); - - _closure->set_scanned_klass(NULL); - } - _count++; - } -}; - class G1ParTask : public AbstractGangTask { protected: G1CollectedHeap* _g1h; @@ -4497,42 +4218,6 @@ public: _n_workers(n_workers) {} - RefToScanQueueSet* queues() { return _queues; } - - RefToScanQueue *work_queue(int i) { - return queues()->queue(i); - } - - ParallelTaskTerminator* terminator() { return &_terminator; } - - // Helps out with CLD processing. - // - // During InitialMark we need to: - // 1) Scavenge all CLDs for the young GC. - // 2) Mark all objects directly reachable from strong CLDs. - template - class G1CLDClosure : public CLDClosure { - G1ParCopyClosure* _oop_closure; - G1ParCopyClosure _oop_in_klass_closure; - G1KlassScanClosure _klass_in_cld_closure; - bool _claim; - - public: - G1CLDClosure(G1ParCopyClosure* oop_closure, - bool only_young, bool claim) - : _oop_closure(oop_closure), - _oop_in_klass_closure(oop_closure->g1(), - oop_closure->pss()), - _klass_in_cld_closure(&_oop_in_klass_closure, only_young), - _claim(claim) { - - } - - void do_cld(ClassLoaderData* cld) { - cld->oops_do(_oop_closure, &_klass_in_cld_closure, _claim); - } - }; - void work(uint worker_id) { if (worker_id >= _n_workers) return; // no work needed this round @@ -4548,62 +4233,18 @@ public: G1ParScanThreadState* pss = _pss->state_for_worker(worker_id); pss->set_ref_processor(rp); - bool only_young = _g1h->collector_state()->gcs_are_young(); - - // Non-IM young GC. - G1ParCopyClosure scan_only_root_cl(_g1h, pss); - G1CLDClosure scan_only_cld_cl(&scan_only_root_cl, - only_young, // Only process dirty klasses. - false); // No need to claim CLDs. - // IM young GC. - // Strong roots closures. - G1ParCopyClosure scan_mark_root_cl(_g1h, pss); - G1CLDClosure scan_mark_cld_cl(&scan_mark_root_cl, - false, // Process all klasses. - true); // Need to claim CLDs. - // Weak roots closures. - G1ParCopyClosure scan_mark_weak_root_cl(_g1h, pss); - G1CLDClosure scan_mark_weak_cld_cl(&scan_mark_weak_root_cl, - false, // Process all klasses. - true); // Need to claim CLDs. - - OopClosure* strong_root_cl; - OopClosure* weak_root_cl; - CLDClosure* strong_cld_cl; - CLDClosure* weak_cld_cl; - - bool trace_metadata = false; - - if (_g1h->collector_state()->during_initial_mark_pause()) { - // We also need to mark copied objects. - strong_root_cl = &scan_mark_root_cl; - strong_cld_cl = &scan_mark_cld_cl; - if (ClassUnloadingWithConcurrentMark) { - weak_root_cl = &scan_mark_weak_root_cl; - weak_cld_cl = &scan_mark_weak_cld_cl; - trace_metadata = true; - } else { - weak_root_cl = &scan_mark_root_cl; - weak_cld_cl = &scan_mark_cld_cl; - } - } else { - strong_root_cl = &scan_only_root_cl; - weak_root_cl = &scan_only_root_cl; - strong_cld_cl = &scan_only_cld_cl; - weak_cld_cl = &scan_only_cld_cl; - } - double start_strong_roots_sec = os::elapsedTime(); - _root_processor->evacuate_roots(strong_root_cl, - weak_root_cl, - strong_cld_cl, - weak_cld_cl, - trace_metadata, - worker_id); + + _root_processor->evacuate_roots(pss->closures(), worker_id); G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, pss); + + // We pass a weak code blobs closure to the remembered set scanning because we want to avoid + // treating the nmethods visited to act as roots for concurrent marking. + // We only want to make sure that the oops in the nmethods are adjusted with regard to the + // objects copied by the current evacuation. size_t cards_scanned = _g1h->g1_rem_set()->oops_into_collection_set_do(&push_heap_rs_cl, - weak_root_cl, + pss->closures()->weak_codeblobs(), worker_id); _pss->add_cards_scanned(worker_id, cards_scanned); @@ -4709,11 +4350,11 @@ public: ~G1StringSymbolTableUnlinkTask() { guarantee(!_process_strings || StringTable::parallel_claimed_index() >= _initial_string_table_size, - err_msg("claim value %d after unlink less than initial string table size %d", - StringTable::parallel_claimed_index(), _initial_string_table_size)); + "claim value %d after unlink less than initial string table size %d", + StringTable::parallel_claimed_index(), _initial_string_table_size); guarantee(!_process_symbols || SymbolTable::parallel_claimed_index() >= _initial_symbol_table_size, - err_msg("claim value %d after unlink less than initial symbol table size %d", - SymbolTable::parallel_claimed_index(), _initial_symbol_table_size)); + "claim value %d after unlink less than initial symbol table size %d", + SymbolTable::parallel_claimed_index(), _initial_symbol_table_size); if (G1TraceStringSymbolTableScrubbing) { gclog_or_tty->print_cr("Cleaned string and symbol table, " @@ -5113,7 +4754,7 @@ public: } else { assert(!obj->is_forwarded(), "invariant" ); assert(cset_state.is_humongous(), - err_msg("Only allowed InCSet state is IsHumongous, but is %d", cset_state.value())); + "Only allowed InCSet state is IsHumongous, but is %d", cset_state.value()); _g1->set_humongous_is_live(obj); } } @@ -5167,7 +4808,7 @@ public: _par_scan_state->push_on_queue(p); } else { assert(!Metaspace::contains((const void*)p), - err_msg("Unexpectedly found a pointer from metadata: " PTR_FORMAT, p2i(p))); + "Unexpectedly found a pointer from metadata: " PTR_FORMAT, p2i(p)); _copy_non_heap_obj_cl->do_oop(p); } } @@ -5264,19 +4905,8 @@ public: G1ParScanThreadState* pss = _pss->state_for_worker(worker_id); pss->set_ref_processor(NULL); - G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, pss); - - G1ParScanAndMarkExtRootClosure copy_mark_non_heap_cl(_g1h, pss); - - OopClosure* copy_non_heap_cl = &only_copy_non_heap_cl; - - if (_g1h->collector_state()->during_initial_mark_pause()) { - // We also need to mark copied objects. - copy_non_heap_cl = ©_mark_non_heap_cl; - } - // Keep alive closure. - G1CopyingKeepAliveClosure keep_alive(_g1h, copy_non_heap_cl, pss); + G1CopyingKeepAliveClosure keep_alive(_g1h, pss->closures()->raw_strong_oops(), pss); // Complete GC closure G1ParEvacuateFollowersClosure drain_queue(_g1h, pss, _task_queues, _terminator); @@ -5364,23 +4994,12 @@ public: pss->set_ref_processor(NULL); assert(pss->queue_is_empty(), "both queue and overflow should be empty"); - G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, pss); - - G1ParScanAndMarkExtRootClosure copy_mark_non_heap_cl(_g1h, pss); - - OopClosure* copy_non_heap_cl = &only_copy_non_heap_cl; - - if (_g1h->collector_state()->during_initial_mark_pause()) { - // We also need to mark copied objects. - copy_non_heap_cl = ©_mark_non_heap_cl; - } - // Is alive closure G1AlwaysAliveClosure always_alive(_g1h); // Copying keep alive closure. Applied to referent objects that need // to be copied. - G1CopyingKeepAliveClosure keep_alive(_g1h, copy_non_heap_cl, pss); + G1CopyingKeepAliveClosure keep_alive(_g1h, pss->closures()->raw_strong_oops(), pss); ReferenceProcessor* rp = _g1h->ref_processor_cm(); @@ -5470,23 +5089,8 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per pss->set_ref_processor(NULL); assert(pss->queue_is_empty(), "pre-condition"); - // We do not embed a reference processor in the copying/scanning - // closures while we're actually processing the discovered - // reference objects. - - G1ParScanExtRootClosure only_copy_non_heap_cl(this, pss); - - G1ParScanAndMarkExtRootClosure copy_mark_non_heap_cl(this, pss); - - OopClosure* copy_non_heap_cl = &only_copy_non_heap_cl; - - if (collector_state()->during_initial_mark_pause()) { - // We also need to mark copied objects. - copy_non_heap_cl = ©_mark_non_heap_cl; - } - // Keep alive closure. - G1CopyingKeepAliveClosure keep_alive(this, copy_non_heap_cl, pss); + G1CopyingKeepAliveClosure keep_alive(this, pss->closures()->raw_strong_oops(), pss); // Serial Complete GC closure G1STWDrainQueueClosure drain_queue(this, pss); @@ -5501,8 +5105,7 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per &keep_alive, &drain_queue, NULL, - _gc_timer_stw, - _gc_tracer_stw->gc_id()); + _gc_timer_stw); } else { // Parallel reference processing assert(rp->num_q() == no_of_gc_workers, "sanity"); @@ -5513,8 +5116,7 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per &keep_alive, &drain_queue, &par_task_executor, - _gc_timer_stw, - _gc_tracer_stw->gc_id()); + _gc_timer_stw); } _gc_tracer_stw->report_gc_reference_stats(stats); @@ -5666,7 +5268,9 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info, G enqueue_discovered_references(per_thread_states); redirty_logged_cards(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif } void G1CollectedHeap::record_obj_copy_mem_stats() { @@ -5823,7 +5427,7 @@ void G1CollectedHeap::verify_dirty_young_regions() { bool G1CollectedHeap::verify_no_bits_over_tams(const char* bitmap_name, CMBitMapRO* bitmap, HeapWord* tams, HeapWord* end) { guarantee(tams <= end, - err_msg("tams: " PTR_FORMAT " end: " PTR_FORMAT, p2i(tams), p2i(end))); + "tams: " PTR_FORMAT " end: " PTR_FORMAT, p2i(tams), p2i(end)); HeapWord* result = bitmap->getNextMarkedWordAddress(tams, end); if (result < end) { gclog_or_tty->cr(); @@ -6174,9 +5778,8 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure { } guarantee(obj->is_typeArray(), - err_msg("Only eagerly reclaiming type arrays is supported, but the object " - PTR_FORMAT " is not.", - p2i(r->bottom()))); + "Only eagerly reclaiming type arrays is supported, but the object " + PTR_FORMAT " is not.", p2i(r->bottom())); if (G1TraceEagerReclaimHumongousObjects) { gclog_or_tty->print_cr("Dead humongous region %u size " SIZE_FORMAT " start " PTR_FORMAT " length %u with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d", @@ -6405,8 +6008,8 @@ void G1CollectedHeap::increase_used(size_t bytes) { void G1CollectedHeap::decrease_used(size_t bytes) { assert(_summary_bytes_used >= bytes, - err_msg("invariant: _summary_bytes_used: " SIZE_FORMAT " should be >= bytes: " SIZE_FORMAT, - _summary_bytes_used, bytes)); + "invariant: _summary_bytes_used: " SIZE_FORMAT " should be >= bytes: " SIZE_FORMAT, + _summary_bytes_used, bytes); _summary_bytes_used -= bytes; } @@ -6488,9 +6091,9 @@ void G1CollectedHeap::rebuild_region_sets(bool free_list_only) { } } assert(used_unlocked() == recalculate_used(), - err_msg("inconsistent used_unlocked(), " - "value: " SIZE_FORMAT " recalculated: " SIZE_FORMAT, - used_unlocked(), recalculate_used())); + "inconsistent used_unlocked(), " + "value: " SIZE_FORMAT " recalculated: " SIZE_FORMAT, + used_unlocked(), recalculate_used()); } void G1CollectedHeap::set_refine_cte_cl_concurrency(bool concurrent) { @@ -6631,35 +6234,35 @@ public: if (hr->is_young()) { // TODO } else if (hr->is_starts_humongous()) { - assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->hrm_index())); + assert(hr->containing_set() == _humongous_set, "Heap region %u is starts humongous but not in humongous set.", hr->hrm_index()); _humongous_count.increment(1u, hr->capacity()); } else if (hr->is_empty()) { - assert(_hrm->is_free(hr), err_msg("Heap region %u is empty but not on the free list.", hr->hrm_index())); + assert(_hrm->is_free(hr), "Heap region %u is empty but not on the free list.", hr->hrm_index()); _free_count.increment(1u, hr->capacity()); } else if (hr->is_old()) { - assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrm_index())); + assert(hr->containing_set() == _old_set, "Heap region %u is old but not in the old set.", hr->hrm_index()); _old_count.increment(1u, hr->capacity()); } else { // There are no other valid region types. Check for one invalid // one we can identify: pinned without old or humongous set. - assert(!hr->is_pinned(), err_msg("Heap region %u is pinned but not old (archive) or humongous.", hr->hrm_index())); + assert(!hr->is_pinned(), "Heap region %u is pinned but not old (archive) or humongous.", hr->hrm_index()); ShouldNotReachHere(); } return false; } void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionManager* free_list) { - guarantee(old_set->length() == _old_count.length(), err_msg("Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count.length())); - guarantee(old_set->total_capacity_bytes() == _old_count.capacity(), err_msg("Old set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - old_set->total_capacity_bytes(), _old_count.capacity())); + guarantee(old_set->length() == _old_count.length(), "Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count.length()); + guarantee(old_set->total_capacity_bytes() == _old_count.capacity(), "Old set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + old_set->total_capacity_bytes(), _old_count.capacity()); - guarantee(humongous_set->length() == _humongous_count.length(), err_msg("Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count.length())); - guarantee(humongous_set->total_capacity_bytes() == _humongous_count.capacity(), err_msg("Hum set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - humongous_set->total_capacity_bytes(), _humongous_count.capacity())); + guarantee(humongous_set->length() == _humongous_count.length(), "Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count.length()); + guarantee(humongous_set->total_capacity_bytes() == _humongous_count.capacity(), "Hum set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + humongous_set->total_capacity_bytes(), _humongous_count.capacity()); - guarantee(free_list->num_free_regions() == _free_count.length(), err_msg("Free list count mismatch. Expected %u, actual %u.", free_list->num_free_regions(), _free_count.length())); - guarantee(free_list->total_capacity_bytes() == _free_count.capacity(), err_msg("Free list capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - free_list->total_capacity_bytes(), _free_count.capacity())); + guarantee(free_list->num_free_regions() == _free_count.length(), "Free list count mismatch. Expected %u, actual %u.", free_list->num_free_regions(), _free_count.length()); + guarantee(free_list->total_capacity_bytes() == _free_count.capacity(), "Free list capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + free_list->total_capacity_bytes(), _free_count.capacity()); } }; @@ -6715,9 +6318,9 @@ class RegisterNMethodOopClosure: public OopClosure { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); HeapRegion* hr = _g1h->heap_region_containing(obj); assert(!hr->is_continues_humongous(), - err_msg("trying to add code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT - " starting at " HR_FORMAT, - p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()))); + "trying to add code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT + " starting at " HR_FORMAT, + p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region())); // HeapRegion::add_strong_code_root_locked() avoids adding duplicate entries. hr->add_strong_code_root_locked(_nm); @@ -6742,9 +6345,9 @@ class UnregisterNMethodOopClosure: public OopClosure { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); HeapRegion* hr = _g1h->heap_region_containing(obj); assert(!hr->is_continues_humongous(), - err_msg("trying to remove code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT - " starting at " HR_FORMAT, - p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()))); + "trying to remove code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT + " starting at " HR_FORMAT, + p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region())); hr->remove_strong_code_root(_nm); } diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 5f47e21d34f..dc4c5ef1a80 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -39,6 +39,7 @@ #include "gc/g1/hSpaceCounters.hpp" #include "gc/g1/heapRegionManager.hpp" #include "gc/g1/heapRegionSet.hpp" +#include "gc/g1/youngList.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/plab.hpp" @@ -64,7 +65,6 @@ class SpaceClosure; class CompactibleSpaceClosure; class Space; class G1CollectorPolicy; -class GenRemSet; class G1RemSet; class HeapRegionRemSetIterator; class ConcurrentMark; @@ -88,79 +88,6 @@ typedef GenericTaskQueueSet RefToScanQueueSet; typedef int RegionIdx_t; // needs to hold [ 0..max_regions() ) typedef int CardIdx_t; // needs to hold [ 0..CardsPerRegion ) -class YoungList : public CHeapObj { -private: - G1CollectedHeap* _g1h; - - HeapRegion* _head; - - HeapRegion* _survivor_head; - HeapRegion* _survivor_tail; - - HeapRegion* _curr; - - uint _length; - uint _survivor_length; - - size_t _last_sampled_rs_lengths; - size_t _sampled_rs_lengths; - - void empty_list(HeapRegion* list); - -public: - YoungList(G1CollectedHeap* g1h); - - void push_region(HeapRegion* hr); - void add_survivor_region(HeapRegion* hr); - - void empty_list(); - bool is_empty() { return _length == 0; } - uint length() { return _length; } - uint eden_length() { return length() - survivor_length(); } - uint survivor_length() { return _survivor_length; } - - // Currently we do not keep track of the used byte sum for the - // young list and the survivors and it'd be quite a lot of work to - // do so. When we'll eventually replace the young list with - // instances of HeapRegionLinkedList we'll get that for free. So, - // we'll report the more accurate information then. - size_t eden_used_bytes() { - assert(length() >= survivor_length(), "invariant"); - return (size_t) eden_length() * HeapRegion::GrainBytes; - } - size_t survivor_used_bytes() { - return (size_t) survivor_length() * HeapRegion::GrainBytes; - } - - void rs_length_sampling_init(); - bool rs_length_sampling_more(); - void rs_length_sampling_next(); - - void reset_sampled_info() { - _last_sampled_rs_lengths = 0; - } - size_t sampled_rs_lengths() { return _last_sampled_rs_lengths; } - - // for development purposes - void reset_auxilary_lists(); - void clear() { _head = NULL; _length = 0; } - - void clear_survivors() { - _survivor_head = NULL; - _survivor_tail = NULL; - _survivor_length = 0; - } - - HeapRegion* first_region() { return _head; } - HeapRegion* first_survivor_region() { return _survivor_head; } - HeapRegion* last_survivor_region() { return _survivor_tail; } - - // debugging - bool check_list_well_formed(); - bool check_list_empty(bool check_sample = true); - void print(); -}; - // The G1 STW is alive closure. // An instance is embedded into the G1CH and used as the // (optional) _is_alive_non_header closure in the STW @@ -368,17 +295,17 @@ private: // These are macros so that, if the assert fires, we get the correct // line number, file, etc. -#define heap_locking_asserts_err_msg(_extra_message_) \ - err_msg("%s : Heap_lock locked: %s, at safepoint: %s, is VM thread: %s", \ - (_extra_message_), \ - BOOL_TO_STR(Heap_lock->owned_by_self()), \ - BOOL_TO_STR(SafepointSynchronize::is_at_safepoint()), \ - BOOL_TO_STR(Thread::current()->is_VM_thread())) +#define heap_locking_asserts_params(_extra_message_) \ + "%s : Heap_lock locked: %s, at safepoint: %s, is VM thread: %s", \ + (_extra_message_), \ + BOOL_TO_STR(Heap_lock->owned_by_self()), \ + BOOL_TO_STR(SafepointSynchronize::is_at_safepoint()), \ + BOOL_TO_STR(Thread::current()->is_VM_thread()) #define assert_heap_locked() \ do { \ assert(Heap_lock->owned_by_self(), \ - heap_locking_asserts_err_msg("should be holding the Heap_lock")); \ + heap_locking_asserts_params("should be holding the Heap_lock")); \ } while (0) #define assert_heap_locked_or_at_safepoint(_should_be_vm_thread_) \ @@ -386,7 +313,7 @@ private: assert(Heap_lock->owned_by_self() || \ (SafepointSynchronize::is_at_safepoint() && \ ((_should_be_vm_thread_) == Thread::current()->is_VM_thread())), \ - heap_locking_asserts_err_msg("should be holding the Heap_lock or " \ + heap_locking_asserts_params("should be holding the Heap_lock or " \ "should be at a safepoint")); \ } while (0) @@ -394,21 +321,21 @@ private: do { \ assert(Heap_lock->owned_by_self() && \ !SafepointSynchronize::is_at_safepoint(), \ - heap_locking_asserts_err_msg("should be holding the Heap_lock and " \ + heap_locking_asserts_params("should be holding the Heap_lock and " \ "should not be at a safepoint")); \ } while (0) #define assert_heap_not_locked() \ do { \ assert(!Heap_lock->owned_by_self(), \ - heap_locking_asserts_err_msg("should not be holding the Heap_lock")); \ + heap_locking_asserts_params("should not be holding the Heap_lock")); \ } while (0) #define assert_heap_not_locked_and_not_at_safepoint() \ do { \ assert(!Heap_lock->owned_by_self() && \ !SafepointSynchronize::is_at_safepoint(), \ - heap_locking_asserts_err_msg("should not be holding the Heap_lock and " \ + heap_locking_asserts_params("should not be holding the Heap_lock and " \ "should not be at a safepoint")); \ } while (0) @@ -416,13 +343,13 @@ private: do { \ assert(SafepointSynchronize::is_at_safepoint() && \ ((_should_be_vm_thread_) == Thread::current()->is_VM_thread()), \ - heap_locking_asserts_err_msg("should be at a safepoint")); \ + heap_locking_asserts_params("should be at a safepoint")); \ } while (0) #define assert_not_at_safepoint() \ do { \ assert(!SafepointSynchronize::is_at_safepoint(), \ - heap_locking_asserts_err_msg("should not be at a safepoint")); \ + heap_locking_asserts_params("should not be at a safepoint")); \ } while (0) protected: @@ -571,7 +498,16 @@ protected: HeapWord* satisfy_failed_allocation(size_t word_size, AllocationContext_t context, bool* succeeded); +private: + // Helper method for satisfy_failed_allocation() + HeapWord* satisfy_failed_allocation_helper(size_t word_size, + AllocationContext_t context, + bool do_gc, + bool clear_all_soft_refs, + bool expect_null_mutator_alloc_region, + bool* gc_succeeded); +protected: // Attempting to expand the heap sufficiently // to support an allocation of the given "word_size". If // successful, perform the allocation and return the address of the @@ -1045,6 +981,7 @@ public: return CollectedHeap::G1CollectedHeap; } + const G1CollectorState* collector_state() const { return &_collector_state; } G1CollectorState* collector_state() { return &_collector_state; } // The current policy object for the collector. @@ -1073,9 +1010,11 @@ public: // continues humongous regions too. void reset_gc_time_stamps(HeapRegion* hr); - void iterate_dirty_card_closure(CardTableEntryClosure* cl, - DirtyCardQueue* into_cset_dcq, - bool concurrent, uint worker_i); + // Apply the given closure on all cards in the Hot Card Cache, emptying it. + void iterate_hcc_closure(CardTableEntryClosure* cl, uint worker_i); + + // Apply the given closure on all cards in the Dirty Card Queue Set, emptying it. + void iterate_dirty_card_closure(CardTableEntryClosure* cl, uint worker_i); // The shared block offset table array. G1BlockOffsetSharedArray* bot_shared() const { return _bot_shared; } diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp index e5364ff8b71..9478dcac231 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp @@ -67,8 +67,8 @@ inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm.at inline uint G1CollectedHeap::addr_to_region(HeapWord* addr) const { assert(is_in_reserved(addr), - err_msg("Cannot calculate region index for address " PTR_FORMAT " that is outside of the heap [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(addr), p2i(reserved_region().start()), p2i(reserved_region().end()))); + "Cannot calculate region index for address " PTR_FORMAT " that is outside of the heap [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(addr), p2i(reserved_region().start()), p2i(reserved_region().end())); return (uint)(pointer_delta(addr, reserved_region().start(), sizeof(uint8_t)) >> HeapRegion::LogOfHRGrainBytes); } @@ -80,8 +80,8 @@ template inline HeapRegion* G1CollectedHeap::heap_region_containing_raw(const T addr) const { assert(addr != NULL, "invariant"); assert(is_in_g1_reserved((const void*) addr), - err_msg("Address " PTR_FORMAT " is outside of the heap ranging from [" PTR_FORMAT " to " PTR_FORMAT ")", - p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end()))); + "Address " PTR_FORMAT " is outside of the heap ranging from [" PTR_FORMAT " to " PTR_FORMAT ")", + p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end())); return _hrm.addr_to_region((HeapWord*) addr); } diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index c9a635f208a..41cdd6c5a33 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -80,6 +80,7 @@ static double non_young_other_cost_per_region_ms_defaults[] = { }; G1CollectorPolicy::G1CollectorPolicy() : + _predictor(G1ConfidencePercent / 100.0), _parallel_gc_threads(ParallelGCThreads), _recent_gc_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), @@ -92,6 +93,7 @@ G1CollectorPolicy::G1CollectorPolicy() : _prev_collection_pause_end_ms(0.0), _rs_length_diff_seq(new TruncatedSeq(TruncatedSeqLength)), _cost_per_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _cost_scan_hcc_seq(new TruncatedSeq(TruncatedSeqLength)), _young_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), _mixed_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), _cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)), @@ -112,6 +114,8 @@ G1CollectorPolicy::G1CollectorPolicy() : new TruncatedSeq(NumPrevPausesForHeuristics)), _recent_avg_pause_time_ratio(0.0), + _rs_lengths_prediction(0), + _max_survivor_regions(0), _eden_used_bytes_before_gc(0), _survivor_used_bytes_before_gc(0), @@ -124,8 +128,6 @@ G1CollectorPolicy::G1CollectorPolicy() : _survivor_cset_region_length(0), _old_cset_region_length(0), - _sigma(G1ConfidencePercent / 100.0), - _collection_set(NULL), _collection_set_bytes_used_before(0), @@ -148,12 +150,12 @@ G1CollectorPolicy::G1CollectorPolicy() : _gc_overhead_perc(0.0) { - // SurvRateGroups below must be initialized after '_sigma' because they - // indirectly access '_sigma' through this object passed to their constructor. + // SurvRateGroups below must be initialized after the predictor because they + // indirectly use it through this object passed to their constructor. _short_lived_surv_rate_group = - new SurvRateGroup(this, "Short Lived", G1YoungSurvRateNumRegionsSummary); + new SurvRateGroup(&_predictor, "Short Lived", G1YoungSurvRateNumRegionsSummary); _survivor_surv_rate_group = - new SurvRateGroup(this, "Survivor", G1YoungSurvRateNumRegionsSummary); + new SurvRateGroup(&_predictor, "Survivor", G1YoungSurvRateNumRegionsSummary); // Set up the region size and associated fields. Given that the // policy is created before the heap, we have to set this up here, @@ -190,6 +192,7 @@ G1CollectorPolicy::G1CollectorPolicy() : _rs_length_diff_seq->add(rs_length_diff_defaults[index]); _cost_per_card_ms_seq->add(cost_per_card_ms_defaults[index]); + _cost_scan_hcc_seq->add(0.0); _young_cards_per_entry_ratio_seq->add( young_cards_per_entry_ratio_defaults[index]); _cost_per_entry_ms_seq->add(cost_per_entry_ms_defaults[index]); @@ -264,9 +267,6 @@ G1CollectorPolicy::G1CollectorPolicy() : _concurrent_mark_remark_times_ms->add(0.05); _concurrent_mark_cleanup_times_ms->add(0.20); _tenuring_threshold = MaxTenuringThreshold; - // _max_survivor_regions will be calculated by - // update_young_list_target_length() during initialization. - _max_survivor_regions = 0; assert(GCTimeRatio > 0, "we should have set it to a default value set_g1_gc_flags() " @@ -288,9 +288,13 @@ G1CollectorPolicy::G1CollectorPolicy() : _collectionSetChooser = new CollectionSetChooser(); } +double G1CollectorPolicy::get_new_prediction(TruncatedSeq const* seq) const { + return _predictor.get_new_prediction(seq); +} + void G1CollectorPolicy::initialize_alignments() { _space_alignment = HeapRegion::GrainBytes; - size_t card_table_alignment = GenRemSet::max_alignment_constraint(); + size_t card_table_alignment = CardTableRS::ct_max_alignment_constraint(); size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); _heap_alignment = MAX3(card_table_alignment, _space_alignment, page_size); } @@ -315,7 +319,7 @@ void G1CollectorPolicy::post_heap_initialize() { } } -G1CollectorState* G1CollectorPolicy::collector_state() { return _g1->collector_state(); } +G1CollectorState* G1CollectorPolicy::collector_state() const { return _g1->collector_state(); } G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true), _min_desired_young_length(0), _max_desired_young_length(0) { @@ -426,8 +430,8 @@ void G1CollectorPolicy::init() { _young_list_fixed_length = _young_gen_sizer->min_desired_young_length(); } _free_regions_at_end_of_collection = _g1->num_free_regions(); - update_young_list_target_length(); + update_young_list_target_length(); // We may immediately start allocating regions and placing them on the // collection set list. Initialize the per-collection set info start_incremental_cset_building(); @@ -441,7 +445,7 @@ void G1CollectorPolicy::initialize_gc_policy_counters() { bool G1CollectorPolicy::predict_will_fit(uint young_length, double base_time_ms, uint base_free_regions, - double target_pause_time_ms) { + double target_pause_time_ms) const { if (young_length >= base_free_regions) { // end condition 1: not enough space for the young regions return false; @@ -458,9 +462,8 @@ bool G1CollectorPolicy::predict_will_fit(uint young_length, return false; } - size_t free_bytes = - (base_free_regions - young_length) * HeapRegion::GrainBytes; - if ((2.0 * sigma()) * (double) bytes_to_copy > (double) free_bytes) { + size_t free_bytes = (base_free_regions - young_length) * HeapRegion::GrainBytes; + if ((2.0 /* magic */ * _predictor.sigma()) * bytes_to_copy > free_bytes) { // end condition 3: out-of-space (conservatively!) return false; } @@ -480,7 +483,7 @@ void G1CollectorPolicy::record_new_heap_size(uint new_number_of_regions) { } uint G1CollectorPolicy::calculate_young_list_desired_min_length( - uint base_min_length) { + uint base_min_length) const { uint desired_min_length = 0; if (adaptive_young_list_length()) { if (_alloc_rate_ms_seq->num() > 3) { @@ -497,7 +500,7 @@ uint G1CollectorPolicy::calculate_young_list_desired_min_length( return MAX2(_young_gen_sizer->min_desired_young_length(), desired_min_length); } -uint G1CollectorPolicy::calculate_young_list_desired_max_length() { +uint G1CollectorPolicy::calculate_young_list_desired_max_length() const { // Here, we might want to also take into account any additional // constraints (i.e., user-defined minimum bound). Currently, we // effectively don't set this bound. @@ -575,7 +578,7 @@ uint G1CollectorPolicy::calculate_young_list_target_length(size_t rs_lengths, uint base_min_length, uint desired_min_length, - uint desired_max_length) { + uint desired_max_length) const { assert(adaptive_young_list_length(), "pre-condition"); assert(collector_state()->gcs_are_young(), "only call this for young GCs"); @@ -675,7 +678,7 @@ G1CollectorPolicy::calculate_young_list_target_length(size_t rs_lengths, return base_min_length + min_young_length; } -double G1CollectorPolicy::predict_survivor_regions_evac_time() { +double G1CollectorPolicy::predict_survivor_regions_evac_time() const { double survivor_regions_evac_time = 0.0; for (HeapRegion * r = _recorded_survivor_head; r != NULL && r != _recorded_survivor_tail->get_next_young_region(); @@ -813,8 +816,8 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec) { update_survivors_policy(); assert(_g1->used() == _g1->recalculate_used(), - err_msg("sanity, used: " SIZE_FORMAT " recalculate_used: " SIZE_FORMAT, - _g1->used(), _g1->recalculate_used())); + "sanity, used: " SIZE_FORMAT " recalculate_used: " SIZE_FORMAT, + _g1->used(), _g1->recalculate_used()); double s_w_t_ms = (start_time_sec - _stop_world_start) * 1000.0; _trace_young_gen_time_data.record_start_collection(s_w_t_ms); @@ -857,7 +860,7 @@ void G1CollectorPolicy::record_concurrent_mark_remark_end() { _cur_mark_stop_world_time_ms += elapsed_time_ms; _prev_collection_pause_end_ms += elapsed_time_ms; - _mmu_tracker->add_pause(_mark_remark_start_sec, end_time_sec, _g1->gc_tracer_cm()->gc_id()); + _mmu_tracker->add_pause(_mark_remark_start_sec, end_time_sec); } void G1CollectorPolicy::record_concurrent_mark_cleanup_start() { @@ -952,8 +955,7 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t collector_state()->set_initiate_conc_mark_if_possible(true); } - _mmu_tracker->add_pause(end_time_sec - pause_time_ms/1000.0, - end_time_sec, _g1->gc_tracer_stw()->gc_id()); + _mmu_tracker->add_pause(end_time_sec - pause_time_ms/1000.0, end_time_sec); if (update_stats) { _trace_young_gen_time_data.record_end_collection(pause_time_ms, phase_times()); @@ -1047,10 +1049,12 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t if (update_stats) { double cost_per_card_ms = 0.0; + double cost_scan_hcc = phase_times()->average_time_ms(G1GCPhaseTimes::ScanHCC); if (_pending_cards > 0) { - cost_per_card_ms = phase_times()->average_time_ms(G1GCPhaseTimes::UpdateRS) / (double) _pending_cards; + cost_per_card_ms = (phase_times()->average_time_ms(G1GCPhaseTimes::UpdateRS) - cost_scan_hcc) / (double) _pending_cards; _cost_per_card_ms_seq->add(cost_per_card_ms); } + _cost_scan_hcc_seq->add(cost_scan_hcc); double cost_per_entry_ms = 0.0; if (cards_scanned > 10) { @@ -1147,8 +1151,25 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t // Note that _mmu_tracker->max_gc_time() returns the time in seconds. double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0; - adjust_concurrent_refinement(phase_times()->average_time_ms(G1GCPhaseTimes::UpdateRS), - phase_times()->sum_thread_work_items(G1GCPhaseTimes::UpdateRS), update_rs_time_goal_ms); + + double scan_hcc_time_ms = phase_times()->average_time_ms(G1GCPhaseTimes::ScanHCC); + + if (update_rs_time_goal_ms < scan_hcc_time_ms) { + ergo_verbose2(ErgoTiming, + "adjust concurrent refinement thresholds", + ergo_format_reason("Scanning the HCC expected to take longer than Update RS time goal") + ergo_format_ms("Update RS time goal") + ergo_format_ms("Scan HCC time"), + update_rs_time_goal_ms, + scan_hcc_time_ms); + + update_rs_time_goal_ms = 0; + } else { + update_rs_time_goal_ms -= scan_hcc_time_ms; + } + adjust_concurrent_refinement(phase_times()->average_time_ms(G1GCPhaseTimes::UpdateRS) - scan_hcc_time_ms, + phase_times()->sum_thread_work_items(G1GCPhaseTimes::UpdateRS), + update_rs_time_goal_ms); _collectionSetChooser->verify(); } @@ -1174,7 +1195,7 @@ void G1CollectorPolicy::record_heap_size_info_at_start(bool full) { } } -void G1CollectorPolicy::print_heap_transition(size_t bytes_before) { +void G1CollectorPolicy::print_heap_transition(size_t bytes_before) const { size_t bytes_after = _g1->used(); size_t capacity = _g1->capacity(); @@ -1187,11 +1208,11 @@ void G1CollectorPolicy::print_heap_transition(size_t bytes_before) { proper_unit_for_byte_size(capacity)); } -void G1CollectorPolicy::print_heap_transition() { +void G1CollectorPolicy::print_heap_transition() const { print_heap_transition(_heap_used_bytes_before_gc); } -void G1CollectorPolicy::print_detailed_heap_transition(bool full) { +void G1CollectorPolicy::print_detailed_heap_transition(bool full) const { YoungList* young_list = _g1->young_list(); size_t eden_used_bytes_after_gc = young_list->eden_used_bytes(); @@ -1249,7 +1270,7 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, cg1r->set_red_zone(g * k_gr); cg1r->reinitialize_threads(); - int processing_threshold_delta = MAX2((int)(cg1r->green_zone() * sigma()), 1); + int processing_threshold_delta = MAX2((int)(cg1r->green_zone() * _predictor.sigma()), 1); int processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta, cg1r->yellow_zone()); // Change the barrier params @@ -1266,17 +1287,125 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, dcqs.notify_if_necessary(); } -double -G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards, - size_t scanned_cards) { +size_t G1CollectorPolicy::predict_rs_length_diff() const { + return (size_t) get_new_prediction(_rs_length_diff_seq); +} + +double G1CollectorPolicy::predict_alloc_rate_ms() const { + return get_new_prediction(_alloc_rate_ms_seq); +} + +double G1CollectorPolicy::predict_cost_per_card_ms() const { + return get_new_prediction(_cost_per_card_ms_seq); +} + +double G1CollectorPolicy::predict_scan_hcc_ms() const { + return get_new_prediction(_cost_scan_hcc_seq); +} + +double G1CollectorPolicy::predict_rs_update_time_ms(size_t pending_cards) const { + return pending_cards * predict_cost_per_card_ms() + predict_scan_hcc_ms(); +} + +double G1CollectorPolicy::predict_young_cards_per_entry_ratio() const { + return get_new_prediction(_young_cards_per_entry_ratio_seq); +} + +double G1CollectorPolicy::predict_mixed_cards_per_entry_ratio() const { + if (_mixed_cards_per_entry_ratio_seq->num() < 2) { + return predict_young_cards_per_entry_ratio(); + } else { + return get_new_prediction(_mixed_cards_per_entry_ratio_seq); + } +} + +size_t G1CollectorPolicy::predict_young_card_num(size_t rs_length) const { + return (size_t) (rs_length * predict_young_cards_per_entry_ratio()); +} + +size_t G1CollectorPolicy::predict_non_young_card_num(size_t rs_length) const { + return (size_t)(rs_length * predict_mixed_cards_per_entry_ratio()); +} + +double G1CollectorPolicy::predict_rs_scan_time_ms(size_t card_num) const { + if (collector_state()->gcs_are_young()) { + return card_num * get_new_prediction(_cost_per_entry_ms_seq); + } else { + return predict_mixed_rs_scan_time_ms(card_num); + } +} + +double G1CollectorPolicy::predict_mixed_rs_scan_time_ms(size_t card_num) const { + if (_mixed_cost_per_entry_ms_seq->num() < 3) { + return card_num * get_new_prediction(_cost_per_entry_ms_seq); + } else { + return card_num * get_new_prediction(_mixed_cost_per_entry_ms_seq); + } +} + +double G1CollectorPolicy::predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const { + if (_cost_per_byte_ms_during_cm_seq->num() < 3) { + return (1.1 * bytes_to_copy) * get_new_prediction(_cost_per_byte_ms_seq); + } else { + return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_during_cm_seq); + } +} + +double G1CollectorPolicy::predict_object_copy_time_ms(size_t bytes_to_copy) const { + if (collector_state()->during_concurrent_mark()) { + return predict_object_copy_time_ms_during_cm(bytes_to_copy); + } else { + return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_seq); + } +} + +double G1CollectorPolicy::predict_constant_other_time_ms() const { + return get_new_prediction(_constant_other_time_ms_seq); +} + +double G1CollectorPolicy::predict_young_other_time_ms(size_t young_num) const { + return young_num * get_new_prediction(_young_other_cost_per_region_ms_seq); +} + +double G1CollectorPolicy::predict_non_young_other_time_ms(size_t non_young_num) const { + return non_young_num * get_new_prediction(_non_young_other_cost_per_region_ms_seq); +} + +double G1CollectorPolicy::predict_remark_time_ms() const { + return get_new_prediction(_concurrent_mark_remark_times_ms); +} + +double G1CollectorPolicy::predict_cleanup_time_ms() const { + return get_new_prediction(_concurrent_mark_cleanup_times_ms); +} + +double G1CollectorPolicy::predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const { + TruncatedSeq* seq = surv_rate_group->get_seq(age); + guarantee(seq->num() > 0, "There should be some young gen survivor samples available. Tried to access with age %d", age); + double pred = get_new_prediction(seq); + if (pred > 1.0) { + pred = 1.0; + } + return pred; +} + +double G1CollectorPolicy::predict_yg_surv_rate(int age) const { + return predict_yg_surv_rate(age, _short_lived_surv_rate_group); +} + +double G1CollectorPolicy::accum_yg_surv_rate_pred(int age) const { + return _short_lived_surv_rate_group->accum_surv_rate_pred(age); +} + +double G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards, + size_t scanned_cards) const { return predict_rs_update_time_ms(pending_cards) + predict_rs_scan_time_ms(scanned_cards) + predict_constant_other_time_ms(); } -double -G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) { +double G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) const { size_t rs_length = predict_rs_length_diff(); size_t card_num; if (collector_state()->gcs_are_young()) { @@ -1287,7 +1416,7 @@ G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) { return predict_base_elapsed_time_ms(pending_cards, card_num); } -size_t G1CollectorPolicy::predict_bytes_to_copy(HeapRegion* hr) { +size_t G1CollectorPolicy::predict_bytes_to_copy(HeapRegion* hr) const { size_t bytes_to_copy; if (hr->is_marked()) bytes_to_copy = hr->max_live_bytes(); @@ -1295,14 +1424,13 @@ size_t G1CollectorPolicy::predict_bytes_to_copy(HeapRegion* hr) { assert(hr->is_young() && hr->age_in_surv_rate_group() != -1, "invariant"); int age = hr->age_in_surv_rate_group(); double yg_surv_rate = predict_yg_surv_rate(age, hr->surv_rate_group()); - bytes_to_copy = (size_t) ((double) hr->used() * yg_surv_rate); + bytes_to_copy = (size_t) (hr->used() * yg_surv_rate); } return bytes_to_copy; } -double -G1CollectorPolicy::predict_region_elapsed_time_ms(HeapRegion* hr, - bool for_young_gc) { +double G1CollectorPolicy::predict_region_elapsed_time_ms(HeapRegion* hr, + bool for_young_gc) const { size_t rs_length = hr->rem_set()->occupied(); size_t card_num; @@ -1329,9 +1457,8 @@ G1CollectorPolicy::predict_region_elapsed_time_ms(HeapRegion* hr, return region_elapsed_time_ms; } -void -G1CollectorPolicy::init_cset_region_lengths(uint eden_cset_region_length, - uint survivor_cset_region_length) { +void G1CollectorPolicy::init_cset_region_lengths(uint eden_cset_region_length, + uint survivor_cset_region_length) { _eden_cset_region_length = eden_cset_region_length; _survivor_cset_region_length = survivor_cset_region_length; _old_cset_region_length = 0; @@ -1348,7 +1475,7 @@ void G1CollectorPolicy::update_recent_gc_times(double end_time_sec, _prev_collection_pause_end_ms = end_time_sec * 1000.0; } -size_t G1CollectorPolicy::expansion_amount() { +size_t G1CollectorPolicy::expansion_amount() const { double recent_gc_overhead = recent_avg_pause_time_ratio() * 100.0; double threshold = _gc_overhead_perc; if (recent_gc_overhead > threshold) { @@ -1397,13 +1524,13 @@ void G1CollectorPolicy::print_yg_surv_rate_info() const { #endif // PRODUCT } -bool G1CollectorPolicy::is_young_list_full() { +bool G1CollectorPolicy::is_young_list_full() const { uint young_list_length = _g1->young_list()->length(); uint young_list_target_length = _young_list_target_length; return young_list_length >= young_list_target_length; } -bool G1CollectorPolicy::can_expand_young_list() { +bool G1CollectorPolicy::can_expand_young_list() const { uint young_list_length = _g1->young_list()->length(); uint young_list_max_length = _young_list_max_length; return young_list_length < young_list_max_length; @@ -1557,7 +1684,7 @@ public: } }; -uint G1CollectorPolicy::calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) { +uint G1CollectorPolicy::calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const { assert(n_workers > 0, "Active gc workers should be greater than 0"); const uint overpartition_factor = 4; const uint min_chunk_size = MAX2(n_regions / n_workers, 1U); @@ -1584,7 +1711,7 @@ G1CollectorPolicy::record_concurrent_mark_cleanup_end() { _concurrent_mark_cleanup_times_ms->add(elapsed_time_ms); _cur_mark_stop_world_time_ms += elapsed_time_ms; _prev_collection_pause_end_ms += elapsed_time_ms; - _mmu_tracker->add_pause(_mark_cleanup_start_sec, end_sec, _g1->gc_tracer_cm()->gc_id()); + _mmu_tracker->add_pause(_mark_cleanup_start_sec, end_sec); } // Add the heap region at the head of the non-incremental collection set @@ -1783,7 +1910,7 @@ void G1CollectorPolicy::print_collection_set(HeapRegion* list_head, outputStream } #endif // !PRODUCT -double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) { +double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) const { // Returns the given amount of reclaimable bytes (that represents // the amount of reclaimable space still to be collected) as a // percentage of the current heap capacity. @@ -1792,7 +1919,7 @@ double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) { } bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str, - const char* false_action_str) { + const char* false_action_str) const { CollectionSetChooser* cset_chooser = _collectionSetChooser; if (cset_chooser->is_empty()) { ergo_verbose0(ErgoMixedGCs, @@ -1830,7 +1957,7 @@ bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str, return true; } -uint G1CollectorPolicy::calc_min_old_cset_length() { +uint G1CollectorPolicy::calc_min_old_cset_length() const { // The min old CSet region bound is based on the maximum desired // number of mixed GCs after a cycle. I.e., even if some old regions // look expensive, we should add them to the CSet anyway to make @@ -1851,13 +1978,13 @@ uint G1CollectorPolicy::calc_min_old_cset_length() { return (uint) result; } -uint G1CollectorPolicy::calc_max_old_cset_length() { +uint G1CollectorPolicy::calc_max_old_cset_length() const { // The max old CSet region bound is based on the threshold expressed // as a percentage of the heap size. I.e., it should bound the // number of old regions added to the CSet irrespective of how many // of them are available. - G1CollectedHeap* g1h = G1CollectedHeap::heap(); + const G1CollectedHeap* g1h = G1CollectedHeap::heap(); const size_t region_num = g1h->num_regions(); const size_t perc = (size_t) G1OldCSetRegionThresholdPercent; size_t result = region_num * perc / 100; @@ -1876,8 +2003,7 @@ double G1CollectorPolicy::finalize_young_cset_part(double target_pause_time_ms) finalize_incremental_cset_building(); guarantee(target_pause_time_ms > 0.0, - err_msg("target_pause_time_ms = %1.6lf should be positive", - target_pause_time_ms)); + "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); guarantee(_collection_set == NULL, "Precondition"); double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp index ab2b2fea961..8904170bcaf 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp @@ -29,6 +29,7 @@ #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1InCSetState.hpp" #include "gc/g1/g1MMUTracker.hpp" +#include "gc/g1/g1Predictions.hpp" #include "gc/shared/collectorPolicy.hpp" // A G1CollectorPolicy makes policy decisions that determine the @@ -155,13 +156,17 @@ public: uint max_desired_young_length() { return _max_desired_young_length; } - bool adaptive_young_list_length() { + bool adaptive_young_list_length() const { return _adaptive_size; } }; class G1CollectorPolicy: public CollectorPolicy { -private: + private: + G1Predictions _predictor; + + double get_new_prediction(TruncatedSeq const* seq) const; + // either equal to the number of parallel threads, if ParallelGCThreads // has been set, or 1 otherwise int _parallel_gc_threads; @@ -169,10 +174,6 @@ private: // The number of GC threads currently active. uintx _no_of_gc_threads; - enum SomePrivateConstants { - NumPrevPausesForHeuristics = 10 - }; - G1MMUTracker* _mmu_tracker; void initialize_alignments(); @@ -211,7 +212,8 @@ private: uint _reserve_regions; enum PredictionConstants { - TruncatedSeqLength = 10 + TruncatedSeqLength = 10, + NumPrevPausesForHeuristics = 10 }; TruncatedSeq* _alloc_rate_ms_seq; @@ -219,6 +221,7 @@ private: TruncatedSeq* _rs_length_diff_seq; TruncatedSeq* _cost_per_card_ms_seq; + TruncatedSeq* _cost_scan_hcc_seq; TruncatedSeq* _young_cards_per_entry_ratio_seq; TruncatedSeq* _mixed_cards_per_entry_ratio_seq; TruncatedSeq* _cost_per_entry_ms_seq; @@ -242,33 +245,17 @@ private: void init_cset_region_lengths(uint eden_cset_region_length, uint survivor_cset_region_length); - uint eden_cset_region_length() { return _eden_cset_region_length; } - uint survivor_cset_region_length() { return _survivor_cset_region_length; } - uint old_cset_region_length() { return _old_cset_region_length; } + uint eden_cset_region_length() const { return _eden_cset_region_length; } + uint survivor_cset_region_length() const { return _survivor_cset_region_length; } + uint old_cset_region_length() const { return _old_cset_region_length; } uint _free_regions_at_end_of_collection; size_t _recorded_rs_lengths; size_t _max_rs_lengths; - double _sigma; size_t _rs_lengths_prediction; - double sigma() { return _sigma; } - - // A function that prevents us putting too much stock in small sample - // sets. Returns a number between 2.0 and 1.0, depending on the number - // of samples. 5 or more samples yields one; fewer scales linearly from - // 2.0 at 1 sample to 1.0 at 5. - double confidence_factor(int samples) { - if (samples > 4) return 1.0; - else return 1.0 + sigma() * ((double)(5 - samples))/2.0; - } - - double get_new_neg_prediction(TruncatedSeq* seq) { - return seq->davg() - sigma() * seq->dsd(); - } - #ifndef PRODUCT bool verify_young_ages(HeapRegion* head, SurvRateGroup *surv_rate_group); #endif // PRODUCT @@ -285,6 +272,8 @@ private: size_t _pending_cards; public: + G1Predictions& predictor() { return _predictor; } + // Accessors void set_region_eden(HeapRegion* hr, int young_index_in_cset) { @@ -303,161 +292,91 @@ public: bool verify_young_ages(); #endif // PRODUCT - double get_new_prediction(TruncatedSeq* seq) { - return MAX2(seq->davg() + sigma() * seq->dsd(), - seq->davg() * confidence_factor(seq->num())); - } - void record_max_rs_lengths(size_t rs_lengths) { _max_rs_lengths = rs_lengths; } - size_t predict_rs_length_diff() { - return (size_t) get_new_prediction(_rs_length_diff_seq); - } + size_t predict_rs_length_diff() const; - double predict_alloc_rate_ms() { - return get_new_prediction(_alloc_rate_ms_seq); - } + double predict_alloc_rate_ms() const; - double predict_cost_per_card_ms() { - return get_new_prediction(_cost_per_card_ms_seq); - } + double predict_cost_per_card_ms() const; - double predict_rs_update_time_ms(size_t pending_cards) { - return (double) pending_cards * predict_cost_per_card_ms(); - } + double predict_scan_hcc_ms() const; - double predict_young_cards_per_entry_ratio() { - return get_new_prediction(_young_cards_per_entry_ratio_seq); - } + double predict_rs_update_time_ms(size_t pending_cards) const; - double predict_mixed_cards_per_entry_ratio() { - if (_mixed_cards_per_entry_ratio_seq->num() < 2) { - return predict_young_cards_per_entry_ratio(); - } else { - return get_new_prediction(_mixed_cards_per_entry_ratio_seq); - } - } + double predict_young_cards_per_entry_ratio() const; - size_t predict_young_card_num(size_t rs_length) { - return (size_t) ((double) rs_length * - predict_young_cards_per_entry_ratio()); - } + double predict_mixed_cards_per_entry_ratio() const; - size_t predict_non_young_card_num(size_t rs_length) { - return (size_t) ((double) rs_length * - predict_mixed_cards_per_entry_ratio()); - } + size_t predict_young_card_num(size_t rs_length) const; - double predict_rs_scan_time_ms(size_t card_num) { - if (collector_state()->gcs_are_young()) { - return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq); - } else { - return predict_mixed_rs_scan_time_ms(card_num); - } - } + size_t predict_non_young_card_num(size_t rs_length) const; - double predict_mixed_rs_scan_time_ms(size_t card_num) { - if (_mixed_cost_per_entry_ms_seq->num() < 3) { - return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq); - } else { - return (double) (card_num * - get_new_prediction(_mixed_cost_per_entry_ms_seq)); - } - } + double predict_rs_scan_time_ms(size_t card_num) const; - double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) { - if (_cost_per_byte_ms_during_cm_seq->num() < 3) { - return (1.1 * (double) bytes_to_copy) * - get_new_prediction(_cost_per_byte_ms_seq); - } else { - return (double) bytes_to_copy * - get_new_prediction(_cost_per_byte_ms_during_cm_seq); - } - } + double predict_mixed_rs_scan_time_ms(size_t card_num) const; - double predict_object_copy_time_ms(size_t bytes_to_copy) { - if (collector_state()->during_concurrent_mark()) { - return predict_object_copy_time_ms_during_cm(bytes_to_copy); - } else { - return (double) bytes_to_copy * - get_new_prediction(_cost_per_byte_ms_seq); - } - } + double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const; - double predict_constant_other_time_ms() { - return get_new_prediction(_constant_other_time_ms_seq); - } + double predict_object_copy_time_ms(size_t bytes_to_copy) const; - double predict_young_other_time_ms(size_t young_num) { - return (double) young_num * - get_new_prediction(_young_other_cost_per_region_ms_seq); - } + double predict_constant_other_time_ms() const; - double predict_non_young_other_time_ms(size_t non_young_num) { - return (double) non_young_num * - get_new_prediction(_non_young_other_cost_per_region_ms_seq); - } + double predict_young_other_time_ms(size_t young_num) const; - double predict_base_elapsed_time_ms(size_t pending_cards); + double predict_non_young_other_time_ms(size_t non_young_num) const; + + double predict_base_elapsed_time_ms(size_t pending_cards) const; double predict_base_elapsed_time_ms(size_t pending_cards, - size_t scanned_cards); - size_t predict_bytes_to_copy(HeapRegion* hr); - double predict_region_elapsed_time_ms(HeapRegion* hr, bool for_young_gc); + size_t scanned_cards) const; + size_t predict_bytes_to_copy(HeapRegion* hr) const; + double predict_region_elapsed_time_ms(HeapRegion* hr, bool for_young_gc) const; void set_recorded_rs_lengths(size_t rs_lengths); - uint cset_region_length() { return young_cset_region_length() + + uint cset_region_length() const { return young_cset_region_length() + old_cset_region_length(); } - uint young_cset_region_length() { return eden_cset_region_length() + + uint young_cset_region_length() const { return eden_cset_region_length() + survivor_cset_region_length(); } - double predict_survivor_regions_evac_time(); + double predict_survivor_regions_evac_time() const; + + bool should_update_surv_rate_group_predictors() { + return collector_state()->last_gc_was_young() && !collector_state()->in_marking_window(); + } void cset_regions_freed() { - bool propagate = collector_state()->should_propagate(); - _short_lived_surv_rate_group->all_surviving_words_recorded(propagate); - _survivor_surv_rate_group->all_surviving_words_recorded(propagate); - // also call it on any more surv rate groups + bool update = should_update_surv_rate_group_predictors(); + + _short_lived_surv_rate_group->all_surviving_words_recorded(update); + _survivor_surv_rate_group->all_surviving_words_recorded(update); } G1MMUTracker* mmu_tracker() { return _mmu_tracker; } - double max_pause_time_ms() { + const G1MMUTracker* mmu_tracker() const { + return _mmu_tracker; + } + + double max_pause_time_ms() const { return _mmu_tracker->max_gc_time() * 1000.0; } - double predict_remark_time_ms() { - return get_new_prediction(_concurrent_mark_remark_times_ms); - } + double predict_remark_time_ms() const; - double predict_cleanup_time_ms() { - return get_new_prediction(_concurrent_mark_cleanup_times_ms); - } + double predict_cleanup_time_ms() const; // Returns an estimate of the survival rate of the region at yg-age // "yg_age". - double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) { - TruncatedSeq* seq = surv_rate_group->get_seq(age); - if (seq->num() == 0) - gclog_or_tty->print("BARF! age is %d", age); - guarantee( seq->num() > 0, "invariant" ); - double pred = get_new_prediction(seq); - if (pred > 1.0) - pred = 1.0; - return pred; - } + double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const; - double predict_yg_surv_rate(int age) { - return predict_yg_surv_rate(age, _short_lived_surv_rate_group); - } + double predict_yg_surv_rate(int age) const; - double accum_yg_surv_rate_pred(int age) { - return _short_lived_surv_rate_group->accum_surv_rate_pred(age); - } + double accum_yg_surv_rate_pred(int age) const; private: // Statistics kept per GC stoppage, pause or full. @@ -536,7 +455,7 @@ private: // The ratio of gc time to elapsed time, computed over recent pauses. double _recent_avg_pause_time_ratio; - double recent_avg_pause_time_ratio() { + double recent_avg_pause_time_ratio() const { return _recent_avg_pause_time_ratio; } @@ -556,12 +475,12 @@ private: // Calculate and return the minimum desired young list target // length. This is the minimum desired young list length according // to the user's inputs. - uint calculate_young_list_desired_min_length(uint base_min_length); + uint calculate_young_list_desired_min_length(uint base_min_length) const; // Calculate and return the maximum desired young list target // length. This is the maximum desired young list length according // to the user's inputs. - uint calculate_young_list_desired_max_length(); + uint calculate_young_list_desired_max_length() const; // Calculate and return the maximum young list target length that // can fit into the pause time goal. The parameters are: rs_lengths @@ -572,11 +491,11 @@ private: uint calculate_young_list_target_length(size_t rs_lengths, uint base_min_length, uint desired_min_length, - uint desired_max_length); + uint desired_max_length) const; // Calculate and return chunk size (in number of regions) for parallel // concurrent mark cleanup. - uint calculate_parallel_work_chunk_size(uint n_workers, uint n_regions); + uint calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const; // Check whether a given young length (young_length) fits into the // given target pause time and whether the prediction for the amount @@ -584,19 +503,19 @@ private: // given free space (expressed by base_free_regions). It is used by // calculate_young_list_target_length(). bool predict_will_fit(uint young_length, double base_time_ms, - uint base_free_regions, double target_pause_time_ms); + uint base_free_regions, double target_pause_time_ms) const; // Calculate the minimum number of old regions we'll add to the CSet // during a mixed GC. - uint calc_min_old_cset_length(); + uint calc_min_old_cset_length() const; // Calculate the maximum number of old regions we'll add to the CSet // during a mixed GC. - uint calc_max_old_cset_length(); + uint calc_max_old_cset_length() const; // Returns the given amount of uncollected reclaimable space // as a percentage of the current heap capacity. - double reclaimable_bytes_perc(size_t reclaimable_bytes); + double reclaimable_bytes_perc(size_t reclaimable_bytes) const; public: @@ -604,7 +523,7 @@ public: virtual G1CollectorPolicy* as_g1_policy() { return this; } - G1CollectorState* collector_state(); + G1CollectorState* collector_state() const; G1GCPhaseTimes* phase_times() const { return _phase_times; } @@ -658,9 +577,9 @@ public: // Print heap sizing transition (with less and more detail). - void print_heap_transition(size_t bytes_before); - void print_heap_transition(); - void print_detailed_heap_transition(bool full = false); + void print_heap_transition(size_t bytes_before) const; + void print_heap_transition() const; + void print_detailed_heap_transition(bool full = false) const; void record_stop_world_start(); void record_concurrent_pause(); @@ -672,7 +591,7 @@ public: } // The amount of space we copied during a GC. - size_t bytes_copied_during_gc() { + size_t bytes_copied_during_gc() const { return _bytes_copied_during_gc; } @@ -684,7 +603,7 @@ public: // next GC should be mixed. The two action strings are used // in the ergo output when the method returns true or false. bool next_gc_should_be_mixed(const char* true_action_str, - const char* false_action_str); + const char* false_action_str) const; // Choose a new collection set. Marks the chosen regions as being // "in_collection_set", and links them together. The head and number of @@ -764,7 +683,7 @@ public: // If an expansion would be appropriate, because recent GC overhead had // exceeded the desired limit, return an amount to expand by. - virtual size_t expansion_amount(); + virtual size_t expansion_amount() const; // Print tracing information. void print_tracing_info() const; @@ -783,15 +702,15 @@ public: size_t young_list_target_length() const { return _young_list_target_length; } - bool is_young_list_full(); + bool is_young_list_full() const; - bool can_expand_young_list(); + bool can_expand_young_list() const; - uint young_list_max_length() { + uint young_list_max_length() const { return _young_list_max_length; } - bool adaptive_young_list_length() { + bool adaptive_young_list_length() const { return _young_gen_sizer->adaptive_young_list_length(); } @@ -832,14 +751,14 @@ public: static const uint REGIONS_UNLIMITED = (uint) -1; - uint max_regions(InCSetState dest) { + uint max_regions(InCSetState dest) const { switch (dest.value()) { case InCSetState::Young: return _max_survivor_regions; case InCSetState::Old: return REGIONS_UNLIMITED; default: - assert(false, err_msg("Unknown dest state: " CSETSTATE_FORMAT, dest.value())); + assert(false, "Unknown dest state: " CSETSTATE_FORMAT, dest.value()); break; } // keep some compilers happy @@ -862,7 +781,7 @@ public: _recorded_survivor_tail = tail; } - uint recorded_survivor_regions() { + uint recorded_survivor_regions() const { return _recorded_survivor_regions; } @@ -878,15 +797,4 @@ public: virtual void post_heap_initialize(); }; -// This should move to some place more general... - -// If we have "n" measurements, and we've kept track of their "sum" and the -// "sum_of_squares" of the measurements, this returns the variance of the -// sequence. -inline double variance(int n, double sum_of_squares, double sum) { - double n_d = (double)n; - double avg = sum/n_d; - return (sum_of_squares - 2.0 * avg * sum + n_d * avg * avg) / n_d; -} - #endif // SHARE_VM_GC_G1_G1COLLECTORPOLICY_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp index 6b7f00ebaf9..3a14fcee41f 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp @@ -104,28 +104,24 @@ class G1CollectorState VALUE_OBJ_CLASS_SPEC { void set_full_collection(bool v) { _full_collection = v; } // Getters - bool gcs_are_young() { return _gcs_are_young; } - bool last_gc_was_young() { return _last_gc_was_young; } - bool last_young_gc() { return _last_young_gc; } - bool during_initial_mark_pause() { return _during_initial_mark_pause; } - bool initiate_conc_mark_if_possible() { return _initiate_conc_mark_if_possible; } - bool during_marking() { return _during_marking; } - bool mark_in_progress() { return _mark_in_progress; } - bool in_marking_window() { return _in_marking_window; } - bool in_marking_window_im() { return _in_marking_window_im; } - bool concurrent_cycle_started() { return _concurrent_cycle_started; } - bool full_collection() { return _full_collection; } + bool gcs_are_young() const { return _gcs_are_young; } + bool last_gc_was_young() const { return _last_gc_was_young; } + bool last_young_gc() const { return _last_young_gc; } + bool during_initial_mark_pause() const { return _during_initial_mark_pause; } + bool initiate_conc_mark_if_possible() const { return _initiate_conc_mark_if_possible; } + bool during_marking() const { return _during_marking; } + bool mark_in_progress() const { return _mark_in_progress; } + bool in_marking_window() const { return _in_marking_window; } + bool in_marking_window_im() const { return _in_marking_window_im; } + bool concurrent_cycle_started() const { return _concurrent_cycle_started; } + bool full_collection() const { return _full_collection; } // Composite booleans (clients worry about flickering) - bool during_concurrent_mark() { + bool during_concurrent_mark() const { return (_in_marking_window && !_in_marking_window_im); } - bool should_propagate() { // XXX should have a more suitable state name or abstraction for this - return (_last_young_gc && !_in_marking_window); - } - - G1YCType yc_type() { + G1YCType yc_type() const { if (during_initial_mark_pause()) { return InitialMark; } else if (mark_in_progress()) { diff --git a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp b/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp index 1480c2d5087..f984848b0cb 100644 --- a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp @@ -56,6 +56,7 @@ const char* G1ErgoVerbose::to_string(int tag) { case ErgoCSetConstruction: return "CSet Construction"; case ErgoConcCycles: return "Concurrent Cycles"; case ErgoMixedGCs: return "Mixed GCs"; + case ErgoTiming: return "Timing"; default: ShouldNotReachHere(); // Keep the Windows compiler happy diff --git a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp b/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp index b7f1edd2f49..c36fe98521d 100644 --- a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp @@ -70,6 +70,7 @@ typedef enum { ErgoCSetConstruction, ErgoConcCycles, ErgoMixedGCs, + ErgoTiming, ErgoHeuristicNum } ErgoHeuristic; diff --git a/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp b/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp index 1b53cb12d06..1126e40e7c0 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp @@ -165,9 +165,9 @@ public: size_t size_second_obj = ((oop)end_first_obj)->size(); HeapWord* end_of_second_obj = end_first_obj + size_second_obj; assert(end == end_of_second_obj, - err_msg("More than two objects were used to fill the area from " PTR_FORMAT " to " PTR_FORMAT ", " - "second objects size " SIZE_FORMAT " ends at " PTR_FORMAT, - p2i(start), p2i(end), size_second_obj, p2i(end_of_second_obj))); + "More than two objects were used to fill the area from " PTR_FORMAT " to " PTR_FORMAT ", " + "second objects size " SIZE_FORMAT " ends at " PTR_FORMAT, + p2i(start), p2i(end), size_second_obj, p2i(end_of_second_obj)); #endif } } @@ -215,7 +215,7 @@ public: bool during_initial_mark = _g1h->collector_state()->during_initial_mark_pause(); bool during_conc_mark = _g1h->collector_state()->mark_in_progress(); - assert(!hr->is_pinned(), err_msg("Unexpected pinned region at index %u", hr->hrm_index())); + assert(!hr->is_pinned(), "Unexpected pinned region at index %u", hr->hrm_index()); assert(hr->in_collection_set(), "bad CS"); if (_hrclaimer->claim_region(hr->hrm_index())) { diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp index e228d473ed4..349982f4f9d 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp @@ -45,13 +45,13 @@ void G1EvacStats::adjust_desired_plab_sz() { if (_allocated == 0) { assert((_unused == 0), - err_msg("Inconsistency in PLAB stats: " - "_allocated: " SIZE_FORMAT ", " - "_wasted: " SIZE_FORMAT ", " - "_region_end_waste: " SIZE_FORMAT ", " - "_unused: " SIZE_FORMAT ", " - "_used : " SIZE_FORMAT, - _allocated, _wasted, _region_end_waste, _unused, used())); + "Inconsistency in PLAB stats: " + "_allocated: " SIZE_FORMAT ", " + "_wasted: " SIZE_FORMAT ", " + "_region_end_waste: " SIZE_FORMAT ", " + "_unused: " SIZE_FORMAT ", " + "_used : " SIZE_FORMAT, + _allocated, _wasted, _region_end_waste, _unused, used()); _allocated = 1; } // The size of the PLAB caps the amount of space that can be wasted at the diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index dd186072db3..c9d6ae92c55 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc/g1/concurrentG1Refine.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1Log.hpp" @@ -130,8 +131,8 @@ class WorkerDataArray : public CHeapObj { WorkerDataArray* thread_work_items() { return _thread_work_items; } void set(uint worker_i, T value) { - assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); - assert(_data[worker_i] == WorkerDataArray::uninitialized(), err_msg("Overwriting data for worker %d in %s", worker_i, _title)); + assert(worker_i < _length, "Worker %d is greater than max: %d", worker_i, _length); + assert(_data[worker_i] == WorkerDataArray::uninitialized(), "Overwriting data for worker %d in %s", worker_i, _title); _data[worker_i] = value; _has_new_data = true; } @@ -142,14 +143,14 @@ class WorkerDataArray : public CHeapObj { } T get(uint worker_i) { - assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); - assert(_data[worker_i] != WorkerDataArray::uninitialized(), err_msg("No data added for worker %d", worker_i)); + assert(worker_i < _length, "Worker %d is greater than max: %d", worker_i, _length); + assert(_data[worker_i] != WorkerDataArray::uninitialized(), "No data added for worker %d", worker_i); return _data[worker_i]; } void add(uint worker_i, T value) { - assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); - assert(_data[worker_i] != WorkerDataArray::uninitialized(), err_msg("No data to add to for worker %d", worker_i)); + assert(worker_i < _length, "Worker %d is greater than max: %d", worker_i, _length); + assert(_data[worker_i] != WorkerDataArray::uninitialized(), "No data to add to for worker %d", worker_i); _data[worker_i] += value; _has_new_data = true; } @@ -235,7 +236,7 @@ void WorkerDataArray::verify(uint active_threads) { assert(active_threads <= _length, "Wrong number of active threads"); for (uint i = 0; i < active_threads; i++) { assert(_data[i] != WorkerDataArray::uninitialized(), - err_msg("Invalid data for worker %u in '%s'", i, _title)); + "Invalid data for worker %u in '%s'", i, _title); } if (_thread_work_items != NULL) { _thread_work_items->verify(active_threads); @@ -269,6 +270,8 @@ G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _gc_par_phases[SATBFiltering] = new WorkerDataArray(max_gc_threads, "SATB Filtering (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[UpdateRS] = new WorkerDataArray(max_gc_threads, "Update RS (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[ScanHCC] = new WorkerDataArray(max_gc_threads, "Scan HCC (ms)", true, G1Log::LevelFiner, 3); + _gc_par_phases[ScanHCC]->set_enabled(ConcurrentG1Refine::hot_card_cache_enabled()); _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS (ms)", true, G1Log::LevelFiner, 2); _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning (ms)", true, G1Log::LevelFiner, 2); _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy (ms)", true, G1Log::LevelFiner, 2); @@ -479,7 +482,7 @@ class G1GCParPhasePrinter : public StackObj { print_count_values(buf, phase_id, thread_work_items); } - assert(thread_work_items->_print_sum, err_msg("%s does not have print sum true even though it is a count", thread_work_items->_title)); + assert(thread_work_items->_print_sum, "%s does not have print sum true even though it is a count", thread_work_items->_title); buf.append_and_print_cr(" Min: " SIZE_FORMAT ", Avg: %.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT ", Sum: " SIZE_FORMAT "]", _phase_times->min_thread_work_items(phase_id), _phase_times->average_thread_work_items(phase_id), _phase_times->max_thread_work_items(phase_id), diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp index ac64f6a88eb..87752426d04 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp @@ -56,6 +56,7 @@ class G1GCPhaseTimes : public CHeapObj { WeakCLDRoots, SATBFiltering, UpdateRS, + ScanHCC, ScanRS, CodeRoots, ObjCopy, diff --git a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp index 2b45155f552..b7c176d632b 100644 --- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp +++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp @@ -26,7 +26,6 @@ #include "gc/g1/dirtyCardQueue.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1HotCardCache.hpp" -#include "gc/g1/g1RemSet.hpp" #include "runtime/atomic.inline.hpp" G1HotCardCache::G1HotCardCache(G1CollectedHeap *g1h): @@ -81,9 +80,7 @@ jbyte* G1HotCardCache::insert(jbyte* card_ptr) { return (previous_ptr == current_ptr) ? previous_ptr : card_ptr; } -void G1HotCardCache::drain(uint worker_i, - G1RemSet* g1rs, - DirtyCardQueue* into_cset_dcq) { +void G1HotCardCache::drain(CardTableEntryClosure* cl, uint worker_i) { if (!default_use_cache()) { assert(_hot_cache == NULL, "Logic"); return; @@ -101,22 +98,8 @@ void G1HotCardCache::drain(uint worker_i, for (size_t i = start_idx; i < end_idx; i++) { jbyte* card_ptr = _hot_cache[i]; if (card_ptr != NULL) { - if (g1rs->refine_card(card_ptr, worker_i, true)) { - // The part of the heap spanned by the card contains references - // that point into the current collection set. - // We need to record the card pointer in the DirtyCardQueueSet - // that we use for such cards. - // - // The only time we care about recording cards that contain - // references that point into the collection set is during - // RSet updating while within an evacuation pause. - // In this case worker_i should be the id of a GC worker thread - assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint"); - assert(worker_i < ParallelGCThreads, - err_msg("incorrect worker id: %u", worker_i)); - - into_cset_dcq->enqueue(card_ptr); - } + bool result = cl->do_card_ptr(card_ptr, worker_i); + assert(result, "Closure should always return true"); } else { break; } diff --git a/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp b/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp index 09edcd8bc00..36a609db30d 100644 --- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp +++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp @@ -32,9 +32,9 @@ #include "runtime/thread.hpp" #include "utilities/globalDefinitions.hpp" +class CardTableEntryClosure; class DirtyCardQueue; class G1CollectedHeap; -class G1RemSet; class HeapRegion; // An evicting cache of cards that have been logged by the G1 post @@ -84,11 +84,11 @@ class G1HotCardCache: public CHeapObj { // The number of cached cards a thread claims when flushing the cache static const int ClaimChunkSize = 32; - bool default_use_cache() const { + public: + static bool default_use_cache() { return (G1ConcRSLogCacheSize > 0); } - public: G1HotCardCache(G1CollectedHeap* g1h); ~G1HotCardCache(); @@ -113,7 +113,7 @@ class G1HotCardCache: public CHeapObj { // Refine the cards that have delayed as a result of // being in the cache. - void drain(uint worker_i, G1RemSet* g1rs, DirtyCardQueue* into_cset_dcq); + void drain(CardTableEntryClosure* cl, uint worker_i); // Set up for parallel processing of the cards in the hot cache void reset_hot_cache_claimed_index() { diff --git a/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp b/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp index db8a0b86f00..6490fea9ad3 100644 --- a/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp @@ -51,15 +51,11 @@ struct InCSetState { enum { // Selection of the values were driven to micro-optimize the encoding and // frequency of the checks. - // The most common check is whether the region is in the collection set or not. - // This encoding allows us to use an != 0 check which in some architectures - // (x86*) can be encoded slightly more efficently than a normal comparison - // against zero. - // The same situation occurs when checking whether the region is humongous - // or not, which is encoded by values < 0. + // The most common check is whether the region is in the collection set or not, + // this encoding allows us to use an > 0 check. // The other values are simply encoded in increasing generation order, which // makes getting the next generation fast by a simple increment. - Humongous = -1, // The region is humongous - note that actually any value < 0 would be possible here. + Humongous = -1, // The region is humongous NotInCSet = 0, // The region is not in the collection set. Young = 1, // The region is in the collection set and a young region. Old = 2, // The region is in the collection set and an old region. @@ -67,16 +63,17 @@ struct InCSetState { }; InCSetState(in_cset_state_t value = NotInCSet) : _value(value) { - assert(is_valid(), err_msg("Invalid state %d", _value)); + assert(is_valid(), "Invalid state %d", _value); } in_cset_state_t value() const { return _value; } void set_old() { _value = Old; } - bool is_in_cset_or_humongous() const { return _value != NotInCSet; } + bool is_in_cset_or_humongous() const { return is_in_cset() || is_humongous(); } bool is_in_cset() const { return _value > NotInCSet; } - bool is_humongous() const { return _value < NotInCSet; } + + bool is_humongous() const { return _value == Humongous; } bool is_young() const { return _value == Young; } bool is_old() const { return _value == Old; } @@ -104,7 +101,7 @@ class G1InCSetStateFastTestBiasedMappedArray : public G1BiasedMappedArraygc_id()); + GCTraceTime tm("phase 1", G1Log::fine() && Verbose, true, gc_timer()); G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -146,8 +148,7 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, &GenMarkSweep::keep_alive, &GenMarkSweep::follow_stack_closure, NULL, - gc_timer(), - gc_tracer()->gc_id()); + gc_timer()); gc_tracer()->report_gc_reference_stats(stats); @@ -168,7 +169,9 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, if (VerifyDuringGC) { HandleMark hm; // handle scope - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif g1h->prepare_for_verify(); // Note: we can verify only the heap here. When an object is // marked, the previous value of the mark word (including @@ -200,7 +203,7 @@ void G1MarkSweep::mark_sweep_phase2() { // phase2, phase3 and phase4, but the ValidateMarkSweep live oops // tracking expects us to do so. See comment under phase4. - GCTraceTime tm("phase 2", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); + GCTraceTime tm("phase 2", G1Log::fine() && Verbose, true, gc_timer()); prepare_compaction(); } @@ -233,7 +236,7 @@ void G1MarkSweep::mark_sweep_phase3() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); // Adjust the pointers to reflect the new locations - GCTraceTime tm("phase 3", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); + GCTraceTime tm("phase 3", G1Log::fine() && Verbose, true, gc_timer()); // Need cleared claim bits for the roots processing ClassLoaderDataGraph::clear_claimed_marks(); @@ -294,7 +297,7 @@ void G1MarkSweep::mark_sweep_phase4() { // to use a higher index (saved from phase2) when verifying perm_gen. G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCTraceTime tm("phase 4", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); + GCTraceTime tm("phase 4", G1Log::fine() && Verbose, true, gc_timer()); G1SpaceCompactClosure blk; g1h->heap_region_iterate(&blk); diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp index 15f217ac011..1d1c5cb0503 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp @@ -31,31 +31,32 @@ #include "utilities/stack.inline.hpp" G1ParCopyHelper::G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : - G1ParClosureSuper(g1, par_scan_state), _scanned_klass(NULL), - _cm(_g1->concurrent_mark()) { } - -G1ParCopyHelper::G1ParCopyHelper(G1CollectedHeap* g1) : - G1ParClosureSuper(g1), _scanned_klass(NULL), - _cm(_g1->concurrent_mark()) { } - -G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1) : - _g1(g1), _par_scan_state(NULL), _worker_id(UINT_MAX) { } + G1ParClosureSuper(g1, par_scan_state), + _worker_id(par_scan_state->worker_id()), + _scanned_klass(NULL), + _cm(_g1->concurrent_mark()) +{ } G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : - _g1(g1), _par_scan_state(NULL), - _worker_id(UINT_MAX) { - set_par_scan_thread_state(par_scan_state); -} + _g1(g1), _par_scan_state(par_scan_state) +{ } -void G1ParClosureSuper::set_par_scan_thread_state(G1ParScanThreadState* par_scan_state) { - assert(_par_scan_state == NULL, "_par_scan_state must only be set once"); - assert(par_scan_state != NULL, "Must set par_scan_state to non-NULL."); +void G1KlassScanClosure::do_klass(Klass* klass) { + // If the klass has not been dirtied we know that there's + // no references into the young gen and we can skip it. + if (!_process_only_dirty || klass->has_modified_oops()) { + // Clean the klass since we're going to scavenge all the metadata. + klass->clear_modified_oops(); - _par_scan_state = par_scan_state; - _worker_id = par_scan_state->worker_id(); + // Tell the closure that this klass is the Klass to scavenge + // and is the one to dirty if oops are left pointing into the young gen. + _closure->set_scanned_klass(klass); - assert(_worker_id < ParallelGCThreads, - err_msg("The given worker id %u must be less than the number of threads %u", _worker_id, ParallelGCThreads)); + klass->oops_do(_closure); + + _closure->set_scanned_klass(NULL); + } + _count++; } // Generate G1 specialized oop_oop_iterate functions. diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp index 6310ab171d6..4ea0c653c44 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp @@ -52,15 +52,12 @@ class G1ParClosureSuper : public OopsInHeapRegionClosure { protected: G1CollectedHeap* _g1; G1ParScanThreadState* _par_scan_state; - uint _worker_id; -public: - // Initializes the instance, leaving _par_scan_state uninitialized. Must be done - // later using the set_par_scan_thread_state() method. - G1ParClosureSuper(G1CollectedHeap* g1); - G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state); - bool apply_to_weak_ref_discovered_field() { return true; } - void set_par_scan_thread_state(G1ParScanThreadState* par_scan_state); + G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state); + ~G1ParClosureSuper() { } + +public: + virtual bool apply_to_weak_ref_discovered_field() { return true; } }; class G1ParPushHeapRSClosure : public G1ParClosureSuper { @@ -76,36 +73,41 @@ public: class G1ParScanClosure : public G1ParClosureSuper { public: - G1ParScanClosure(G1CollectedHeap* g1) : G1ParClosureSuper(g1) { } + G1ParScanClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : + G1ParClosureSuper(g1, par_scan_state) { } template void do_oop_nv(T* p); virtual void do_oop(oop* p) { do_oop_nv(p); } virtual void do_oop(narrowOop* p) { do_oop_nv(p); } - void set_ref_processor(ReferenceProcessor* ref_processor) { _ref_processor = ref_processor; } + void set_ref_processor(ReferenceProcessor* rp) { + set_ref_processor_internal(rp); + } }; // Add back base class for metadata class G1ParCopyHelper : public G1ParClosureSuper { protected: + uint _worker_id; // Cache value from par_scan_state. Klass* _scanned_klass; ConcurrentMark* _cm; // Mark the object if it's not already marked. This is used to mark // objects pointed to by roots that are guaranteed not to move // during the GC (i.e., non-CSet objects). It is MT-safe. - void mark_object(oop obj); + inline void mark_object(oop obj); // Mark the object if it's not already marked. This is used to mark // objects pointed to by roots that have been forwarded during a // GC. It is MT-safe. - void mark_forwarded_object(oop from_obj, oop to_obj); - public: - G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state); - G1ParCopyHelper(G1CollectedHeap* g1); + inline void mark_forwarded_object(oop from_obj, oop to_obj); + G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state); + ~G1ParCopyHelper() { } + + public: void set_scanned_klass(Klass* k) { _scanned_klass = k; } - template void do_klass_barrier(T* p, oop new_obj); + template inline void do_klass_barrier(T* p, oop new_obj); }; enum G1Barrier { @@ -127,26 +129,23 @@ private: public: G1ParCopyClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : G1ParCopyHelper(g1, par_scan_state) { - assert(_ref_processor == NULL, "sanity"); - } - - G1ParCopyClosure(G1CollectedHeap* g1) : G1ParCopyHelper(g1) { - assert(_ref_processor == NULL, "sanity"); + assert(ref_processor() == NULL, "sanity"); } template void do_oop_nv(T* p) { do_oop_work(p); } virtual void do_oop(oop* p) { do_oop_nv(p); } virtual void do_oop(narrowOop* p) { do_oop_nv(p); } - - G1CollectedHeap* g1() { return _g1; }; - G1ParScanThreadState* pss() { return _par_scan_state; } }; -typedef G1ParCopyClosure G1ParScanExtRootClosure; -typedef G1ParCopyClosure G1ParScanAndMarkExtRootClosure; -typedef G1ParCopyClosure G1ParScanAndMarkWeakExtRootClosure; -// We use a separate closure to handle references during evacuation -// failure processing. +class G1KlassScanClosure : public KlassClosure { + G1ParCopyHelper* _closure; + bool _process_only_dirty; + int _count; + public: + G1KlassScanClosure(G1ParCopyHelper* closure, bool process_only_dirty) + : _process_only_dirty(process_only_dirty), _closure(closure), _count(0) {} + void do_klass(Klass* klass); +}; class FilterIntoCSClosure: public ExtendedOopClosure { G1CollectedHeap* _g1; diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp index a6f9ccafc35..c6cef194d71 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp @@ -91,7 +91,7 @@ inline void G1ParScanClosure::do_oop_nv(T* p) { if (state.is_humongous()) { _g1->set_humongous_is_live(obj); } - _par_scan_state->update_rs(_from, p, _worker_id); + _par_scan_state->update_rs(_from, p); } } } @@ -225,4 +225,78 @@ inline void G1UpdateRSOrPushRefOopClosure::do_oop_nv(T* p) { } } +template +void G1ParCopyHelper::do_klass_barrier(T* p, oop new_obj) { + if (_g1->heap_region_containing_raw(new_obj)->is_young()) { + _scanned_klass->record_modified_oops(); + } +} + +void G1ParCopyHelper::mark_object(oop obj) { + assert(!_g1->heap_region_containing(obj)->in_collection_set(), "should not mark objects in the CSet"); + + // We know that the object is not moving so it's safe to read its size. + _cm->grayRoot(obj, (size_t) obj->size(), _worker_id); +} + +void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) { + assert(from_obj->is_forwarded(), "from obj should be forwarded"); + assert(from_obj->forwardee() == to_obj, "to obj should be the forwardee"); + assert(from_obj != to_obj, "should not be self-forwarded"); + + assert(_g1->heap_region_containing(from_obj)->in_collection_set(), "from obj should be in the CSet"); + assert(!_g1->heap_region_containing(to_obj)->in_collection_set(), "should not mark objects in the CSet"); + + // The object might be in the process of being copied by another + // worker so we cannot trust that its to-space image is + // well-formed. So we have to read its size from its from-space + // image which we know should not be changing. + _cm->grayRoot(to_obj, (size_t) from_obj->size(), _worker_id); +} + +template +template +void G1ParCopyClosure::do_oop_work(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + + if (oopDesc::is_null(heap_oop)) { + return; + } + + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + + assert(_worker_id == _par_scan_state->worker_id(), "sanity"); + + const InCSetState state = _g1->in_cset_state(obj); + if (state.is_in_cset()) { + oop forwardee; + markOop m = obj->mark(); + if (m->is_marked()) { + forwardee = (oop) m->decode_pointer(); + } else { + forwardee = _par_scan_state->copy_to_survivor_space(state, obj, m); + } + assert(forwardee != NULL, "forwardee should not be NULL"); + oopDesc::encode_store_heap_oop(p, forwardee); + if (do_mark_object != G1MarkNone && forwardee != obj) { + // If the object is self-forwarded we don't need to explicitly + // mark it, the evacuation failure protocol will do so. + mark_forwarded_object(obj, forwardee); + } + + if (barrier == G1BarrierKlass) { + do_klass_barrier(p, forwardee); + } + } else { + if (state.is_humongous()) { + _g1->set_humongous_is_live(obj); + } + // The object is not in collection set. If we're a root scanning + // closure during an initial mark pause then attempt to mark the object. + if (do_mark_object == G1MarkFromRoot) { + mark_object(obj); + } + } +} + #endif // SHARE_VM_GC_G1_G1OOPCLOSURES_INLINE_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp index f586dfdb088..0a42184f3ca 100644 --- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp +++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp @@ -57,13 +57,13 @@ void G1PageBasedVirtualSpace::initialize_with_page_size(ReservedSpace rs, size_t vmassert(page_size > 0, "Page size must be non-zero."); guarantee(is_ptr_aligned(rs.base(), page_size), - err_msg("Reserved space base " PTR_FORMAT " is not aligned to requested page size " SIZE_FORMAT, p2i(rs.base()), page_size)); + "Reserved space base " PTR_FORMAT " is not aligned to requested page size " SIZE_FORMAT, p2i(rs.base()), page_size); guarantee(is_size_aligned(used_size, os::vm_page_size()), - err_msg("Given used reserved space size needs to be OS page size aligned (%d bytes) but is " SIZE_FORMAT, os::vm_page_size(), used_size)); + "Given used reserved space size needs to be OS page size aligned (%d bytes) but is " SIZE_FORMAT, os::vm_page_size(), used_size); guarantee(used_size <= rs.size(), - err_msg("Used size of reserved space " SIZE_FORMAT " bytes is smaller than reservation at " SIZE_FORMAT " bytes", used_size, rs.size())); + "Used size of reserved space " SIZE_FORMAT " bytes is smaller than reservation at " SIZE_FORMAT " bytes", used_size, rs.size()); guarantee(is_size_aligned(rs.size(), page_size), - err_msg("Expected that the virtual space is size aligned, but " SIZE_FORMAT " is not aligned to page size " SIZE_FORMAT, rs.size(), page_size)); + "Expected that the virtual space is size aligned, but " SIZE_FORMAT " is not aligned to page size " SIZE_FORMAT, rs.size(), page_size); _low_boundary = rs.base(); _high_boundary = _low_boundary + used_size; @@ -137,23 +137,23 @@ char* G1PageBasedVirtualSpace::page_start(size_t index) const { bool G1PageBasedVirtualSpace::is_after_last_page(size_t index) const { guarantee(index <= _committed.size(), - err_msg("Given boundary page " SIZE_FORMAT " is beyond managed page count " SIZE_FORMAT, index, _committed.size())); + "Given boundary page " SIZE_FORMAT " is beyond managed page count " SIZE_FORMAT, index, _committed.size()); return index == _committed.size(); } void G1PageBasedVirtualSpace::commit_preferred_pages(size_t start, size_t num_pages) { vmassert(num_pages > 0, "No full pages to commit"); vmassert(start + num_pages <= _committed.size(), - err_msg("Tried to commit area from page " SIZE_FORMAT " to page " SIZE_FORMAT " " - "that is outside of managed space of " SIZE_FORMAT " pages", - start, start + num_pages, _committed.size())); + "Tried to commit area from page " SIZE_FORMAT " to page " SIZE_FORMAT " " + "that is outside of managed space of " SIZE_FORMAT " pages", + start, start + num_pages, _committed.size()); char* start_addr = page_start(start); size_t size = num_pages * _page_size; os::commit_memory_or_exit(start_addr, size, _page_size, _executable, err_msg("Failed to commit area from " PTR_FORMAT " to " PTR_FORMAT " of length " SIZE_FORMAT ".", - p2i(start_addr), p2i(start_addr + size), size)); + p2i(start_addr), p2i(start_addr + size), size)); } void G1PageBasedVirtualSpace::commit_tail() { @@ -162,14 +162,14 @@ void G1PageBasedVirtualSpace::commit_tail() { char* const aligned_end_address = (char*)align_ptr_down(_high_boundary, _page_size); os::commit_memory_or_exit(aligned_end_address, _tail_size, os::vm_page_size(), _executable, err_msg("Failed to commit tail area from " PTR_FORMAT " to " PTR_FORMAT " of length " SIZE_FORMAT ".", - p2i(aligned_end_address), p2i(_high_boundary), _tail_size)); + p2i(aligned_end_address), p2i(_high_boundary), _tail_size)); } void G1PageBasedVirtualSpace::commit_internal(size_t start_page, size_t end_page) { guarantee(start_page < end_page, - err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + "Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page); guarantee(end_page <= _committed.size(), - err_msg("Given end page " SIZE_FORMAT " is beyond end of managed page amount of " SIZE_FORMAT, end_page, _committed.size())); + "Given end page " SIZE_FORMAT " is beyond end of managed page amount of " SIZE_FORMAT, end_page, _committed.size()); size_t pages = end_page - start_page; bool need_to_commit_tail = is_after_last_page(end_page) && is_last_page_partial(); @@ -195,7 +195,7 @@ char* G1PageBasedVirtualSpace::bounded_end_addr(size_t end_page) const { void G1PageBasedVirtualSpace::pretouch_internal(size_t start_page, size_t end_page) { guarantee(start_page < end_page, - err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + "Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page); os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page)); } @@ -226,7 +226,7 @@ bool G1PageBasedVirtualSpace::commit(size_t start_page, size_t size_in_pages) { void G1PageBasedVirtualSpace::uncommit_internal(size_t start_page, size_t end_page) { guarantee(start_page < end_page, - err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + "Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page); char* start_addr = page_start(start_page); os::uncommit_memory(start_addr, pointer_delta(bounded_end_addr(end_page), start_addr, sizeof(char))); diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp index 99cb4b0bc1f..8ddc22852dc 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp @@ -27,6 +27,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1OopClosures.inline.hpp" #include "gc/g1/g1ParScanThreadState.inline.hpp" +#include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "oops/oop.inline.hpp" @@ -37,15 +38,14 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, _refs(g1h->task_queue(worker_id)), _dcq(&g1h->dirty_card_queue_set()), _ct_bs(g1h->g1_barrier_set()), - _g1_rem(g1h->g1_rem_set()), + _closures(NULL), _hash_seed(17), _worker_id(worker_id), _tenuring_threshold(g1h->g1_policy()->tenuring_threshold()), _age_table(false), - _scanner(g1h), + _scanner(g1h, this), _old_gen_is_full(false) { - _scanner.set_par_scan_thread_state(this); // we allocate G1YoungSurvRateNumRegions plus one entries, since // we "sacrifice" entry 0 to keep track of surviving bytes for // non-young regions (where the age is -1) @@ -69,6 +69,8 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, // need to be moved to the next space. _dest[InCSetState::Young] = InCSetState::Old; _dest[InCSetState::Old] = InCSetState::Old; + + _closures = G1EvacuationRootClosures::create_root_closures(this, _g1h); } // Pass locally gathered statistics to global state. @@ -86,6 +88,7 @@ void G1ParScanThreadState::flush(size_t* surviving_young_words) { G1ParScanThreadState::~G1ParScanThreadState() { delete _plab_allocator; + delete _closures; FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base); } @@ -97,10 +100,10 @@ void G1ParScanThreadState::waste(size_t& wasted, size_t& undo_wasted) { bool G1ParScanThreadState::verify_ref(narrowOop* ref) const { assert(ref != NULL, "invariant"); assert(UseCompressedOops, "sanity"); - assert(!has_partial_array_mask(ref), err_msg("ref=" PTR_FORMAT, p2i(ref))); + assert(!has_partial_array_mask(ref), "ref=" PTR_FORMAT, p2i(ref)); oop p = oopDesc::load_decode_heap_oop(ref); assert(_g1h->is_in_g1_reserved(p), - err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p))); + "ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p)); return true; } @@ -110,11 +113,11 @@ bool G1ParScanThreadState::verify_ref(oop* ref) const { // Must be in the collection set--it's already been copied. oop p = clear_partial_array_mask(ref); assert(_g1h->obj_in_cs(p), - err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p))); + "ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p)); } else { oop p = oopDesc::load_decode_heap_oop(ref); assert(_g1h->is_in_g1_reserved(p), - err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p))); + "ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p)); } return true; } @@ -147,8 +150,8 @@ HeapWord* G1ParScanThreadState::allocate_in_next_plab(InCSetState const state, size_t word_sz, AllocationContext_t const context, bool previous_plab_refill_failed) { - assert(state.is_in_cset_or_humongous(), err_msg("Unexpected state: " CSETSTATE_FORMAT, state.value())); - assert(dest->is_in_cset_or_humongous(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value())); + assert(state.is_in_cset_or_humongous(), "Unexpected state: " CSETSTATE_FORMAT, state.value()); + assert(dest->is_in_cset_or_humongous(), "Unexpected dest: " CSETSTATE_FORMAT, dest->value()); // Right now we only have two types of regions (young / old) so // let's keep the logic here simple. We can generalize it when necessary. @@ -177,7 +180,7 @@ HeapWord* G1ParScanThreadState::allocate_in_next_plab(InCSetState const state, return obj_ptr; } else { _old_gen_is_full = previous_plab_refill_failed; - assert(dest->is_old(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value())); + assert(dest->is_old(), "Unexpected dest: " CSETSTATE_FORMAT, dest->value()); // no other space to try. return NULL; } @@ -359,8 +362,7 @@ void G1ParScanThreadStateSet::flush() { } oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markOop m) { - assert(_g1h->obj_in_cs(old), - err_msg("Object " PTR_FORMAT " should be in the CSet", p2i(old))); + assert(_g1h->obj_in_cs(old), "Object " PTR_FORMAT " should be in the CSet", p2i(old)); oop forward_ptr = old->forward_to_atomic(old); if (forward_ptr == NULL) { @@ -383,9 +385,9 @@ oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markOop m) { // space for this object (old != forward_ptr) or they beat us in // self-forwarding it (old == forward_ptr). assert(old == forward_ptr || !_g1h->obj_in_cs(forward_ptr), - err_msg("Object " PTR_FORMAT " forwarded to: " PTR_FORMAT " " - "should not be in the CSet", - p2i(old), p2i(forward_ptr))); + "Object " PTR_FORMAT " forwarded to: " PTR_FORMAT " " + "should not be in the CSet", + p2i(old), p2i(forward_ptr)); return forward_ptr; } } diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp index 9986379c84e..df7f6ddf83b 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp @@ -36,6 +36,7 @@ #include "oops/oop.hpp" class G1PLABAllocator; +class G1EvacuationRootClosures; class HeapRegion; class outputStream; @@ -45,7 +46,7 @@ class G1ParScanThreadState : public CHeapObj { RefToScanQueue* _refs; DirtyCardQueue _dcq; G1SATBCardTableModRefBS* _ct_bs; - G1RemSet* _g1_rem; + G1EvacuationRootClosures* _closures; G1PLABAllocator* _plab_allocator; @@ -75,9 +76,9 @@ class G1ParScanThreadState : public CHeapObj { InCSetState dest(InCSetState original) const { assert(original.is_valid(), - err_msg("Original state invalid: " CSETSTATE_FORMAT, original.value())); + "Original state invalid: " CSETSTATE_FORMAT, original.value()); assert(_dest[original.value()].is_valid_gen(), - err_msg("Dest state is invalid: " CSETSTATE_FORMAT, _dest[original.value()].value())); + "Dest state is invalid: " CSETSTATE_FORMAT, _dest[original.value()].value()); return _dest[original.value()]; } @@ -97,7 +98,7 @@ class G1ParScanThreadState : public CHeapObj { template void push_on_queue(T* ref); - template void update_rs(HeapRegion* from, T* p, uint tid) { + template void update_rs(HeapRegion* from, T* p) { // If the new value of the field points to the same region or // is the to-space, we don't need to include it in the Rset updates. if (!from->is_in_reserved(oopDesc::load_decode_heap_oop(p)) && !from->is_survivor()) { @@ -109,6 +110,7 @@ class G1ParScanThreadState : public CHeapObj { } } + G1EvacuationRootClosures* closures() { return _closures; } uint worker_id() { return _worker_id; } // Returns the current amount of waste due to alignment or not being able to fit diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp index c213745be4b..e2a35812f84 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp @@ -52,11 +52,11 @@ template void G1ParScanThreadState::do_oop_evac(T* p, HeapRegion* from _g1h->set_humongous_is_live(obj); } else { assert(!in_cset_state.is_in_cset_or_humongous(), - err_msg("In_cset_state must be NotInCSet here, but is " CSETSTATE_FORMAT, in_cset_state.value())); + "In_cset_state must be NotInCSet here, but is " CSETSTATE_FORMAT, in_cset_state.value()); } assert(obj != NULL, "Must be"); - update_rs(from, p, _worker_id); + update_rs(from, p); } template inline void G1ParScanThreadState::push_on_queue(T* ref) { @@ -82,7 +82,7 @@ inline void G1ParScanThreadState::do_oop_partial_array(oop* p) { // to-space object. int next_index = to_obj_array->length(); assert(0 <= next_index && next_index < length, - err_msg("invariant, next index: %d, length: %d", next_index, length)); + "invariant, next index: %d, length: %d", next_index, length); int start = next_index; int end = length; diff --git a/hotspot/src/share/vm/gc/g1/g1Predictions.cpp b/hotspot/src/share/vm/gc/g1/g1Predictions.cpp new file mode 100644 index 00000000000..12092beeca4 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1Predictions.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1Predictions.hpp" + +#ifndef PRODUCT + +void G1Predictions::test() { + double const epsilon = 1e-6; + { + // Some basic formula tests with confidence = 0.0 + G1Predictions predictor(0.0); + TruncatedSeq s; + + double p0 = predictor.get_new_prediction(&s); + assert(p0 < epsilon, "Initial prediction of empty sequence must be 0.0 but is %f", p0); + + s.add(5.0); + double p1 = predictor.get_new_prediction(&s); + assert(fabs(p1 - 5.0) < epsilon, "Prediction should be 5.0 but is %f", p1); + for (int i = 0; i < 40; i++) { + s.add(5.0); + } + double p2 = predictor.get_new_prediction(&s); + assert(fabs(p2 - 5.0) < epsilon, "Prediction should be 5.0 but is %f", p1); + } + + { + // The following tests checks that the initial predictions are based on the + // average of the sequence and not on the stddev (which is 0). + G1Predictions predictor(0.5); + TruncatedSeq s; + + s.add(1.0); + double p1 = predictor.get_new_prediction(&s); + assert(p1 > 1.0, "First prediction must be larger than average, but avg is %f and prediction %f", s.davg(), p1); + s.add(1.0); + double p2 = predictor.get_new_prediction(&s); + assert(p2 < p1, "First prediction must be larger than second, but they are %f %f", p1, p2); + s.add(1.0); + double p3 = predictor.get_new_prediction(&s); + assert(p3 < p2, "Second prediction must be larger than third, but they are %f %f", p2, p3); + s.add(1.0); + s.add(1.0); // Five elements are now in the sequence. + double p5 = predictor.get_new_prediction(&s); + assert(p5 < p3, "Fifth prediction must be smaller than third, but they are %f %f", p3, p5); + assert(fabs(p5 - 1.0) < epsilon, "Prediction must be 1.0+epsilon, but is %f", p5); + } + + { + // The following tests checks that initially prediction based on the average is + // used, that gets overridden by the stddev prediction at the end. + G1Predictions predictor(0.5); + TruncatedSeq s; + + s.add(0.5); + double p1 = predictor.get_new_prediction(&s); + assert(p1 > 0.5, "First prediction must be larger than average, but avg is %f and prediction %f", s.davg(), p1); + s.add(0.2); + double p2 = predictor.get_new_prediction(&s); + assert(p2 < p1, "First prediction must be larger than second, but they are %f %f", p1, p2); + s.add(0.5); + double p3 = predictor.get_new_prediction(&s); + assert(p3 < p2, "Second prediction must be larger than third, but they are %f %f", p2, p3); + s.add(0.2); + s.add(2.0); + double p5 = predictor.get_new_prediction(&s); + assert(p5 > p3, "Fifth prediction must be bigger than third, but they are %f %f", p3, p5); + } +} + +void TestPredictions_test() { + G1Predictions::test(); +} + +#endif diff --git a/hotspot/src/share/vm/gc/g1/g1Predictions.hpp b/hotspot/src/share/vm/gc/g1/g1Predictions.hpp new file mode 100644 index 00000000000..e82319b61a8 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1Predictions.hpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_G1PREDICTIONS_HPP +#define SHARE_VM_GC_G1_G1PREDICTIONS_HPP + +#include "memory/allocation.inline.hpp" +#include "utilities/numberSeq.hpp" + +// Utility class containing various helper methods for prediction. +class G1Predictions VALUE_OBJ_CLASS_SPEC { + private: + double _sigma; + + // This function is used to estimate the stddev of sample sets. There is some + // special consideration of small sample sets: the actual stddev for them is + // not very useful, so we calculate some value based on the sample average. + // Five or more samples yields zero (at that point we use the stddev); fewer + // scale the sample set average linearly from two times the average to 0.5 times + // it. + double stddev_estimate(TruncatedSeq const* seq) const { + double estimate = seq->dsd(); + int const samples = seq->num(); + if (samples < 5) { + estimate = MAX2(seq->davg() * (5 - samples) / 2.0, estimate); + } + return estimate; + } + public: + G1Predictions(double sigma) : _sigma(sigma) { + assert(sigma >= 0.0, "Confidence must be larger than or equal to zero"); + } + + // Confidence factor. + double sigma() const { return _sigma; } + + double get_new_prediction(TruncatedSeq const* seq) const { + return seq->davg() + _sigma * stddev_estimate(seq); + } + +#ifndef PRODUCT + static void test(); +#endif +}; + +#endif // SHARE_VM_GC_G1_G1PREDICTIONS_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp index 374ca385abf..cfac671de88 100644 --- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp @@ -113,7 +113,7 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { virtual void commit_regions(uint start_idx, size_t num_regions) { for (uint i = start_idx; i < start_idx + num_regions; i++) { - assert(!_commit_map.at(i), err_msg("Trying to commit storage at region %u that is already committed", i)); + assert(!_commit_map.at(i), "Trying to commit storage at region %u that is already committed", i); size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); bool zero_filled = false; @@ -128,7 +128,7 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { virtual void uncommit_regions(uint start_idx, size_t num_regions) { for (uint i = start_idx; i < start_idx + num_regions; i++) { - assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region %u that is not committed", i)); + assert(_commit_map.at(i), "Trying to uncommit storage at region %u that is not committed", i); size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); assert(old_refcount > 0, "must be"); diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index 0aa48e6d4c9..700ae50610b 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -26,7 +26,6 @@ #include "gc/g1/concurrentG1Refine.hpp" #include "gc/g1/concurrentG1RefineThread.hpp" #include "gc/g1/g1BlockOffsetTable.inline.hpp" -#include "gc/g1/g1CodeBlobClosure.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" @@ -228,15 +227,13 @@ public: }; size_t G1RemSet::scanRS(G1ParPushHeapRSClosure* oc, - OopClosure* non_heap_roots, + CodeBlobClosure* heap_region_codeblobs, uint worker_i) { double rs_time_start = os::elapsedTime(); - G1CodeBlobClosure code_root_cl(non_heap_roots); - HeapRegion *startRegion = _g1->start_cset_region_for_worker(worker_i); - ScanRSClosure scanRScl(oc, &code_root_cl, worker_i); + ScanRSClosure scanRScl(oc, heap_region_codeblobs, worker_i); _g1->collection_set_iterate_from(startRegion, &scanRScl); scanRScl.set_try_claimed(); @@ -263,6 +260,7 @@ public: DirtyCardQueue* into_cset_dcq) : _g1rs(g1h->g1_rem_set()), _into_cset_dcq(into_cset_dcq) {} + bool do_card_ptr(jbyte* card_ptr, uint worker_i) { // The only time we care about recording cards that // contain references that point into the collection set @@ -285,11 +283,16 @@ public: }; void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i) { - G1GCParPhaseTimesTracker x(_g1p->phase_times(), G1GCPhaseTimes::UpdateRS, worker_i); - // Apply the given closure to all remaining log entries. RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq); - _g1->iterate_dirty_card_closure(&into_cset_update_rs_cl, into_cset_dcq, false, worker_i); + G1GCParPhaseTimesTracker x(_g1p->phase_times(), G1GCPhaseTimes::UpdateRS, worker_i); + { + // Apply the closure to the entries of the hot card cache. + G1GCParPhaseTimesTracker y(_g1p->phase_times(), G1GCPhaseTimes::ScanHCC, worker_i); + _g1->iterate_hcc_closure(&into_cset_update_rs_cl, worker_i); + } + // Apply the closure to all remaining log entries. + _g1->iterate_dirty_card_closure(&into_cset_update_rs_cl, worker_i); } void G1RemSet::cleanupHRRS() { @@ -297,7 +300,7 @@ void G1RemSet::cleanupHRRS() { } size_t G1RemSet::oops_into_collection_set_do(G1ParPushHeapRSClosure* oc, - OopClosure* non_heap_roots, + CodeBlobClosure* heap_region_codeblobs, uint worker_i) { #if CARD_REPEAT_HISTO ct_freq_update_histo_and_reset(); @@ -320,7 +323,7 @@ size_t G1RemSet::oops_into_collection_set_do(G1ParPushHeapRSClosure* oc, DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set()); updateRS(&into_cset_dcq, worker_i); - size_t cards_scanned = scanRS(oc, non_heap_roots, worker_i); + size_t cards_scanned = scanRS(oc, heap_region_codeblobs, worker_i); // We now clear the cached values of _cset_rs_update_cl for this worker _cset_rs_update_cl[worker_i] = NULL; @@ -413,11 +416,11 @@ G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h, bool G1RemSet::refine_card(jbyte* card_ptr, uint worker_i, bool check_for_refs_into_cset) { assert(_g1->is_in_exact(_ct_bs->addr_for(card_ptr)), - err_msg("Card at " PTR_FORMAT " index " SIZE_FORMAT " representing heap at " PTR_FORMAT " (%u) must be in committed heap", - p2i(card_ptr), - _ct_bs->index_for(_ct_bs->addr_for(card_ptr)), - p2i(_ct_bs->addr_for(card_ptr)), - _g1->addr_to_region(_ct_bs->addr_for(card_ptr)))); + "Card at " PTR_FORMAT " index " SIZE_FORMAT " representing heap at " PTR_FORMAT " (%u) must be in committed heap", + p2i(card_ptr), + _ct_bs->index_for(_ct_bs->addr_for(card_ptr)), + p2i(_ct_bs->addr_for(card_ptr)), + _g1->addr_to_region(_ct_bs->addr_for(card_ptr))); // If the card is no longer dirty, nothing to do. if (*card_ptr != CardTableModRefBS::dirty_card_val()) { diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp index 8a670de58f9..7a278ba55b5 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp @@ -95,7 +95,7 @@ public: // Returns the number of cards scanned while looking for pointers // into the collection set. size_t oops_into_collection_set_do(G1ParPushHeapRSClosure* blk, - OopClosure* non_heap_roots, + CodeBlobClosure* heap_region_codeblobs, uint worker_i); // Prepare for and cleanup after an oops_into_collection_set_do @@ -107,7 +107,7 @@ public: void cleanup_after_oops_into_collection_set_do(); size_t scanRS(G1ParPushHeapRSClosure* oc, - OopClosure* non_heap_roots, + CodeBlobClosure* heap_region_codeblobs, uint worker_i); void updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i); diff --git a/hotspot/src/share/vm/gc/g1/g1RootClosures.cpp b/hotspot/src/share/vm/gc/g1/g1RootClosures.cpp new file mode 100644 index 00000000000..2f393e425ae --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1RootClosures.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#include "gc/g1/bufferingOopClosure.hpp" +#include "gc/g1/g1CodeBlobClosure.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1OopClosures.inline.hpp" +#include "gc/g1/g1RootClosures.hpp" + +class G1ParScanThreadState; + +// Simple holder object for a complete set of closures used by the G1 evacuation code. +template +class G1SharedClosures VALUE_OBJ_CLASS_SPEC { +public: + G1ParCopyClosure _oops; + G1ParCopyClosure _oop_in_klass; + G1KlassScanClosure _klass_in_cld_closure; + CLDToKlassAndOopClosure _clds; + G1CodeBlobClosure _codeblobs; + BufferingOopClosure _buffered_oops; + + G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty_klasses, bool must_claim_cld) : + _oops(g1h, pss), + _oop_in_klass(g1h, pss), + _klass_in_cld_closure(&_oop_in_klass, process_only_dirty_klasses), + _clds(&_klass_in_cld_closure, &_oops, must_claim_cld), + _codeblobs(&_oops), + _buffered_oops(&_oops) {} +}; + +class G1EvacuationClosures : public G1EvacuationRootClosures { + G1SharedClosures _closures; + +public: + G1EvacuationClosures(G1CollectedHeap* g1h, + G1ParScanThreadState* pss, + bool gcs_are_young) : + _closures(g1h, pss, gcs_are_young, /* must_claim_cld */ false) {} + + OopClosure* weak_oops() { return &_closures._buffered_oops; } + OopClosure* strong_oops() { return &_closures._buffered_oops; } + + CLDClosure* weak_clds() { return &_closures._clds; } + CLDClosure* strong_clds() { return &_closures._clds; } + CLDClosure* thread_root_clds() { return NULL; } + CLDClosure* second_pass_weak_clds() { return NULL; } + + CodeBlobClosure* strong_codeblobs() { return &_closures._codeblobs; } + CodeBlobClosure* weak_codeblobs() { return &_closures._codeblobs; } + + void flush() { _closures._buffered_oops.done(); } + double closure_app_seconds() { return _closures._buffered_oops.closure_app_seconds(); } + + OopClosure* raw_strong_oops() { return &_closures._oops; } + + bool trace_metadata() { return false; } +}; + +// Closures used during initial mark. +// The treatment of "weak" roots is selectable through the template parameter, +// this is usually used to control unloading of classes and interned strings. +template +class G1InitalMarkClosures : public G1EvacuationRootClosures { + G1SharedClosures _strong; + G1SharedClosures _weak; + + // Filter method to help with returning the appropriate closures + // depending on the class template parameter. + template + T* null_if(T* t) { + if (Mark == MarkWeak) { + return NULL; + } + return t; + } + +public: + G1InitalMarkClosures(G1CollectedHeap* g1h, + G1ParScanThreadState* pss) : + _strong(g1h, pss, /* process_only_dirty_klasses */ false, /* must_claim_cld */ true), + _weak(g1h, pss, /* process_only_dirty_klasses */ false, /* must_claim_cld */ true) {} + + OopClosure* weak_oops() { return &_weak._buffered_oops; } + OopClosure* strong_oops() { return &_strong._buffered_oops; } + + // If MarkWeak is G1MarkPromotedFromRoot then the weak CLDs must be processed in a second pass. + CLDClosure* weak_clds() { return null_if(&_weak._clds); } + CLDClosure* strong_clds() { return &_strong._clds; } + + // If MarkWeak is G1MarkFromRoot then all CLDs are processed by the weak and strong variants + // return a NULL closure for the following specialized versions in that case. + CLDClosure* thread_root_clds() { return null_if(&_strong._clds); } + CLDClosure* second_pass_weak_clds() { return null_if(&_weak._clds); } + + CodeBlobClosure* strong_codeblobs() { return &_strong._codeblobs; } + CodeBlobClosure* weak_codeblobs() { return &_weak._codeblobs; } + + void flush() { + _strong._buffered_oops.done(); + _weak._buffered_oops.done(); + } + + double closure_app_seconds() { + return _strong._buffered_oops.closure_app_seconds() + + _weak._buffered_oops.closure_app_seconds(); + } + + OopClosure* raw_strong_oops() { return &_strong._oops; } + + // If we are not marking all weak roots then we are tracing + // which metadata is alive. + bool trace_metadata() { return MarkWeak == G1MarkPromotedFromRoot; } +}; + +G1EvacuationRootClosures* G1EvacuationRootClosures::create_root_closures(G1ParScanThreadState* pss, G1CollectedHeap* g1h) { + if (g1h->collector_state()->during_initial_mark_pause()) { + if (ClassUnloadingWithConcurrentMark) { + return new G1InitalMarkClosures(g1h, pss); + } else { + return new G1InitalMarkClosures(g1h, pss); + } + } else { + return new G1EvacuationClosures(g1h, pss, g1h->collector_state()->gcs_are_young()); + } +} diff --git a/hotspot/src/share/vm/gc/g1/g1RootClosures.hpp b/hotspot/src/share/vm/gc/g1/g1RootClosures.hpp new file mode 100644 index 00000000000..e4a707f74b0 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1RootClosures.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_G1ROOTCLOSURESET_HPP +#define SHARE_VM_GC_G1_G1ROOTCLOSURESET_HPP + +#include "memory/allocation.hpp" +#include "memory/iterator.hpp" + +class G1CollectedHeap; +class G1ParScanThreadState; + +class G1RootClosures : public CHeapObj { +public: + // Closures to process raw oops in the root set. + virtual OopClosure* weak_oops() = 0; + virtual OopClosure* strong_oops() = 0; + + // Closures to process CLDs in the root set. + virtual CLDClosure* weak_clds() = 0; + virtual CLDClosure* strong_clds() = 0; + + // Applied to the CLDs reachable from the thread stacks. + virtual CLDClosure* thread_root_clds() = 0; + + // Applied to code blobs reachable as strong roots. + virtual CodeBlobClosure* strong_codeblobs() = 0; +}; + +class G1EvacuationRootClosures : public G1RootClosures { +public: + // Flush any buffered state and deferred processing + virtual void flush() = 0; + virtual double closure_app_seconds() = 0; + + // Applied to the weakly reachable CLDs when all strongly reachable + // CLDs are guaranteed to have been processed. + virtual CLDClosure* second_pass_weak_clds() = 0; + + // Get a raw oop closure for processing oops, bypassing the flushing above. + virtual OopClosure* raw_strong_oops() = 0; + + // Applied to code blobs treated as weak roots. + virtual CodeBlobClosure* weak_codeblobs() = 0; + + // Is this closure used for tracing metadata? + virtual bool trace_metadata() = 0; + + static G1EvacuationRootClosures* create_root_closures(G1ParScanThreadState* pss, G1CollectedHeap* g1h); +}; + +#endif // SHARE_VM_GC_G1_G1ROOTCLOSURESET_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp b/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp index 51b5bde3977..14b175320b3 100644 --- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp @@ -33,7 +33,7 @@ #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" -#include "gc/g1/g1RemSet.inline.hpp" +#include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1RootProcessor.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "memory/allocation.inline.hpp" @@ -70,40 +70,19 @@ G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h, uint n_workers) : _lock(Mutex::leaf, "G1 Root Scanning barrier lock", false, Monitor::_safepoint_check_never), _n_workers_discovered_strong_classes(0) {} -void G1RootProcessor::evacuate_roots(OopClosure* scan_non_heap_roots, - OopClosure* scan_non_heap_weak_roots, - CLDClosure* scan_strong_clds, - CLDClosure* scan_weak_clds, - bool trace_metadata, - uint worker_i) { - // First scan the shared roots. +void G1RootProcessor::evacuate_roots(G1EvacuationRootClosures* closures, uint worker_i) { double ext_roots_start = os::elapsedTime(); G1GCPhaseTimes* phase_times = _g1h->g1_policy()->phase_times(); - BufferingOopClosure buf_scan_non_heap_roots(scan_non_heap_roots); - BufferingOopClosure buf_scan_non_heap_weak_roots(scan_non_heap_weak_roots); - - OopClosure* const weak_roots = &buf_scan_non_heap_weak_roots; - OopClosure* const strong_roots = &buf_scan_non_heap_roots; - - // CodeBlobClosures are not interoperable with BufferingOopClosures - G1CodeBlobClosure root_code_blobs(scan_non_heap_roots); - - process_java_roots(strong_roots, - trace_metadata ? scan_strong_clds : NULL, - scan_strong_clds, - trace_metadata ? NULL : scan_weak_clds, - &root_code_blobs, - phase_times, - worker_i); + process_java_roots(closures, phase_times, worker_i); // This is the point where this worker thread will not find more strong CLDs/nmethods. // Report this so G1 can synchronize the strong and weak CLDs/nmethods processing. - if (trace_metadata) { + if (closures->trace_metadata()) { worker_has_discovered_all_strong_classes(); } - process_vm_roots(strong_roots, weak_roots, phase_times, worker_i); + process_vm_roots(closures, phase_times, worker_i); { // Now the CM ref_processor roots. @@ -113,11 +92,11 @@ void G1RootProcessor::evacuate_roots(OopClosure* scan_non_heap_roots, // concurrent mark ref processor as roots and keep entries // (which are added by the marking threads) on them live // until they can be processed at the end of marking. - _g1h->ref_processor_cm()->weak_oops_do(&buf_scan_non_heap_roots); + _g1h->ref_processor_cm()->weak_oops_do(closures->strong_oops()); } } - if (trace_metadata) { + if (closures->trace_metadata()) { { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::WaitForStrongCLD, worker_i); // Barrier to make sure all workers passed @@ -127,18 +106,18 @@ void G1RootProcessor::evacuate_roots(OopClosure* scan_non_heap_roots, // Now take the complement of the strong CLDs. G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::WeakCLDRoots, worker_i); - ClassLoaderDataGraph::roots_cld_do(NULL, scan_weak_clds); + assert(closures->second_pass_weak_clds() != NULL, "Should be non-null if we are tracing metadata."); + ClassLoaderDataGraph::roots_cld_do(NULL, closures->second_pass_weak_clds()); } else { phase_times->record_time_secs(G1GCPhaseTimes::WaitForStrongCLD, worker_i, 0.0); phase_times->record_time_secs(G1GCPhaseTimes::WeakCLDRoots, worker_i, 0.0); + assert(closures->second_pass_weak_clds() == NULL, "Should be null if not tracing metadata."); } // Finish up any enqueued closure apps (attributed as object copy time). - buf_scan_non_heap_roots.done(); - buf_scan_non_heap_weak_roots.done(); + closures->flush(); - double obj_copy_time_sec = buf_scan_non_heap_roots.closure_app_seconds() - + buf_scan_non_heap_weak_roots.closure_app_seconds(); + double obj_copy_time_sec = closures->closure_app_seconds(); phase_times->record_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, obj_copy_time_sec); @@ -159,22 +138,68 @@ void G1RootProcessor::evacuate_roots(OopClosure* scan_non_heap_roots, _process_strong_tasks.all_tasks_completed(n_workers()); } +// Adaptor to pass the closures to the strong roots in the VM. +class StrongRootsClosures : public G1RootClosures { + OopClosure* _roots; + CLDClosure* _clds; + CodeBlobClosure* _blobs; +public: + StrongRootsClosures(OopClosure* roots, CLDClosure* clds, CodeBlobClosure* blobs) : + _roots(roots), _clds(clds), _blobs(blobs) {} + + OopClosure* weak_oops() { return NULL; } + OopClosure* strong_oops() { return _roots; } + + CLDClosure* weak_clds() { return NULL; } + CLDClosure* strong_clds() { return _clds; } + CLDClosure* thread_root_clds() { return _clds; } + + CodeBlobClosure* strong_codeblobs() { return _blobs; } +}; + void G1RootProcessor::process_strong_roots(OopClosure* oops, CLDClosure* clds, CodeBlobClosure* blobs) { + StrongRootsClosures closures(oops, clds, blobs); - process_java_roots(oops, clds, clds, NULL, blobs, NULL, 0); - process_vm_roots(oops, NULL, NULL, 0); + process_java_roots(&closures, NULL, 0); + process_vm_roots(&closures, NULL, 0); _process_strong_tasks.all_tasks_completed(n_workers()); } +// Adaptor to pass the closures to all the roots in the VM. +class AllRootsClosures : public G1RootClosures { + OopClosure* _roots; + CLDClosure* _clds; +public: + AllRootsClosures(OopClosure* roots, CLDClosure* clds) : + _roots(roots), _clds(clds) {} + + OopClosure* weak_oops() { return _roots; } + OopClosure* strong_oops() { return _roots; } + + // By returning the same CLDClosure for both weak and strong CLDs we ensure + // that a single walk of the CLDG will invoke the closure on all CLDs i the + // system. + CLDClosure* weak_clds() { return _clds; } + CLDClosure* strong_clds() { return _clds; } + // We don't want to visit CLDs more than once, so we return NULL for the + // thread root CLDs. + CLDClosure* thread_root_clds() { return NULL; } + + // We don't want to visit code blobs more than once, so we return NULL for the + // strong case and walk the entire code cache as a separate step. + CodeBlobClosure* strong_codeblobs() { return NULL; } +}; + void G1RootProcessor::process_all_roots(OopClosure* oops, CLDClosure* clds, CodeBlobClosure* blobs) { + AllRootsClosures closures(oops, clds); - process_java_roots(oops, NULL, clds, clds, NULL, NULL, 0); - process_vm_roots(oops, oops, NULL, 0); + process_java_roots(&closures, NULL, 0); + process_vm_roots(&closures, NULL, 0); if (!_process_strong_tasks.is_task_claimed(G1RP_PS_CodeCache_oops_do)) { CodeCache::blobs_do(blobs); @@ -183,35 +208,36 @@ void G1RootProcessor::process_all_roots(OopClosure* oops, _process_strong_tasks.all_tasks_completed(n_workers()); } -void G1RootProcessor::process_java_roots(OopClosure* strong_roots, - CLDClosure* thread_stack_clds, - CLDClosure* strong_clds, - CLDClosure* weak_clds, - CodeBlobClosure* strong_code, +void G1RootProcessor::process_java_roots(G1RootClosures* closures, G1GCPhaseTimes* phase_times, uint worker_i) { - assert(thread_stack_clds == NULL || weak_clds == NULL, "There is overlap between those, only one may be set"); + assert(closures->thread_root_clds() == NULL || closures->weak_clds() == NULL, "There is overlap between those, only one may be set"); // Iterating over the CLDG and the Threads are done early to allow us to // first process the strong CLDs and nmethods and then, after a barrier, // let the thread process the weak CLDs and nmethods. { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CLDGRoots, worker_i); if (!_process_strong_tasks.is_task_claimed(G1RP_PS_ClassLoaderDataGraph_oops_do)) { - ClassLoaderDataGraph::roots_cld_do(strong_clds, weak_clds); + ClassLoaderDataGraph::roots_cld_do(closures->strong_clds(), closures->weak_clds()); } } { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ThreadRoots, worker_i); bool is_par = n_workers() > 1; - Threads::possibly_parallel_oops_do(is_par, strong_roots, thread_stack_clds, strong_code); + Threads::possibly_parallel_oops_do(is_par, + closures->strong_oops(), + closures->thread_root_clds(), + closures->strong_codeblobs()); } } -void G1RootProcessor::process_vm_roots(OopClosure* strong_roots, - OopClosure* weak_roots, +void G1RootProcessor::process_vm_roots(G1RootClosures* closures, G1GCPhaseTimes* phase_times, uint worker_i) { + OopClosure* strong_roots = closures->strong_oops(); + OopClosure* weak_roots = closures->weak_oops(); + { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::UniverseRoots, worker_i); if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Universe_oops_do)) { diff --git a/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp b/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp index 4948c1c9fce..ad0f0479810 100644 --- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp @@ -32,8 +32,10 @@ class CLDClosure; class CodeBlobClosure; class G1CollectedHeap; +class G1EvacuationRootClosures; class G1GCPhaseTimes; class G1ParPushHeapRSClosure; +class G1RootClosures; class Monitor; class OopClosure; class SubTasksDone; @@ -71,16 +73,11 @@ class G1RootProcessor : public StackObj { void worker_has_discovered_all_strong_classes(); void wait_until_all_strong_classes_discovered(); - void process_java_roots(OopClosure* scan_non_heap_roots, - CLDClosure* thread_stack_clds, - CLDClosure* scan_strong_clds, - CLDClosure* scan_weak_clds, - CodeBlobClosure* scan_strong_code, + void process_java_roots(G1RootClosures* closures, G1GCPhaseTimes* phase_times, uint worker_i); - void process_vm_roots(OopClosure* scan_non_heap_roots, - OopClosure* scan_non_heap_weak_roots, + void process_vm_roots(G1RootClosures* closures, G1GCPhaseTimes* phase_times, uint worker_i); @@ -90,12 +87,7 @@ public: // Apply closures to the strongly and weakly reachable roots in the system // in a single pass. // Record and report timing measurements for sub phases using the worker_i - void evacuate_roots(OopClosure* scan_non_heap_roots, - OopClosure* scan_non_heap_weak_roots, - CLDClosure* scan_strong_clds, - CLDClosure* scan_weak_clds, - bool trace_metadata, - uint worker_i); + void evacuate_roots(G1EvacuationRootClosures* closures, uint worker_i); // Apply oops, clds and blobs to all strongly reachable roots in the system void process_strong_roots(OopClosure* oops, diff --git a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp index 330ee24af36..36bb3d8c062 100644 --- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp +++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp @@ -247,3 +247,52 @@ G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr, bool whole_heap) { } } } + +void G1SATBCardTableModRefBS::write_ref_nmethod_post(oop* dst, nmethod* nm) { + oop obj = oopDesc::load_heap_oop(dst); + if (obj != NULL) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + HeapRegion* hr = g1h->heap_region_containing(obj); + hr->add_strong_code_root(nm); + } +} + +class G1EnsureLastRefToRegion : public OopClosure { + G1CollectedHeap* _g1h; + HeapRegion* _hr; + oop* _dst; + + bool _value; +public: + G1EnsureLastRefToRegion(G1CollectedHeap* g1h, HeapRegion* hr, oop* dst) : + _g1h(g1h), _hr(hr), _dst(dst), _value(true) {} + + void do_oop(oop* p) { + if (_value && p != _dst) { + oop obj = oopDesc::load_heap_oop(p); + if (obj != NULL) { + HeapRegion* hr = _g1h->heap_region_containing(obj); + if (hr == _hr) { + // Another reference to the same region. + _value = false; + } + } + } + } + void do_oop(narrowOop* p) { ShouldNotReachHere(); } + bool value() const { return _value; } +}; + +void G1SATBCardTableModRefBS::write_ref_nmethod_pre(oop* dst, nmethod* nm) { + oop obj = oopDesc::load_heap_oop(dst); + if (obj != NULL) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + HeapRegion* hr = g1h->heap_region_containing(obj); + G1EnsureLastRefToRegion ensure_last_ref(g1h, hr, dst); + nm->oops_do(&ensure_last_ref); + if (ensure_last_ref.value()) { + // Last reference to this region, remove the nmethod from the rset. + hr->remove_strong_code_root(nm); + } + } +} diff --git a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp index cad5f33c9d6..6f5e8868156 100644 --- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp +++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp @@ -38,6 +38,7 @@ class G1SATBCardTableLoggingModRefBS; // snapshot-at-the-beginning marking. class G1SATBCardTableModRefBS: public CardTableModRefBS { + friend class VMStructs; protected: enum G1CardValues { g1_young_gen = CT_MR_BS_last_reserved << 1 @@ -122,6 +123,9 @@ public: jbyte val = _byte_map[card_index]; return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); } + virtual void write_ref_nmethod_pre(oop* dst, nmethod* nm); + virtual void write_ref_nmethod_post(oop* dst, nmethod* nm); + }; template<> diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index 3482e873862..4297d76a5c7 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_GC_G1_G1_GLOBALS_HPP #include "runtime/globals.hpp" +#include // for DBL_MAX // // Defines all globals flags used by the garbage-first compiler. // @@ -61,6 +62,7 @@ "update buffer processing info " \ "(0 means do not periodically generate this info); " \ "it also requires -XX:+G1SummarizeRSetStats") \ + range(0, max_intx) \ \ diagnostic(bool, G1TraceConcRefinement, false, \ "Trace G1 concurrent refinement") \ @@ -71,7 +73,7 @@ product(double, G1ConcMarkStepDurationMillis, 10.0, \ "Target duration of individual concurrent marking steps " \ "in milliseconds.") \ - range(1.0, (double)max_uintx) \ + range(1.0, DBL_MAX) \ \ product(intx, G1RefProcDrainInterval, 10, \ "The number of discovered reference objects to process before " \ @@ -89,9 +91,11 @@ \ product(size_t, G1SATBBufferSize, 1*K, \ "Number of entries in an SATB log buffer.") \ + range(1, max_uintx) \ \ develop(intx, G1SATBProcessCompletedThreshold, 20, \ "Number of completed buffers that triggers log processing.") \ + range(0, max_jint) \ \ product(uintx, G1SATBBufferEnqueueingThresholdPercent, 60, \ "Before enqueueing them, each mutator thread tries to do some " \ @@ -114,26 +118,31 @@ \ product(size_t, G1UpdateBufferSize, 256, \ "Size of an update buffer") \ + range(1, NOT_LP64(32*M) LP64_ONLY(1*G)) \ \ product(intx, G1ConcRefinementYellowZone, 0, \ "Number of enqueued update buffers that will " \ "trigger concurrent processing. Will be selected ergonomically " \ "by default.") \ + range(0, max_intx) \ \ product(intx, G1ConcRefinementRedZone, 0, \ "Maximum number of enqueued update buffers before mutator " \ "threads start processing new ones instead of enqueueing them. " \ "Will be selected ergonomically by default. Zero will disable " \ "concurrent processing.") \ + range(0, max_intx) \ \ product(intx, G1ConcRefinementGreenZone, 0, \ "The number of update buffers that are left in the queue by the " \ "concurrent processing threads. Will be selected ergonomically " \ "by default.") \ + range(0, max_intx) \ \ product(intx, G1ConcRefinementServiceIntervalMillis, 300, \ "The last concurrent refinement thread wakes up every " \ "specified number of milliseconds to do miscellaneous work.") \ + range(0, max_jint) \ \ product(intx, G1ConcRefinementThresholdStep, 0, \ "Each time the rset update queue increases by this amount " \ @@ -143,6 +152,7 @@ product(intx, G1RSetUpdatingPauseTimePercent, 10, \ "A target percentage of time that is allowed to be spend on " \ "process RS update buffers during the collection pause.") \ + range(0, 100) \ \ product(bool, G1UseAdaptiveConcRefinement, true, \ "Select green, yellow and red zones adaptively to meet the " \ @@ -158,18 +168,24 @@ \ develop(intx, G1RSetRegionEntriesBase, 256, \ "Max number of regions in a fine-grain table per MB.") \ + range(1, max_jint/wordSize) \ \ product(intx, G1RSetRegionEntries, 0, \ "Max number of regions for which we keep bitmaps." \ "Will be set ergonomically by default") \ + range(0, max_jint/wordSize) \ + constraint(G1RSetRegionEntriesConstraintFunc,AfterErgo) \ \ develop(intx, G1RSetSparseRegionEntriesBase, 4, \ "Max number of entries per region in a sparse table " \ "per MB.") \ + range(1, max_jint/wordSize) \ \ product(intx, G1RSetSparseRegionEntries, 0, \ "Max number of entries per region in a sparse table." \ "Will be set ergonomically by default.") \ + range(0, max_jint/wordSize) \ + constraint(G1RSetSparseRegionEntriesConstraintFunc,AfterErgo) \ \ develop(bool, G1RecordHRRSOops, false, \ "When true, record recent calls to rem set operations.") \ @@ -180,6 +196,7 @@ develop(intx, G1MaxVerifyFailures, -1, \ "The maximum number of verification failures to print. " \ "-1 means print all.") \ + range(-1, max_jint) \ \ develop(bool, G1ScrubRemSets, true, \ "When true, do RS scrubbing after cleanup.") \ @@ -193,11 +210,13 @@ develop(intx, G1YoungSurvRateNumRegionsSummary, 0, \ "the number of regions for which we'll print a surv rate " \ "summary.") \ + range(0, max_intx) \ + constraint(G1YoungSurvRateNumRegionsSummaryConstraintFunc,AfterErgo)\ \ product(uintx, G1ReservePercent, 10, \ "It determines the minimum reserve we should have in the heap " \ "to minimize the probability of promotion failure.") \ - range(0, 100) \ + range(0, 50) \ \ diagnostic(bool, G1PrintHeapRegions, false, \ "If set G1 will print information on which regions are being " \ @@ -215,10 +234,13 @@ \ product(size_t, G1HeapRegionSize, 0, \ "Size of the G1 regions.") \ + range(0, 32*M) \ + constraint(G1HeapRegionSizeConstraintFunc,AfterMemoryInit) \ \ product(uintx, G1ConcRefinementThreads, 0, \ "If non-0 is the number of parallel rem set update threads, " \ "otherwise the value is determined ergonomically.") \ + range(0, (max_jint-1)/wordSize) \ \ develop(bool, G1VerifyCTCleanup, false, \ "Verify card table cleanup.") \ @@ -226,6 +248,7 @@ product(size_t, G1RSetScanBlockSize, 64, \ "Size of a work unit of cards claimed by a worker thread" \ "during RSet scanning.") \ + range(1, max_uintx) \ \ develop(uintx, G1SecondaryFreeListAppendLength, 5, \ "The number of regions we will add to the secondary free list " \ @@ -262,6 +285,7 @@ experimental(uintx, G1NewSizePercent, 5, \ "Percentage (0-100) of the heap size to use as default " \ "minimum young gen size.") \ + range(0, 100) \ constraint(G1NewSizePercentConstraintFunc,AfterErgo) \ \ experimental(uintx, G1MixedGCLiveThresholdPercent, 85, \ diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.cpp b/hotspot/src/share/vm/gc/g1/heapRegion.cpp index a706ceeb8c7..75e017ff3c2 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp @@ -165,7 +165,7 @@ void HeapRegion::hr_clear(bool par, bool clear_space, bool locked) { assert(_end == orig_end(), "we should have already filtered out humongous regions"); assert(!in_collection_set(), - err_msg("Should not clear heap region %u in the collection set", hrm_index())); + "Should not clear heap region %u in the collection set", hrm_index()); set_allocation_context(AllocationContext::system()); set_young_index_in_cset(-1); @@ -292,9 +292,9 @@ void HeapRegion::initialize(MemRegion mr, bool clear_space, bool mangle_space) { record_timestamp(); assert(mr.end() == orig_end(), - err_msg("Given region end address " PTR_FORMAT " should match exactly " - "bottom plus one region size, i.e. " PTR_FORMAT, - p2i(mr.end()), p2i(orig_end()))); + "Given region end address " PTR_FORMAT " should match exactly " + "bottom plus one region size, i.e. " PTR_FORMAT, + p2i(mr.end()), p2i(orig_end())); } CompactibleSpace* HeapRegion::next_compaction_space() const { @@ -327,7 +327,7 @@ void HeapRegion::note_self_forwarding_removal_end(bool during_initial_mark, bool during_conc_mark, size_t marked_bytes) { assert(marked_bytes <= used(), - err_msg("marked: " SIZE_FORMAT " used: " SIZE_FORMAT, marked_bytes, used())); + "marked: " SIZE_FORMAT " used: " SIZE_FORMAT, marked_bytes, used()); _prev_top_at_mark_start = top(); _prev_marked_bytes = marked_bytes; } diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.hpp b/hotspot/src/share/vm/gc/g1/heapRegion.hpp index 6966bc8e806..e43b2e62d6d 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp @@ -31,7 +31,6 @@ #include "gc/g1/survRateGroup.hpp" #include "gc/shared/ageTable.hpp" #include "gc/shared/spaceDecorator.hpp" -#include "gc/shared/watermark.hpp" #include "utilities/macros.hpp" // A HeapRegion is the smallest piece of a G1CollectedHeap that @@ -542,9 +541,9 @@ class HeapRegion: public G1OffsetTableContigSpace { void set_containing_set(HeapRegionSetBase* containing_set) { assert((containing_set == NULL && _containing_set != NULL) || (containing_set != NULL && _containing_set == NULL), - err_msg("containing_set: " PTR_FORMAT " " - "_containing_set: " PTR_FORMAT, - p2i(containing_set), p2i(_containing_set))); + "containing_set: " PTR_FORMAT " " + "_containing_set: " PTR_FORMAT, + p2i(containing_set), p2i(_containing_set)); _containing_set = containing_set; } diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp index 20fe8662b76..1b2fada7a23 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp @@ -132,10 +132,10 @@ HeapRegion::block_size(const HeapWord *addr) const { } assert(ClassUnloadingWithConcurrentMark, - err_msg("All blocks should be objects if G1 Class Unloading isn't used. " - "HR: [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ") " - "addr: " PTR_FORMAT, - p2i(bottom()), p2i(top()), p2i(end()), p2i(addr))); + "All blocks should be objects if G1 Class Unloading isn't used. " + "HR: [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ") " + "addr: " PTR_FORMAT, + p2i(bottom()), p2i(top()), p2i(end()), p2i(addr)); // Old regions' dead objects may have dead classes // We need to find the next live object in some other diff --git a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp index f57284abdfd..56e1234113a 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp @@ -92,7 +92,7 @@ void HeapRegionManager::commit_regions(uint index, size_t num_regions) { } void HeapRegionManager::uncommit_regions(uint start, size_t num_regions) { - guarantee(num_regions >= 1, err_msg("Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start)); + guarantee(num_regions >= 1, "Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start); guarantee(_num_committed >= num_regions, "pre-condition"); // Print before uncommitting. @@ -132,7 +132,7 @@ void HeapRegionManager::make_regions_available(uint start, uint num_regions) { _available_map.par_set_range(start, start + num_regions, BitMap::unknown_range); for (uint i = start; i < start + num_regions; i++) { - assert(is_available(i), err_msg("Just made region %u available but is apparently not.", i)); + assert(is_available(i), "Just made region %u available but is apparently not.", i); HeapRegion* hr = at(i); if (G1CollectedHeap::heap()->hr_printer()->is_active()) { G1CollectedHeap::heap()->hr_printer()->commit(hr->bottom(), hr->end()); @@ -213,8 +213,8 @@ uint HeapRegionManager::find_contiguous(size_t num, bool empty_only) { HeapRegion* hr = _regions.get_by_index(i); // sanity check guarantee((!empty_only && !is_available(i)) || (is_available(i) && hr != NULL && hr->is_empty()), - err_msg("Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT - " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr))); + "Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT + " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr)); } return found; } else { @@ -224,7 +224,7 @@ uint HeapRegionManager::find_contiguous(size_t num, bool empty_only) { HeapRegion* HeapRegionManager::next_region_in_heap(const HeapRegion* r) const { guarantee(r != NULL, "Start region must be a valid region"); - guarantee(is_available(r->hrm_index()), err_msg("Trying to iterate starting from region %u which is not in the heap", r->hrm_index())); + guarantee(is_available(r->hrm_index()), "Trying to iterate starting from region %u which is not in the heap", r->hrm_index()); for (uint i = r->hrm_index() + 1; i < _allocated_heapregions_length; i++) { HeapRegion* hr = _regions.get_by_index(i); if (is_available(i)) { @@ -241,7 +241,7 @@ void HeapRegionManager::iterate(HeapRegionClosure* blk) const { if (!is_available(i)) { continue; } - guarantee(at(i) != NULL, err_msg("Tried to access region %u that has a NULL HeapRegion*", i)); + guarantee(at(i) != NULL, "Tried to access region %u that has a NULL HeapRegion*", i); bool res = blk->doHeapRegion(at(i)); if (res) { blk->incomplete(); @@ -273,7 +273,7 @@ uint HeapRegionManager::find_unavailable_from_idx(uint start_idx, uint* res_idx) assert(!is_available(i), "just checking"); } assert(cur == max_length() || num_regions == 0 || is_available(cur), - err_msg("The region at the current position %u must be available or at the end of the heap.", cur)); + "The region at the current position %u must be available or at the end of the heap.", cur); #endif return num_regions; } @@ -374,8 +374,8 @@ void HeapRegionManager::par_iterate(HeapRegionClosure* blk, uint worker_id, Heap assert(chr->is_continues_humongous(), "Must be humongous region"); assert(chr->humongous_start_region() == r, - err_msg("Must work on humongous continuation of the original start region " - PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr))); + "Must work on humongous continuation of the original start region " + PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr)); assert(!hrclaimer->is_region_claimed(ch_index), "Must not have been claimed yet because claiming of humongous continuation first claims the start region"); @@ -440,9 +440,9 @@ uint HeapRegionManager::shrink_by(uint num_regions_to_remove) { void HeapRegionManager::shrink_at(uint index, size_t num_regions) { #ifdef ASSERT for (uint i = index; i < (index + num_regions); i++) { - assert(is_available(i), err_msg("Expected available region at index %u", i)); - assert(at(i)->is_empty(), err_msg("Expected empty region at index %u", i)); - assert(at(i)->is_free(), err_msg("Expected free region at index %u", i)); + assert(is_available(i), "Expected available region at index %u", i); + assert(at(i)->is_empty(), "Expected empty region at index %u", i); + assert(at(i)->is_free(), "Expected free region at index %u", i); } #endif uncommit_regions(index, num_regions); @@ -479,11 +479,11 @@ uint HeapRegionManager::find_empty_from_idx_reverse(uint start_idx, uint* res_id void HeapRegionManager::verify() { guarantee(length() <= _allocated_heapregions_length, - err_msg("invariant: _length: %u _allocated_length: %u", - length(), _allocated_heapregions_length)); + "invariant: _length: %u _allocated_length: %u", + length(), _allocated_heapregions_length); guarantee(_allocated_heapregions_length <= max_length(), - err_msg("invariant: _allocated_length: %u _max_length: %u", - _allocated_heapregions_length, max_length())); + "invariant: _allocated_length: %u _max_length: %u", + _allocated_heapregions_length, max_length()); bool prev_committed = true; uint num_committed = 0; @@ -495,12 +495,12 @@ void HeapRegionManager::verify() { } num_committed++; HeapRegion* hr = _regions.get_by_index(i); - guarantee(hr != NULL, err_msg("invariant: i: %u", i)); + guarantee(hr != NULL, "invariant: i: %u", i); guarantee(!prev_committed || hr->bottom() == prev_end, - err_msg("invariant i: %u " HR_FORMAT " prev_end: " PTR_FORMAT, - i, HR_FORMAT_PARAMS(hr), p2i(prev_end))); + "invariant i: %u " HR_FORMAT " prev_end: " PTR_FORMAT, + i, HR_FORMAT_PARAMS(hr), p2i(prev_end)); guarantee(hr->hrm_index() == i, - err_msg("invariant: i: %u hrm_index(): %u", i, hr->hrm_index())); + "invariant: i: %u hrm_index(): %u", i, hr->hrm_index()); // Asserts will fire if i is >= _length HeapWord* addr = hr->bottom(); guarantee(addr_to_region(addr) == hr, "sanity"); @@ -515,10 +515,10 @@ void HeapRegionManager::verify() { } } for (uint i = _allocated_heapregions_length; i < max_length(); i++) { - guarantee(_regions.get_by_index(i) == NULL, err_msg("invariant i: %u", i)); + guarantee(_regions.get_by_index(i) == NULL, "invariant i: %u", i); } - guarantee(num_committed == _num_committed, err_msg("Found %u committed regions, but should be %u", num_committed, _num_committed)); + guarantee(num_committed == _num_committed, "Found %u committed regions, but should be %u", num_committed, _num_committed); _free_list.verify(); } diff --git a/hotspot/src/share/vm/gc/g1/heapRegionManager.inline.hpp b/hotspot/src/share/vm/gc/g1/heapRegionManager.inline.hpp index b22120b99dc..1eb26d0aa47 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionManager.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.inline.hpp @@ -31,9 +31,9 @@ inline HeapRegion* HeapRegionManager::addr_to_region(HeapWord* addr) const { assert(addr < heap_end(), - err_msg("addr: " PTR_FORMAT " end: " PTR_FORMAT, p2i(addr), p2i(heap_end()))); + "addr: " PTR_FORMAT " end: " PTR_FORMAT, p2i(addr), p2i(heap_end())); assert(addr >= heap_bottom(), - err_msg("addr: " PTR_FORMAT " bottom: " PTR_FORMAT, p2i(addr), p2i(heap_bottom()))); + "addr: " PTR_FORMAT " bottom: " PTR_FORMAT, p2i(addr), p2i(heap_bottom())); HeapRegion* hr = _regions.get_by_address(addr); return hr; diff --git a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp index 03c43ffa315..3186ff9f311 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp @@ -376,8 +376,8 @@ void FromCardCache::initialize(uint n_par_rs, uint max_num_regions) { void FromCardCache::invalidate(uint start_idx, size_t new_num_regions) { guarantee((size_t)start_idx + new_num_regions <= max_uintx, - err_msg("Trying to invalidate beyond maximum region, from %u size " SIZE_FORMAT, - start_idx, new_num_regions)); + "Trying to invalidate beyond maximum region, from %u size " SIZE_FORMAT, + start_idx, new_num_regions); for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { uint end_idx = (start_idx + (uint)new_num_regions); assert(end_idx <= _max_regions, "Must be within max."); @@ -1013,7 +1013,7 @@ bool HeapRegionRemSetIterator::fine_has_next(size_t& card_index) { card_index = _cur_region_card_offset + _cur_card_in_prt; guarantee(_cur_card_in_prt < HeapRegion::CardsPerRegion, - err_msg("Card index " SIZE_FORMAT " must be within the region", _cur_card_in_prt)); + "Card index " SIZE_FORMAT " must be within the region", _cur_card_in_prt); return true; } @@ -1182,8 +1182,8 @@ void PerRegionTable::test_fl_mem_size() { size_t min_prt_size = sizeof(void*) + dummy->bm()->size_in_words() * HeapWordSize; assert(dummy->mem_size() > min_prt_size, - err_msg("PerRegionTable memory usage is suspiciously small, only has " SIZE_FORMAT " bytes. " - "Should be at least " SIZE_FORMAT " bytes.", dummy->mem_size(), min_prt_size)); + "PerRegionTable memory usage is suspiciously small, only has " SIZE_FORMAT " bytes. " + "Should be at least " SIZE_FORMAT " bytes.", dummy->mem_size(), min_prt_size); free(dummy); guarantee(dummy->mem_size() == fl_mem_size(), "fl_mem_size() does not return the correct element size"); // try to reset the state diff --git a/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp b/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp index f4635fdfabd..ce56dc3cc2e 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp @@ -37,14 +37,14 @@ void HeapRegionSetBase::fill_in_ext_msg(hrs_ext_msg* msg, const char* message) { #ifndef PRODUCT void HeapRegionSetBase::verify_region(HeapRegion* hr) { - assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrm_index())); - assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrm_index())); // currently we don't use these sets for young regions - assert(hr->is_humongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrm_index(), name())); - assert(hr->is_free() == regions_free(), err_msg("Wrong free state for region %u and set %s", hr->hrm_index(), name())); - assert(!hr->is_free() || hr->is_empty(), err_msg("Free region %u is not empty for set %s", hr->hrm_index(), name())); + assert(hr->containing_set() == this, "Inconsistent containing set for %u", hr->hrm_index()); + assert(!hr->is_young(), "Adding young region %u", hr->hrm_index()); // currently we don't use these sets for young regions + assert(hr->is_humongous() == regions_humongous(), "Wrong humongous state for region %u and set %s", hr->hrm_index(), name()); + assert(hr->is_free() == regions_free(), "Wrong free state for region %u and set %s", hr->hrm_index(), name()); + assert(!hr->is_free() || hr->is_empty(), "Free region %u is not empty for set %s", hr->hrm_index(), name()); assert(!hr->is_empty() || hr->is_free() || hr->is_archive(), - err_msg("Empty region %u is not free or archive for set %s", hr->hrm_index(), name())); - assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrm_index())); + "Empty region %u is not free or archive for set %s", hr->hrm_index(), name()); + assert(hr->rem_set()->verify_ready_for_par_iteration(), "Wrong iteration state %u", hr->hrm_index()); } #endif @@ -57,14 +57,14 @@ void HeapRegionSetBase::verify() { guarantee(( is_empty() && length() == 0 && total_capacity_bytes() == 0) || (!is_empty() && length() > 0 && total_capacity_bytes() > 0) , - hrs_ext_msg(this, "invariant")); + "%s", hrs_ext_msg(this, "invariant").buffer()); } void HeapRegionSetBase::verify_start() { // See comment in verify() about MT safety and verification. check_mt_safety(); assert(!_verify_in_progress, - hrs_ext_msg(this, "verification should not be in progress")); + "%s", hrs_ext_msg(this, "verification should not be in progress").buffer()); // Do the basic verification first before we do the checks over the regions. HeapRegionSetBase::verify(); @@ -76,7 +76,7 @@ void HeapRegionSetBase::verify_end() { // See comment in verify() about MT safety and verification. check_mt_safety(); assert(_verify_in_progress, - hrs_ext_msg(this, "verification should be in progress")); + "%s", hrs_ext_msg(this, "verification should be in progress").buffer()); _verify_in_progress = false; } @@ -151,7 +151,7 @@ void FreeRegionList::add_ordered(FreeRegionList* from_list) { #endif // ASSERT if (is_empty()) { - assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant")); + assert(length() == 0 && _tail == NULL, "%s", hrs_ext_msg(this, "invariant").buffer()); _head = from_list->_head; _tail = from_list->_tail; } else { @@ -198,8 +198,8 @@ void FreeRegionList::add_ordered(FreeRegionList* from_list) { void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) { check_mt_safety(); - assert(num_regions >= 1, hrs_ext_msg(this, "pre-condition")); - assert(!is_empty(), hrs_ext_msg(this, "pre-condition")); + assert(num_regions >= 1, "%s", hrs_ext_msg(this, "pre-condition").buffer()); + assert(!is_empty(), "%s", hrs_ext_msg(this, "pre-condition").buffer()); verify_optional(); DEBUG_ONLY(uint old_length = length();) @@ -212,22 +212,22 @@ void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) { HeapRegion* prev = curr->prev(); assert(count < num_regions, - hrs_err_msg("[%s] should not come across more regions " - "pending for removal than num_regions: %u", - name(), num_regions)); + "%s", hrs_err_msg("[%s] should not come across more regions " + "pending for removal than num_regions: %u", + name(), num_regions).buffer()); if (prev == NULL) { - assert(_head == curr, hrs_ext_msg(this, "invariant")); + assert(_head == curr, "%s", hrs_ext_msg(this, "invariant").buffer()); _head = next; } else { - assert(_head != curr, hrs_ext_msg(this, "invariant")); + assert(_head != curr, "%s", hrs_ext_msg(this, "invariant").buffer()); prev->set_next(next); } if (next == NULL) { - assert(_tail == curr, hrs_ext_msg(this, "invariant")); + assert(_tail == curr, "%s", hrs_ext_msg(this, "invariant").buffer()); _tail = prev; } else { - assert(_tail != curr, hrs_ext_msg(this, "invariant")); + assert(_tail != curr, "%s", hrs_ext_msg(this, "invariant").buffer()); next->set_prev(prev); } if (_last = curr) { @@ -243,12 +243,12 @@ void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) { } assert(count == num_regions, - hrs_err_msg("[%s] count: %u should be == num_regions: %u", - name(), count, num_regions)); + "%s", hrs_err_msg("[%s] count: %u should be == num_regions: %u", + name(), count, num_regions).buffer()); assert(length() + num_regions == old_length, - hrs_err_msg("[%s] new length should be consistent " - "new length: %u old length: %u num_regions: %u", - name(), length(), old_length, num_regions)); + "%s", hrs_err_msg("[%s] new length should be consistent " + "new length: %u old length: %u num_regions: %u", + name(), length(), old_length, num_regions).buffer()); verify_optional(); } @@ -305,8 +305,8 @@ void FreeRegionList::verify_list() { count++; guarantee(count < _unrealistically_long_length, - hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: " PTR_FORMAT " prev0: " PTR_FORMAT " " "prev1: " PTR_FORMAT " length: %u", - name(), count, p2i(curr), p2i(prev0), p2i(prev1), length())); + "%s", hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: " PTR_FORMAT " prev0: " PTR_FORMAT " " "prev1: " PTR_FORMAT " length: %u", + name(), count, p2i(curr), p2i(prev0), p2i(prev1), length()).buffer()); if (curr->next() != NULL) { guarantee(curr->next()->prev() == curr, "Next or prev pointers messed up"); @@ -321,11 +321,11 @@ void FreeRegionList::verify_list() { curr = curr->next(); } - guarantee(_tail == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), _tail->hrm_index(), prev0->hrm_index())); + guarantee(_tail == prev0, "Expected %s to end with %u but it ended with %u.", name(), _tail->hrm_index(), prev0->hrm_index()); guarantee(_tail == NULL || _tail->next() == NULL, "_tail should not have a next"); - guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count)); - guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - name(), total_capacity_bytes(), capacity)); + guarantee(length() == count, "%s count mismatch. Expected %u, actual %u.", name(), length(), count); + guarantee(total_capacity_bytes() == capacity, "%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + name(), total_capacity_bytes(), capacity); } // Note on the check_mt_safety() methods below: diff --git a/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp b/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp index c9936421a5f..fa370f059a9 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp @@ -29,9 +29,9 @@ inline void HeapRegionSetBase::add(HeapRegion* hr) { check_mt_safety(); - assert(hr->containing_set() == NULL, hrs_ext_msg(this, "should not already have a containing set %u")); - assert(hr->next() == NULL, hrs_ext_msg(this, "should not already be linked")); - assert(hr->prev() == NULL, hrs_ext_msg(this, "should not already be linked")); + assert(hr->containing_set() == NULL, "%s", hrs_ext_msg(this, "should not already have a containing set %u").buffer()); + assert(hr->next() == NULL, "%s", hrs_ext_msg(this, "should not already be linked").buffer()); + assert(hr->prev() == NULL, "%s", hrs_ext_msg(this, "should not already be linked").buffer()); _count.increment(1u, hr->capacity()); hr->set_containing_set(this); @@ -41,18 +41,18 @@ inline void HeapRegionSetBase::add(HeapRegion* hr) { inline void HeapRegionSetBase::remove(HeapRegion* hr) { check_mt_safety(); verify_region(hr); - assert(hr->next() == NULL, hrs_ext_msg(this, "should already be unlinked")); - assert(hr->prev() == NULL, hrs_ext_msg(this, "should already be unlinked")); + assert(hr->next() == NULL, "%s", hrs_ext_msg(this, "should already be unlinked").buffer()); + assert(hr->prev() == NULL, "%s", hrs_ext_msg(this, "should already be unlinked").buffer()); hr->set_containing_set(NULL); - assert(_count.length() > 0, hrs_ext_msg(this, "pre-condition")); + assert(_count.length() > 0, "%s", hrs_ext_msg(this, "pre-condition").buffer()); _count.decrement(1u, hr->capacity()); } inline void FreeRegionList::add_ordered(HeapRegion* hr) { assert((length() == 0 && _head == NULL && _tail == NULL && _last == NULL) || (length() > 0 && _head != NULL && _tail != NULL), - hrs_ext_msg(this, "invariant")); + "%s", hrs_ext_msg(this, "invariant").buffer()); // add() will verify the region and check mt safety. add(hr); @@ -129,7 +129,7 @@ inline HeapRegion* FreeRegionList::remove_region(bool from_head) { return NULL; } assert(length() > 0 && _head != NULL && _tail != NULL, - hrs_ext_msg(this, "invariant")); + "%s", hrs_ext_msg(this, "invariant").buffer()); HeapRegion* hr; diff --git a/hotspot/src/share/vm/gc/g1/heapRegionType.hpp b/hotspot/src/share/vm/gc/g1/heapRegionType.hpp index c4d182237f0..1d3041dceca 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionType.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionType.hpp @@ -28,7 +28,7 @@ #include "memory/allocation.hpp" #define hrt_assert_is_valid(tag) \ - assert(is_valid((tag)), err_msg("invalid HR type: %u", (uint) (tag))) + assert(is_valid((tag)), "invalid HR type: %u", (uint) (tag)) class HeapRegionType VALUE_OBJ_CLASS_SPEC { private: @@ -97,8 +97,7 @@ private: hrt_assert_is_valid(tag); hrt_assert_is_valid(before); hrt_assert_is_valid(_tag); - assert(_tag == before, - err_msg("HR tag: %u, expected: %u new tag; %u", _tag, before, tag)); + assert(_tag == before, "HR tag: %u, expected: %u new tag; %u", _tag, before, tag); _tag = tag; } diff --git a/hotspot/src/share/vm/gc/g1/satbQueue.cpp b/hotspot/src/share/vm/gc/g1/satbQueue.cpp index 4b7a6e00481..2c9d1adb57b 100644 --- a/hotspot/src/share/vm/gc/g1/satbQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/satbQueue.cpp @@ -77,16 +77,16 @@ void ObjPtrQueue::flush() { inline bool requires_marking(const void* entry, G1CollectedHeap* heap) { // Includes rejection of NULL pointers. assert(heap->is_in_reserved(entry), - err_msg("Non-heap pointer in SATB buffer: " PTR_FORMAT, p2i(entry))); + "Non-heap pointer in SATB buffer: " PTR_FORMAT, p2i(entry)); HeapRegion* region = heap->heap_region_containing_raw(entry); - assert(region != NULL, err_msg("No region for " PTR_FORMAT, p2i(entry))); + assert(region != NULL, "No region for " PTR_FORMAT, p2i(entry)); if (entry >= region->next_top_at_mark_start()) { return false; } assert(((oop)entry)->is_oop(true /* ignore mark word */), - err_msg("Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry))); + "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry)); return true; } diff --git a/hotspot/src/share/vm/gc/g1/survRateGroup.cpp b/hotspot/src/share/vm/gc/g1/survRateGroup.cpp index a4a58aa4e28..653efa7148d 100644 --- a/hotspot/src/share/vm/gc/g1/survRateGroup.cpp +++ b/hotspot/src/share/vm/gc/g1/survRateGroup.cpp @@ -24,15 +24,15 @@ #include "precompiled.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" -#include "gc/g1/g1CollectorPolicy.hpp" +#include "gc/g1/g1Predictions.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/g1/survRateGroup.hpp" #include "memory/allocation.hpp" -SurvRateGroup::SurvRateGroup(G1CollectorPolicy* g1p, +SurvRateGroup::SurvRateGroup(G1Predictions* predictor, const char* name, size_t summary_surv_rates_len) : - _g1p(g1p), _name(name), + _predictor(predictor), _name(name), _summary_surv_rates_len(summary_surv_rates_len), _summary_surv_rates_max_len(0), _summary_surv_rates(NULL), @@ -52,10 +52,13 @@ SurvRateGroup::SurvRateGroup(G1CollectorPolicy* g1p, start_adding_regions(); } +double SurvRateGroup::get_new_prediction(TruncatedSeq const* seq) const { + return _predictor->get_new_prediction(seq); +} + void SurvRateGroup::reset() { _all_regions_allocated = 0; _setup_seq_num = 0; - _accum_surv_rate = 0.0; _last_pred = 0.0; // the following will set up the arrays with length 1 _region_num = 1; @@ -76,15 +79,12 @@ void SurvRateGroup::reset() { _region_num = 0; } -void -SurvRateGroup::start_adding_regions() { +void SurvRateGroup::start_adding_regions() { _setup_seq_num = _stats_arrays_length; _region_num = 0; - _accum_surv_rate = 0.0; } -void -SurvRateGroup::stop_adding_regions() { +void SurvRateGroup::stop_adding_regions() { if (_region_num > _stats_arrays_length) { double* old_surv_rate = _surv_rate; double* old_accum_surv_rate_pred = _accum_surv_rate_pred; @@ -119,33 +119,12 @@ SurvRateGroup::stop_adding_regions() { } } -double -SurvRateGroup::accum_surv_rate(size_t adjustment) { - // we might relax this one in the future... - guarantee( adjustment == 0 || adjustment == 1, "pre-condition" ); - - double ret = _accum_surv_rate; - if (adjustment > 0) { - TruncatedSeq* seq = get_seq(_region_num+1); - double surv_rate = _g1p->get_new_prediction(seq); - ret += surv_rate; - } - - return ret; -} - -int -SurvRateGroup::next_age_index() { - TruncatedSeq* seq = get_seq(_region_num); - double surv_rate = _g1p->get_new_prediction(seq); - _accum_surv_rate += surv_rate; - +int SurvRateGroup::next_age_index() { ++_region_num; return (int) ++_all_regions_allocated; } -void -SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) { +void SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) { guarantee( 0 <= age_in_group && (size_t) age_in_group < _region_num, "pre-condition" ); guarantee( _surv_rate[age_in_group] <= 0.00001, @@ -161,9 +140,8 @@ SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) { } } -void -SurvRateGroup::all_surviving_words_recorded(bool propagate) { - if (propagate && _region_num > 0) { // conservative +void SurvRateGroup::all_surviving_words_recorded(bool update_predictors) { + if (update_predictors && _region_num > 0) { // conservative double surv_rate = _surv_rate_pred[_region_num-1]->last(); for (size_t i = _region_num; i < _stats_arrays_length; ++i) { guarantee( _surv_rate[i] <= 0.00001, @@ -175,24 +153,22 @@ SurvRateGroup::all_surviving_words_recorded(bool propagate) { double accum = 0.0; double pred = 0.0; for (size_t i = 0; i < _stats_arrays_length; ++i) { - pred = _g1p->get_new_prediction(_surv_rate_pred[i]); + pred = get_new_prediction(_surv_rate_pred[i]); if (pred > 1.0) pred = 1.0; accum += pred; _accum_surv_rate_pred[i] = accum; - // gclog_or_tty->print_cr("age %3d, accum %10.2lf", i, accum); } _last_pred = pred; } #ifndef PRODUCT -void -SurvRateGroup::print() { +void SurvRateGroup::print() { gclog_or_tty->print_cr("Surv Rate Group: %s (" SIZE_FORMAT " entries)", _name, _region_num); for (size_t i = 0; i < _region_num; ++i) { gclog_or_tty->print_cr(" age " SIZE_FORMAT_W(4) " surv rate %6.2lf %% pred %6.2lf %%", - i, _surv_rate[i] * 100.0, - _g1p->get_new_prediction(_surv_rate_pred[i]) * 100.0); + i, _surv_rate[i] * 100.0, + _predictor->get_new_prediction(_surv_rate_pred[i]) * 100.0); } } @@ -211,9 +187,9 @@ SurvRateGroup::print_surv_rate_summary() { size_t limit = MIN2((int) length, 10); while (index < limit) { gclog_or_tty->print_cr(" " SIZE_FORMAT_W(4) - " %6.2lf%% %6.2lf", - index, _summary_surv_rates[index]->avg() * 100.0, - (double) _summary_surv_rates[index]->num()); + " %6.2lf%% %6.2lf", + index, _summary_surv_rates[index]->avg() * 100.0, + (double) _summary_surv_rates[index]->num()); ++index; } @@ -230,9 +206,9 @@ SurvRateGroup::print_surv_rate_summary() { if (index == length || num % 10 == 0) { gclog_or_tty->print_cr(" " SIZE_FORMAT_W(4) " .. " SIZE_FORMAT_W(4) - " %6.2lf%% %6.2lf", - (index-1) / 10 * 10, index-1, sum / (double) num, - (double) samples / (double) num); + " %6.2lf%% %6.2lf", + (index-1) / 10 * 10, index-1, sum / (double) num, + (double) samples / (double) num); sum = 0.0; num = 0; samples = 0; diff --git a/hotspot/src/share/vm/gc/g1/survRateGroup.hpp b/hotspot/src/share/vm/gc/g1/survRateGroup.hpp index cb5d2872680..a4fbe3bf690 100644 --- a/hotspot/src/share/vm/gc/g1/survRateGroup.hpp +++ b/hotspot/src/share/vm/gc/g1/survRateGroup.hpp @@ -27,18 +27,20 @@ #include "utilities/numberSeq.hpp" -class G1CollectorPolicy; +class G1Predictions; class SurvRateGroup : public CHeapObj { private: - G1CollectorPolicy* _g1p; + G1Predictions* _predictor; + + double get_new_prediction(TruncatedSeq const* seq) const; + const char* _name; size_t _stats_arrays_length; double* _surv_rate; double* _accum_surv_rate_pred; double _last_pred; - double _accum_surv_rate; TruncatedSeq** _surv_rate_pred; NumberSeq** _summary_surv_rates; size_t _summary_surv_rates_len; @@ -49,18 +51,18 @@ private: size_t _setup_seq_num; public: - SurvRateGroup(G1CollectorPolicy* g1p, + SurvRateGroup(G1Predictions* predictor, const char* name, size_t summary_surv_rates_len); void reset(); void start_adding_regions(); void stop_adding_regions(); void record_surviving_words(int age_in_group, size_t surv_words); - void all_surviving_words_recorded(bool propagate); + void all_surviving_words_recorded(bool update_predictors); const char* name() { return _name; } size_t region_num() { return _region_num; } - double accum_surv_rate_pred(int age) { + double accum_surv_rate_pred(int age) const { assert(age >= 0, "must be"); if ((size_t)age < _stats_arrays_length) return _accum_surv_rate_pred[age]; @@ -70,9 +72,7 @@ public: } } - double accum_surv_rate(size_t adjustment); - - TruncatedSeq* get_seq(size_t age) { + TruncatedSeq* get_seq(size_t age) const { if (age >= _setup_seq_num) { guarantee( _setup_seq_num > 0, "invariant" ); age = _setup_seq_num-1; diff --git a/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp b/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp index 316a14fbc72..0040a4f1422 100644 --- a/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp +++ b/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp @@ -26,6 +26,7 @@ #include "gc/g1/concurrentMarkThread.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" +#include "gc/shared/gcId.hpp" #include "gc/g1/g1Log.hpp" #include "gc/g1/vm_operations_g1.hpp" #include "gc/shared/gcTimer.hpp" @@ -66,8 +67,8 @@ VM_G1IncCollectionPause::VM_G1IncCollectionPause(uint gc_count_before, _should_retry_gc(false), _old_marking_cycles_completed_before(0) { guarantee(target_pause_time_ms > 0.0, - err_msg("target_pause_time_ms = %1.6lf should be positive", - target_pause_time_ms)); + "target_pause_time_ms = %1.6lf should be positive", + target_pause_time_ms); _gc_cause = gc_cause; } @@ -227,7 +228,8 @@ void VM_CGC_Operation::release_and_notify_pending_list_lock() { void VM_CGC_Operation::doit() { TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCTraceTime t(_printGCMessage, G1Log::fine(), true, g1h->gc_timer_cm(), g1h->concurrent_mark()->concurrent_gc_id()); + GCIdMark gc_id_mark(_gc_id); + GCTraceTime t(_printGCMessage, G1Log::fine(), true, g1h->gc_timer_cm()); IsGCActiveMark x; _cl->do_void(); } diff --git a/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp b/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp index e4149aaa52d..262e7bd871c 100644 --- a/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp +++ b/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_GC_G1_VM_OPERATIONS_G1_HPP #include "gc/g1/g1AllocationContext.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/vmGCOperations.hpp" // VM_operations for the G1 collector. @@ -104,6 +105,7 @@ class VM_CGC_Operation: public VM_Operation { VoidClosure* _cl; const char* _printGCMessage; bool _needs_pll; + uint _gc_id; protected: // java.lang.ref.Reference support @@ -112,7 +114,7 @@ protected: public: VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg, bool needs_pll) - : _cl(cl), _printGCMessage(printGCMsg), _needs_pll(needs_pll) { } + : _cl(cl), _printGCMessage(printGCMsg), _needs_pll(needs_pll), _gc_id(GCId::current()) { } virtual VMOp_Type type() const { return VMOp_CGC_Operation; } virtual void doit(); virtual bool doit_prologue(); diff --git a/hotspot/src/share/vm/gc/g1/youngList.cpp b/hotspot/src/share/vm/gc/g1/youngList.cpp new file mode 100644 index 00000000000..4224541a72d --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/youngList.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1CollectorPolicy.hpp" +#include "gc/g1/heapRegion.hpp" +#include "gc/g1/heapRegion.inline.hpp" +#include "gc/g1/heapRegionRemSet.hpp" +#include "gc/g1/youngList.hpp" +#include "utilities/ostream.hpp" + +YoungList::YoungList(G1CollectedHeap* g1h) : + _g1h(g1h), _head(NULL), _length(0), _last_sampled_rs_lengths(0), + _survivor_head(NULL), _survivor_tail(NULL), _survivor_length(0) { + guarantee(check_list_empty(false), "just making sure..."); +} + +void YoungList::push_region(HeapRegion *hr) { + assert(!hr->is_young(), "should not already be young"); + assert(hr->get_next_young_region() == NULL, "cause it should!"); + + hr->set_next_young_region(_head); + _head = hr; + + _g1h->g1_policy()->set_region_eden(hr, (int) _length); + ++_length; +} + +void YoungList::add_survivor_region(HeapRegion* hr) { + assert(hr->is_survivor(), "should be flagged as survivor region"); + assert(hr->get_next_young_region() == NULL, "cause it should!"); + + hr->set_next_young_region(_survivor_head); + if (_survivor_head == NULL) { + _survivor_tail = hr; + } + _survivor_head = hr; + ++_survivor_length; +} + +void YoungList::empty_list(HeapRegion* list) { + while (list != NULL) { + HeapRegion* next = list->get_next_young_region(); + list->set_next_young_region(NULL); + list->uninstall_surv_rate_group(); + // This is called before a Full GC and all the non-empty / + // non-humongous regions at the end of the Full GC will end up as + // old anyway. + list->set_old(); + list = next; + } +} + +void YoungList::empty_list() { + assert(check_list_well_formed(), "young list should be well formed"); + + empty_list(_head); + _head = NULL; + _length = 0; + + empty_list(_survivor_head); + _survivor_head = NULL; + _survivor_tail = NULL; + _survivor_length = 0; + + _last_sampled_rs_lengths = 0; + + assert(check_list_empty(false), "just making sure..."); +} + +bool YoungList::check_list_well_formed() { + bool ret = true; + + uint length = 0; + HeapRegion* curr = _head; + HeapRegion* last = NULL; + while (curr != NULL) { + if (!curr->is_young()) { + gclog_or_tty->print_cr("### YOUNG REGION " PTR_FORMAT "-" PTR_FORMAT " " + "incorrectly tagged (y: %d, surv: %d)", + p2i(curr->bottom()), p2i(curr->end()), + curr->is_young(), curr->is_survivor()); + ret = false; + } + ++length; + last = curr; + curr = curr->get_next_young_region(); + } + ret = ret && (length == _length); + + if (!ret) { + gclog_or_tty->print_cr("### YOUNG LIST seems not well formed!"); + gclog_or_tty->print_cr("### list has %u entries, _length is %u", + length, _length); + } + + return ret; +} + +bool YoungList::check_list_empty(bool check_sample) { + bool ret = true; + + if (_length != 0) { + gclog_or_tty->print_cr("### YOUNG LIST should have 0 length, not %u", + _length); + ret = false; + } + if (check_sample && _last_sampled_rs_lengths != 0) { + gclog_or_tty->print_cr("### YOUNG LIST has non-zero last sampled RS lengths"); + ret = false; + } + if (_head != NULL) { + gclog_or_tty->print_cr("### YOUNG LIST does not have a NULL head"); + ret = false; + } + if (!ret) { + gclog_or_tty->print_cr("### YOUNG LIST does not seem empty"); + } + + return ret; +} + +void +YoungList::rs_length_sampling_init() { + _sampled_rs_lengths = 0; + _curr = _head; +} + +bool +YoungList::rs_length_sampling_more() { + return _curr != NULL; +} + +void +YoungList::rs_length_sampling_next() { + assert( _curr != NULL, "invariant" ); + size_t rs_length = _curr->rem_set()->occupied(); + + _sampled_rs_lengths += rs_length; + + // The current region may not yet have been added to the + // incremental collection set (it gets added when it is + // retired as the current allocation region). + if (_curr->in_collection_set()) { + // Update the collection set policy information for this region + _g1h->g1_policy()->update_incremental_cset_info(_curr, rs_length); + } + + _curr = _curr->get_next_young_region(); + if (_curr == NULL) { + _last_sampled_rs_lengths = _sampled_rs_lengths; + // gclog_or_tty->print_cr("last sampled RS lengths = %d", _last_sampled_rs_lengths); + } +} + +void +YoungList::reset_auxilary_lists() { + guarantee( is_empty(), "young list should be empty" ); + assert(check_list_well_formed(), "young list should be well formed"); + + // Add survivor regions to SurvRateGroup. + _g1h->g1_policy()->note_start_adding_survivor_regions(); + _g1h->g1_policy()->finished_recalculating_age_indexes(true /* is_survivors */); + + int young_index_in_cset = 0; + for (HeapRegion* curr = _survivor_head; + curr != NULL; + curr = curr->get_next_young_region()) { + _g1h->g1_policy()->set_region_survivor(curr, young_index_in_cset); + + // The region is a non-empty survivor so let's add it to + // the incremental collection set for the next evacuation + // pause. + _g1h->g1_policy()->add_region_to_incremental_cset_rhs(curr); + young_index_in_cset += 1; + } + assert((uint) young_index_in_cset == _survivor_length, "post-condition"); + _g1h->g1_policy()->note_stop_adding_survivor_regions(); + + _head = _survivor_head; + _length = _survivor_length; + if (_survivor_head != NULL) { + assert(_survivor_tail != NULL, "cause it shouldn't be"); + assert(_survivor_length > 0, "invariant"); + _survivor_tail->set_next_young_region(NULL); + } + + // Don't clear the survivor list handles until the start of + // the next evacuation pause - we need it in order to re-tag + // the survivor regions from this evacuation pause as 'young' + // at the start of the next. + + _g1h->g1_policy()->finished_recalculating_age_indexes(false /* is_survivors */); + + assert(check_list_well_formed(), "young list should be well formed"); +} + +void YoungList::print() { + HeapRegion* lists[] = {_head, _survivor_head}; + const char* names[] = {"YOUNG", "SURVIVOR"}; + + for (uint list = 0; list < ARRAY_SIZE(lists); ++list) { + gclog_or_tty->print_cr("%s LIST CONTENTS", names[list]); + HeapRegion *curr = lists[list]; + if (curr == NULL) { + gclog_or_tty->print_cr(" empty"); + } + while (curr != NULL) { + gclog_or_tty->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT ", N: " PTR_FORMAT ", age: %4d", + HR_FORMAT_PARAMS(curr), + p2i(curr->prev_top_at_mark_start()), + p2i(curr->next_top_at_mark_start()), + curr->age_in_surv_rate_group_cond()); + curr = curr->get_next_young_region(); + } + } + + gclog_or_tty->cr(); +} diff --git a/hotspot/src/share/vm/gc/g1/youngList.hpp b/hotspot/src/share/vm/gc/g1/youngList.hpp new file mode 100644 index 00000000000..36108b807db --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/youngList.hpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_YOUNGLIST_HPP +#define SHARE_VM_GC_G1_YOUNGLIST_HPP + +#include "memory/allocation.hpp" +#include "runtime/globals.hpp" + +class YoungList : public CHeapObj { +private: + G1CollectedHeap* _g1h; + + HeapRegion* _head; + + HeapRegion* _survivor_head; + HeapRegion* _survivor_tail; + + HeapRegion* _curr; + + uint _length; + uint _survivor_length; + + size_t _last_sampled_rs_lengths; + size_t _sampled_rs_lengths; + + void empty_list(HeapRegion* list); + +public: + YoungList(G1CollectedHeap* g1h); + + void push_region(HeapRegion* hr); + void add_survivor_region(HeapRegion* hr); + + void empty_list(); + bool is_empty() { return _length == 0; } + uint length() { return _length; } + uint eden_length() { return length() - survivor_length(); } + uint survivor_length() { return _survivor_length; } + + // Currently we do not keep track of the used byte sum for the + // young list and the survivors and it'd be quite a lot of work to + // do so. When we'll eventually replace the young list with + // instances of HeapRegionLinkedList we'll get that for free. So, + // we'll report the more accurate information then. + size_t eden_used_bytes() { + assert(length() >= survivor_length(), "invariant"); + return (size_t) eden_length() * HeapRegion::GrainBytes; + } + size_t survivor_used_bytes() { + return (size_t) survivor_length() * HeapRegion::GrainBytes; + } + + void rs_length_sampling_init(); + bool rs_length_sampling_more(); + void rs_length_sampling_next(); + + void reset_sampled_info() { + _last_sampled_rs_lengths = 0; + } + size_t sampled_rs_lengths() { return _last_sampled_rs_lengths; } + + // for development purposes + void reset_auxilary_lists(); + void clear() { _head = NULL; _length = 0; } + + void clear_survivors() { + _survivor_head = NULL; + _survivor_tail = NULL; + _survivor_length = 0; + } + + HeapRegion* first_region() { return _head; } + HeapRegion* first_survivor_region() { return _survivor_head; } + HeapRegion* last_survivor_region() { return _survivor_tail; } + + // debugging + bool check_list_well_formed(); + bool check_list_empty(bool check_sample = true); + void print(); +}; + +#endif // SHARE_VM_GC_G1_YOUNGLIST_HPP diff --git a/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp b/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp index 7659cd73fa3..a2ce06fd768 100644 --- a/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp +++ b/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp @@ -285,7 +285,7 @@ void CardTableExtension::scavenge_contents_parallel(ObjectStartArray* start_arra while (p < to) { Prefetch::write(p, interval); oop m = oop(p); - assert(m->is_oop_or_null(), err_msg("Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m))); + assert(m->is_oop_or_null(), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m)); pm->push_contents(m); p += m->size(); } @@ -293,7 +293,7 @@ void CardTableExtension::scavenge_contents_parallel(ObjectStartArray* start_arra } else { while (p < to) { oop m = oop(p); - assert(m->is_oop_or_null(), err_msg("Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m))); + assert(m->is_oop_or_null(), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m)); pm->push_contents(m); p += m->size(); } diff --git a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp index c424531bb26..85a908ed794 100644 --- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp +++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp @@ -26,6 +26,7 @@ #include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/gcTaskThread.hpp" #include "gc/shared/adaptiveSizePolicy.hpp" +#include "gc/shared/gcId.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "runtime/mutex.hpp" @@ -48,8 +49,8 @@ const char* GCTask::Kind::to_string(kind value) { case ordinary_task: result = "ordinary task"; break; - case barrier_task: - result = "barrier task"; + case wait_for_barrier_task: + result = "wait for barrier task"; break; case noop_task: result = "noop task"; @@ -61,33 +62,24 @@ const char* GCTask::Kind::to_string(kind value) { return result; }; -GCTask::GCTask() : - _kind(Kind::ordinary_task), - _affinity(GCTaskManager::sentinel_worker()){ - initialize(); +GCTask::GCTask() { + initialize(Kind::ordinary_task, GCId::current()); } -GCTask::GCTask(Kind::kind kind) : - _kind(kind), - _affinity(GCTaskManager::sentinel_worker()) { - initialize(); +GCTask::GCTask(Kind::kind kind) { + initialize(kind, GCId::current()); } -GCTask::GCTask(uint affinity) : - _kind(Kind::ordinary_task), - _affinity(affinity) { - initialize(); +GCTask::GCTask(Kind::kind kind, uint gc_id) { + initialize(kind, gc_id); } -GCTask::GCTask(Kind::kind kind, uint affinity) : - _kind(kind), - _affinity(affinity) { - initialize(); -} - -void GCTask::initialize() { +void GCTask::initialize(Kind::kind kind, uint gc_id) { + _kind = kind; + _affinity = GCTaskManager::sentinel_worker(); _older = NULL; _newer = NULL; + _gc_id = gc_id; } void GCTask::destruct() { @@ -378,16 +370,7 @@ SynchronizedGCTaskQueue::~SynchronizedGCTaskQueue() { GCTaskManager::GCTaskManager(uint workers) : _workers(workers), _active_workers(0), - _idle_workers(0), - _ndc(NULL) { - initialize(); -} - -GCTaskManager::GCTaskManager(uint workers, NotifyDoneClosure* ndc) : - _workers(workers), - _active_workers(0), - _idle_workers(0), - _ndc(ndc) { + _idle_workers(0) { initialize(); } @@ -404,7 +387,6 @@ void GCTaskManager::initialize() { GCTaskQueue* unsynchronized_queue = GCTaskQueue::create_on_c_heap(); _queue = SynchronizedGCTaskQueue::create(unsynchronized_queue, lock()); _noop_task = NoopGCTask::create_on_c_heap(); - _idle_inactive_task = WaitForBarrierGCTask::create_on_c_heap(); _resource_flag = NEW_C_HEAP_ARRAY(bool, workers(), mtGC); { // Set up worker threads. @@ -437,7 +419,6 @@ void GCTaskManager::initialize() { } reset_delivered_tasks(); reset_completed_tasks(); - reset_noop_tasks(); reset_barriers(); reset_emptied_queue(); for (uint s = 0; s < workers(); s += 1) { @@ -450,8 +431,6 @@ GCTaskManager::~GCTaskManager() { assert(queue()->is_empty(), "still have queued work"); NoopGCTask::destroy(_noop_task); _noop_task = NULL; - WaitForBarrierGCTask::destroy(_idle_inactive_task); - _idle_inactive_task = NULL; if (_thread != NULL) { for (uint i = 0; i < workers(); i += 1) { GCTaskThread::destroy(thread(i)); @@ -483,9 +462,9 @@ void GCTaskManager::set_active_gang() { Threads::number_of_non_daemon_threads()); assert(!all_workers_active() || active_workers() == ParallelGCThreads, - err_msg("all_workers_active() is incorrect: " - "active %d ParallelGCThreads %u", active_workers(), - ParallelGCThreads)); + "all_workers_active() is incorrect: " + "active %d ParallelGCThreads %u", active_workers(), + ParallelGCThreads); if (TraceDynamicGCThreads) { gclog_or_tty->print_cr("GCTaskManager::set_active_gang(): " "all_workers_active() %d workers %d " @@ -507,7 +486,7 @@ void GCTaskManager::task_idle_workers() { // the GCTaskManager's monitor so that the "more_inactive_workers" // count is correct. MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); - _idle_inactive_task->set_should_wait(true); + _wait_helper.set_should_wait(true); // active_workers are a number being requested. idle_workers // are the number currently idle. If all the workers are being // requested to be active but some are already idle, reduce @@ -550,7 +529,7 @@ void GCTaskManager::release_idle_workers() { { MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); - _idle_inactive_task->set_should_wait(false); + _wait_helper.set_should_wait(false); monitor()->notify_all(); // Release monitor } @@ -671,7 +650,6 @@ GCTask* GCTaskManager::get_task(uint which) { // Just hand back a Noop task, // in case someone wanted us to release resources, or whatever. result = noop_task(); - increment_noop_tasks(); } assert(result != NULL, "shouldn't have null task"); if (TraceGCTaskManager) { @@ -706,11 +684,6 @@ void GCTaskManager::note_completion(uint which) { if (TraceGCTaskManager) { tty->print_cr(" GCTaskManager::note_completion(%u) done", which); } - // Notify client that we are done. - NotifyDoneClosure* ndc = notify_done_closure(); - if (ndc != NULL) { - ndc->notify(this); - } } if (TraceGCTaskManager) { tty->print_cr(" GCTaskManager::note_completion(%u) (%s)->notify_all", @@ -751,7 +724,7 @@ uint GCTaskManager::decrement_busy_workers() { } void GCTaskManager::release_all_resources() { - // If you want this to be done atomically, do it in a BarrierGCTask. + // If you want this to be done atomically, do it in a WaitForBarrierGCTask. for (uint i = 0; i < workers(); i += 1) { set_resource_flag(i, true); } @@ -813,25 +786,22 @@ void GCTaskManager::set_resource_flag(uint which, bool value) { // NoopGCTask // -NoopGCTask* NoopGCTask::create() { - NoopGCTask* result = new NoopGCTask(false); - return result; -} - NoopGCTask* NoopGCTask::create_on_c_heap() { - NoopGCTask* result = new(ResourceObj::C_HEAP, mtGC) NoopGCTask(true); + NoopGCTask* result = new(ResourceObj::C_HEAP, mtGC) NoopGCTask(); return result; } void NoopGCTask::destroy(NoopGCTask* that) { if (that != NULL) { that->destruct(); - if (that->is_c_heap_obj()) { - FreeHeap(that); - } + FreeHeap(that); } } +// This task should never be performing GC work that require +// a valid GC id. +NoopGCTask::NoopGCTask() : GCTask(GCTask::Kind::noop_task, GCId::undefined()) { } + void NoopGCTask::destruct() { // This has to know it's superclass structure, just like the constructor. this->GCTask::destruct(); @@ -857,12 +827,12 @@ IdleGCTask* IdleGCTask::create_on_c_heap() { } void IdleGCTask::do_it(GCTaskManager* manager, uint which) { - WaitForBarrierGCTask* wait_for_task = manager->idle_inactive_task(); + WaitHelper* wait_helper = manager->wait_helper(); if (TraceGCTaskManager) { tty->print_cr("[" INTPTR_FORMAT "]" " IdleGCTask:::do_it()" " should_wait: %s", - p2i(this), wait_for_task->should_wait() ? "true" : "false"); + p2i(this), wait_helper->should_wait() ? "true" : "false"); } MutexLockerEx ml(manager->monitor(), Mutex::_no_safepoint_check_flag); if (TraceDynamicGCThreads) { @@ -871,7 +841,7 @@ void IdleGCTask::do_it(GCTaskManager* manager, uint which) { // Increment has to be done when the idle tasks are created. // manager->increment_idle_workers(); manager->monitor()->notify_all(); - while (wait_for_task->should_wait()) { + while (wait_helper->should_wait()) { if (TraceGCTaskManager) { tty->print_cr("[" INTPTR_FORMAT "]" " IdleGCTask::do_it()" @@ -888,7 +858,7 @@ void IdleGCTask::do_it(GCTaskManager* manager, uint which) { tty->print_cr("[" INTPTR_FORMAT "]" " IdleGCTask::do_it() returns" " should_wait: %s", - p2i(this), wait_for_task->should_wait() ? "true" : "false"); + p2i(this), wait_helper->should_wait() ? "true" : "false"); } // Release monitor(). } @@ -909,140 +879,52 @@ void IdleGCTask::destruct() { } // -// BarrierGCTask +// WaitForBarrierGCTask // - -void BarrierGCTask::do_it(GCTaskManager* manager, uint which) { - // Wait for this to be the only busy worker. - // ??? I thought of having a StackObj class - // whose constructor would grab the lock and come to the barrier, - // and whose destructor would release the lock, - // but that seems like too much mechanism for two lines of code. - MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); - do_it_internal(manager, which); - // Release manager->lock(). +WaitForBarrierGCTask* WaitForBarrierGCTask::create() { + WaitForBarrierGCTask* result = new WaitForBarrierGCTask(); + return result; } -void BarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) { +WaitForBarrierGCTask::WaitForBarrierGCTask() : GCTask(GCTask::Kind::wait_for_barrier_task) { } + +void WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) { + if (that != NULL) { + if (TraceGCTaskManager) { + tty->print_cr("[" INTPTR_FORMAT "] WaitForBarrierGCTask::destroy()", p2i(that)); + } + that->destruct(); + } +} + +void WaitForBarrierGCTask::destruct() { + if (TraceGCTaskManager) { + tty->print_cr("[" INTPTR_FORMAT "] WaitForBarrierGCTask::destruct()", p2i(this)); + } + this->GCTask::destruct(); + // Clean up that should be in the destructor, + // except that ResourceMarks don't call destructors. + _wait_helper.release_monitor(); +} + +void WaitForBarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) { // Wait for this to be the only busy worker. assert(manager->monitor()->owned_by_self(), "don't own the lock"); assert(manager->is_blocked(), "manager isn't blocked"); while (manager->busy_workers() > 1) { if (TraceGCTaskManager) { - tty->print_cr("BarrierGCTask::do_it(%u) waiting on %u workers", + tty->print_cr("WaitForBarrierGCTask::do_it(%u) waiting on %u workers", which, manager->busy_workers()); } manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0); } } -void BarrierGCTask::destruct() { - this->GCTask::destruct(); - // Nothing else to do. -} - -// -// ReleasingBarrierGCTask -// - -void ReleasingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { - MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); - do_it_internal(manager, which); - manager->release_all_resources(); - // Release manager->lock(). -} - -void ReleasingBarrierGCTask::destruct() { - this->BarrierGCTask::destruct(); - // Nothing else to do. -} - -// -// NotifyingBarrierGCTask -// - -void NotifyingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { - MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); - do_it_internal(manager, which); - NotifyDoneClosure* ndc = notify_done_closure(); - if (ndc != NULL) { - ndc->notify(manager); - } - // Release manager->lock(). -} - -void NotifyingBarrierGCTask::destruct() { - this->BarrierGCTask::destruct(); - // Nothing else to do. -} - -// -// WaitForBarrierGCTask -// -WaitForBarrierGCTask* WaitForBarrierGCTask::create() { - WaitForBarrierGCTask* result = new WaitForBarrierGCTask(false); - return result; -} - -WaitForBarrierGCTask* WaitForBarrierGCTask::create_on_c_heap() { - WaitForBarrierGCTask* result = - new (ResourceObj::C_HEAP, mtGC) WaitForBarrierGCTask(true); - return result; -} - -WaitForBarrierGCTask::WaitForBarrierGCTask(bool on_c_heap) : - _is_c_heap_obj(on_c_heap) { - _monitor = MonitorSupply::reserve(); - set_should_wait(true); - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::WaitForBarrierGCTask()" - " monitor: " INTPTR_FORMAT, - p2i(this), p2i(monitor())); - } -} - -void WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) { - if (that != NULL) { - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::destroy()" - " is_c_heap_obj: %s" - " monitor: " INTPTR_FORMAT, - p2i(that), - that->is_c_heap_obj() ? "true" : "false", - p2i(that->monitor())); - } - that->destruct(); - if (that->is_c_heap_obj()) { - FreeHeap(that); - } - } -} - -void WaitForBarrierGCTask::destruct() { - assert(monitor() != NULL, "monitor should not be NULL"); - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::destruct()" - " monitor: " INTPTR_FORMAT, - p2i(this), p2i(monitor())); - } - this->BarrierGCTask::destruct(); - // Clean up that should be in the destructor, - // except that ResourceMarks don't call destructors. - if (monitor() != NULL) { - MonitorSupply::release(monitor()); - } - _monitor = (Monitor*) 0xDEAD000F; -} - void WaitForBarrierGCTask::do_it(GCTaskManager* manager, uint which) { if (TraceGCTaskManager) { tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::do_it() waiting for idle" - " monitor: " INTPTR_FORMAT, - p2i(this), p2i(monitor())); + " WaitForBarrierGCTask::do_it() waiting for idle", + p2i(this)); } { // First, wait for the barrier to arrive. @@ -1050,24 +932,30 @@ void WaitForBarrierGCTask::do_it(GCTaskManager* manager, uint which) { do_it_internal(manager, which); // Release manager->lock(). } - { - // Then notify the waiter. - MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); - set_should_wait(false); - // Waiter doesn't miss the notify in the wait_for method - // since it checks the flag after grabbing the monitor. - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::do_it()" - " [" INTPTR_FORMAT "] (%s)->notify_all()", - p2i(this), p2i(monitor()), monitor()->name()); - } - monitor()->notify_all(); - // Release monitor(). + // Then notify the waiter. + _wait_helper.notify(); +} + +WaitHelper::WaitHelper() : _should_wait(true), _monitor(MonitorSupply::reserve()) { + if (TraceGCTaskManager) { + tty->print_cr("[" INTPTR_FORMAT "]" + " WaitHelper::WaitHelper()" + " monitor: " INTPTR_FORMAT, + p2i(this), p2i(monitor())); } } -void WaitForBarrierGCTask::wait_for(bool reset) { +void WaitHelper::release_monitor() { + assert(_monitor != NULL, ""); + MonitorSupply::release(_monitor); + _monitor = NULL; +} + +WaitHelper::~WaitHelper() { + release_monitor(); +} + +void WaitHelper::wait_for(bool reset) { if (TraceGCTaskManager) { tty->print_cr("[" INTPTR_FORMAT "]" " WaitForBarrierGCTask::wait_for()" @@ -1100,6 +988,20 @@ void WaitForBarrierGCTask::wait_for(bool reset) { } } +void WaitHelper::notify() { + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); + set_should_wait(false); + // Waiter doesn't miss the notify in the wait_for method + // since it checks the flag after grabbing the monitor. + if (TraceGCTaskManager) { + tty->print_cr("[" INTPTR_FORMAT "]" + " WaitForBarrierGCTask::do_it()" + " [" INTPTR_FORMAT "] (%s)->notify_all()", + p2i(this), p2i(monitor()), monitor()->name()); + } + monitor()->notify_all(); +} + Mutex* MonitorSupply::_lock = NULL; GrowableArray* MonitorSupply::_freelist = NULL; diff --git a/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp b/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp index 6dee6763723..9d462039ad7 100644 --- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp +++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp @@ -38,12 +38,8 @@ class GCTask; class GCTaskQueue; class SynchronizedGCTaskQueue; class GCTaskManager; -class NotifyDoneClosure; // Some useful subclasses of GCTask. You can also make up your own. class NoopGCTask; -class BarrierGCTask; -class ReleasingBarrierGCTask; -class NotifyingBarrierGCTask; class WaitForBarrierGCTask; class IdleGCTask; // A free list of Monitor*'s. @@ -64,7 +60,7 @@ public: enum kind { unknown_task, ordinary_task, - barrier_task, + wait_for_barrier_task, noop_task, idle_task }; @@ -72,13 +68,16 @@ public: }; private: // Instance state. - const Kind::kind _kind; // For runtime type checking. - const uint _affinity; // Which worker should run task. + Kind::kind _kind; // For runtime type checking. + uint _affinity; // Which worker should run task. GCTask* _newer; // Tasks are on doubly-linked ... GCTask* _older; // ... lists. + uint _gc_id; // GC Id to use for the thread that executes this task public: virtual char* name() { return (char *)"task"; } + uint gc_id() { return _gc_id; } + // Abstract do_it method virtual void do_it(GCTaskManager* manager, uint which) = 0; // Accessors @@ -105,7 +104,7 @@ public: return kind()==Kind::ordinary_task; } bool is_barrier_task() const { - return kind()==Kind::barrier_task; + return kind()==Kind::wait_for_barrier_task; } bool is_noop_task() const { return kind()==Kind::noop_task; @@ -120,17 +119,14 @@ protected: GCTask(); // A GCTask of a particular kind, usually barrier or noop. GCTask(Kind::kind kind); - // An ordinary GCTask with an affinity. - GCTask(uint affinity); - // A GCTask of a particular kind, with and affinity. - GCTask(Kind::kind kind, uint affinity); + GCTask(Kind::kind kind, uint gc_id); // We want a virtual destructor because virtual methods, // but since ResourceObj's don't have their destructors // called, we don't have one at all. Instead we have // this method, which gets called by subclasses to clean up. virtual void destruct(); // Methods. - void initialize(); + void initialize(Kind::kind kind, uint gc_id); }; // A doubly-linked list of GCTasks. @@ -276,21 +272,26 @@ protected: ~SynchronizedGCTaskQueue(); }; -// This is an abstract base class for getting notifications -// when a GCTaskManager is done. -class NotifyDoneClosure : public CHeapObj { -public: - // The notification callback method. - virtual void notify(GCTaskManager* manager) = 0; -protected: - // Constructor. - NotifyDoneClosure() { - // Nothing to do. +class WaitHelper VALUE_OBJ_CLASS_SPEC { + private: + Monitor* _monitor; + volatile bool _should_wait; + public: + WaitHelper(); + ~WaitHelper(); + void wait_for(bool reset); + void notify(); + void set_should_wait(bool value) { + _should_wait = value; } - // Virtual destructor because virtual methods. - virtual ~NotifyDoneClosure() { - // Nothing to do. + + Monitor* monitor() const { + return _monitor; } + bool should_wait() const { + return _should_wait; + } + void release_monitor(); }; // Dynamic number of GC threads @@ -365,7 +366,6 @@ class GCTaskManager : public CHeapObj { friend class IdleGCTask; private: // Instance state. - NotifyDoneClosure* _ndc; // Notify on completion. const uint _workers; // Number of workers. Monitor* _monitor; // Notification of changes. SynchronizedGCTaskQueue* _queue; // Queue of tasks. @@ -379,17 +379,13 @@ private: uint _barriers; // Count of barrier tasks. uint _emptied_queue; // Times we emptied the queue. NoopGCTask* _noop_task; // The NoopGCTask instance. - uint _noop_tasks; // Count of noop tasks. - WaitForBarrierGCTask* _idle_inactive_task;// Task for inactive workers + WaitHelper _wait_helper; // Used by inactive worker volatile uint _idle_workers; // Number of idled workers public: // Factory create and destroy methods. static GCTaskManager* create(uint workers) { return new GCTaskManager(workers); } - static GCTaskManager* create(uint workers, NotifyDoneClosure* ndc) { - return new GCTaskManager(workers, ndc); - } static void destroy(GCTaskManager* that) { if (that != NULL) { delete that; @@ -409,8 +405,8 @@ public: Monitor * lock() const { return _monitor; } - WaitForBarrierGCTask* idle_inactive_task() { - return _idle_inactive_task; + WaitHelper* wait_helper() { + return &_wait_helper; } // Methods. // Add the argument task to be run. @@ -452,8 +448,6 @@ protected: // Constructors. Clients use factory, but there might be subclasses. // Create a GCTaskManager with the appropriate number of workers. GCTaskManager(uint workers); - // Create a GCTaskManager that calls back when there's no more work. - GCTaskManager(uint workers, NotifyDoneClosure* ndc); // Make virtual if necessary. ~GCTaskManager(); // Accessors. @@ -469,9 +463,6 @@ protected: // Sets the number of threads that will be used in a collection void set_active_gang(); - NotifyDoneClosure* notify_done_closure() const { - return _ndc; - } SynchronizedGCTaskQueue* queue() const { return _queue; } @@ -540,17 +531,6 @@ protected: void reset_emptied_queue() { _emptied_queue = 0; } - // Count of the number of noop tasks we've handed out, - // e.g., to handle resource release requests. - uint noop_tasks() const { - return _noop_tasks; - } - void increment_noop_tasks() { - _noop_tasks += 1; - } - void reset_noop_tasks() { - _noop_tasks = 0; - } void increment_idle_workers() { _idle_workers++; } @@ -575,11 +555,8 @@ protected: // A noop task that does nothing, // except take us around the GCTaskThread loop. class NoopGCTask : public GCTask { -private: - const bool _is_c_heap_obj; // Is this a CHeapObj? public: // Factory create and destroy methods. - static NoopGCTask* create(); static NoopGCTask* create_on_c_heap(); static void destroy(NoopGCTask* that); @@ -590,147 +567,39 @@ public: } protected: // Constructor. - NoopGCTask(bool on_c_heap) : - GCTask(GCTask::Kind::noop_task), - _is_c_heap_obj(on_c_heap) { - // Nothing to do. - } - // Destructor-like method. - void destruct(); - // Accessors. - bool is_c_heap_obj() const { - return _is_c_heap_obj; - } -}; - -// A BarrierGCTask blocks other tasks from starting, -// and waits until it is the only task running. -class BarrierGCTask : public GCTask { -public: - // Factory create and destroy methods. - static BarrierGCTask* create() { - return new BarrierGCTask(); - } - static void destroy(BarrierGCTask* that) { - if (that != NULL) { - that->destruct(); - delete that; - } - } - // Methods from GCTask. - void do_it(GCTaskManager* manager, uint which); -protected: - // Constructor. Clients use factory, but there might be subclasses. - BarrierGCTask() : - GCTask(GCTask::Kind::barrier_task) { - // Nothing to do. - } - // Destructor-like method. - void destruct(); - - virtual char* name() { return (char *)"barrier task"; } - // Methods. - // Wait for this to be the only task running. - void do_it_internal(GCTaskManager* manager, uint which); -}; - -// A ReleasingBarrierGCTask is a BarrierGCTask -// that tells all the tasks to release their resource areas. -class ReleasingBarrierGCTask : public BarrierGCTask { -public: - // Factory create and destroy methods. - static ReleasingBarrierGCTask* create() { - return new ReleasingBarrierGCTask(); - } - static void destroy(ReleasingBarrierGCTask* that) { - if (that != NULL) { - that->destruct(); - delete that; - } - } - // Methods from GCTask. - void do_it(GCTaskManager* manager, uint which); -protected: - // Constructor. Clients use factory, but there might be subclasses. - ReleasingBarrierGCTask() : - BarrierGCTask() { - // Nothing to do. - } + NoopGCTask(); // Destructor-like method. void destruct(); }; -// A NotifyingBarrierGCTask is a BarrierGCTask -// that calls a notification method when it is the only task running. -class NotifyingBarrierGCTask : public BarrierGCTask { -private: - // Instance state. - NotifyDoneClosure* _ndc; // The callback object. -public: - // Factory create and destroy methods. - static NotifyingBarrierGCTask* create(NotifyDoneClosure* ndc) { - return new NotifyingBarrierGCTask(ndc); - } - static void destroy(NotifyingBarrierGCTask* that) { - if (that != NULL) { - that->destruct(); - delete that; - } - } - // Methods from GCTask. - void do_it(GCTaskManager* manager, uint which); -protected: - // Constructor. Clients use factory, but there might be subclasses. - NotifyingBarrierGCTask(NotifyDoneClosure* ndc) : - BarrierGCTask(), - _ndc(ndc) { - assert(notify_done_closure() != NULL, "can't notify on NULL"); - } - // Destructor-like method. - void destruct(); - // Accessor. - NotifyDoneClosure* notify_done_closure() const { return _ndc; } -}; - -// A WaitForBarrierGCTask is a BarrierGCTask +// A WaitForBarrierGCTask is a GCTask // with a method you can call to wait until // the BarrierGCTask is done. -// This may cover many of the uses of NotifyingBarrierGCTasks. -class WaitForBarrierGCTask : public BarrierGCTask { +class WaitForBarrierGCTask : public GCTask { friend class GCTaskManager; friend class IdleGCTask; private: // Instance state. - Monitor* _monitor; // Guard and notify changes. - volatile bool _should_wait; // true=>wait, false=>proceed. - const bool _is_c_heap_obj; // Was allocated on the heap. + WaitHelper _wait_helper; + WaitForBarrierGCTask(); public: virtual char* name() { return (char *) "waitfor-barrier-task"; } // Factory create and destroy methods. static WaitForBarrierGCTask* create(); - static WaitForBarrierGCTask* create_on_c_heap(); static void destroy(WaitForBarrierGCTask* that); // Methods. void do_it(GCTaskManager* manager, uint which); - void wait_for(bool reset); - void set_should_wait(bool value) { - _should_wait = value; - } protected: - // Constructor. Clients use factory, but there might be subclasses. - WaitForBarrierGCTask(bool on_c_heap); // Destructor-like method. void destruct(); - // Accessors. - Monitor* monitor() const { - return _monitor; - } - bool should_wait() const { - return _should_wait; - } - bool is_c_heap_obj() { - return _is_c_heap_obj; + + // Methods. + // Wait for this to be the only task running. + void do_it_internal(GCTaskManager* manager, uint which); + + void wait_for(bool reset) { + _wait_helper.wait_for(reset); } }; diff --git a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp index dced20a3284..8e3f62c0c57 100644 --- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp +++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/gcTaskThread.hpp" +#include "gc/shared/gcId.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" @@ -124,6 +125,7 @@ void GCTaskThread::run() { for (; /* break */; ) { // This will block until there is a task to be gotten. GCTask* task = manager()->get_task(which()); + GCIdMark gc_id_mark(task->gc_id()); // Record if this is an idle task for later use. bool is_idle_task = task->is_idle_task(); // In case the update is costly diff --git a/hotspot/src/share/vm/gc/parallel/mutableNUMASpace.cpp b/hotspot/src/share/vm/gc/parallel/mutableNUMASpace.cpp index d82e94ca146..e53d195d639 100644 --- a/hotspot/src/share/vm/gc/parallel/mutableNUMASpace.cpp +++ b/hotspot/src/share/vm/gc/parallel/mutableNUMASpace.cpp @@ -85,8 +85,8 @@ void MutableNUMASpace::ensure_parsability() { while (words_left_to_fill > 0) { size_t words_to_fill = MIN2(words_left_to_fill, CollectedHeap::filler_array_max_size()); assert(words_to_fill >= CollectedHeap::min_fill_size(), - err_msg("Remaining size (" SIZE_FORMAT ") is too small to fill (based on " SIZE_FORMAT " and " SIZE_FORMAT ")", - words_to_fill, words_left_to_fill, CollectedHeap::filler_array_max_size())); + "Remaining size (" SIZE_FORMAT ") is too small to fill (based on " SIZE_FORMAT " and " SIZE_FORMAT ")", + words_to_fill, words_left_to_fill, CollectedHeap::filler_array_max_size()); CollectedHeap::fill_with_object((HeapWord*)cur_top, words_to_fill); if (!os::numa_has_static_binding()) { size_t touched_words = words_to_fill; @@ -971,7 +971,7 @@ void MutableNUMASpace::LGRPSpace::scan_pages(size_t page_size, size_t page_count break; } if (e != scan_end) { - assert(e < scan_end, err_msg("e: " PTR_FORMAT " scan_end: " PTR_FORMAT, p2i(e), p2i(scan_end))); + assert(e < scan_end, "e: " PTR_FORMAT " scan_end: " PTR_FORMAT, p2i(e), p2i(scan_end)); if ((page_expected.size != page_size || page_expected.lgrp_id != lgrp_id()) && page_expected.size != 0) { diff --git a/hotspot/src/share/vm/gc/parallel/objectStartArray.cpp b/hotspot/src/share/vm/gc/parallel/objectStartArray.cpp index 6b599e6f521..81d9d1bb833 100644 --- a/hotspot/src/share/vm/gc/parallel/objectStartArray.cpp +++ b/hotspot/src/share/vm/gc/parallel/objectStartArray.cpp @@ -127,8 +127,8 @@ void ObjectStartArray::reset() { bool ObjectStartArray::object_starts_in_range(HeapWord* start_addr, HeapWord* end_addr) const { assert(start_addr <= end_addr, - err_msg("Range is wrong. start_addr (" PTR_FORMAT ") is after end_addr (" PTR_FORMAT ")", - p2i(start_addr), p2i(end_addr))); + "Range is wrong. start_addr (" PTR_FORMAT ") is after end_addr (" PTR_FORMAT ")", + p2i(start_addr), p2i(end_addr)); if (start_addr > end_addr) { return false; } diff --git a/hotspot/src/share/vm/gc/parallel/objectStartArray.hpp b/hotspot/src/share/vm/gc/parallel/objectStartArray.hpp index 7cbb37eabf5..3c51c4e12d0 100644 --- a/hotspot/src/share/vm/gc/parallel/objectStartArray.hpp +++ b/hotspot/src/share/vm/gc/parallel/objectStartArray.hpp @@ -121,8 +121,8 @@ class ObjectStartArray : public CHeapObj { #define assert_covered_region_contains(addr) \ assert(_covered_region.contains(addr), \ - err_msg(#addr " (" PTR_FORMAT ") is not in covered region [" PTR_FORMAT ", " PTR_FORMAT "]", \ - p2i(addr), p2i(_covered_region.start()), p2i(_covered_region.end()))) + #addr " (" PTR_FORMAT ") is not in covered region [" PTR_FORMAT ", " PTR_FORMAT "]", \ + p2i(addr), p2i(_covered_region.start()), p2i(_covered_region.end())) void allocate_block(HeapWord* p) { assert_covered_region_contains(p); diff --git a/hotspot/src/share/vm/gc/parallel/parMarkBitMap.hpp b/hotspot/src/share/vm/gc/parallel/parMarkBitMap.hpp index be56e7ac7e3..acf2f917d59 100644 --- a/hotspot/src/share/vm/gc/parallel/parMarkBitMap.hpp +++ b/hotspot/src/share/vm/gc/parallel/parMarkBitMap.hpp @@ -390,9 +390,9 @@ inline void ParMarkBitMap::verify_bit(idx_t bit) const { inline void ParMarkBitMap::verify_addr(HeapWord* addr) const { // Allow one past the last valid address; useful for loop bounds. assert(addr >= region_start(), - err_msg("addr too small, addr: " PTR_FORMAT " region start: " PTR_FORMAT, p2i(addr), p2i(region_start()))); + "addr too small, addr: " PTR_FORMAT " region start: " PTR_FORMAT, p2i(addr), p2i(region_start())); assert(addr <= region_end(), - err_msg("addr too big, addr: " PTR_FORMAT " region end: " PTR_FORMAT, p2i(addr), p2i(region_end()))); + "addr too big, addr: " PTR_FORMAT " region end: " PTR_FORMAT, p2i(addr), p2i(region_end())); } #endif // #ifdef ASSERT diff --git a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.inline.hpp b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.inline.hpp index 71e0f917850..5ee4b0f6481 100644 --- a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.inline.hpp +++ b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.inline.hpp @@ -48,7 +48,7 @@ inline bool ParallelScavengeHeap::is_in_young(oop p) { // Assumes the the old gen address range is lower than that of the young gen. bool result = ((HeapWord*)p) >= young_gen()->reserved().start(); assert(result == young_gen()->is_in_reserved(p), - err_msg("incorrect test - result=%d, p=" PTR_FORMAT, result, p2i((void*)p))); + "incorrect test - result=%d, p=" PTR_FORMAT, result, p2i((void*)p)); return result; } #endif // SHARE_VM_GC_PARALLEL_PARALLELSCAVENGEHEAP_INLINE_HPP diff --git a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp index d0fd38051b7..6cdbab8881c 100644 --- a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp +++ b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp @@ -53,7 +53,7 @@ void ThreadRootsMarkingTask::do_it(GCTaskManager* manager, uint which) { ResourceMark rm; NOT_PRODUCT(GCTraceTime tm("ThreadRootsMarkingTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -82,7 +82,7 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) { assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("MarkFromRootsTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm); @@ -153,7 +153,7 @@ void RefProcTaskProxy::do_it(GCTaskManager* manager, uint which) assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("RefProcTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm); @@ -209,7 +209,7 @@ void StealMarkingTask::do_it(GCTaskManager* manager, uint which) { assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("StealMarkingTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -241,7 +241,7 @@ void StealRegionCompactionTask::do_it(GCTaskManager* manager, uint which) { assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("StealRegionCompactionTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -254,9 +254,9 @@ void StealRegionCompactionTask::do_it(GCTaskManager* manager, uint which) { if (use_all_workers) { which_stack_index = which; assert(manager->active_workers() == ParallelGCThreads, - err_msg("all_workers_active has been incorrectly set: " - " active %d ParallelGCThreads %u", manager->active_workers(), - ParallelGCThreads)); + "all_workers_active has been incorrectly set: " + " active %d ParallelGCThreads %u", manager->active_workers(), + ParallelGCThreads); } else { which_stack_index = ParCompactionManager::pop_recycled_stack_index(); } @@ -308,7 +308,7 @@ UpdateDensePrefixTask::UpdateDensePrefixTask( void UpdateDensePrefixTask::do_it(GCTaskManager* manager, uint which) { NOT_PRODUCT(GCTraceTime tm("UpdateDensePrefixTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -323,7 +323,7 @@ void DrainStacksCompactionTask::do_it(GCTaskManager* manager, uint which) { assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("DrainStacksCompactionTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -333,9 +333,9 @@ void DrainStacksCompactionTask::do_it(GCTaskManager* manager, uint which) { if (use_all_workers) { which_stack_index = which; assert(manager->active_workers() == ParallelGCThreads, - err_msg("all_workers_active has been incorrectly set: " - " active %d ParallelGCThreads %u", manager->active_workers(), - ParallelGCThreads)); + "all_workers_active has been incorrectly set: " + " active %d ParallelGCThreads %u", manager->active_workers(), + ParallelGCThreads); } else { which_stack_index = stack_index(); } diff --git a/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp b/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp index d2c7b2bc2d4..69720fb3e4e 100644 --- a/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp +++ b/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp @@ -529,10 +529,7 @@ void PSAdaptiveSizePolicy::compute_old_gen_free_space( set_decide_at_full_gc(decide_at_full_gc_true); adjust_promo_for_pause_time(is_full_gc, &desired_promo_size, &desired_eden_size); } - } else if (_avg_minor_pause->padded_average() > gc_minor_pause_goal_sec()) { - // Adjust only for the minor pause time goal - adjust_promo_for_minor_pause_time(is_full_gc, &desired_promo_size, &desired_eden_size); - } else if(adjusted_mutator_cost() < _throughput_goal) { + } else if (adjusted_mutator_cost() < _throughput_goal) { // This branch used to require that (mutator_cost() > 0.0 in 1.4.2. // This sometimes resulted in skipping to the minimize footprint // code. Change this to try and reduce GC time if mutator time is @@ -670,36 +667,6 @@ void PSAdaptiveSizePolicy::decay_supplemental_growth(bool is_full_gc) { } } -void PSAdaptiveSizePolicy::adjust_promo_for_minor_pause_time(bool is_full_gc, - size_t* desired_promo_size_ptr, size_t* desired_eden_size_ptr) { - - if (PSAdjustTenuredGenForMinorPause) { - if (is_full_gc) { - set_decide_at_full_gc(decide_at_full_gc_true); - } - // If the desired eden size is as small as it will get, - // try to adjust the old gen size. - if (*desired_eden_size_ptr <= _space_alignment) { - // Vary the old gen size to reduce the young gen pause. This - // may not be a good idea. This is just a test. - if (minor_pause_old_estimator()->decrement_will_decrease()) { - set_change_old_gen_for_min_pauses(decrease_old_gen_for_min_pauses_true); - *desired_promo_size_ptr = - _promo_size - promo_decrement_aligned_down(*desired_promo_size_ptr); - } else { - set_change_old_gen_for_min_pauses(increase_old_gen_for_min_pauses_true); - size_t promo_heap_delta = - promo_increment_with_supplement_aligned_up(*desired_promo_size_ptr); - if ((*desired_promo_size_ptr + promo_heap_delta) > - *desired_promo_size_ptr) { - *desired_promo_size_ptr = - _promo_size + promo_heap_delta; - } - } - } - } -} - void PSAdaptiveSizePolicy::adjust_eden_for_minor_pause_time(bool is_full_gc, size_t* desired_eden_size_ptr) { @@ -733,10 +700,7 @@ void PSAdaptiveSizePolicy::adjust_promo_for_pause_time(bool is_full_gc, // a change less than the required alignment is probably not worth // attempting. - if (_avg_minor_pause->padded_average() > _avg_major_pause->padded_average()) { - adjust_promo_for_minor_pause_time(is_full_gc, desired_promo_size_ptr, desired_eden_size_ptr); - // major pause adjustments - } else if (is_full_gc) { + if (_avg_minor_pause->padded_average() <= _avg_major_pause->padded_average() && is_full_gc) { // Adjust for the major pause time only at full gc's because the // affects of a change can only be seen at full gc's. @@ -774,44 +738,8 @@ void PSAdaptiveSizePolicy::adjust_eden_for_pause_time(bool is_full_gc, // a change less than the required alignment is probably not worth // attempting. if (_avg_minor_pause->padded_average() > _avg_major_pause->padded_average()) { - adjust_eden_for_minor_pause_time(is_full_gc, - desired_eden_size_ptr); - // major pause adjustments - } else if (is_full_gc) { - // Adjust for the major pause time only at full gc's because the - // affects of a change can only be seen at full gc's. - if (PSAdjustYoungGenForMajorPause) { - // If the promo size is at the minimum (i.e., the old gen - // size will not actually decrease), consider changing the - // young gen size. - if (*desired_promo_size_ptr < _space_alignment) { - // If increasing the young generation will decrease the old gen - // pause, do it. - // During startup there is noise in the statistics for deciding - // on whether to increase or decrease the young gen size. For - // some number of iterations, just try to increase the young - // gen size if the major pause is too long to try and establish - // good statistics for later decisions. - if (major_pause_young_estimator()->increment_will_decrease() || - (_young_gen_change_for_major_pause_count - <= AdaptiveSizePolicyInitializingSteps)) { - set_change_young_gen_for_maj_pauses( - increase_young_gen_for_maj_pauses_true); - eden_heap_delta = eden_increment_aligned_up(*desired_eden_size_ptr); - *desired_eden_size_ptr = _eden_size + eden_heap_delta; - _young_gen_change_for_major_pause_count++; - } else { - // Record that decreasing the young gen size would decrease - // the major pause - set_change_young_gen_for_maj_pauses( - decrease_young_gen_for_maj_pauses_true); - eden_heap_delta = eden_decrement_aligned_down(*desired_eden_size_ptr); - *desired_eden_size_ptr = _eden_size - eden_heap_delta; - } - } - } + adjust_eden_for_minor_pause_time(is_full_gc, desired_eden_size_ptr); } - if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr( "PSAdaptiveSizePolicy::adjust_eden_for_pause_time " diff --git a/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.hpp b/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.hpp index 696ec8868cf..2d3899c878c 100644 --- a/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.hpp +++ b/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.hpp @@ -134,10 +134,6 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { AdaptivePaddedAverage* avg_major_pause() const { return _avg_major_pause; } double gc_minor_pause_goal_sec() const { return _gc_minor_pause_goal_sec; } - // Change the young generation size to achieve a minor GC pause time goal - void adjust_promo_for_minor_pause_time(bool is_full_gc, - size_t* desired_promo_size_ptr, - size_t* desired_eden_size_ptr); void adjust_eden_for_minor_pause_time(bool is_full_gc, size_t* desired_eden_size_ptr); // Change the generation sizes to achieve a GC pause time goal diff --git a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp index e7799f34637..87f17fabd49 100644 --- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp +++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp @@ -36,6 +36,7 @@ #include "gc/serial/markSweep.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcHeapSummary.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" @@ -113,6 +114,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCause::Cause gc_cause = heap->gc_cause(); + GCIdMark gc_id_mark; _gc_timer->register_gc_start(); _gc_tracer->report_gc_start(gc_cause, _gc_timer->gc_start()); @@ -165,7 +167,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { HandleMark hm; TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer->gc_id()); + GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(true /* Full GC */,gc_cause); @@ -189,7 +191,9 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { allocate_stacks(); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif ref_processor()->enable_discovery(); ref_processor()->setup_policy(clear_all_softrefs); @@ -198,9 +202,11 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { mark_sweep_phase2(); +#if defined(COMPILER2) || INCLUDE_JVMCI // Don't add any more derived pointers during phase3 - COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity")); - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); + assert(DerivedPointerTable::is_active(), "Sanity"); + DerivedPointerTable::set_active(false); +#endif mark_sweep_phase3(); @@ -245,7 +251,9 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { CodeCache::gc_epilogue(); JvmtiExport::gc_epilogue(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif ref_processor()->enqueue_discovered_references(NULL); @@ -508,7 +516,7 @@ void PSMarkSweep::deallocate_stacks() { void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - GCTraceTime tm("phase 1", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 1", PrintGCDetails && Verbose, true, _gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); @@ -541,7 +549,7 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { ref_processor()->setup_policy(clear_all_softrefs); const ReferenceProcessorStats& stats = ref_processor()->process_discovered_references( - is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL, _gc_timer, _gc_tracer->gc_id()); + is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL, _gc_timer); gc_tracer()->report_gc_reference_stats(stats); } @@ -567,7 +575,7 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { void PSMarkSweep::mark_sweep_phase2() { - GCTraceTime tm("phase 2", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 2", PrintGCDetails && Verbose, true, _gc_timer); // Now all live objects are marked, compute the new object addresses. @@ -594,7 +602,7 @@ static PSAlwaysTrueClosure always_true; void PSMarkSweep::mark_sweep_phase3() { // Adjust the pointers to reflect the new locations - GCTraceTime tm("phase 3", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 3", PrintGCDetails && Verbose, true, _gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); @@ -634,7 +642,7 @@ void PSMarkSweep::mark_sweep_phase3() { void PSMarkSweep::mark_sweep_phase4() { EventMark m("4 compact heap"); - GCTraceTime tm("phase 4", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 4", PrintGCDetails && Verbose, true, _gc_timer); // All pointers are now adjusted, move objects accordingly diff --git a/hotspot/src/share/vm/gc/parallel/psOldGen.hpp b/hotspot/src/share/vm/gc/parallel/psOldGen.hpp index 943a39cc3f3..fb25db6c163 100644 --- a/hotspot/src/share/vm/gc/parallel/psOldGen.hpp +++ b/hotspot/src/share/vm/gc/parallel/psOldGen.hpp @@ -65,15 +65,15 @@ class PSOldGen : public CHeapObj { // Explictly capture current covered_region in a local MemRegion covered_region = this->start_array()->covered_region(); assert(covered_region.contains(new_memregion), - err_msg("new region is not in covered_region [ " PTR_FORMAT ", " PTR_FORMAT " ], " - "new region [ " PTR_FORMAT ", " PTR_FORMAT " ], " - "object space [ " PTR_FORMAT ", " PTR_FORMAT " ]", - p2i(covered_region.start()), - p2i(covered_region.end()), - p2i(new_memregion.start()), - p2i(new_memregion.end()), - p2i(this->object_space()->used_region().start()), - p2i(this->object_space()->used_region().end()))); + "new region is not in covered_region [ " PTR_FORMAT ", " PTR_FORMAT " ], " + "new region [ " PTR_FORMAT ", " PTR_FORMAT " ], " + "object space [ " PTR_FORMAT ", " PTR_FORMAT " ]", + p2i(covered_region.start()), + p2i(covered_region.end()), + p2i(new_memregion.start()), + p2i(new_memregion.end()), + p2i(this->object_space()->used_region().start()), + p2i(this->object_space()->used_region().end())); } #endif diff --git a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp index 7028c8dd10a..570b3eda244 100644 --- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp @@ -40,6 +40,7 @@ #include "gc/parallel/psYoungGen.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcHeapSummary.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" @@ -960,7 +961,7 @@ void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values) // at each young gen gc. Do the update unconditionally (even though a // promotion failure does not swap spaces) because an unknown number of young // collections will have swapped the spaces an unknown number of times. - GCTraceTime tm("pre compact", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("pre compact", print_phases(), true, &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _space_info[from_space_id].set_space(heap->young_gen()->from_space()); _space_info[to_space_id].set_space(heap->young_gen()->to_space()); @@ -1003,7 +1004,7 @@ void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values) void PSParallelCompact::post_compact() { - GCTraceTime tm("post compact", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("post compact", print_phases(), true, &_gc_timer); for (unsigned int id = old_space_id; id < last_space_id; ++id) { // Clear the marking bitmap, summary data and split info. @@ -1045,7 +1046,9 @@ void PSParallelCompact::post_compact() CodeCache::gc_epilogue(); JvmtiExport::gc_epilogue(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif ref_processor()->enqueue_discovered_references(NULL); @@ -1348,13 +1351,6 @@ HeapWord* PSParallelCompact::compute_dense_prefix(const SpaceId id, bool maximum_compaction) { - if (ParallelOldGCSplitALot) { - if (_space_info[id].dense_prefix() != _space_info[id].space()->bottom()) { - // The value was chosen to provoke splitting a young gen space; use it. - return _space_info[id].dense_prefix(); - } - } - const size_t region_size = ParallelCompactData::RegionSize; const ParallelCompactData& sd = summary_data(); @@ -1427,220 +1423,9 @@ PSParallelCompact::compute_dense_prefix(const SpaceId id, } } -#if 0 - // Something to consider: if the region with the best ratio is 'close to' the - // first region w/free space, choose the first region with free space - // ("first-free"). The first-free region is usually near the start of the - // heap, which means we are copying most of the heap already, so copy a bit - // more to get complete compaction. - if (pointer_delta(best_cp, full_cp, sizeof(RegionData)) < 4) { - _maximum_compaction_gc_num = total_invocations(); - best_cp = full_cp; - } -#endif // #if 0 - return sd.region_to_addr(best_cp); } -#ifndef PRODUCT -void -PSParallelCompact::fill_with_live_objects(SpaceId id, HeapWord* const start, - size_t words) -{ - if (TraceParallelOldGCSummaryPhase) { - tty->print_cr("fill_with_live_objects [" PTR_FORMAT " " PTR_FORMAT ") " - SIZE_FORMAT, p2i(start), p2i(start + words), words); - } - - ObjectStartArray* const start_array = _space_info[id].start_array(); - CollectedHeap::fill_with_objects(start, words); - for (HeapWord* p = start; p < start + words; p += oop(p)->size()) { - _mark_bitmap.mark_obj(p, words); - _summary_data.add_obj(p, words); - start_array->allocate_block(p); - } -} - -void -PSParallelCompact::summarize_new_objects(SpaceId id, HeapWord* start) -{ - ParallelCompactData& sd = summary_data(); - MutableSpace* space = _space_info[id].space(); - - // Find the source and destination start addresses. - HeapWord* const src_addr = sd.region_align_down(start); - HeapWord* dst_addr; - if (src_addr < start) { - dst_addr = sd.addr_to_region_ptr(src_addr)->destination(); - } else if (src_addr > space->bottom()) { - // The start (the original top() value) is aligned to a region boundary so - // the associated region does not have a destination. Compute the - // destination from the previous region. - RegionData* const cp = sd.addr_to_region_ptr(src_addr) - 1; - dst_addr = cp->destination() + cp->data_size(); - } else { - // Filling the entire space. - dst_addr = space->bottom(); - } - assert(dst_addr != NULL, "sanity"); - - // Update the summary data. - bool result = _summary_data.summarize(_space_info[id].split_info(), - src_addr, space->top(), NULL, - dst_addr, space->end(), - _space_info[id].new_top_addr()); - assert(result, "should not fail: bad filler object size"); -} - -void -PSParallelCompact::provoke_split_fill_survivor(SpaceId id) -{ - if (total_invocations() % (ParallelOldGCSplitInterval * 3) != 0) { - return; - } - - MutableSpace* const space = _space_info[id].space(); - if (space->is_empty()) { - HeapWord* b = space->bottom(); - HeapWord* t = b + space->capacity_in_words() / 2; - space->set_top(t); - if (ZapUnusedHeapArea) { - space->set_top_for_allocations(); - } - - size_t min_size = CollectedHeap::min_fill_size(); - size_t obj_len = min_size; - while (b + obj_len <= t) { - CollectedHeap::fill_with_object(b, obj_len); - mark_bitmap()->mark_obj(b, obj_len); - summary_data().add_obj(b, obj_len); - b += obj_len; - obj_len = (obj_len & (min_size*3)) + min_size; // 8 16 24 32 8 16 24 32 ... - } - if (b < t) { - // The loop didn't completely fill to t (top); adjust top downward. - space->set_top(b); - if (ZapUnusedHeapArea) { - space->set_top_for_allocations(); - } - } - - HeapWord** nta = _space_info[id].new_top_addr(); - bool result = summary_data().summarize(_space_info[id].split_info(), - space->bottom(), space->top(), NULL, - space->bottom(), space->end(), nta); - assert(result, "space must fit into itself"); - } -} - -void -PSParallelCompact::provoke_split(bool & max_compaction) -{ - if (total_invocations() % ParallelOldGCSplitInterval != 0) { - return; - } - - const size_t region_size = ParallelCompactData::RegionSize; - ParallelCompactData& sd = summary_data(); - - MutableSpace* const eden_space = _space_info[eden_space_id].space(); - MutableSpace* const from_space = _space_info[from_space_id].space(); - const size_t eden_live = pointer_delta(eden_space->top(), - _space_info[eden_space_id].new_top()); - const size_t from_live = pointer_delta(from_space->top(), - _space_info[from_space_id].new_top()); - - const size_t min_fill_size = CollectedHeap::min_fill_size(); - const size_t eden_free = pointer_delta(eden_space->end(), eden_space->top()); - const size_t eden_fillable = eden_free >= min_fill_size ? eden_free : 0; - const size_t from_free = pointer_delta(from_space->end(), from_space->top()); - const size_t from_fillable = from_free >= min_fill_size ? from_free : 0; - - // Choose the space to split; need at least 2 regions live (or fillable). - SpaceId id; - MutableSpace* space; - size_t live_words; - size_t fill_words; - if (eden_live + eden_fillable >= region_size * 2) { - id = eden_space_id; - space = eden_space; - live_words = eden_live; - fill_words = eden_fillable; - } else if (from_live + from_fillable >= region_size * 2) { - id = from_space_id; - space = from_space; - live_words = from_live; - fill_words = from_fillable; - } else { - return; // Give up. - } - assert(fill_words == 0 || fill_words >= min_fill_size, "sanity"); - - if (live_words < region_size * 2) { - // Fill from top() to end() w/live objects of mixed sizes. - HeapWord* const fill_start = space->top(); - live_words += fill_words; - - space->set_top(fill_start + fill_words); - if (ZapUnusedHeapArea) { - space->set_top_for_allocations(); - } - - HeapWord* cur_addr = fill_start; - while (fill_words > 0) { - const size_t r = (size_t)os::random() % (region_size / 2) + min_fill_size; - size_t cur_size = MIN2(align_object_size_(r), fill_words); - if (fill_words - cur_size < min_fill_size) { - cur_size = fill_words; // Avoid leaving a fragment too small to fill. - } - - CollectedHeap::fill_with_object(cur_addr, cur_size); - mark_bitmap()->mark_obj(cur_addr, cur_size); - sd.add_obj(cur_addr, cur_size); - - cur_addr += cur_size; - fill_words -= cur_size; - } - - summarize_new_objects(id, fill_start); - } - - max_compaction = false; - - // Manipulate the old gen so that it has room for about half of the live data - // in the target young gen space (live_words / 2). - id = old_space_id; - space = _space_info[id].space(); - const size_t free_at_end = space->free_in_words(); - const size_t free_target = align_object_size(live_words / 2); - const size_t dead = pointer_delta(space->top(), _space_info[id].new_top()); - - if (free_at_end >= free_target + min_fill_size) { - // Fill space above top() and set the dense prefix so everything survives. - HeapWord* const fill_start = space->top(); - const size_t fill_size = free_at_end - free_target; - space->set_top(space->top() + fill_size); - if (ZapUnusedHeapArea) { - space->set_top_for_allocations(); - } - fill_with_live_objects(id, fill_start, fill_size); - summarize_new_objects(id, fill_start); - _space_info[id].set_dense_prefix(sd.region_align_down(space->top())); - } else if (dead + free_at_end > free_target) { - // Find a dense prefix that makes the right amount of space available. - HeapWord* cur = sd.region_align_down(space->top()); - HeapWord* cur_destination = sd.addr_to_region_ptr(cur)->destination(); - size_t dead_to_right = pointer_delta(space->end(), cur_destination); - while (dead_to_right < free_target) { - cur -= region_size; - cur_destination = sd.addr_to_region_ptr(cur)->destination(); - dead_to_right = pointer_delta(space->end(), cur_destination); - } - _space_info[id].set_dense_prefix(cur); - } -} -#endif // #ifndef PRODUCT - void PSParallelCompact::summarize_spaces_quick() { for (unsigned int i = 0; i < last_space_id; ++i) { @@ -1652,12 +1437,6 @@ void PSParallelCompact::summarize_spaces_quick() assert(result, "space must fit into itself"); _space_info[i].set_dense_prefix(space->bottom()); } - -#ifndef PRODUCT - if (ParallelOldGCSplitALot) { - provoke_split_fill_survivor(to_space_id); - } -#endif // #ifndef PRODUCT } void PSParallelCompact::fill_dense_prefix_end(SpaceId id) @@ -1742,8 +1521,7 @@ void PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction) { assert(id < last_space_id, "id out of range"); - assert(_space_info[id].dense_prefix() == _space_info[id].space()->bottom() || - ParallelOldGCSplitALot && id == old_space_id, + assert(_space_info[id].dense_prefix() == _space_info[id].space()->bottom(), "should have been reset in summarize_spaces_quick()"); const MutableSpace* space = _space_info[id].space(); @@ -1824,7 +1602,7 @@ void PSParallelCompact::summary_phase_msg(SpaceId dst_space_id, void PSParallelCompact::summary_phase(ParCompactionManager* cm, bool maximum_compaction) { - GCTraceTime tm("summary phase", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("summary phase", print_phases(), true, &_gc_timer); // trace("2"); #ifdef ASSERT @@ -1863,11 +1641,6 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm, // XXX - should also try to expand maximum_compaction = true; } -#ifndef PRODUCT - if (ParallelOldGCSplitALot && old_space_total_live < old_capacity) { - provoke_split(maximum_compaction); - } -#endif // #ifndef PRODUCT // Old generations. summarize_space(old_space_id, maximum_compaction); @@ -1984,6 +1757,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + GCIdMark gc_id_mark; _gc_timer.register_gc_start(); _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start()); @@ -2031,7 +1805,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { gc_task_manager()->task_idle_workers(); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer.gc_id()); + GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(true /* Full GC */,gc_cause); @@ -2042,7 +1816,9 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { CodeCache::gc_prologue(); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif ref_processor()->enable_discovery(); ref_processor()->setup_policy(maximum_heap_compaction); @@ -2056,8 +1832,10 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { && GCCause::is_user_requested_gc(gc_cause); summary_phase(vmthread_cm, maximum_heap_compaction || max_on_system_gc); - COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity")); - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_active(), "Sanity"); + DerivedPointerTable::set_active(false); +#endif // adjust_roots() updates Universe::_intArrayKlassObj which is // needed by the compaction for filling holes in the dense prefix. @@ -2331,7 +2109,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, bool maximum_heap_compaction, ParallelOldTracer *gc_tracer) { // Recursively traverse all live objects and mark them - GCTraceTime tm("marking phase", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("marking phase", print_phases(), true, &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); @@ -2346,7 +2124,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, ClassLoaderDataGraph::clear_claimed_marks(); { - GCTraceTime tm_m("par mark", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm_m("par mark", print_phases(), true, &_gc_timer); ParallelScavengeHeap::ParStrongRootsScope psrs; @@ -2375,24 +2153,24 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, // Process reference objects found during marking { - GCTraceTime tm_r("reference processing", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm_r("reference processing", print_phases(), true, &_gc_timer); ReferenceProcessorStats stats; if (ref_processor()->processing_is_mt()) { RefProcTaskExecutor task_executor; stats = ref_processor()->process_discovered_references( is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, - &task_executor, &_gc_timer, _gc_tracer.gc_id()); + &task_executor, &_gc_timer); } else { stats = ref_processor()->process_discovered_references( is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, NULL, - &_gc_timer, _gc_tracer.gc_id()); + &_gc_timer); } gc_tracer->report_gc_reference_stats(stats); } - GCTraceTime tm_c("class unloading", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm_c("class unloading", print_phases(), true, &_gc_timer); // This is the point where the entire marking should have completed. assert(cm->marking_stacks_empty(), "Marking should have completed"); @@ -2423,7 +2201,7 @@ static PSAlwaysTrueClosure always_true; void PSParallelCompact::adjust_roots() { // Adjust the pointers to reflect the new locations - GCTraceTime tm("adjust roots", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("adjust roots", print_phases(), true, &_gc_timer); // Need new claim bits when tracing through and adjusting pointers. ClassLoaderDataGraph::clear_claimed_marks(); @@ -2459,7 +2237,7 @@ void PSParallelCompact::adjust_roots() { void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q, uint parallel_gc_threads) { - GCTraceTime tm("drain task setup", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("drain task setup", print_phases(), true, &_gc_timer); // Find the threads that are active unsigned int which = 0; @@ -2533,7 +2311,7 @@ void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q, void PSParallelCompact::enqueue_dense_prefix_tasks(GCTaskQueue* q, uint parallel_gc_threads) { - GCTraceTime tm("dense prefix task setup", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("dense prefix task setup", print_phases(), true, &_gc_timer); ParallelCompactData& sd = PSParallelCompact::summary_data(); @@ -2615,7 +2393,7 @@ void PSParallelCompact::enqueue_region_stealing_tasks( GCTaskQueue* q, ParallelTaskTerminator* terminator_ptr, uint parallel_gc_threads) { - GCTraceTime tm("steal task setup", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("steal task setup", print_phases(), true, &_gc_timer); // Once a thread has drained it's stack, it should try to steal regions from // other threads. @@ -2663,7 +2441,7 @@ void PSParallelCompact::write_block_fill_histogram(outputStream* const out) void PSParallelCompact::compact() { // trace("5"); - GCTraceTime tm("compaction phase", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("compaction phase", print_phases(), true, &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); @@ -2679,7 +2457,7 @@ void PSParallelCompact::compact() { enqueue_region_stealing_tasks(q, &terminator, active_gc_threads); { - GCTraceTime tm_pc("par compact", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm_pc("par compact", print_phases(), true, &_gc_timer); gc_task_manager()->execute_and_wait(q); @@ -2693,7 +2471,7 @@ void PSParallelCompact::compact() { { // Update the deferred objects, if any. Any compaction manager can be used. - GCTraceTime tm_du("deferred updates", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm_du("deferred updates", print_phases(), true, &_gc_timer); ParCompactionManager* cm = ParCompactionManager::manager_array(0); for (unsigned int id = old_space_id; id < last_space_id; ++id) { update_deferred_objects(cm, SpaceId(id)); @@ -2851,7 +2629,7 @@ void PSParallelCompact::update_deferred_objects(ParCompactionManager* cm, start_array->allocate_block(addr); } cm->update_contents(oop(addr)); - assert(oop(addr)->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(oop(addr)))); + assert(oop(addr)->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(addr))); } } } @@ -3400,7 +3178,7 @@ MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) { oop moved_oop = (oop) destination(); compaction_manager()->update_contents(moved_oop); - assert(moved_oop->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(moved_oop))); + assert(moved_oop->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(moved_oop)); update_state(words); assert(destination() == (HeapWord*)moved_oop + moved_oop->size(), "sanity"); diff --git a/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp b/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp index 808270a715b..09f37ef8fc1 100644 --- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp +++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp @@ -1059,24 +1059,6 @@ class PSParallelCompact : AllStatic { // Clear the summary data source_region field for the specified addresses. static void clear_source_region(HeapWord* beg_addr, HeapWord* end_addr); -#ifndef PRODUCT - // Routines to provoke splitting a young gen space (ParallelOldGCSplitALot). - - // Fill the region [start, start + words) with live object(s). Only usable - // for the old and permanent generations. - static void fill_with_live_objects(SpaceId id, HeapWord* const start, - size_t words); - // Include the new objects in the summary data. - static void summarize_new_objects(SpaceId id, HeapWord* start); - - // Add live objects to a survivor space since it's rare that both survivors - // are non-empty. - static void provoke_split_fill_survivor(SpaceId id); - - // Add live objects and/or choose the dense prefix to provoke splitting. - static void provoke_split(bool & maximum_compaction); -#endif - static void summarize_spaces_quick(); static void summarize_space(SpaceId id, bool maximum_compaction); static void summary_phase(ParCompactionManager* cm, bool maximum_compaction); diff --git a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp index 7057121165a..0d4a6dad31d 100644 --- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp +++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp @@ -36,6 +36,7 @@ #include "gc/shared/collectorPolicy.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcHeapSummary.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" @@ -278,6 +279,7 @@ bool PSScavenge::invoke_no_policy() { return false; } + GCIdMark gc_id_mark; _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start()); bool promotion_failure_occurred = false; @@ -295,11 +297,6 @@ bool PSScavenge::invoke_no_policy() { young_gen->eden_space()->accumulate_statistics(); } - if (ZapUnusedHeapArea) { - // Save information needed to minimize mangling - heap->record_gen_tops_before_GC(); - } - heap->print_heap_before_gc(); heap->trace_heap_before_gc(&_gc_tracer); @@ -322,7 +319,7 @@ bool PSScavenge::invoke_no_policy() { HandleMark hm; TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer.gc_id()); + GCTraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(false /* not full GC */,gc_cause); @@ -342,16 +339,15 @@ bool PSScavenge::invoke_no_policy() { CardTableExtension::verify_all_young_refs_imprecise(); } - if (!ScavengeWithObjectsInToSpace) { - assert(young_gen->to_space()->is_empty(), - "Attempt to scavenge with live objects in to_space"); - young_gen->to_space()->clear(SpaceDecorator::Mangle); - } else if (ZapUnusedHeapArea) { - young_gen->to_space()->mangle_unused_area(); - } + assert(young_gen->to_space()->is_empty(), + "Attempt to scavenge with live objects in to_space"); + young_gen->to_space()->clear(SpaceDecorator::Mangle); + save_to_space_top_before_gc(); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif reference_processor()->enable_discovery(); reference_processor()->setup_policy(false); @@ -387,7 +383,7 @@ bool PSScavenge::invoke_no_policy() { // We'll use the promotion manager again later. PSPromotionManager* promotion_manager = PSPromotionManager::vm_thread_promotion_manager(); { - GCTraceTime tm("Scavenge", false, false, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("Scavenge", false, false, &_gc_timer); ParallelScavengeHeap::ParStrongRootsScope psrs; GCTaskQueue* q = GCTaskQueue::create(); @@ -429,7 +425,7 @@ bool PSScavenge::invoke_no_policy() { // Process reference objects discovered during scavenge { - GCTraceTime tm("References", false, false, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("References", false, false, &_gc_timer); reference_processor()->setup_policy(false); // not always_clear reference_processor()->set_active_mt_degree(active_workers); @@ -440,10 +436,10 @@ bool PSScavenge::invoke_no_policy() { PSRefProcTaskExecutor task_executor; stats = reference_processor()->process_discovered_references( &_is_alive_closure, &keep_alive, &evac_followers, &task_executor, - &_gc_timer, _gc_tracer.gc_id()); + &_gc_timer); } else { stats = reference_processor()->process_discovered_references( - &_is_alive_closure, &keep_alive, &evac_followers, NULL, &_gc_timer, _gc_tracer.gc_id()); + &_is_alive_closure, &keep_alive, &evac_followers, NULL, &_gc_timer); } _gc_tracer.report_gc_reference_stats(stats); @@ -458,7 +454,7 @@ bool PSScavenge::invoke_no_policy() { } { - GCTraceTime tm("StringTable", false, false, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("StringTable", false, false, &_gc_timer); // Unlink any dead interned Strings and process the remaining live ones. PSScavengeRootsClosure root_closure(promotion_manager); StringTable::unlink_or_oops_do(&_is_alive_closure, &root_closure); @@ -473,6 +469,8 @@ bool PSScavenge::invoke_no_policy() { } } + _gc_tracer.report_tenuring_threshold(tenuring_threshold()); + // Let the size policy know we're done. Note that we count promotion // failure cleanup time as part of the collection (otherwise, we're // implicitly saying it's mutator time). @@ -623,12 +621,14 @@ bool PSScavenge::invoke_no_policy() { assert(young_gen->to_space()->is_empty(), "to space should be empty now"); } - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif NOT_PRODUCT(reference_processor()->verify_no_references_recorded()); { - GCTraceTime tm("Prune Scavenge Root Methods", false, false, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("Prune Scavenge Root Methods", false, false, &_gc_timer); CodeCache::prune_scavenge_root_nmethods(); } @@ -672,13 +672,6 @@ bool PSScavenge::invoke_no_policy() { heap->print_heap_after_gc(); heap->trace_heap_after_gc(&_gc_tracer); - _gc_tracer.report_tenuring_threshold(tenuring_threshold()); - - if (ZapUnusedHeapArea) { - young_gen->eden_space()->check_mangled_unused_area_complete(); - young_gen->from_space()->check_mangled_unused_area_complete(); - young_gen->to_space()->check_mangled_unused_area_complete(); - } scavenge_exit.update(); @@ -761,15 +754,13 @@ bool PSScavenge::should_attempt_scavenge() { PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); - if (!ScavengeWithObjectsInToSpace) { - // Do not attempt to promote unless to_space is empty - if (!young_gen->to_space()->is_empty()) { - _consecutive_skipped_scavenges++; - if (UsePerfData) { - counters->update_scavenge_skipped(to_space_not_empty); - } - return false; + // Do not attempt to promote unless to_space is empty + if (!young_gen->to_space()->is_empty()) { + _consecutive_skipped_scavenges++; + if (UsePerfData) { + counters->update_scavenge_skipped(to_space_not_empty); } + return false; } // Test to see if the scavenge will likely fail. @@ -819,7 +810,7 @@ void PSScavenge::initialize() { if (AlwaysTenure || NeverTenure) { assert(MaxTenuringThreshold == 0 || MaxTenuringThreshold == markOopDesc::max_age + 1, - err_msg("MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is %d", (int) MaxTenuringThreshold)); + "MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is %d", (int) MaxTenuringThreshold); _tenuring_threshold = MaxTenuringThreshold; } else { // We want to smooth out our startup times for the AdaptiveSizePolicy diff --git a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp index 8744f74db88..29f3aeb65a0 100644 --- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/serial/defNewGeneration.inline.hpp" +#include "gc/shared/cardTableRS.hpp" #include "gc/shared/collectorCounters.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcLocker.inline.hpp" @@ -33,7 +34,6 @@ #include "gc/shared/gcTraceTime.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/genOopClosures.inline.hpp" -#include "gc/shared/genRemSet.hpp" #include "gc/shared/generationSpec.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/space.inline.hpp" @@ -69,8 +69,7 @@ bool DefNewGeneration::IsAliveClosure::do_object_b(oop p) { DefNewGeneration::KeepAliveClosure:: KeepAliveClosure(ScanWeakRefClosure* cl) : _cl(cl) { - GenRemSet* rs = GenCollectedHeap::heap()->rem_set(); - _rs = (CardTableRS*)rs; + _rs = GenCollectedHeap::heap()->rem_set(); } void DefNewGeneration::KeepAliveClosure::do_oop(oop* p) { DefNewGeneration::KeepAliveClosure::do_oop_work(p); } @@ -583,7 +582,7 @@ void DefNewGeneration::collect(bool full, init_assuming_no_promotion_failure(); - GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL, gc_tracer.gc_id()); + GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); // Capture heap used before collection (for printing). size_t gch_prev_used = gch->used(); @@ -646,8 +645,9 @@ void DefNewGeneration::collect(bool full, rp->setup_policy(clear_all_soft_refs); const ReferenceProcessorStats& stats = rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers, - NULL, _gc_timer, gc_tracer.gc_id()); + NULL, _gc_timer); gc_tracer.report_gc_reference_stats(stats); + gc_tracer.report_tenuring_threshold(tenuring_threshold()); if (!_promotion_failed) { // Swap the survivor spaces. @@ -712,7 +712,6 @@ void DefNewGeneration::collect(bool full, update_time_of_last_gc(now); gch->trace_heap_after_gc(&gc_tracer); - gc_tracer.report_tenuring_threshold(tenuring_threshold()); _gc_timer->register_gc_end(); diff --git a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp index b826ed7f3f0..73f9be21e3e 100644 --- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp +++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp @@ -70,7 +70,7 @@ void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_so set_ref_processor(rp); rp->setup_policy(clear_all_softrefs); - GCTraceTime t1(GCCauseString("Full GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL, _gc_tracer->gc_id()); + GCTraceTime t1(GCCauseString("Full GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); gch->trace_heap_before_gc(_gc_tracer); @@ -96,8 +96,10 @@ void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_so mark_sweep_phase2(); // Don't add any more derived pointers during phase3 - COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity")); - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_active(), "Sanity"); + DerivedPointerTable::set_active(false); +#endif mark_sweep_phase3(); @@ -115,7 +117,7 @@ void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_so // can clear the card table. Otherwise, we must invalidate // it (consider all cards dirty). In the future, we might consider doing // compaction within generations only, and doing card-table sliding. - GenRemSet* rs = gch->rem_set(); + CardTableRS* rs = gch->rem_set(); Generation* old_gen = gch->old_gen(); // Clear/invalidate below make use of the "prev_used_regions" saved earlier. @@ -186,7 +188,7 @@ void GenMarkSweep::deallocate_stacks() { void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - GCTraceTime tm("phase 1", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 1", PrintGC && Verbose, true, _gc_timer); GenCollectedHeap* gch = GenCollectedHeap::heap(); @@ -217,7 +219,7 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { ref_processor()->setup_policy(clear_all_softrefs); const ReferenceProcessorStats& stats = ref_processor()->process_discovered_references( - &is_alive, &keep_alive, &follow_stack_closure, NULL, _gc_timer, _gc_tracer->gc_id()); + &is_alive, &keep_alive, &follow_stack_closure, NULL, _gc_timer); gc_tracer()->report_gc_reference_stats(stats); } @@ -259,7 +261,7 @@ void GenMarkSweep::mark_sweep_phase2() { GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCTraceTime tm("phase 2", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 2", PrintGC && Verbose, true, _gc_timer); gch->prepare_for_compaction(); } @@ -275,7 +277,7 @@ void GenMarkSweep::mark_sweep_phase3() { GenCollectedHeap* gch = GenCollectedHeap::heap(); // Adjust the pointers to reflect the new locations - GCTraceTime tm("phase 3", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 3", PrintGC && Verbose, true, _gc_timer); // Need new claim bits for the pointer adjustment tracing. ClassLoaderDataGraph::clear_claimed_marks(); @@ -327,7 +329,7 @@ void GenMarkSweep::mark_sweep_phase4() { // to use a higher index (saved from phase2) when verifying perm_gen. GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer); GenCompactClosure blk; gch->generation_iterate(&blk, true); diff --git a/hotspot/src/share/vm/gc/serial/markSweep.hpp b/hotspot/src/share/vm/gc/serial/markSweep.hpp index d53f3a1f0c7..1f25bcf284c 100644 --- a/hotspot/src/share/vm/gc/serial/markSweep.hpp +++ b/hotspot/src/share/vm/gc/serial/markSweep.hpp @@ -196,7 +196,9 @@ public: virtual void do_cld(ClassLoaderData* cld); void do_cld_nv(ClassLoaderData* cld); - void set_ref_processor(ReferenceProcessor* rp) { _ref_processor = rp; } + void set_ref_processor(ReferenceProcessor* rp) { + set_ref_processor_internal(rp); + } }; class PreservedMark VALUE_OBJ_CLASS_SPEC { diff --git a/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp b/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp index 7f88c6c361e..8a526938e10 100644 --- a/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp +++ b/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp @@ -42,7 +42,7 @@ TenuredGeneration::TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, - GenRemSet* remset) : + CardTableRS* remset) : CardGeneration(rs, initial_byte_size, remset) { HeapWord* bottom = (HeapWord*) _virtual_space.low(); @@ -129,8 +129,8 @@ void TenuredGeneration::compute_new_size() { CardGeneration::compute_new_size(); assert(used() == used_after_gc && used_after_gc <= capacity(), - err_msg("used: " SIZE_FORMAT " used_after_gc: " SIZE_FORMAT - " capacity: " SIZE_FORMAT, used(), used_after_gc, capacity())); + "used: " SIZE_FORMAT " used_after_gc: " SIZE_FORMAT + " capacity: " SIZE_FORMAT, used(), used_after_gc, capacity()); } void TenuredGeneration::update_gc_stats(Generation* current_generation, diff --git a/hotspot/src/share/vm/gc/serial/tenuredGeneration.hpp b/hotspot/src/share/vm/gc/serial/tenuredGeneration.hpp index e6a38a389b5..f9ec569dbca 100644 --- a/hotspot/src/share/vm/gc/serial/tenuredGeneration.hpp +++ b/hotspot/src/share/vm/gc/serial/tenuredGeneration.hpp @@ -58,7 +58,7 @@ class TenuredGeneration: public CardGeneration { public: TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, - GenRemSet* remset); + CardTableRS* remset); Generation::Name kind() { return Generation::MarkSweepCompact; } diff --git a/hotspot/src/share/vm/gc/shared/ageTable.cpp b/hotspot/src/share/vm/gc/shared/ageTable.cpp index cfa2a648323..638ce40c7ec 100644 --- a/hotspot/src/share/vm/gc/shared/ageTable.cpp +++ b/hotspot/src/share/vm/gc/shared/ageTable.cpp @@ -78,7 +78,7 @@ uint ageTable::compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCoun if (AlwaysTenure || NeverTenure) { assert(MaxTenuringThreshold == 0 || MaxTenuringThreshold == markOopDesc::max_age + 1, - err_msg("MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is " UINTX_FORMAT, MaxTenuringThreshold)); + "MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is " UINTX_FORMAT, MaxTenuringThreshold); result = MaxTenuringThreshold; } else { size_t total = 0; diff --git a/hotspot/src/share/vm/gc/shared/barrierSet.hpp b/hotspot/src/share/vm/gc/shared/barrierSet.hpp index 2069d028ea8..39ce1161127 100644 --- a/hotspot/src/share/vm/gc/shared/barrierSet.hpp +++ b/hotspot/src/share/vm/gc/shared/barrierSet.hpp @@ -188,6 +188,9 @@ public: static void static_write_ref_array_pre(HeapWord* start, size_t count); static void static_write_ref_array_post(HeapWord* start, size_t count); + virtual void write_ref_nmethod_pre(oop* dst, nmethod* nm) {} + virtual void write_ref_nmethod_post(oop* dst, nmethod* nm) {} + protected: virtual void write_ref_array_work(MemRegion mr) = 0; public: diff --git a/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp b/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp index 36876f0a0b5..9bf2eb5bdb1 100644 --- a/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp +++ b/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp @@ -543,11 +543,11 @@ HeapWord* BlockOffsetArrayNonContigSpace::block_start_unsafe( size_t n_cards_back = entry_to_cards_back(offset); q -= (N_words * n_cards_back); assert(q >= _sp->bottom(), - err_msg("q = " PTR_FORMAT " crossed below bottom = " PTR_FORMAT, - p2i(q), p2i(_sp->bottom()))); + "q = " PTR_FORMAT " crossed below bottom = " PTR_FORMAT, + p2i(q), p2i(_sp->bottom())); assert(q < _sp->end(), - err_msg("q = " PTR_FORMAT " crossed above end = " PTR_FORMAT, - p2i(q), p2i(_sp->end()))); + "q = " PTR_FORMAT " crossed above end = " PTR_FORMAT, + p2i(q), p2i(_sp->end())); index -= n_cards_back; offset = _array->offset_array(index); } @@ -555,11 +555,11 @@ HeapWord* BlockOffsetArrayNonContigSpace::block_start_unsafe( index--; q -= offset; assert(q >= _sp->bottom(), - err_msg("q = " PTR_FORMAT " crossed below bottom = " PTR_FORMAT, - p2i(q), p2i(_sp->bottom()))); + "q = " PTR_FORMAT " crossed below bottom = " PTR_FORMAT, + p2i(q), p2i(_sp->bottom())); assert(q < _sp->end(), - err_msg("q = " PTR_FORMAT " crossed above end = " PTR_FORMAT, - p2i(q), p2i(_sp->end()))); + "q = " PTR_FORMAT " crossed above end = " PTR_FORMAT, + p2i(q), p2i(_sp->end())); HeapWord* n = q; while (n <= addr) { @@ -567,17 +567,17 @@ HeapWord* BlockOffsetArrayNonContigSpace::block_start_unsafe( q = n; n += _sp->block_size(n); assert(n > q, - err_msg("Looping at n = " PTR_FORMAT " with last = " PTR_FORMAT "," - " while querying blk_start(" PTR_FORMAT ")" - " on _sp = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(n), p2i(last), p2i(addr), p2i(_sp->bottom()), p2i(_sp->end()))); + "Looping at n = " PTR_FORMAT " with last = " PTR_FORMAT "," + " while querying blk_start(" PTR_FORMAT ")" + " on _sp = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(n), p2i(last), p2i(addr), p2i(_sp->bottom()), p2i(_sp->end())); } assert(q <= addr, - err_msg("wrong order for current (" INTPTR_FORMAT ")" " <= arg (" INTPTR_FORMAT ")", - p2i(q), p2i(addr))); + "wrong order for current (" INTPTR_FORMAT ")" " <= arg (" INTPTR_FORMAT ")", + p2i(q), p2i(addr)); assert(addr <= n, - err_msg("wrong order for arg (" INTPTR_FORMAT ") <= next (" INTPTR_FORMAT ")", - p2i(addr), p2i(n))); + "wrong order for arg (" INTPTR_FORMAT ") <= next (" INTPTR_FORMAT ")", + p2i(addr), p2i(n)); return q; } diff --git a/hotspot/src/share/vm/gc/shared/cardGeneration.cpp b/hotspot/src/share/vm/gc/shared/cardGeneration.cpp index 06a4c90cb58..f85e798de4e 100644 --- a/hotspot/src/share/vm/gc/shared/cardGeneration.cpp +++ b/hotspot/src/share/vm/gc/shared/cardGeneration.cpp @@ -26,9 +26,9 @@ #include "gc/shared/blockOffsetTable.inline.hpp" #include "gc/shared/cardGeneration.inline.hpp" +#include "gc/shared/cardTableRS.hpp" #include "gc/shared/gcLocker.hpp" #include "gc/shared/genOopClosures.inline.hpp" -#include "gc/shared/genRemSet.hpp" #include "gc/shared/generationSpec.hpp" #include "gc/shared/space.inline.hpp" #include "memory/iterator.hpp" @@ -37,7 +37,7 @@ CardGeneration::CardGeneration(ReservedSpace rs, size_t initial_byte_size, - GenRemSet* remset) : + CardTableRS* remset) : Generation(rs, initial_byte_size), _rs(remset), _shrink_factor(0), _min_heap_delta_bytes(), _capacity_at_prologue(), _used_at_prologue() diff --git a/hotspot/src/share/vm/gc/shared/cardGeneration.hpp b/hotspot/src/share/vm/gc/shared/cardGeneration.hpp index 497855da16a..dde7de620f3 100644 --- a/hotspot/src/share/vm/gc/shared/cardGeneration.hpp +++ b/hotspot/src/share/vm/gc/shared/cardGeneration.hpp @@ -37,7 +37,7 @@ class CardGeneration: public Generation { friend class VMStructs; protected: // This is shared with other generations. - GenRemSet* _rs; + CardTableRS* _rs; // This is local to this generation. BlockOffsetSharedArray* _bts; @@ -52,7 +52,7 @@ class CardGeneration: public Generation { size_t _capacity_at_prologue; size_t _used_at_prologue; - CardGeneration(ReservedSpace rs, size_t initial_byte_size, GenRemSet* remset); + CardGeneration(ReservedSpace rs, size_t initial_byte_size, CardTableRS* remset); virtual void assert_correct_size_change_locking() = 0; diff --git a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp index 84cb340ae7a..1ede220ab61 100644 --- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp +++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp @@ -126,9 +126,9 @@ class CardTableModRefBS: public ModRefBarrierSet { // Mapping from address to card marking array entry jbyte* byte_for(const void* p) const { assert(_whole_heap.contains(p), - err_msg("Attempt to access p = " PTR_FORMAT " out of bounds of " - " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end()))); + "Attempt to access p = " PTR_FORMAT " out of bounds of " + " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end())); jbyte* result = &byte_map_base[uintptr_t(p) >> card_shift]; assert(result >= _byte_map && result < _byte_map + _byte_map_size, "out of bounds accessor for card marking array"); @@ -294,18 +294,18 @@ public: size_t delta = pointer_delta(p, byte_map_base, sizeof(jbyte)); HeapWord* result = (HeapWord*) (delta << card_shift); assert(_whole_heap.contains(result), - err_msg("Returning result = " PTR_FORMAT " out of bounds of " - " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(result), p2i(_whole_heap.start()), p2i(_whole_heap.end()))); + "Returning result = " PTR_FORMAT " out of bounds of " + " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(result), p2i(_whole_heap.start()), p2i(_whole_heap.end())); return result; } // Mapping from address to card marking array index. size_t index_for(void* p) { assert(_whole_heap.contains(p), - err_msg("Attempt to access p = " PTR_FORMAT " out of bounds of " - " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end()))); + "Attempt to access p = " PTR_FORMAT " out of bounds of " + " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end())); return byte_for(p) - _byte_map; } diff --git a/hotspot/src/share/vm/gc/shared/cardTableRS.cpp b/hotspot/src/share/vm/gc/shared/cardTableRS.cpp index 8af127ce984..b26d8739531 100644 --- a/hotspot/src/share/vm/gc/shared/cardTableRS.cpp +++ b/hotspot/src/share/vm/gc/shared/cardTableRS.cpp @@ -34,8 +34,48 @@ #include "runtime/os.hpp" #include "utilities/macros.hpp" +class HasAccumulatedModifiedOopsClosure : public KlassClosure { + bool _found; + public: + HasAccumulatedModifiedOopsClosure() : _found(false) {} + void do_klass(Klass* klass) { + if (_found) { + return; + } + + if (klass->has_accumulated_modified_oops()) { + _found = true; + } + } + bool found() { + return _found; + } +}; + +bool KlassRemSet::mod_union_is_clear() { + HasAccumulatedModifiedOopsClosure closure; + ClassLoaderDataGraph::classes_do(&closure); + + return !closure.found(); +} + + +class ClearKlassModUnionClosure : public KlassClosure { + public: + void do_klass(Klass* klass) { + if (klass->has_accumulated_modified_oops()) { + klass->clear_accumulated_modified_oops(); + } + } +}; + +void KlassRemSet::clear_mod_union() { + ClearKlassModUnionClosure closure; + ClassLoaderDataGraph::classes_do(&closure); +} + CardTableRS::CardTableRS(MemRegion whole_heap) : - GenRemSet(), + _bs(NULL), _cur_youngergen_card_val(youngergenP1_card) { _ct_bs = new CardTableModRefBSForCTRS(whole_heap); @@ -278,10 +318,10 @@ void CardTableRS::younger_refs_in_space_iterate(Space* sp, // CMS+ParNew until related bug is fixed. MemRegion ur = sp->used_region(); assert(ur.contains(urasm) || (UseConcMarkSweepGC), - err_msg("Did you forget to call save_marks()? " - "[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in " - "[" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end()))); + "Did you forget to call save_marks()? " + "[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in " + "[" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end())); // In the case of CMS+ParNew, issue a warning if (!ur.contains(urasm)) { assert(UseConcMarkSweepGC, "Tautology: see assert above"); @@ -342,25 +382,25 @@ protected: template void do_oop_work(T* p) { HeapWord* jp = (HeapWord*)p; assert(jp >= _begin && jp < _end, - err_msg("Error: jp " PTR_FORMAT " should be within " - "[_begin, _end) = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(jp), p2i(_begin), p2i(_end))); + "Error: jp " PTR_FORMAT " should be within " + "[_begin, _end) = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(jp), p2i(_begin), p2i(_end)); oop obj = oopDesc::load_decode_heap_oop(p); guarantee(obj == NULL || (HeapWord*)obj >= _boundary, - err_msg("pointer " PTR_FORMAT " at " PTR_FORMAT " on " - "clean card crosses boundary" PTR_FORMAT, - p2i((HeapWord*)obj), p2i(jp), p2i(_boundary))); + "pointer " PTR_FORMAT " at " PTR_FORMAT " on " + "clean card crosses boundary" PTR_FORMAT, + p2i(obj), p2i(jp), p2i(_boundary)); } public: VerifyCleanCardClosure(HeapWord* b, HeapWord* begin, HeapWord* end) : _boundary(b), _begin(begin), _end(end) { assert(b <= begin, - err_msg("Error: boundary " PTR_FORMAT " should be at or below begin " PTR_FORMAT, - p2i(b), p2i(begin))); + "Error: boundary " PTR_FORMAT " should be at or below begin " PTR_FORMAT, + p2i(b), p2i(begin)); assert(begin <= end, - err_msg("Error: begin " PTR_FORMAT " should be strictly below end " PTR_FORMAT, - p2i(begin), p2i(end))); + "Error: begin " PTR_FORMAT " should be strictly below end " PTR_FORMAT, + p2i(begin), p2i(end)); } virtual void do_oop(oop* p) { VerifyCleanCardClosure::do_oop_work(p); } diff --git a/hotspot/src/share/vm/gc/shared/cardTableRS.hpp b/hotspot/src/share/vm/gc/shared/cardTableRS.hpp index 1f15118a9e0..2a11147b4cb 100644 --- a/hotspot/src/share/vm/gc/shared/cardTableRS.hpp +++ b/hotspot/src/share/vm/gc/shared/cardTableRS.hpp @@ -26,16 +26,26 @@ #define SHARE_VM_GC_SHARED_CARDTABLERS_HPP #include "gc/shared/cardTableModRefBSForCTRS.hpp" -#include "gc/shared/genRemSet.hpp" #include "memory/memRegion.hpp" class Space; class OopsInGenClosure; -// This kind of "GenRemSet" uses a card table both as shared data structure +// Helper to remember modified oops in all klasses. +class KlassRemSet { + bool _accumulate_modified_oops; + public: + KlassRemSet() : _accumulate_modified_oops(false) {} + void set_accumulate_modified_oops(bool value) { _accumulate_modified_oops = value; } + bool accumulate_modified_oops() { return _accumulate_modified_oops; } + bool mod_union_is_clear(); + void clear_mod_union(); +}; + +// This RemSet uses a card table both as shared data structure // for a mod ref barrier set and for the rem set information. -class CardTableRS: public GenRemSet { +class CardTableRS: public CHeapObj { friend class VMStructs; // Below are private classes used in impl. friend class VerifyCTSpaceClosure; @@ -54,9 +64,10 @@ class CardTableRS: public GenRemSet { return CardTableModRefBSForCTRS::card_is_dirty_wrt_gen_iter(cv); } - CardTableModRefBSForCTRS* _ct_bs; + KlassRemSet _klass_rem_set; + BarrierSet* _bs; - virtual void younger_refs_in_space_iterate(Space* sp, OopsInGenClosure* cl, uint n_threads); + CardTableModRefBSForCTRS* _ct_bs; void verify_space(Space* s, HeapWord* gen_start); @@ -104,11 +115,18 @@ public: CardTableRS(MemRegion whole_heap); ~CardTableRS(); - // *** GenRemSet functions. - CardTableRS* as_CardTableRS() { return this; } + // Return the barrier set associated with "this." + BarrierSet* bs() { return _bs; } + + // Set the barrier set. + void set_bs(BarrierSet* bs) { _bs = bs; } + + KlassRemSet* klass_rem_set() { return &_klass_rem_set; } CardTableModRefBSForCTRS* ct_bs() { return _ct_bs; } + void younger_refs_in_space_iterate(Space* sp, OopsInGenClosure* cl, uint n_threads); + // Override. void prepare_for_younger_refs_iterate(bool parallel); diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp index 67f11886f3d..e581bbb47c2 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp @@ -231,7 +231,7 @@ void CollectedHeap::set_barrier_set(BarrierSet* barrier_set) { void CollectedHeap::pre_initialize() { // Used for ReduceInitialCardMarks (when COMPILER2 is used); // otherwise remains unused. -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI _defer_initial_card_mark = ReduceInitialCardMarks && can_elide_tlab_store_barriers() && (DeferInitialCardMark || card_mark_must_follow_store()); #else @@ -459,7 +459,7 @@ CollectedHeap::fill_with_array(HeapWord* start, size_t words, bool zap) const size_t payload_size = words - filler_array_hdr_size(); const size_t len = payload_size * HeapWordSize / sizeof(jint); - assert((int)len >= 0, err_msg("size too large " SIZE_FORMAT " becomes %d", words, (int)len)); + assert((int)len >= 0, "size too large " SIZE_FORMAT " becomes %d", words, (int)len); // Set the length first for concurrent GC. ((arrayOop)start)->set_length((int)len); @@ -539,7 +539,7 @@ void CollectedHeap::ensure_parsability(bool retire_tlabs) { " to threads list is doomed to failure!"); for (JavaThread *thread = Threads::first(); thread; thread = thread->next()) { if (use_tlab) thread->tlab().make_parsable(retire_tlabs); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // The deferred store barriers must all have been flushed to the // card-table (or other remembered set structure) before GC starts // processing the card-table (or other remembered set). @@ -573,13 +573,15 @@ void CollectedHeap::resize_all_tlabs() { void CollectedHeap::pre_full_gc_dump(GCTimer* timer) { if (HeapDumpBeforeFullGC) { - GCTraceTime tt("Heap Dump (before full gc): ", PrintGCDetails, false, timer, GCId::create()); + GCIdMarkAndRestore gc_id_mark; + GCTraceTime tt("Heap Dump (before full gc): ", PrintGCDetails, false, timer); // We are doing a full collection and a heap dump before // full collection has been requested. HeapDumper::dump_heap(); } if (PrintClassHistogramBeforeFullGC) { - GCTraceTime tt("Class Histogram (before full gc): ", PrintGCDetails, true, timer, GCId::create()); + GCIdMarkAndRestore gc_id_mark; + GCTraceTime tt("Class Histogram (before full gc): ", PrintGCDetails, true, timer); VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */); inspector.doit(); } @@ -587,11 +589,13 @@ void CollectedHeap::pre_full_gc_dump(GCTimer* timer) { void CollectedHeap::post_full_gc_dump(GCTimer* timer) { if (HeapDumpAfterFullGC) { - GCTraceTime tt("Heap Dump (after full gc): ", PrintGCDetails, false, timer, GCId::create()); + GCIdMarkAndRestore gc_id_mark; + GCTraceTime tt("Heap Dump (after full gc): ", PrintGCDetails, false, timer); HeapDumper::dump_heap(); } if (PrintClassHistogramAfterFullGC) { - GCTraceTime tt("Class Histogram (after full gc): ", PrintGCDetails, true, timer, GCId::create()); + GCIdMarkAndRestore gc_id_mark; + GCTraceTime tt("Class Histogram (after full gc): ", PrintGCDetails, true, timer); VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */); inspector.doit(); } @@ -622,12 +626,12 @@ void CollectedHeap::test_is_in() { assert(heap_start >= ((uintptr_t)NULL + epsilon), "sanity"); void* before_heap = (void*)(heap_start - epsilon); assert(!heap->is_in(before_heap), - err_msg("before_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(before_heap))); + "before_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(before_heap)); // Test that a pointer to after the heap end is reported as outside the heap. assert(heap_end <= ((uintptr_t)-1 - epsilon), "sanity"); void* after_heap = (void*)(heap_end + epsilon); assert(!heap->is_in(after_heap), - err_msg("after_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(after_heap))); + "after_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(after_heap)); } #endif diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp index 772b46c4772..d12941b14fe 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp @@ -90,7 +90,8 @@ class CollectedHeap : public CHeapObj { GCHeapLog* _gc_heap_log; - // Used in support of ReduceInitialCardMarks; only consulted if COMPILER2 is being used + // Used in support of ReduceInitialCardMarks; only consulted if COMPILER2 + // or INCLUDE_JVMCI is being used bool _defer_initial_card_mark; MemRegion _reserved; diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp index 726990908cc..ef4de405437 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp @@ -244,9 +244,9 @@ inline HeapWord* CollectedHeap::align_allocation_or_fail(HeapWord* addr, } assert(is_ptr_aligned(addr, HeapWordSize), - err_msg("Address " PTR_FORMAT " is not properly aligned.", p2i(addr))); + "Address " PTR_FORMAT " is not properly aligned.", p2i(addr)); assert(is_size_aligned(alignment_in_bytes, HeapWordSize), - err_msg("Alignment size %u is incorrect.", alignment_in_bytes)); + "Alignment size %u is incorrect.", alignment_in_bytes); HeapWord* new_addr = (HeapWord*) align_pointer_up(addr, alignment_in_bytes); size_t padding = pointer_delta(new_addr, addr); @@ -258,13 +258,13 @@ inline HeapWord* CollectedHeap::align_allocation_or_fail(HeapWord* addr, if (padding < CollectedHeap::min_fill_size()) { padding += alignment_in_bytes / HeapWordSize; assert(padding >= CollectedHeap::min_fill_size(), - err_msg("alignment_in_bytes %u is expect to be larger " - "than the minimum object size", alignment_in_bytes)); + "alignment_in_bytes %u is expect to be larger " + "than the minimum object size", alignment_in_bytes); new_addr = addr + padding; } - assert(new_addr > addr, err_msg("Unexpected arithmetic overflow " - PTR_FORMAT " not greater than " PTR_FORMAT, p2i(new_addr), p2i(addr))); + assert(new_addr > addr, "Unexpected arithmetic overflow " + PTR_FORMAT " not greater than " PTR_FORMAT, p2i(new_addr), p2i(addr)); if(new_addr < end) { CollectedHeap::fill_with_object(addr, padding); return new_addr; diff --git a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp index 6ee140ee9ac..568de2d0ef8 100644 --- a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp @@ -78,11 +78,11 @@ void CollectorPolicy::initialize_flags() { assert(_space_alignment != 0, "Space alignment not set up properly"); assert(_heap_alignment != 0, "Heap alignment not set up properly"); assert(_heap_alignment >= _space_alignment, - err_msg("heap_alignment: " SIZE_FORMAT " less than space_alignment: " SIZE_FORMAT, - _heap_alignment, _space_alignment)); + "heap_alignment: " SIZE_FORMAT " less than space_alignment: " SIZE_FORMAT, + _heap_alignment, _space_alignment); assert(_heap_alignment % _space_alignment == 0, - err_msg("heap_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, - _heap_alignment, _space_alignment)); + "heap_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, + _heap_alignment, _space_alignment); if (FLAG_IS_CMDLINE(MaxHeapSize)) { if (FLAG_IS_CMDLINE(InitialHeapSize) && InitialHeapSize > MaxHeapSize) { @@ -152,7 +152,7 @@ bool CollectorPolicy::use_should_clear_all_soft_refs(bool v) { return result; } -GenRemSet* CollectorPolicy::create_rem_set(MemRegion whole_heap) { +CardTableRS* CollectorPolicy::create_rem_set(MemRegion whole_heap) { return new CardTableRS(whole_heap); } @@ -173,7 +173,7 @@ size_t CollectorPolicy::compute_heap_alignment() { // byte entry and the os page size is 4096, the maximum heap size should // be 512*4096 = 2MB aligned. - size_t alignment = GenRemSet::max_alignment_constraint(); + size_t alignment = CardTableRS::ct_max_alignment_constraint(); if (UseLargePages) { // In presence of large pages we have to make sure that our @@ -275,14 +275,14 @@ void GenCollectorPolicy::initialize_flags() { assert(_gen_alignment != 0, "Generation alignment not set up properly"); assert(_heap_alignment >= _gen_alignment, - err_msg("heap_alignment: " SIZE_FORMAT " less than gen_alignment: " SIZE_FORMAT, - _heap_alignment, _gen_alignment)); + "heap_alignment: " SIZE_FORMAT " less than gen_alignment: " SIZE_FORMAT, + _heap_alignment, _gen_alignment); assert(_gen_alignment % _space_alignment == 0, - err_msg("gen_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, - _gen_alignment, _space_alignment)); + "gen_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, + _gen_alignment, _space_alignment); assert(_heap_alignment % _gen_alignment == 0, - err_msg("heap_alignment: " SIZE_FORMAT " not aligned by gen_alignment: " SIZE_FORMAT, - _heap_alignment, _gen_alignment)); + "heap_alignment: " SIZE_FORMAT " not aligned by gen_alignment: " SIZE_FORMAT, + _heap_alignment, _gen_alignment); // All generational heaps have a youngest gen; handle those flags here @@ -1012,14 +1012,14 @@ public: MarkSweepPolicy msp; msp.initialize_all(); - assert(msp.min_young_size() <= expected, err_msg("%zu > %zu", msp.min_young_size(), expected)); + assert(msp.min_young_size() <= expected, "%zu > %zu", msp.min_young_size(), expected); } static void verify_young_initial(size_t expected) { MarkSweepPolicy msp; msp.initialize_all(); - assert(msp.initial_young_size() == expected, err_msg("%zu != %zu", msp.initial_young_size(), expected)); + assert(msp.initial_young_size() == expected, "%zu != %zu", msp.initial_young_size(), expected); } static void verify_scaled_young_initial(size_t initial_heap_size) { @@ -1033,23 +1033,23 @@ public: } size_t expected = msp.scale_by_NewRatio_aligned(initial_heap_size); - assert(msp.initial_young_size() == expected, err_msg("%zu != %zu", msp.initial_young_size(), expected)); + assert(msp.initial_young_size() == expected, "%zu != %zu", msp.initial_young_size(), expected); assert(FLAG_IS_ERGO(NewSize) && NewSize == expected, - err_msg("NewSize should have been set ergonomically to %zu, but was %zu", expected, NewSize)); + "NewSize should have been set ergonomically to %zu, but was %zu", expected, NewSize); } static void verify_old_min(size_t expected) { MarkSweepPolicy msp; msp.initialize_all(); - assert(msp.min_old_size() <= expected, err_msg("%zu > %zu", msp.min_old_size(), expected)); + assert(msp.min_old_size() <= expected, "%zu > %zu", msp.min_old_size(), expected); } static void verify_old_initial(size_t expected) { MarkSweepPolicy msp; msp.initialize_all(); - assert(msp.initial_old_size() == expected, err_msg("%zu != %zu", msp.initial_old_size(), expected)); + assert(msp.initial_old_size() == expected, "%zu != %zu", msp.initial_old_size(), expected); } diff --git a/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp b/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp index fbbcfcb0c22..d42ed13b6d1 100644 --- a/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp @@ -26,7 +26,7 @@ #define SHARE_VM_GC_SHARED_COLLECTORPOLICY_HPP #include "gc/shared/barrierSet.hpp" -#include "gc/shared/genRemSet.hpp" +#include "gc/shared/cardTableRS.hpp" #include "gc/shared/generationSpec.hpp" #include "memory/allocation.hpp" #include "utilities/macros.hpp" @@ -143,7 +143,7 @@ class CollectorPolicy : public CHeapObj { #endif // INCLUDE_ALL_GCS - virtual GenRemSet* create_rem_set(MemRegion reserved); + virtual CardTableRS* create_rem_set(MemRegion reserved); // This method controls how a collector satisfies a request // for a block of memory. "gc_time_limit_was_exceeded" will diff --git a/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp b/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp index ce4e74875ca..f9b86321fe1 100644 --- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp +++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp @@ -33,10 +33,6 @@ #include "runtime/javaCalls.hpp" #include "runtime/os.hpp" -// CopyrightVersion 1.2 - -int ConcurrentGCThread::_CGC_flag = CGC_nil; - ConcurrentGCThread::ConcurrentGCThread() : _should_terminate(false), _has_terminated(false) { }; diff --git a/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp b/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp index 8647eee2254..4876e84e3da 100644 --- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp +++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp @@ -35,19 +35,6 @@ protected: bool _should_terminate; bool _has_terminated; - enum CGC_flag_type { - CGC_nil = 0x0, - CGC_dont_suspend = 0x1, - CGC_CGC_safepoint = 0x2, - CGC_VM_safepoint = 0x4 - }; - - static int _CGC_flag; - - static bool CGC_flag_is_set(int b) { return (_CGC_flag & b) != 0; } - static int set_CGC_flag(int b) { return _CGC_flag |= b; } - static int reset_CGC_flag(int b) { return _CGC_flag &= ~b; } - // Create and start the thread (setting it's priority high.) void create_and_start(); @@ -63,13 +50,10 @@ protected: void terminate(); public: - // Constructor - ConcurrentGCThread(); - ~ConcurrentGCThread() {} // Exists to call NamedThread destructor. // Tester - bool is_ConcurrentGC_thread() const { return true; } + bool is_ConcurrentGC_thread() const { return true; } }; // The SurrogateLockerThread is used by concurrent GC threads for diff --git a/hotspot/src/share/vm/gc/shared/gcCause.hpp b/hotspot/src/share/vm/gc/shared/gcCause.hpp index 13e86416d55..39cee93ed9c 100644 --- a/hotspot/src/share/vm/gc/shared/gcCause.hpp +++ b/hotspot/src/share/vm/gc/shared/gcCause.hpp @@ -95,9 +95,9 @@ class GCCause : public AllStatic { // Causes for collection of the tenured gernation inline static bool is_tenured_allocation_failure_gc(GCCause::Cause cause) { assert(cause != GCCause::_old_generation_too_full_to_scavenge && - cause != GCCause::_old_generation_expanded_on_last_scavenge, - err_msg("This GCCause may be correct but is not expected yet: %s", - to_string(cause))); + cause != GCCause::_old_generation_expanded_on_last_scavenge, + "This GCCause may be correct but is not expected yet: %s", + to_string(cause)); // _tenured_generation_full or _cms_generation_full for full tenured generations // _adaptive_size_policy for a full collection after a young GC // _allocation_failure is the generic cause a collection which could result @@ -141,14 +141,14 @@ class GCCauseString : StackObj { _position = jio_snprintf(_buffer, _length, "%s ", prefix); } assert(_position >= 0 && _position <= _length, - err_msg("Need to increase the buffer size in GCCauseString? %d", _position)); + "Need to increase the buffer size in GCCauseString? %d", _position); } GCCauseString& append(const char* str) { int res = jio_snprintf(_buffer + _position, _length - _position, "%s", str); _position += res; assert(res >= 0 && _position <= _length, - err_msg("Need to increase the buffer size in GCCauseString? %d", res)); + "Need to increase the buffer size in GCCauseString? %d", res); return *this; } diff --git a/hotspot/src/share/vm/gc/shared/gcId.cpp b/hotspot/src/share/vm/gc/shared/gcId.cpp index 811f3988614..a87bbe9d31e 100644 --- a/hotspot/src/share/vm/gc/shared/gcId.cpp +++ b/hotspot/src/share/vm/gc/shared/gcId.cpp @@ -25,18 +25,50 @@ #include "precompiled.hpp" #include "gc/shared/gcId.hpp" #include "runtime/safepoint.hpp" +#include "runtime/thread.inline.hpp" uint GCId::_next_id = 0; -const GCId GCId::create() { - return GCId(_next_id++); +NamedThread* currentNamedthread() { + assert(Thread::current()->is_Named_thread(), "This thread must be NamedThread"); + return (NamedThread*)Thread::current(); } -const GCId GCId::peek() { - return GCId(_next_id); + +const uint GCId::create() { + return _next_id++; } -const GCId GCId::undefined() { - return GCId(UNDEFINED); + +const uint GCId::current() { + assert(currentNamedthread()->gc_id() != undefined(), "Using undefined GC id."); + return current_raw(); } -bool GCId::is_undefined() const { - return _id == UNDEFINED; + +const uint GCId::current_raw() { + return currentNamedthread()->gc_id(); +} + +GCIdMark::GCIdMark() : _gc_id(GCId::create()) { + currentNamedthread()->set_gc_id(_gc_id); +} + +GCIdMark::GCIdMark(uint gc_id) : _gc_id(gc_id) { + currentNamedthread()->set_gc_id(_gc_id); +} + +GCIdMark::~GCIdMark() { + currentNamedthread()->set_gc_id(GCId::undefined()); +} + +GCIdMarkAndRestore::GCIdMarkAndRestore() : _gc_id(GCId::create()) { + _previous_gc_id = GCId::current_raw(); + currentNamedthread()->set_gc_id(_gc_id); +} + +GCIdMarkAndRestore::GCIdMarkAndRestore(uint gc_id) : _gc_id(gc_id) { + _previous_gc_id = GCId::current_raw(); + currentNamedthread()->set_gc_id(_gc_id); +} + +GCIdMarkAndRestore::~GCIdMarkAndRestore() { + currentNamedthread()->set_gc_id(_previous_gc_id); } diff --git a/hotspot/src/share/vm/gc/shared/gcId.hpp b/hotspot/src/share/vm/gc/shared/gcId.hpp index 1cc9f3829cb..2e09fd84a67 100644 --- a/hotspot/src/share/vm/gc/shared/gcId.hpp +++ b/hotspot/src/share/vm/gc/shared/gcId.hpp @@ -27,25 +27,36 @@ #include "memory/allocation.hpp" -class GCId VALUE_OBJ_CLASS_SPEC { - private: - uint _id; - GCId(uint id) : _id(id) {} - GCId() { } // Unused - +class GCId : public AllStatic { + friend class GCIdMark; + friend class GCIdMarkAndRestore; static uint _next_id; static const uint UNDEFINED = (uint)-1; + static const uint create(); public: - uint id() const { - assert(_id != UNDEFINED, "Using undefined GC ID"); - return _id; - } - bool is_undefined() const; + // Returns the currently active GC id. Asserts that there is an active GC id. + static const uint current(); + // Same as current() but can return undefined() if no GC id is currently active + static const uint current_raw(); + static const uint undefined() { return UNDEFINED; } +}; - static const GCId create(); - static const GCId peek(); - static const GCId undefined(); +class GCIdMark : public StackObj { + uint _gc_id; + public: + GCIdMark(); + GCIdMark(uint gc_id); + ~GCIdMark(); +}; + +class GCIdMarkAndRestore : public StackObj { + uint _gc_id; + uint _previous_gc_id; + public: + GCIdMarkAndRestore(); + GCIdMarkAndRestore(uint gc_id); + ~GCIdMarkAndRestore(); }; #endif // SHARE_VM_GC_SHARED_GCID_HPP diff --git a/hotspot/src/share/vm/gc/shared/gcTrace.cpp b/hotspot/src/share/vm/gc/shared/gcTrace.cpp index e73eb386848..becf4b5b867 100644 --- a/hotspot/src/share/vm/gc/shared/gcTrace.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTrace.cpp @@ -40,31 +40,16 @@ #include "gc/g1/evacuationInfo.hpp" #endif -#define assert_unset_gc_id() assert(_shared_gc_info.gc_id().is_undefined(), "GC already started?") -#define assert_set_gc_id() assert(!_shared_gc_info.gc_id().is_undefined(), "GC not started?") - void GCTracer::report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp) { - assert_unset_gc_id(); - - GCId gc_id = GCId::create(); - _shared_gc_info.set_gc_id(gc_id); _shared_gc_info.set_cause(cause); _shared_gc_info.set_start_timestamp(timestamp); } void GCTracer::report_gc_start(GCCause::Cause cause, const Ticks& timestamp) { - assert_unset_gc_id(); - report_gc_start_impl(cause, timestamp); } -bool GCTracer::has_reported_gc_start() const { - return !_shared_gc_info.gc_id().is_undefined(); -} - void GCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); - _shared_gc_info.set_sum_of_pauses(time_partitions->sum_of_pauses()); _shared_gc_info.set_longest_pause(time_partitions->longest_pause()); _shared_gc_info.set_end_timestamp(timestamp); @@ -74,16 +59,10 @@ void GCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_p } void GCTracer::report_gc_end(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); - report_gc_end_impl(timestamp, time_partitions); - - _shared_gc_info.set_gc_id(GCId::undefined()); } void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) const { - assert_set_gc_id(); - send_reference_stats_event(REF_SOFT, rps.soft_count()); send_reference_stats_event(REF_WEAK, rps.weak_count()); send_reference_stats_event(REF_FINAL, rps.final_count()); @@ -92,14 +71,12 @@ void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) con #if INCLUDE_SERVICES class ObjectCountEventSenderClosure : public KlassInfoClosure { - const GCId _gc_id; const double _size_threshold_percentage; const size_t _total_size_in_words; const Ticks _timestamp; public: - ObjectCountEventSenderClosure(GCId gc_id, size_t total_size_in_words, const Ticks& timestamp) : - _gc_id(gc_id), + ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp) : _size_threshold_percentage(ObjectCountCutOffPercent / 100), _total_size_in_words(total_size_in_words), _timestamp(timestamp) @@ -107,7 +84,7 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { - ObjectCountEventSender::send(entry, _gc_id, _timestamp); + ObjectCountEventSender::send(entry, _timestamp); } } @@ -119,7 +96,6 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { }; void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl) { - assert_set_gc_id(); assert(is_alive_cl != NULL, "Must supply function to check liveness"); if (ObjectCountEventSender::should_send_event()) { @@ -129,7 +105,7 @@ void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl) { if (!cit.allocation_failed()) { HeapInspection hi(false, false, false, NULL); hi.populate_table(&cit, is_alive_cl); - ObjectCountEventSenderClosure event_sender(_shared_gc_info.gc_id(), cit.size_of_instances_in_words(), Ticks::now()); + ObjectCountEventSenderClosure event_sender(cit.size_of_instances_in_words(), Ticks::now()); cit.iterate(&event_sender); } } @@ -137,14 +113,10 @@ void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl) { #endif // INCLUDE_SERVICES void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const { - assert_set_gc_id(); - send_gc_heap_summary_event(when, heap_summary); } void GCTracer::report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& summary) const { - assert_set_gc_id(); - send_meta_space_summary_event(when, summary); send_metaspace_chunk_free_list_summary(when, Metaspace::NonClassType, summary.metaspace_chunk_free_list_summary()); @@ -154,7 +126,6 @@ void GCTracer::report_metaspace_summary(GCWhen::Type when, const MetaspaceSummar } void YoungGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); assert(_tenuring_threshold != UNSET_TENURING_THRESHOLD, "Tenuring threshold has not been reported"); GCTracer::report_gc_end_impl(timestamp, time_partitions); @@ -164,8 +135,6 @@ void YoungGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* t } void YoungGCTracer::report_promotion_failed(const PromotionFailedInfo& pf_info) const { - assert_set_gc_id(); - send_promotion_failed_event(pf_info); } @@ -189,78 +158,56 @@ bool YoungGCTracer::should_report_promotion_outside_plab_event() const { void YoungGCTracer::report_promotion_in_new_plab_event(Klass* klass, size_t obj_size, uint age, bool tenured, size_t plab_size) const { - assert_set_gc_id(); send_promotion_in_new_plab_event(klass, obj_size, age, tenured, plab_size); } void YoungGCTracer::report_promotion_outside_plab_event(Klass* klass, size_t obj_size, uint age, bool tenured) const { - assert_set_gc_id(); send_promotion_outside_plab_event(klass, obj_size, age, tenured); } void OldGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); - GCTracer::report_gc_end_impl(timestamp, time_partitions); send_old_gc_event(); } void ParallelOldTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); - OldGCTracer::report_gc_end_impl(timestamp, time_partitions); send_parallel_old_event(); } void ParallelOldTracer::report_dense_prefix(void* dense_prefix) { - assert_set_gc_id(); - _parallel_old_gc_info.report_dense_prefix(dense_prefix); } void OldGCTracer::report_concurrent_mode_failure() { - assert_set_gc_id(); - send_concurrent_mode_failure_event(); } #if INCLUDE_ALL_GCS -void G1MMUTracer::report_mmu(const GCId& gcId, double timeSlice, double gcTime, double maxTime) { - assert(!gcId.is_undefined(), "Undefined GC id"); - - send_g1_mmu_event(gcId, timeSlice, gcTime, maxTime); +void G1MMUTracer::report_mmu(double timeSlice, double gcTime, double maxTime) { + send_g1_mmu_event(timeSlice, gcTime, maxTime); } void G1NewTracer::report_yc_type(G1YCType type) { - assert_set_gc_id(); - _g1_young_gc_info.set_type(type); } void G1NewTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); - YoungGCTracer::report_gc_end_impl(timestamp, time_partitions); send_g1_young_gc_event(); } void G1NewTracer::report_evacuation_info(EvacuationInfo* info) { - assert_set_gc_id(); - send_evacuation_info_event(info); } void G1NewTracer::report_evacuation_failed(EvacuationFailedInfo& ef_info) { - assert_set_gc_id(); - send_evacuation_failed_event(ef_info); ef_info.reset(); } void G1NewTracer::report_evacuation_statistics(const G1EvacSummary& young_summary, const G1EvacSummary& old_summary) const { - assert_set_gc_id(); - send_young_evacuation_statistics(young_summary); send_old_evacuation_statistics(old_summary); } diff --git a/hotspot/src/share/vm/gc/shared/gcTrace.hpp b/hotspot/src/share/vm/gc/shared/gcTrace.hpp index 0ba5e80daa3..e0db92dbe8f 100644 --- a/hotspot/src/share/vm/gc/shared/gcTrace.hpp +++ b/hotspot/src/share/vm/gc/shared/gcTrace.hpp @@ -52,7 +52,6 @@ class BoolObjectClosure; class SharedGCInfo VALUE_OBJ_CLASS_SPEC { private: - GCId _gc_id; GCName _name; GCCause::Cause _cause; Ticks _start_timestamp; @@ -62,7 +61,6 @@ class SharedGCInfo VALUE_OBJ_CLASS_SPEC { public: SharedGCInfo(GCName name) : - _gc_id(GCId::undefined()), _name(name), _cause(GCCause::_last_gc_cause), _start_timestamp(), @@ -71,9 +69,6 @@ class SharedGCInfo VALUE_OBJ_CLASS_SPEC { _longest_pause() { } - void set_gc_id(GCId gc_id) { _gc_id = gc_id; } - const GCId& gc_id() const { return _gc_id; } - void set_start_timestamp(const Ticks& timestamp) { _start_timestamp = timestamp; } const Ticks start_timestamp() const { return _start_timestamp; } @@ -128,8 +123,6 @@ class GCTracer : public ResourceObj { void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; void report_object_count_after_gc(BoolObjectClosure* object_filter) NOT_SERVICES_RETURN; - bool has_reported_gc_start() const; - const GCId& gc_id() { return _shared_gc_info.gc_id(); } protected: GCTracer(GCName name) : _shared_gc_info(name) {} @@ -242,10 +235,10 @@ class ParNewTracer : public YoungGCTracer { #if INCLUDE_ALL_GCS class G1MMUTracer : public AllStatic { - static void send_g1_mmu_event(const GCId& gcId, double timeSlice, double gcTime, double maxTime); + static void send_g1_mmu_event(double timeSlice, double gcTime, double maxTime); public: - static void report_mmu(const GCId& gcId, double timeSlice, double gcTime, double maxTime); + static void report_mmu(double timeSlice, double gcTime, double maxTime); }; class G1NewTracer : public YoungGCTracer { diff --git a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp index 04cbbfdf34d..da72a232d78 100644 --- a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp @@ -44,7 +44,7 @@ typedef uintptr_t TraceAddress; void GCTracer::send_garbage_collection_event() const { EventGCGarbageCollection event(UNTIMED); if (event.should_commit()) { - event.set_gcId(_shared_gc_info.gc_id().id()); + event.set_gcId(GCId::current()); event.set_name(_shared_gc_info.name()); event.set_cause((u2) _shared_gc_info.cause()); event.set_sumOfPauses(_shared_gc_info.sum_of_pauses()); @@ -58,7 +58,7 @@ void GCTracer::send_garbage_collection_event() const { void GCTracer::send_reference_stats_event(ReferenceType type, size_t count) const { EventGCReferenceStatistics e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_type((u1)type); e.set_count(count); e.commit(); @@ -69,7 +69,7 @@ void GCTracer::send_metaspace_chunk_free_list_summary(GCWhen::Type when, Metaspa const MetaspaceChunkFreeListSummary& summary) const { EventMetaspaceChunkFreeListSummary e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_when(when); e.set_metadataType(mdtype); @@ -92,7 +92,7 @@ void GCTracer::send_metaspace_chunk_free_list_summary(GCWhen::Type when, Metaspa void ParallelOldTracer::send_parallel_old_event() const { EventGCParallelOld e(UNTIMED); if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_densePrefix((TraceAddress)_parallel_old_gc_info.dense_prefix()); e.set_starttime(_shared_gc_info.start_timestamp()); e.set_endtime(_shared_gc_info.end_timestamp()); @@ -103,7 +103,7 @@ void ParallelOldTracer::send_parallel_old_event() const { void YoungGCTracer::send_young_gc_event() const { EventGCYoungGarbageCollection e(UNTIMED); if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_tenuringThreshold(_tenuring_threshold); e.set_starttime(_shared_gc_info.start_timestamp()); e.set_endtime(_shared_gc_info.end_timestamp()); @@ -125,7 +125,7 @@ void YoungGCTracer::send_promotion_in_new_plab_event(Klass* klass, size_t obj_si EventPromoteObjectInNewPLAB event; if (event.should_commit()) { - event.set_gcId(_shared_gc_info.gc_id().id()); + event.set_gcId(GCId::current()); event.set_class(klass); event.set_objectSize(obj_size); event.set_tenured(tenured); @@ -140,7 +140,7 @@ void YoungGCTracer::send_promotion_outside_plab_event(Klass* klass, size_t obj_s EventPromoteObjectOutsidePLAB event; if (event.should_commit()) { - event.set_gcId(_shared_gc_info.gc_id().id()); + event.set_gcId(GCId::current()); event.set_class(klass); event.set_objectSize(obj_size); event.set_tenured(tenured); @@ -152,7 +152,7 @@ void YoungGCTracer::send_promotion_outside_plab_event(Klass* klass, size_t obj_s void OldGCTracer::send_old_gc_event() const { EventGCOldGarbageCollection e(UNTIMED); if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_starttime(_shared_gc_info.start_timestamp()); e.set_endtime(_shared_gc_info.end_timestamp()); e.commit(); @@ -171,7 +171,7 @@ static TraceStructCopyFailed to_trace_struct(const CopyFailedInfo& cf_info) { void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_info) const { EventPromotionFailed e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_data(to_trace_struct(pf_info)); e.set_thread(pf_info.thread()->thread_id()); e.commit(); @@ -182,7 +182,7 @@ void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_in void OldGCTracer::send_concurrent_mode_failure_event() { EventConcurrentModeFailure e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.commit(); } } @@ -191,7 +191,7 @@ void OldGCTracer::send_concurrent_mode_failure_event() { void G1NewTracer::send_g1_young_gc_event() { EventGCG1GarbageCollection e(UNTIMED); if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_type(_g1_young_gc_info.type()); e.set_starttime(_shared_gc_info.start_timestamp()); e.set_endtime(_shared_gc_info.end_timestamp()); @@ -199,10 +199,10 @@ void G1NewTracer::send_g1_young_gc_event() { } } -void G1MMUTracer::send_g1_mmu_event(const GCId& gcId, double timeSlice, double gcTime, double maxTime) { +void G1MMUTracer::send_g1_mmu_event(double timeSlice, double gcTime, double maxTime) { EventGCG1MMU e; if (e.should_commit()) { - e.set_gcId(gcId.id()); + e.set_gcId(GCId::current()); e.set_timeSlice(timeSlice); e.set_gcTime(gcTime); e.set_maxGcTime(maxTime); @@ -213,7 +213,7 @@ void G1MMUTracer::send_g1_mmu_event(const GCId& gcId, double timeSlice, double g void G1NewTracer::send_evacuation_info_event(EvacuationInfo* info) { EventEvacuationInfo e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_cSetRegions(info->collectionset_regions()); e.set_cSetUsedBefore(info->collectionset_used_before()); e.set_cSetUsedAfter(info->collectionset_used_after()); @@ -229,7 +229,7 @@ void G1NewTracer::send_evacuation_info_event(EvacuationInfo* info) { void G1NewTracer::send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const { EventEvacuationFailed e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_data(to_trace_struct(ef_info)); e.commit(); } @@ -253,7 +253,7 @@ static TraceStructG1EvacStats create_g1_evacstats(unsigned gcid, const G1EvacSum void G1NewTracer::send_young_evacuation_statistics(const G1EvacSummary& summary) const { EventGCG1EvacuationYoungStatistics surv_evt; if (surv_evt.should_commit()) { - surv_evt.set_stats(create_g1_evacstats(_shared_gc_info.gc_id().id(), summary)); + surv_evt.set_stats(create_g1_evacstats(GCId::current(), summary)); surv_evt.commit(); } } @@ -261,7 +261,7 @@ void G1NewTracer::send_young_evacuation_statistics(const G1EvacSummary& summary) void G1NewTracer::send_old_evacuation_statistics(const G1EvacSummary& summary) const { EventGCG1EvacuationOldStatistics old_evt; if (old_evt.should_commit()) { - old_evt.set_stats(create_g1_evacstats(_shared_gc_info.gc_id().id(), summary)); + old_evt.set_stats(create_g1_evacstats(GCId::current(), summary)); old_evt.commit(); } } @@ -287,17 +287,16 @@ static TraceStructObjectSpace to_trace_struct(const SpaceSummary& summary) { } class GCHeapSummaryEventSender : public GCHeapSummaryVisitor { - GCId _gc_id; GCWhen::Type _when; public: - GCHeapSummaryEventSender(GCId gc_id, GCWhen::Type when) : _gc_id(gc_id), _when(when) {} + GCHeapSummaryEventSender(GCWhen::Type when) : _when(when) {} void visit(const GCHeapSummary* heap_summary) const { const VirtualSpaceSummary& heap_space = heap_summary->heap(); EventGCHeapSummary e; if (e.should_commit()) { - e.set_gcId(_gc_id.id()); + e.set_gcId(GCId::current()); e.set_when((u1)_when); e.set_heapSpace(to_trace_struct(heap_space)); e.set_heapUsed(heap_summary->used()); @@ -310,7 +309,7 @@ class GCHeapSummaryEventSender : public GCHeapSummaryVisitor { EventG1HeapSummary e; if (e.should_commit()) { - e.set_gcId(_gc_id.id()); + e.set_gcId(GCId::current()); e.set_when((u1)_when); e.set_edenUsedSize(g1_heap_summary->edenUsed()); e.set_edenTotalSize(g1_heap_summary->edenCapacity()); @@ -331,7 +330,7 @@ class GCHeapSummaryEventSender : public GCHeapSummaryVisitor { EventPSHeapSummary e; if (e.should_commit()) { - e.set_gcId(_gc_id.id()); + e.set_gcId(GCId::current()); e.set_when((u1)_when); e.set_oldSpace(to_trace_struct(ps_heap_summary->old())); @@ -346,7 +345,7 @@ class GCHeapSummaryEventSender : public GCHeapSummaryVisitor { }; void GCTracer::send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary& heap_summary) const { - GCHeapSummaryEventSender visitor(_shared_gc_info.gc_id(), when); + GCHeapSummaryEventSender visitor(when); heap_summary.accept(&visitor); } @@ -363,7 +362,7 @@ static TraceStructMetaspaceSizes to_trace_struct(const MetaspaceSizes& sizes) { void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceSummary& meta_space_summary) const { EventMetaspaceSummary e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_when((u1) when); e.set_gcThreshold(meta_space_summary.capacity_until_GC()); e.set_metaspace(to_trace_struct(meta_space_summary.meta_space())); @@ -374,15 +373,12 @@ void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceS } class PhaseSender : public PhaseVisitor { - GCId _gc_id; public: - PhaseSender(GCId gc_id) : _gc_id(gc_id) {} - template void send_phase(PausePhase* pause) { T event(UNTIMED); if (event.should_commit()) { - event.set_gcId(_gc_id.id()); + event.set_gcId(GCId::current()); event.set_name(pause->name()); event.set_starttime(pause->start()); event.set_endtime(pause->end()); @@ -406,7 +402,7 @@ class PhaseSender : public PhaseVisitor { }; void GCTracer::send_phase_events(TimePartitions* time_partitions) const { - PhaseSender phase_reporter(_shared_gc_info.gc_id()); + PhaseSender phase_reporter; TimePartitionPhasesIterator iter(time_partitions); while (iter.has_next()) { diff --git a/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp b/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp index db8755d12aa..dc63333b955 100644 --- a/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp @@ -35,7 +35,7 @@ #include "utilities/ticks.inline.hpp" -GCTraceTime::GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer, GCId gc_id) : +GCTraceTimeImpl::GCTraceTimeImpl(const char* title, bool doit, bool print_cr, GCTimer* timer) : _title(title), _doit(doit), _print_cr(print_cr), _timer(timer), _start_counter() { if (_doit || _timer != NULL) { _start_counter.stamp(); @@ -49,17 +49,13 @@ GCTraceTime::GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* t } if (_doit) { - gclog_or_tty->date_stamp(PrintGCDateStamps); - gclog_or_tty->stamp(PrintGCTimeStamps); - if (PrintGCID) { - gclog_or_tty->print("#%u: ", gc_id.id()); - } + gclog_or_tty->gclog_stamp(); gclog_or_tty->print("[%s", title); gclog_or_tty->flush(); } } -GCTraceTime::~GCTraceTime() { +GCTraceTimeImpl::~GCTraceTimeImpl() { Ticks stop_counter; if (_doit || _timer != NULL) { diff --git a/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp b/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp index 85825a196d9..19fb32f9db6 100644 --- a/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp +++ b/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp @@ -26,12 +26,13 @@ #define SHARE_VM_GC_SHARED_GCTRACETIME_HPP #include "gc/shared/gcTrace.hpp" +#include "memory/allocation.hpp" #include "prims/jni_md.h" #include "utilities/ticks.hpp" class GCTimer; -class GCTraceTime { +class GCTraceTimeImpl VALUE_OBJ_CLASS_SPEC { const char* _title; bool _doit; bool _print_cr; @@ -39,8 +40,16 @@ class GCTraceTime { Ticks _start_counter; public: - GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer, GCId gc_id); - ~GCTraceTime(); + GCTraceTimeImpl(const char* title, bool doit, bool print_cr, GCTimer* timer); + ~GCTraceTimeImpl(); +}; + +class GCTraceTime : public StackObj { + GCTraceTimeImpl _gc_trace_time_impl; + + public: + GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer) : + _gc_trace_time_impl(title, doit, print_cr, timer) {}; }; #endif // SHARE_VM_GC_SHARED_GCTRACETIME_HPP diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp index 6ceed796f6f..c4ab3fe7862 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp @@ -30,6 +30,7 @@ #include "code/icBuffer.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/collectorCounters.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcTraceTime.hpp" @@ -162,8 +163,8 @@ char* GenCollectedHeap::allocate(size_t alignment, "the maximum representable size"); } assert(total_reserved % alignment == 0, - err_msg("Gen size; total_reserved=" SIZE_FORMAT ", alignment=" - SIZE_FORMAT, total_reserved, alignment)); + "Gen size; total_reserved=" SIZE_FORMAT ", alignment=" + SIZE_FORMAT, total_reserved, alignment); *heap_rs = Universe::reserve_heap(total_reserved, alignment); return heap_rs->base(); @@ -315,9 +316,7 @@ void GenCollectedHeap::collect_generation(Generation* gen, bool full, size_t siz bool restore_marks_for_biased_locking) { // Timer for individual generations. Last argument is false: no CR // FIXME: We should try to start the timing earlier to cover more of the GC pause - // The PrintGCDetails logging starts before we have incremented the GC id. We will do that later - // so we can assume here that the next GC id is what we want. - GCTraceTime t1(gen->short_name(), PrintGCDetails, false, NULL, GCId::peek()); + GCTraceTime t1(gen->short_name(), PrintGCDetails, false, NULL); TraceCollectorStats tcs(gen->counters()); TraceMemoryManagerStats tmms(gen->kind(),gc_cause()); @@ -434,6 +433,8 @@ void GenCollectedHeap::do_collection(bool full, return; // GC is disabled (e.g. JNI GetXXXCritical operation) } + GCIdMarkAndRestore gc_id_mark; + const bool do_clear_all_soft_refs = clear_all_soft_refs || collector_policy()->should_clear_all_soft_refs(); @@ -449,9 +450,7 @@ void GenCollectedHeap::do_collection(bool full, bool complete = full && (max_generation == OldGen); const char* gc_cause_prefix = complete ? "Full GC" : "GC"; TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - // The PrintGCDetails logging starts before we have incremented the GC id. We will do that later - // so we can assume here that the next GC id is what we want. - GCTraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, NULL, GCId::peek()); + GCTraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, NULL); gc_prologue(complete); increment_total_collections(complete); @@ -489,6 +488,7 @@ void GenCollectedHeap::do_collection(bool full, bool must_restore_marks_for_biased_locking = false; if (max_generation == OldGen && _old_gen->should_collect(full, size, is_tlab)) { + GCIdMarkAndRestore gc_id_mark; if (!complete) { // The full_collections increment was missed above. increment_total_full_collections(); @@ -823,7 +823,7 @@ bool GenCollectedHeap::create_cms_collector() { assert(_gen_policy->is_concurrent_mark_sweep_policy(), "Unexpected policy type"); CMSCollector* collector = new CMSCollector((ConcurrentMarkSweepGeneration*)_old_gen, - _rem_set->as_CardTableRS(), + _rem_set, _gen_policy->as_concurrent_mark_sweep_policy()); if (collector == NULL || !collector->completed_initialization()) { @@ -891,7 +891,7 @@ void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs, bool GenCollectedHeap::is_in_young(oop p) { bool result = ((HeapWord*)p) < _old_gen->reserved().start(); assert(result == _young_gen->is_in_reserved(p), - err_msg("incorrect test - result=%d, p=" INTPTR_FORMAT, result, p2i((void*)p))); + "incorrect test - result=%d, p=" INTPTR_FORMAT, result, p2i((void*)p)); return result; } @@ -1224,11 +1224,11 @@ class GenGCEpilogueClosure: public GenCollectedHeap::GenClosure { }; void GenCollectedHeap::gc_epilogue(bool full) { -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI assert(DerivedPointerTable::is_empty(), "derived pointer present"); size_t actual_gap = pointer_delta((HeapWord*) (max_uintx-3), *(end_addr())); guarantee(actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps"); -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ resize_all_tlabs(); diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp index ac290c9332d..e7df6cd57dd 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp @@ -64,8 +64,8 @@ private: Generation* _young_gen; Generation* _old_gen; - // The singleton Gen Remembered Set. - GenRemSet* _rem_set; + // The singleton CardTable Remembered Set. + CardTableRS* _rem_set; // The generational collector policy. GenCollectorPolicy* _gen_policy; @@ -361,9 +361,9 @@ public: // collection. virtual bool is_maximal_no_gc() const; - // This function returns the "GenRemSet" object that allows us to scan + // This function returns the CardTableRS object that allows us to scan // generations in a fully generational heap. - GenRemSet* rem_set() { return _rem_set; } + CardTableRS* rem_set() { return _rem_set; } // Convenience function to be used in situations where the heap type can be // asserted to be this type. diff --git a/hotspot/src/share/vm/gc/shared/genOopClosures.hpp b/hotspot/src/share/vm/gc/shared/genOopClosures.hpp index 4cec47220bb..05009cc1372 100644 --- a/hotspot/src/share/vm/gc/shared/genOopClosures.hpp +++ b/hotspot/src/share/vm/gc/shared/genOopClosures.hpp @@ -157,7 +157,7 @@ class FilteringClosure: public ExtendedOopClosure { } public: FilteringClosure(HeapWord* boundary, ExtendedOopClosure* cl) : - ExtendedOopClosure(cl->_ref_processor), _boundary(boundary), + ExtendedOopClosure(cl->ref_processor()), _boundary(boundary), _cl(cl) {} virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); diff --git a/hotspot/src/share/vm/gc/shared/genOopClosures.inline.hpp b/hotspot/src/share/vm/gc/shared/genOopClosures.inline.hpp index e33c94493a1..ea570baa68f 100644 --- a/hotspot/src/share/vm/gc/shared/genOopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc/shared/genOopClosures.inline.hpp @@ -29,7 +29,6 @@ #include "gc/shared/cardTableRS.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/genOopClosures.hpp" -#include "gc/shared/genRemSet.hpp" #include "gc/shared/generation.hpp" #include "gc/shared/space.hpp" @@ -43,8 +42,7 @@ inline void OopsInGenClosure::set_generation(Generation* gen) { _gen_boundary = _gen->reserved().start(); // Barrier set for the heap, must be set after heap is initialized if (_rs == NULL) { - GenRemSet* rs = GenCollectedHeap::heap()->rem_set(); - _rs = (CardTableRS*)rs; + _rs = GenCollectedHeap::heap()->rem_set(); } } diff --git a/hotspot/src/share/vm/gc/shared/genRemSet.cpp b/hotspot/src/share/vm/gc/shared/genRemSet.cpp deleted file mode 100644 index 950072f2efd..00000000000 --- a/hotspot/src/share/vm/gc/shared/genRemSet.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "classfile/classLoaderData.hpp" -#include "gc/shared/cardTableRS.hpp" -#include "gc/shared/genRemSet.hpp" -#include "oops/klass.hpp" - -// This kind of "BarrierSet" allows a "CollectedHeap" to detect and -// enumerate ref fields that have been modified (since the last -// enumeration.) - -uintx GenRemSet::max_alignment_constraint() { - return CardTableRS::ct_max_alignment_constraint(); -} - -class HasAccumulatedModifiedOopsClosure : public KlassClosure { - bool _found; - public: - HasAccumulatedModifiedOopsClosure() : _found(false) {} - void do_klass(Klass* klass) { - if (_found) { - return; - } - - if (klass->has_accumulated_modified_oops()) { - _found = true; - } - } - bool found() { - return _found; - } -}; - -bool KlassRemSet::mod_union_is_clear() { - HasAccumulatedModifiedOopsClosure closure; - ClassLoaderDataGraph::classes_do(&closure); - - return !closure.found(); -} - - -class ClearKlassModUnionClosure : public KlassClosure { - public: - void do_klass(Klass* klass) { - if (klass->has_accumulated_modified_oops()) { - klass->clear_accumulated_modified_oops(); - } - } -}; - -void KlassRemSet::clear_mod_union() { - ClearKlassModUnionClosure closure; - ClassLoaderDataGraph::classes_do(&closure); -} diff --git a/hotspot/src/share/vm/gc/shared/genRemSet.hpp b/hotspot/src/share/vm/gc/shared/genRemSet.hpp deleted file mode 100644 index 58398c9c333..00000000000 --- a/hotspot/src/share/vm/gc/shared/genRemSet.hpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_GC_SHARED_GENREMSET_HPP -#define SHARE_VM_GC_SHARED_GENREMSET_HPP - -#include "oops/oop.hpp" - -// A GenRemSet provides ways of iterating over pointers across generations. -// (This is especially useful for older-to-younger.) - -class Generation; -class BarrierSet; -class OopsInGenClosure; -class CardTableRS; - -// Helper to remember modified oops in all klasses. -class KlassRemSet { - bool _accumulate_modified_oops; - public: - KlassRemSet() : _accumulate_modified_oops(false) {} - void set_accumulate_modified_oops(bool value) { _accumulate_modified_oops = value; } - bool accumulate_modified_oops() { return _accumulate_modified_oops; } - bool mod_union_is_clear(); - void clear_mod_union(); -}; - -class GenRemSet: public CHeapObj { - friend class Generation; - - BarrierSet* _bs; - KlassRemSet _klass_rem_set; - -public: - GenRemSet(BarrierSet * bs) : _bs(bs) {} - GenRemSet() : _bs(NULL) {} - - // These are for dynamic downcasts. Unfortunately that it names the - // possible subtypes (but not that they are subtypes!) Return NULL if - // the cast is invalid. - virtual CardTableRS* as_CardTableRS() { return NULL; } - - // Return the barrier set associated with "this." - BarrierSet* bs() { return _bs; } - - // Set the barrier set. - void set_bs(BarrierSet* bs) { _bs = bs; } - - KlassRemSet* klass_rem_set() { return &_klass_rem_set; } - - // Do any (sequential) processing necessary to prepare for (possibly - // "parallel", if that arg is true) calls to younger_refs_iterate. - virtual void prepare_for_younger_refs_iterate(bool parallel) = 0; - - // Apply the "do_oop" method of "blk" to (exactly) all oop locations - // 1) that are in objects allocated in "g" at the time of the last call - // to "save_Marks", and - // 2) that point to objects in younger generations. - virtual void younger_refs_iterate(Generation* g, OopsInGenClosure* blk, uint n_threads) = 0; - - virtual void younger_refs_in_space_iterate(Space* sp, - OopsInGenClosure* cl, - uint n_threads) = 0; - - // This method is used to notify the remembered set that "new_val" has - // been written into "field" by the garbage collector. - void write_ref_field_gc(void* field, oop new_val); -protected: - virtual void write_ref_field_gc_work(void* field, oop new_val) = 0; -public: - - // A version of the above suitable for use by parallel collectors. - virtual void write_ref_field_gc_par(void* field, oop new_val) = 0; - - // Resize one of the regions covered by the remembered set. - virtual void resize_covered_region(MemRegion new_region) = 0; - - // If the rem set imposes any alignment restrictions on boundaries - // within the heap, this function tells whether they are met. - virtual bool is_aligned(HeapWord* addr) = 0; - - // Returns any alignment constraint that the remembered set imposes upon the - // heap. - static uintx max_alignment_constraint(); - - virtual void verify() = 0; - - // If appropriate, print some information about the remset on "tty". - virtual void print() {} - - // Informs the RS that the given memregion contains no references to - // the young generation. - virtual void clear(MemRegion mr) = 0; - - // Informs the RS that there are no references to the young generation - // from old_gen. - virtual void clear_into_younger(Generation* old_gen) = 0; - - // Informs the RS that refs in the given "mr" may have changed - // arbitrarily, and therefore may contain old-to-young pointers. - // If "whole heap" is true, then this invalidation is part of an - // invalidation of the whole heap, which an implementation might - // handle differently than that of a sub-part of the heap. - virtual void invalidate(MemRegion mr, bool whole_heap = false) = 0; - - // Informs the RS that refs in this generation - // may have changed arbitrarily, and therefore may contain - // old-to-young pointers in arbitrary locations. - virtual void invalidate_or_clear(Generation* old_gen) = 0; -}; - -#endif // SHARE_VM_GC_SHARED_GENREMSET_HPP diff --git a/hotspot/src/share/vm/gc/shared/generation.cpp b/hotspot/src/share/vm/gc/shared/generation.cpp index 78db0befeff..c18734ec77d 100644 --- a/hotspot/src/share/vm/gc/shared/generation.cpp +++ b/hotspot/src/share/vm/gc/shared/generation.cpp @@ -293,7 +293,7 @@ void Generation::oop_iterate(ExtendedOopClosure* cl) { void Generation::younger_refs_in_space_iterate(Space* sp, OopsInGenClosure* cl, uint n_threads) { - GenRemSet* rs = GenCollectedHeap::heap()->rem_set(); + CardTableRS* rs = GenCollectedHeap::heap()->rem_set(); rs->younger_refs_in_space_iterate(sp, cl, n_threads); } diff --git a/hotspot/src/share/vm/gc/shared/generation.hpp b/hotspot/src/share/vm/gc/shared/generation.hpp index 713585710af..8a21dbb2977 100644 --- a/hotspot/src/share/vm/gc/shared/generation.hpp +++ b/hotspot/src/share/vm/gc/shared/generation.hpp @@ -27,7 +27,6 @@ #include "gc/shared/collectorCounters.hpp" #include "gc/shared/referenceProcessor.hpp" -#include "gc/shared/watermark.hpp" #include "memory/allocation.hpp" #include "memory/memRegion.hpp" #include "memory/universe.hpp" @@ -67,7 +66,6 @@ class OopClosure; class ScanClosure; class FastScanClosure; class GenCollectedHeap; -class GenRemSet; class GCStats; // A "ScratchBlock" represents a block of memory in one generation usable by diff --git a/hotspot/src/share/vm/gc/shared/generationSpec.cpp b/hotspot/src/share/vm/gc/shared/generationSpec.cpp index 8f80bae7115..a243d674c58 100644 --- a/hotspot/src/share/vm/gc/shared/generationSpec.cpp +++ b/hotspot/src/share/vm/gc/shared/generationSpec.cpp @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "gc/serial/defNewGeneration.hpp" #include "gc/serial/tenuredGeneration.hpp" -#include "gc/shared/genRemSet.hpp" +#include "gc/shared/cardTableRS.hpp" #include "gc/shared/generationSpec.hpp" #include "memory/binaryTreeDictionary.hpp" #include "memory/filemap.hpp" @@ -36,7 +36,7 @@ #include "gc/cms/parNewGeneration.hpp" #endif // INCLUDE_ALL_GCS -Generation* GenerationSpec::init(ReservedSpace rs, GenRemSet* remset) { +Generation* GenerationSpec::init(ReservedSpace rs, CardTableRS* remset) { switch (name()) { case Generation::DefNew: return new DefNewGeneration(rs, init_size()); @@ -50,8 +50,7 @@ Generation* GenerationSpec::init(ReservedSpace rs, GenRemSet* remset) { case Generation::ConcurrentMarkSweep: { assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set"); - CardTableRS* ctrs = remset->as_CardTableRS(); - if (ctrs == NULL) { + if (remset == NULL) { vm_exit_during_initialization("Rem set incompatibility."); } // Otherwise @@ -60,7 +59,7 @@ Generation* GenerationSpec::init(ReservedSpace rs, GenRemSet* remset) { ConcurrentMarkSweepGeneration* g = NULL; g = new ConcurrentMarkSweepGeneration(rs, - init_size(), ctrs, UseCMSAdaptiveFreeLists, + init_size(), remset, UseCMSAdaptiveFreeLists, (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice); g->initialize_performance_counters(); diff --git a/hotspot/src/share/vm/gc/shared/generationSpec.hpp b/hotspot/src/share/vm/gc/shared/generationSpec.hpp index b1448b8c678..500c5c81804 100644 --- a/hotspot/src/share/vm/gc/shared/generationSpec.hpp +++ b/hotspot/src/share/vm/gc/shared/generationSpec.hpp @@ -45,7 +45,7 @@ public: _max_size(align_size_up(max_size, alignment)) { } - Generation* init(ReservedSpace rs, GenRemSet* remset); + Generation* init(ReservedSpace rs, CardTableRS* remset); // Accessors Generation::Name name() const { return _name; } diff --git a/hotspot/src/share/vm/gc/shared/objectCountEventSender.cpp b/hotspot/src/share/vm/gc/shared/objectCountEventSender.cpp index 8b809ae1545..4146a809d3b 100644 --- a/hotspot/src/share/vm/gc/shared/objectCountEventSender.cpp +++ b/hotspot/src/share/vm/gc/shared/objectCountEventSender.cpp @@ -33,13 +33,13 @@ #include "utilities/ticks.hpp" #if INCLUDE_SERVICES -void ObjectCountEventSender::send(const KlassInfoEntry* entry, GCId gc_id, const Ticks& timestamp) { +void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& timestamp) { #if INCLUDE_TRACE assert(Tracing::is_event_enabled(EventObjectCountAfterGC::eventId), "Only call this method if the event is enabled"); EventObjectCountAfterGC event(UNTIMED); - event.set_gcId(gc_id.id()); + event.set_gcId(GCId::current()); event.set_class(entry->klass()); event.set_count(entry->count()); event.set_totalSize(entry->words() * BytesPerWord); diff --git a/hotspot/src/share/vm/gc/shared/objectCountEventSender.hpp b/hotspot/src/share/vm/gc/shared/objectCountEventSender.hpp index 201d5ddfc0e..c96e7790d2d 100644 --- a/hotspot/src/share/vm/gc/shared/objectCountEventSender.hpp +++ b/hotspot/src/share/vm/gc/shared/objectCountEventSender.hpp @@ -36,7 +36,7 @@ class Ticks; class ObjectCountEventSender : public AllStatic { public: - static void send(const KlassInfoEntry* entry, GCId gc_id, const Ticks& timestamp); + static void send(const KlassInfoEntry* entry, const Ticks& timestamp); static bool should_send_event(); }; diff --git a/hotspot/src/share/vm/gc/shared/plab.cpp b/hotspot/src/share/vm/gc/shared/plab.cpp index d01869a8280..ba8052d8d28 100644 --- a/hotspot/src/share/vm/gc/shared/plab.cpp +++ b/hotspot/src/share/vm/gc/shared/plab.cpp @@ -45,8 +45,8 @@ PLAB::PLAB(size_t desired_plab_sz_) : // ArrayOopDesc::header_size depends on command line initialization. AlignmentReserve = oopDesc::header_size() > MinObjAlignment ? align_object_size(arrayOopDesc::header_size(T_INT)) : 0; assert(min_size() > AlignmentReserve, - err_msg("Minimum PLAB size " SIZE_FORMAT " must be larger than alignment reserve " SIZE_FORMAT " " - "to be able to contain objects", min_size(), AlignmentReserve)); + "Minimum PLAB size " SIZE_FORMAT " must be larger than alignment reserve " SIZE_FORMAT " " + "to be able to contain objects", min_size(), AlignmentReserve); } // If the minimum object size is greater than MinObjAlignment, we can @@ -125,12 +125,12 @@ void PLABStats::adjust_desired_plab_sz() { if (_allocated == 0) { assert(_unused == 0, - err_msg("Inconsistency in PLAB stats: " - "_allocated: " SIZE_FORMAT ", " - "_wasted: " SIZE_FORMAT ", " - "_unused: " SIZE_FORMAT ", " - "_undo_wasted: " SIZE_FORMAT, - _allocated, _wasted, _unused, _undo_wasted)); + "Inconsistency in PLAB stats: " + "_allocated: " SIZE_FORMAT ", " + "_wasted: " SIZE_FORMAT ", " + "_unused: " SIZE_FORMAT ", " + "_undo_wasted: " SIZE_FORMAT, + _allocated, _wasted, _unused, _undo_wasted); _allocated = 1; } diff --git a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp index 0eecaf10469..ba2cd40f35b 100644 --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp @@ -31,6 +31,7 @@ #include "gc/shared/gcTraceTime.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" +#include "memory/allocation.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.hpp" @@ -54,8 +55,11 @@ void ReferenceProcessor::init_statics() { java_lang_ref_SoftReference::set_clock(_soft_ref_timestamp_clock); _always_clear_soft_ref_policy = new AlwaysClearPolicy(); - _default_soft_ref_policy = new COMPILER2_PRESENT(LRUMaxHeapPolicy()) - NOT_COMPILER2(LRUCurrentHeapPolicy()); +#if defined(COMPILER2) || INCLUDE_JVMCI + _default_soft_ref_policy = new LRUMaxHeapPolicy(); +#else + _default_soft_ref_policy = new LRUCurrentHeapPolicy(); +#endif if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) { vm_exit_during_initialization("Could not allocate reference policy object"); } @@ -182,13 +186,27 @@ size_t ReferenceProcessor::total_count(DiscoveredList lists[]) { return total; } +static void log_ref_count(size_t count, bool doit) { + if (doit) { + gclog_or_tty->print(", " SIZE_FORMAT " refs", count); + } +} + +class GCRefTraceTime : public StackObj { + GCTraceTimeImpl _gc_trace_time; + public: + GCRefTraceTime(const char* title, bool doit, GCTimer* timer, size_t count) : + _gc_trace_time(title, doit, false, timer) { + log_ref_count(count, doit); + } +}; + ReferenceProcessorStats ReferenceProcessor::process_discovered_references( BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, AbstractRefProcTaskExecutor* task_executor, - GCTimer* gc_timer, - GCId gc_id) { + GCTimer* gc_timer) { assert(!enqueuing_is_done(), "If here enqueuing should not be complete"); // Stop treating discovered references specially. @@ -206,48 +224,48 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references( bool trace_time = PrintGCDetails && PrintReferenceGC; + // Include cleaners in phantom statistics. We expect Cleaner + // references to be temporary, and don't want to deal with + // possible incompatibilities arising from making it more visible. + ReferenceProcessorStats stats( + total_count(_discoveredSoftRefs), + total_count(_discoveredWeakRefs), + total_count(_discoveredFinalRefs), + total_count(_discoveredPhantomRefs) + total_count(_discoveredCleanerRefs)); + // Soft references - size_t soft_count = 0; { - GCTraceTime tt("SoftReference", trace_time, false, gc_timer, gc_id); - soft_count = - process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, - is_alive, keep_alive, complete_gc, task_executor); + GCRefTraceTime tt("SoftReference", trace_time, gc_timer, stats.soft_count()); + process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, + is_alive, keep_alive, complete_gc, task_executor); } update_soft_ref_master_clock(); // Weak references - size_t weak_count = 0; { - GCTraceTime tt("WeakReference", trace_time, false, gc_timer, gc_id); - weak_count = - process_discovered_reflist(_discoveredWeakRefs, NULL, true, - is_alive, keep_alive, complete_gc, task_executor); + GCRefTraceTime tt("WeakReference", trace_time, gc_timer, stats.weak_count()); + process_discovered_reflist(_discoveredWeakRefs, NULL, true, + is_alive, keep_alive, complete_gc, task_executor); } // Final references - size_t final_count = 0; { - GCTraceTime tt("FinalReference", trace_time, false, gc_timer, gc_id); - final_count = - process_discovered_reflist(_discoveredFinalRefs, NULL, false, - is_alive, keep_alive, complete_gc, task_executor); + GCRefTraceTime tt("FinalReference", trace_time, gc_timer, stats.final_count()); + process_discovered_reflist(_discoveredFinalRefs, NULL, false, + is_alive, keep_alive, complete_gc, task_executor); } // Phantom references - size_t phantom_count = 0; { - GCTraceTime tt("PhantomReference", trace_time, false, gc_timer, gc_id); - phantom_count = - process_discovered_reflist(_discoveredPhantomRefs, NULL, false, - is_alive, keep_alive, complete_gc, task_executor); + GCRefTraceTime tt("PhantomReference", trace_time, gc_timer, stats.phantom_count()); + process_discovered_reflist(_discoveredPhantomRefs, NULL, false, + is_alive, keep_alive, complete_gc, task_executor); - // Process cleaners, but include them in phantom statistics. We expect + // Process cleaners, but include them in phantom timing. We expect // Cleaner references to be temporary, and don't want to deal with // possible incompatibilities arising from making it more visible. - phantom_count += - process_discovered_reflist(_discoveredCleanerRefs, NULL, true, + process_discovered_reflist(_discoveredCleanerRefs, NULL, true, is_alive, keep_alive, complete_gc, task_executor); } @@ -257,14 +275,15 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references( // thus use JNI weak references to circumvent the phantom references and // resurrect a "post-mortem" object. { - GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer, gc_id); + GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer); + NOT_PRODUCT(log_ref_count(count_jni_refs(), trace_time);) if (task_executor != NULL) { task_executor->set_single_threaded_mode(); } process_phaseJNI(is_alive, keep_alive, complete_gc); } - return ReferenceProcessorStats(soft_count, weak_count, final_count, phantom_count); + return stats; } #ifndef PRODUCT @@ -294,12 +313,6 @@ uint ReferenceProcessor::count_jni_refs() { void ReferenceProcessor::process_phaseJNI(BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc) { -#ifndef PRODUCT - if (PrintGCDetails && PrintReferenceGC) { - unsigned int count = count_jni_refs(); - gclog_or_tty->print(", %u refs", count); - } -#endif JNIHandles::weak_oops_do(is_alive, keep_alive); complete_gc->do_void(); } @@ -437,7 +450,7 @@ void DiscoveredListIterator::load_ptrs(DEBUG_ONLY(bool allow_null_referent)) { _discovered_addr = java_lang_ref_Reference::discovered_addr(_ref); oop discovered = java_lang_ref_Reference::discovered(_ref); assert(_discovered_addr && discovered->is_oop_or_null(), - err_msg("Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered))); + "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered)); _next = discovered; _referent_addr = java_lang_ref_Reference::referent_addr(_ref); _referent = java_lang_ref_Reference::referent(_ref); @@ -446,9 +459,9 @@ void DiscoveredListIterator::load_ptrs(DEBUG_ONLY(bool allow_null_referent)) { assert(allow_null_referent ? _referent->is_oop_or_null() : _referent->is_oop(), - err_msg("Expected an oop%s for referent field at " PTR_FORMAT, - (allow_null_referent ? " or NULL" : ""), - p2i(_referent))); + "Expected an oop%s for referent field at " PTR_FORMAT, + (allow_null_referent ? " or NULL" : ""), + p2i(_referent)); } void DiscoveredListIterator::remove() { @@ -578,7 +591,7 @@ ReferenceProcessor::pp2_work_concurrent_discovery(DiscoveredList& refs_list, oop next = java_lang_ref_Reference::next(iter.obj()); if ((iter.referent() == NULL || iter.is_referent_alive() || next != NULL)) { - assert(next->is_oop_or_null(), err_msg("Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next))); + assert(next->is_oop_or_null(), "Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next)); // Remove Reference object from list iter.remove(); // Trace the cohorts @@ -826,8 +839,7 @@ void ReferenceProcessor::balance_all_queues() { balance_queues(_discoveredCleanerRefs); } -size_t -ReferenceProcessor::process_discovered_reflist( +void ReferenceProcessor::process_discovered_reflist( DiscoveredList refs_lists[], ReferencePolicy* policy, bool clear_referent, @@ -850,12 +862,6 @@ ReferenceProcessor::process_discovered_reflist( balance_queues(refs_lists); } - size_t total_list_count = total_count(refs_lists); - - if (PrintReferenceGC && PrintGCDetails) { - gclog_or_tty->print(", " SIZE_FORMAT " refs", total_list_count); - } - // Phase 1 (soft refs only): // . Traverse the list and remove any SoftReferences whose // referents are not alive, but that should be kept alive for @@ -898,8 +904,6 @@ ReferenceProcessor::process_discovered_reflist( is_alive, keep_alive, complete_gc); } } - - return total_list_count; } inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) { @@ -993,9 +997,9 @@ void ReferenceProcessor::verify_referent(oop obj) { bool da = discovery_is_atomic(); oop referent = java_lang_ref_Reference::referent(obj); assert(da ? referent->is_oop() : referent->is_oop_or_null(), - err_msg("Bad referent " INTPTR_FORMAT " found in Reference " - INTPTR_FORMAT " during %satomic discovery ", - p2i(referent), p2i(obj), da ? "" : "non-")); + "Bad referent " INTPTR_FORMAT " found in Reference " + INTPTR_FORMAT " during %satomic discovery ", + p2i(referent), p2i(obj), da ? "" : "non-"); } #endif @@ -1070,7 +1074,7 @@ bool ReferenceProcessor::discover_reference(oop obj, ReferenceType rt) { HeapWord* const discovered_addr = java_lang_ref_Reference::discovered_addr(obj); const oop discovered = java_lang_ref_Reference::discovered(obj); - assert(discovered->is_oop_or_null(), err_msg("Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered))); + assert(discovered->is_oop_or_null(), "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered)); if (discovered != NULL) { // The reference has already been discovered... if (TraceReferenceGC) { @@ -1150,13 +1154,12 @@ void ReferenceProcessor::preclean_discovered_references( OopClosure* keep_alive, VoidClosure* complete_gc, YieldClosure* yield, - GCTimer* gc_timer, - GCId gc_id) { + GCTimer* gc_timer) { // Soft references { GCTraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer, gc_id); + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1169,7 +1172,7 @@ void ReferenceProcessor::preclean_discovered_references( // Weak references { GCTraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer, gc_id); + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1182,7 +1185,7 @@ void ReferenceProcessor::preclean_discovered_references( // Final references { GCTraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer, gc_id); + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1195,7 +1198,7 @@ void ReferenceProcessor::preclean_discovered_references( // Phantom references { GCTraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer, gc_id); + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; diff --git a/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp b/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp index add86a1e928..20c405de7e0 100644 --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp @@ -263,13 +263,13 @@ class ReferenceProcessor : public CHeapObj { } // Process references with a certain reachability level. - size_t process_discovered_reflist(DiscoveredList refs_lists[], - ReferencePolicy* policy, - bool clear_referent, - BoolObjectClosure* is_alive, - OopClosure* keep_alive, - VoidClosure* complete_gc, - AbstractRefProcTaskExecutor* task_executor); + void process_discovered_reflist(DiscoveredList refs_lists[], + ReferencePolicy* policy, + bool clear_referent, + BoolObjectClosure* is_alive, + OopClosure* keep_alive, + VoidClosure* complete_gc, + AbstractRefProcTaskExecutor* task_executor); void process_phaseJNI(BoolObjectClosure* is_alive, OopClosure* keep_alive, @@ -331,8 +331,7 @@ class ReferenceProcessor : public CHeapObj { OopClosure* keep_alive, VoidClosure* complete_gc, YieldClosure* yield, - GCTimer* gc_timer, - GCId gc_id); + GCTimer* gc_timer); // Returns the name of the discovered reference list // occupying the i / _num_q slot. @@ -441,8 +440,7 @@ class ReferenceProcessor : public CHeapObj { OopClosure* keep_alive, VoidClosure* complete_gc, AbstractRefProcTaskExecutor* task_executor, - GCTimer *gc_timer, - GCId gc_id); + GCTimer *gc_timer); // Enqueue references at end of GC (called by the garbage collector) bool enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor = NULL); diff --git a/hotspot/src/share/vm/gc/shared/space.cpp b/hotspot/src/share/vm/gc/shared/space.cpp index f8585043e66..44d0583b8f8 100644 --- a/hotspot/src/share/vm/gc/shared/space.cpp +++ b/hotspot/src/share/vm/gc/shared/space.cpp @@ -529,8 +529,7 @@ void ContiguousSpace::oop_iterate(ExtendedOopClosure* blk) { void ContiguousSpace::object_iterate(ObjectClosure* blk) { if (is_empty()) return; - WaterMark bm = bottom_mark(); - object_iterate_from(bm, blk); + object_iterate_from(bottom(), blk); } // For a ContiguousSpace object_iterate() and safe_object_iterate() @@ -539,12 +538,10 @@ void ContiguousSpace::safe_object_iterate(ObjectClosure* blk) { object_iterate(blk); } -void ContiguousSpace::object_iterate_from(WaterMark mark, ObjectClosure* blk) { - assert(mark.space() == this, "Mark does not match space"); - HeapWord* p = mark.point(); - while (p < top()) { - blk->do_object(oop(p)); - p += oop(p)->size(); +void ContiguousSpace::object_iterate_from(HeapWord* mark, ObjectClosure* blk) { + while (mark < top()) { + blk->do_object(oop(mark)); + mark += oop(mark)->size(); } } @@ -592,8 +589,8 @@ ALL_SINCE_SAVE_MARKS_CLOSURES(ContigSpace_OOP_SINCE_SAVE_MARKS_DEFN) // Very general, slow implementation. HeapWord* ContiguousSpace::block_start_const(const void* p) const { assert(MemRegion(bottom(), end()).contains(p), - err_msg("p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(p), p2i(bottom()), p2i(end()))); + "p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(p), p2i(bottom()), p2i(end())); if (p >= top()) { return top(); } else { @@ -603,24 +600,23 @@ HeapWord* ContiguousSpace::block_start_const(const void* p) const { last = cur; cur += oop(cur)->size(); } - assert(oop(last)->is_oop(), - err_msg(PTR_FORMAT " should be an object start", p2i(last))); + assert(oop(last)->is_oop(), PTR_FORMAT " should be an object start", p2i(last)); return last; } } size_t ContiguousSpace::block_size(const HeapWord* p) const { assert(MemRegion(bottom(), end()).contains(p), - err_msg("p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(p), p2i(bottom()), p2i(end()))); + "p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(p), p2i(bottom()), p2i(end())); HeapWord* current_top = top(); assert(p <= current_top, - err_msg("p > current top - p: " PTR_FORMAT ", current top: " PTR_FORMAT, - p2i(p), p2i(current_top))); + "p > current top - p: " PTR_FORMAT ", current top: " PTR_FORMAT, + p2i(p), p2i(current_top)); assert(p == current_top || oop(p)->is_oop(), - err_msg("p (" PTR_FORMAT ") is not a block start - " - "current_top: " PTR_FORMAT ", is_oop: %s", - p2i(p), p2i(current_top), BOOL_TO_STR(oop(p)->is_oop()))); + "p (" PTR_FORMAT ") is not a block start - " + "current_top: " PTR_FORMAT ", is_oop: %s", + p2i(p), p2i(current_top), BOOL_TO_STR(oop(p)->is_oop())); if (p < current_top) { return oop(p)->size(); } else { diff --git a/hotspot/src/share/vm/gc/shared/space.hpp b/hotspot/src/share/vm/gc/shared/space.hpp index 1665380969a..6b74b872619 100644 --- a/hotspot/src/share/vm/gc/shared/space.hpp +++ b/hotspot/src/share/vm/gc/shared/space.hpp @@ -27,7 +27,6 @@ #include "gc/shared/blockOffsetTable.hpp" #include "gc/shared/cardTableModRefBS.hpp" -#include "gc/shared/watermark.hpp" #include "gc/shared/workgroup.hpp" #include "memory/allocation.hpp" #include "memory/iterator.hpp" @@ -48,7 +47,6 @@ class BlockOffsetArrayContigSpace; class Generation; class CompactibleSpace; class BlockOffsetTable; -class GenRemSet; class CardTableRS; class DirtyCardToOopClosure; @@ -541,9 +539,6 @@ class ContiguousSpace: public CompactibleSpace { void set_saved_mark() { _saved_mark_word = top(); } void reset_saved_mark() { _saved_mark_word = bottom(); } - WaterMark bottom_mark() { return WaterMark(this, bottom()); } - WaterMark top_mark() { return WaterMark(this, top()); } - WaterMark saved_mark() { return WaterMark(this, saved_mark_word()); } bool saved_mark_at_top() const { return saved_mark_word() == top(); } // In debug mode mangle (write it with a particular bit @@ -649,7 +644,7 @@ class ContiguousSpace: public CompactibleSpace { // Same as object_iterate, but starting from "mark", which is required // to denote the start of an object. Objects allocated by // applications of the closure *are* included in the iteration. - virtual void object_iterate_from(WaterMark mark, ObjectClosure* blk); + virtual void object_iterate_from(HeapWord* mark, ObjectClosure* blk); // Very inefficient implementation. virtual HeapWord* block_start_const(const void* p) const; diff --git a/hotspot/src/share/vm/gc/shared/taskqueue.cpp b/hotspot/src/share/vm/gc/shared/taskqueue.cpp index ffb31025607..cc21a1e731f 100644 --- a/hotspot/src/share/vm/gc/shared/taskqueue.cpp +++ b/hotspot/src/share/vm/gc/shared/taskqueue.cpp @@ -92,20 +92,20 @@ void TaskQueueStats::print(outputStream* stream, unsigned int width) const void TaskQueueStats::verify() const { assert(get(push) == get(pop) + get(steal), - err_msg("push=" SIZE_FORMAT " pop=" SIZE_FORMAT " steal=" SIZE_FORMAT, - get(push), get(pop), get(steal))); + "push=" SIZE_FORMAT " pop=" SIZE_FORMAT " steal=" SIZE_FORMAT, + get(push), get(pop), get(steal)); assert(get(pop_slow) <= get(pop), - err_msg("pop_slow=" SIZE_FORMAT " pop=" SIZE_FORMAT, - get(pop_slow), get(pop))); + "pop_slow=" SIZE_FORMAT " pop=" SIZE_FORMAT, + get(pop_slow), get(pop)); assert(get(steal) <= get(steal_attempt), - err_msg("steal=" SIZE_FORMAT " steal_attempt=" SIZE_FORMAT, - get(steal), get(steal_attempt))); + "steal=" SIZE_FORMAT " steal_attempt=" SIZE_FORMAT, + get(steal), get(steal_attempt)); assert(get(overflow) == 0 || get(push) != 0, - err_msg("overflow=" SIZE_FORMAT " push=" SIZE_FORMAT, - get(overflow), get(push))); + "overflow=" SIZE_FORMAT " push=" SIZE_FORMAT, + get(overflow), get(push)); assert(get(overflow_max_len) == 0 || get(overflow) != 0, - err_msg("overflow_max_len=" SIZE_FORMAT " overflow=" SIZE_FORMAT, - get(overflow_max_len), get(overflow))); + "overflow_max_len=" SIZE_FORMAT " overflow=" SIZE_FORMAT, + get(overflow_max_len), get(overflow)); } #endif // ASSERT #endif // TASKQUEUE_STATS diff --git a/hotspot/src/share/vm/gc/shared/workgroup.cpp b/hotspot/src/share/vm/gc/shared/workgroup.cpp index 313b527a180..24295694d09 100644 --- a/hotspot/src/share/vm/gc/shared/workgroup.cpp +++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/workgroup.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" @@ -140,7 +141,7 @@ public: _end_semaphore->wait(); // No workers are allowed to read the state variables after the coordinator has been signaled. - assert(_not_finished == 0, err_msg("%d not finished workers?", _not_finished)); + assert(_not_finished == 0, "%d not finished workers?", _not_finished); _task = NULL; _started = 0; @@ -328,6 +329,7 @@ void GangWorker::print_task_done(WorkData data) { void GangWorker::run_task(WorkData data) { print_task_started(data); + GCIdMark gc_id_mark(data._task->gc_id()); data._task->work(data._worker_id); print_task_done(data); diff --git a/hotspot/src/share/vm/gc/shared/workgroup.hpp b/hotspot/src/share/vm/gc/shared/workgroup.hpp index d276d5d0476..fa72ad440ed 100644 --- a/hotspot/src/share/vm/gc/shared/workgroup.hpp +++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "runtime/globals.hpp" #include "runtime/thread.hpp" +#include "gc/shared/gcId.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -54,9 +55,13 @@ class WorkGang; // You subclass this to supply your own work() method class AbstractGangTask VALUE_OBJ_CLASS_SPEC { const char* _name; + const uint _gc_id; public: - AbstractGangTask(const char* name) : _name(name) {} + AbstractGangTask(const char* name) : + _name(name), + _gc_id(GCId::current_raw()) + {} // The abstract work method. // The argument tells you which member of the gang you are. @@ -64,6 +69,7 @@ class AbstractGangTask VALUE_OBJ_CLASS_SPEC { // Debugging accessor for the name. const char* name() const { return _name; } + const uint gc_id() const { return _gc_id; } }; struct WorkData { @@ -132,7 +138,7 @@ class AbstractWorkGang : public CHeapObj { virtual uint active_workers() const { assert(_active_workers <= _total_workers, - err_msg("_active_workers: %u > _total_workers: %u", _active_workers, _total_workers)); + "_active_workers: %u > _total_workers: %u", _active_workers, _total_workers); assert(UseDynamicNumberOfGCThreads || _active_workers == _total_workers, "Unless dynamic should use total workers"); return _active_workers; diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp index 8dabe185812..4acda1233fa 100644 --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp @@ -90,6 +90,8 @@ class AbstractInterpreter: AllStatic { java_util_zip_CRC32_update, // implementation of java.util.zip.CRC32.update() java_util_zip_CRC32_updateBytes, // implementation of java.util.zip.CRC32.updateBytes() java_util_zip_CRC32_updateByteBuffer, // implementation of java.util.zip.CRC32.updateByteBuffer() + java_util_zip_CRC32C_updateBytes, // implementation of java.util.zip.CRC32C.updateBytes(crc, b[], off, end) + java_util_zip_CRC32C_updateDirectByteBuffer, // implementation of java.util.zip.CRC32C.updateDirectByteBuffer(crc, address, off, end) java_lang_Float_intBitsToFloat, // implementation of java.lang.Float.intBitsToFloat() java_lang_Float_floatToRawIntBits, // implementation of java.lang.Float.floatToRawIntBits() java_lang_Double_longBitsToDouble, // implementation of java.lang.Double.longBitsToDouble() diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 7a9325c54ec..a9252c2bfa7 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -2734,8 +2734,8 @@ run: } DEFAULT: - fatal(err_msg("Unimplemented opcode %d = %s", opcode, - Bytecodes::name((Bytecodes::Code)opcode))); + fatal("Unimplemented opcode %d = %s", opcode, + Bytecodes::name((Bytecodes::Code)opcode)); goto finish; } /* switch(opc) */ @@ -2791,7 +2791,7 @@ run: (int)continuation_bci, p2i(THREAD)); } // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort(except_oop)); + Exceptions::debug_check_abort(except_oop); // Update profiling data. BI_PROFILE_ALIGN_TO_CURRENT_BCI(); @@ -2807,7 +2807,8 @@ run: p2i(THREAD)); } // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort(except_oop)); + Exceptions::debug_check_abort(except_oop); + // No handler in this activation, unwind and try again THREAD->set_pending_exception(except_oop(), NULL, 0); goto handle_return; diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp index 755bf513a0a..2f1bf00d9af 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp @@ -35,7 +35,7 @@ #ifdef ASSERT #define VERIFY_OOP(o_) \ if (VerifyOops) { \ - assert((oop(o_))->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(oop(o_)))); \ + assert((oop(o_))->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(o_))); \ StubRoutines::_verify_oop_count++; \ } #else diff --git a/hotspot/src/share/vm/interpreter/bytecodes.cpp b/hotspot/src/share/vm/interpreter/bytecodes.cpp index a5b53ad3529..78ef212d9bf 100644 --- a/hotspot/src/share/vm/interpreter/bytecodes.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodes.cpp @@ -542,8 +542,7 @@ void Bytecodes::initialize() { Code code = cast(i); Code java = java_code(code); if (can_trap(code) && !can_trap(java)) - fatal(err_msg("%s can trap => %s can trap, too", name(code), - name(java))); + fatal("%s can trap => %s can trap, too", name(code), name(java)); } } } diff --git a/hotspot/src/share/vm/interpreter/bytecodes.hpp b/hotspot/src/share/vm/interpreter/bytecodes.hpp index 78f6c48f595..20990d64b9e 100644 --- a/hotspot/src/share/vm/interpreter/bytecodes.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodes.hpp @@ -353,8 +353,8 @@ class Bytecodes: AllStatic { public: // Conversion - static void check (Code code) { assert(is_defined(code), err_msg("illegal code: %d", (int)code)); } - static void wide_check (Code code) { assert(wide_is_defined(code), err_msg("illegal code: %d", (int)code)); } + static void check (Code code) { assert(is_defined(code), "illegal code: %d", (int)code); } + static void wide_check (Code code) { assert(wide_is_defined(code), "illegal code: %d", (int)code); } static Code cast (int code) { return (Code)code; } diff --git a/hotspot/src/share/vm/interpreter/interpreter.cpp b/hotspot/src/share/vm/interpreter/interpreter.cpp index 7421f3b7dae..eada76cb3bb 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.cpp +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp @@ -104,7 +104,10 @@ CodeletMark::~CodeletMark() { (*_masm)->flush(); // Commit Codelet. - AbstractInterpreter::code()->commit((*_masm)->code()->pure_insts_size(), (*_masm)->code()->strings()); + int committed_code_size = (*_masm)->code()->pure_insts_size(); + if (committed_code_size) { + AbstractInterpreter::code()->commit(committed_code_size, (*_masm)->code()->strings()); + } // Make sure nobody can use _masm outside a CodeletMark lifespan. *_masm = NULL; } @@ -234,6 +237,13 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m) case vmIntrinsics::_updateByteBufferCRC32 : return java_util_zip_CRC32_updateByteBuffer; } } + if (UseCRC32CIntrinsics) { + // Use optimized stub code for CRC32C methods. + switch (m->intrinsic_id()) { + case vmIntrinsics::_updateBytesCRC32C : return java_util_zip_CRC32C_updateBytes; + case vmIntrinsics::_updateDirectByteBufferCRC32C : return java_util_zip_CRC32C_updateDirectByteBuffer; + } + } switch(m->intrinsic_id()) { case vmIntrinsics::_intBitsToFloat: return java_lang_Float_intBitsToFloat; @@ -349,6 +359,8 @@ void AbstractInterpreter::print_method_kind(MethodKind kind) { case java_util_zip_CRC32_update : tty->print("java_util_zip_CRC32_update"); break; case java_util_zip_CRC32_updateBytes : tty->print("java_util_zip_CRC32_updateBytes"); break; case java_util_zip_CRC32_updateByteBuffer : tty->print("java_util_zip_CRC32_updateByteBuffer"); break; + case java_util_zip_CRC32C_updateBytes : tty->print("java_util_zip_CRC32C_updateBytes"); break; + case java_util_zip_CRC32C_updateDirectByteBuffer: tty->print("java_util_zip_CRC32C_updateDirectByteByffer"); break; default: if (kind >= method_handle_invoke_FIRST && kind <= method_handle_invoke_LAST) { @@ -447,11 +459,11 @@ address AbstractInterpreter::deopt_continue_after_entry(Method* method, address address AbstractInterpreter::deopt_reexecute_entry(Method* method, address bcp) { assert(method->contains(bcp), "just checkin'"); Bytecodes::Code code = Bytecodes::java_code_at(method, bcp); -#ifdef COMPILER1 +#if defined(COMPILER1) || INCLUDE_JVMCI if(code == Bytecodes::_athrow ) { return Interpreter::rethrow_exception_entry(); } -#endif /* COMPILER1 */ +#endif /* COMPILER1 || INCLUDE_JVMCI */ return Interpreter::deopt_entry(vtos, 0); } @@ -537,17 +549,18 @@ void AbstractInterpreterGenerator::initialize_method_handle_entries() { address InterpreterGenerator::generate_method_entry( AbstractInterpreter::MethodKind kind) { // determine code generation flags + bool native = false; bool synchronized = false; address entry_point = NULL; switch (kind) { - case Interpreter::zerolocals : break; - case Interpreter::zerolocals_synchronized: synchronized = true; break; - case Interpreter::native : entry_point = generate_native_entry(false); break; - case Interpreter::native_synchronized : entry_point = generate_native_entry(true); break; - case Interpreter::empty : entry_point = generate_empty_entry(); break; + case Interpreter::zerolocals : break; + case Interpreter::zerolocals_synchronized: synchronized = true; break; + case Interpreter::native : native = true; break; + case Interpreter::native_synchronized : native = true; synchronized = true; break; + case Interpreter::empty : entry_point = generate_empty_entry(); break; case Interpreter::accessor : entry_point = generate_accessor_entry(); break; - case Interpreter::abstract : entry_point = generate_abstract_entry(); break; + case Interpreter::abstract : entry_point = generate_abstract_entry(); break; case Interpreter::java_lang_math_sin : // fall thru case Interpreter::java_lang_math_cos : // fall thru @@ -562,33 +575,37 @@ address InterpreterGenerator::generate_method_entry( : entry_point = generate_Reference_get_entry(); break; #ifndef CC_INTERP case Interpreter::java_util_zip_CRC32_update - : entry_point = generate_CRC32_update_entry(); break; + : native = true; entry_point = generate_CRC32_update_entry(); break; case Interpreter::java_util_zip_CRC32_updateBytes : // fall thru case Interpreter::java_util_zip_CRC32_updateByteBuffer - : entry_point = generate_CRC32_updateBytes_entry(kind); break; + : native = true; entry_point = generate_CRC32_updateBytes_entry(kind); break; + case Interpreter::java_util_zip_CRC32C_updateBytes + : // fall thru + case Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer + : entry_point = generate_CRC32C_updateBytes_entry(kind); break; #if defined(TARGET_ARCH_x86) && !defined(_LP64) // On x86_32 platforms, a special entry is generated for the following four methods. // On other platforms the normal entry is used to enter these methods. case Interpreter::java_lang_Float_intBitsToFloat - : entry_point = generate_Float_intBitsToFloat_entry(); break; + : native = true; entry_point = generate_Float_intBitsToFloat_entry(); break; case Interpreter::java_lang_Float_floatToRawIntBits - : entry_point = generate_Float_floatToRawIntBits_entry(); break; + : native = true; entry_point = generate_Float_floatToRawIntBits_entry(); break; case Interpreter::java_lang_Double_longBitsToDouble - : entry_point = generate_Double_longBitsToDouble_entry(); break; + : native = true; entry_point = generate_Double_longBitsToDouble_entry(); break; case Interpreter::java_lang_Double_doubleToRawLongBits - : entry_point = generate_Double_doubleToRawLongBits_entry(); break; + : native = true; entry_point = generate_Double_doubleToRawLongBits_entry(); break; #else case Interpreter::java_lang_Float_intBitsToFloat: case Interpreter::java_lang_Float_floatToRawIntBits: case Interpreter::java_lang_Double_longBitsToDouble: case Interpreter::java_lang_Double_doubleToRawLongBits: - entry_point = generate_native_entry(false); + native = true; break; #endif // defined(TARGET_ARCH_x86) && !defined(_LP64) #endif // CC_INTERP default: - fatal(err_msg("unexpected method kind: %d", kind)); + fatal("unexpected method kind: %d", kind); break; } @@ -596,5 +613,18 @@ address InterpreterGenerator::generate_method_entry( return entry_point; } - return generate_normal_entry(synchronized); + // We expect the normal and native entry points to be generated first so we can reuse them. + if (native) { + entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::native_synchronized : Interpreter::native); + if (entry_point == NULL) { + entry_point = generate_native_entry(synchronized); + } + } else { + entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::zerolocals_synchronized : Interpreter::zerolocals); + if (entry_point == NULL) { + entry_point = generate_normal_entry(synchronized); + } + } + + return entry_point; } diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index d08c5ce8b78..ebc4832283c 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -66,8 +66,6 @@ #include "opto/runtime.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - class UnlockFlagSaver { private: JavaThread* _thread; @@ -444,14 +442,14 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea if (message != NULL) { tty->print_cr("Exception <%s: %s> (" INTPTR_FORMAT ")", h_exception->print_value_string(), message->as_C_string(), - (address)h_exception()); + p2i(h_exception())); } else { tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", h_exception->print_value_string(), - (address)h_exception()); + p2i(h_exception())); } tty->print_cr(" thrown in interpreter method <%s>", h_method->print_value_string()); - tty->print_cr(" at bci %d for thread " INTPTR_FORMAT, current_bci, thread); + tty->print_cr(" at bci %d for thread " INTPTR_FORMAT, current_bci, p2i(thread)); } // Don't go paging in something which won't be used. // else if (extable->length() == 0) { @@ -460,7 +458,7 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea // // warning("performance bug: should not call runtime if method has no exception handlers"); // } // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort(h_exception)); + Exceptions::debug_check_abort(h_exception); // exception handler lookup KlassHandle h_klass(THREAD, h_exception->klass()); @@ -481,6 +479,17 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea } } while (should_repeat == true); +#if INCLUDE_JVMCI + if (UseJVMCICompiler && h_method->method_data() != NULL) { + ResourceMark rm(thread); + ProfileData* pdata = h_method->method_data()->allocate_bci_to_data(current_bci, NULL); + if (pdata != NULL && pdata->is_BitData()) { + BitData* bit_data = (BitData*) pdata; + bit_data->set_exception_seen(); + } + } +#endif + // notify JVMTI of an exception throw; JVMTI will detect if this is a first // time throw or a stack unwinding throw and accordingly notify the debugger if (JvmtiExport::can_post_on_exceptions()) { @@ -858,7 +867,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_from_cache(JavaThread* thread, Bytec resolve_invokedynamic(thread); break; default: - fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(bytecode))); + fatal("unexpected bytecode: %s", Bytecodes::name(bytecode)); break; } } @@ -885,7 +894,7 @@ nmethod* InterpreterRuntime::frequency_counter_overflow(JavaThread* thread, addr #ifndef PRODUCT if (TraceOnStackReplacement) { if (nm != NULL) { - tty->print("OSR entry @ pc: " INTPTR_FORMAT ": ", nm->osr_entry()); + tty->print("OSR entry @ pc: " INTPTR_FORMAT ": ", p2i(nm->osr_entry())); nm->print(); } } @@ -1305,7 +1314,7 @@ void SignatureHandlerLibrary::add(uint64_t fingerprint, address handler) { tty->cr(); tty->print_cr("argument handler #%d at " PTR_FORMAT " for fingerprint " UINT64_FORMAT, _handlers->length(), - handler, + p2i(handler), fingerprint); } _fingerprints->append(fingerprint); @@ -1316,8 +1325,8 @@ void SignatureHandlerLibrary::add(uint64_t fingerprint, address handler) { tty->print_cr("duplicate argument handler #%d for fingerprint " UINT64_FORMAT "(old: " PTR_FORMAT ", new : " PTR_FORMAT ")", _handlers->length(), fingerprint, - _handlers->at(handler_index), - handler); + p2i(_handlers->at(handler_index)), + p2i(handler)); } } } diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 07c63c9b343..7988d6f5f87 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -124,7 +124,7 @@ void CallInfo::set_common(KlassHandle resolved_klass, // Note: with several active threads, the must_be_compiled may be true // while can_be_compiled is false; remove assert // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile"); - if (THREAD->is_Compiler_thread()) { + if (!THREAD->can_call_java()) { // don't force compilation, resolve was on behalf of compiler return; } @@ -179,11 +179,11 @@ CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass) { KlassHandle object_klass = SystemDictionary::Object_klass(); Method * object_resolved_method = object_klass()->vtable()->method_at(index); assert(object_resolved_method->name() == resolved_method->name(), - err_msg("Object and interface method names should match at vtable index %d, %s != %s", - index, object_resolved_method->name()->as_C_string(), resolved_method->name()->as_C_string())); + "Object and interface method names should match at vtable index %d, %s != %s", + index, object_resolved_method->name()->as_C_string(), resolved_method->name()->as_C_string()); assert(object_resolved_method->signature() == resolved_method->signature(), - err_msg("Object and interface method signatures should match at vtable index %d, %s != %s", - index, object_resolved_method->signature()->as_C_string(), resolved_method->signature()->as_C_string())); + "Object and interface method signatures should match at vtable index %d, %s != %s", + index, object_resolved_method->signature()->as_C_string(), resolved_method->signature()->as_C_string()); #endif // ASSERT kind = CallInfo::vtable_call; @@ -192,7 +192,7 @@ CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass) { kind = CallInfo::itable_call; index = resolved_method->itable_index(); } - assert(index == Method::nonvirtual_vtable_index || index >= 0, err_msg("bad index %d", index)); + assert(index == Method::nonvirtual_vtable_index || index >= 0, "bad index %d", index); _call_kind = kind; _call_index = index; _resolved_appendix = Handle(); @@ -215,7 +215,7 @@ void CallInfo::verify() { assert(call_kind() != CallInfo::unknown_kind, "CallInfo must be set"); break; default: - fatal(err_msg_res("Unexpected call kind %d", call_kind())); + fatal("Unexpected call kind %d", call_kind()); } } #endif //ASSERT @@ -450,7 +450,7 @@ methodHandle LinkResolver::lookup_polymorphic_method( } return result; } else if (iid == vmIntrinsics::_invokeGeneric - && !THREAD->is_Compiler_thread() + && THREAD->can_call_java() && appendix_result_or_null != NULL) { // This is a method with type-checking semantics. // We will ask Java code to spin an adapter method for it. @@ -499,7 +499,7 @@ methodHandle LinkResolver::lookup_polymorphic_method( result->print(); } assert(actual_size_of_params == expected_size_of_params, - err_msg("%d != %d", actual_size_of_params, expected_size_of_params)); + "%d != %d", actual_size_of_params, expected_size_of_params); #endif //ASSERT assert(appendix_result_or_null != NULL, ""); diff --git a/hotspot/src/share/vm/interpreter/linkResolver.hpp b/hotspot/src/share/vm/interpreter/linkResolver.hpp index d3fda4368ef..77cd1632549 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp @@ -174,9 +174,11 @@ class LinkResolver: AllStatic { static methodHandle lookup_polymorphic_method(const LinkInfo& link_info, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS); + JVMCI_ONLY(public:) // Needed for CompilerToVM.resolveMethod() // Not Linktime so doesn't take LinkInfo static methodHandle lookup_instance_method_in_klasses ( KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); + JVMCI_ONLY(private:) // Similar loader constraint checking functions that throw // LinkageError with descriptive message. diff --git a/hotspot/src/share/vm/interpreter/oopMapCache.cpp b/hotspot/src/share/vm/interpreter/oopMapCache.cpp index 14985be348a..2233f1b0f3f 100644 --- a/hotspot/src/share/vm/interpreter/oopMapCache.cpp +++ b/hotspot/src/share/vm/interpreter/oopMapCache.cpp @@ -31,8 +31,6 @@ #include "runtime/handles.inline.hpp" #include "runtime/signature.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - class OopMapCacheEntry: private InterpreterOopMap { friend class InterpreterOopMap; friend class OopMapForCacheEntry; @@ -213,31 +211,6 @@ void InterpreterOopMap::iterate_oop(OffsetClosure* oop_closure) const { } } - -#ifdef ENABLE_ZAP_DEAD_LOCALS - -void InterpreterOopMap::iterate_all(OffsetClosure* oop_closure, OffsetClosure* value_closure, OffsetClosure* dead_closure) { - int n = number_of_entries(); - int word_index = 0; - uintptr_t value = 0; - uintptr_t mask = 0; - // iterate over entries - for (int i = 0; i < n; i++, mask <<= bits_per_entry) { - // get current word - if (mask == 0) { - value = bit_mask()[word_index++]; - mask = 1; - } - // test for dead values & oops, and for live values - if ((value & (mask << dead_bit_number)) != 0) dead_closure->offset_do(i); // call this for all dead values or oops - else if ((value & (mask << oop_bit_number)) != 0) oop_closure->offset_do(i); // call this for all live oops - else value_closure->offset_do(i); // call this for all live values - } -} - -#endif - - void InterpreterOopMap::print() const { int n = number_of_entries(); tty->print("oop map for "); @@ -297,12 +270,6 @@ bool OopMapCacheEntry::verify_mask(CellTypeState* vars, CellTypeState* stack, in bool v2 = vars[i].is_reference() ? true : false; assert(v1 == v2, "locals oop mask generation error"); if (TraceOopMapGeneration && Verbose) tty->print("%d", v1 ? 1 : 0); -#ifdef ENABLE_ZAP_DEAD_LOCALS - bool v3 = is_dead(i) ? true : false; - bool v4 = !vars[i].is_live() ? true : false; - assert(v3 == v4, "locals live mask generation error"); - assert(!(v1 && v3), "dead value marked as oop"); -#endif } if (TraceOopMapGeneration && Verbose) { tty->cr(); tty->print("Stack (%d): ", stack_top); } @@ -311,12 +278,6 @@ bool OopMapCacheEntry::verify_mask(CellTypeState* vars, CellTypeState* stack, in bool v2 = stack[j].is_reference() ? true : false; assert(v1 == v2, "stack oop mask generation error"); if (TraceOopMapGeneration && Verbose) tty->print("%d", v1 ? 1 : 0); -#ifdef ENABLE_ZAP_DEAD_LOCALS - bool v3 = is_dead(max_locals + j) ? true : false; - bool v4 = !stack[j].is_live() ? true : false; - assert(v3 == v4, "stack live mask generation error"); - assert(!(v1 && v3), "dead value marked as oop"); -#endif } if (TraceOopMapGeneration && Verbose) tty->cr(); return true; diff --git a/hotspot/src/share/vm/interpreter/oopMapCache.hpp b/hotspot/src/share/vm/interpreter/oopMapCache.hpp index dbdd4cb1a88..19bf0044925 100644 --- a/hotspot/src/share/vm/interpreter/oopMapCache.hpp +++ b/hotspot/src/share/vm/interpreter/oopMapCache.hpp @@ -141,9 +141,6 @@ class InterpreterOopMap: ResourceObj { int expression_stack_size() const { return _expression_stack_size; } -#ifdef ENABLE_ZAP_DEAD_LOCALS - void iterate_all(OffsetClosure* oop_closure, OffsetClosure* value_closure, OffsetClosure* dead_closure); -#endif }; class OopMapCache : public CHeapObj { diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp index 6e7c282017e..8d75f5e1ed4 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp @@ -412,17 +412,6 @@ void TemplateInterpreterGenerator::generate_all() { method_entry(java_lang_math_pow ) method_entry(java_lang_ref_reference_get) - if (UseCRC32Intrinsics) { - method_entry(java_util_zip_CRC32_update) - method_entry(java_util_zip_CRC32_updateBytes) - method_entry(java_util_zip_CRC32_updateByteBuffer) - } - - method_entry(java_lang_Float_intBitsToFloat); - method_entry(java_lang_Float_floatToRawIntBits); - method_entry(java_lang_Double_longBitsToDouble); - method_entry(java_lang_Double_doubleToRawLongBits); - initialize_method_handle_entries(); // all native method kinds (must be one contiguous block) @@ -431,6 +420,22 @@ void TemplateInterpreterGenerator::generate_all() { method_entry(native_synchronized) Interpreter::_native_entry_end = Interpreter::code()->code_end(); + if (UseCRC32Intrinsics) { + method_entry(java_util_zip_CRC32_update) + method_entry(java_util_zip_CRC32_updateBytes) + method_entry(java_util_zip_CRC32_updateByteBuffer) + } + + if (UseCRC32CIntrinsics) { + method_entry(java_util_zip_CRC32C_updateBytes) + method_entry(java_util_zip_CRC32C_updateDirectByteBuffer) + } + + method_entry(java_lang_Float_intBitsToFloat); + method_entry(java_lang_Float_floatToRawIntBits); + method_entry(java_lang_Double_longBitsToDouble); + method_entry(java_lang_Double_doubleToRawLongBits); + #undef method_entry // Bytecodes @@ -602,7 +607,7 @@ address* TemplateInterpreter::invoke_return_entry_table_for(Bytecodes::Code code case Bytecodes::_invokedynamic: return Interpreter::invokedynamic_return_entry_table(); default: - fatal(err_msg("invalid bytecode: %s", Bytecodes::name(code))); + fatal("invalid bytecode: %s", Bytecodes::name(code)); return NULL; } } @@ -624,7 +629,7 @@ address TemplateInterpreter::return_entry(TosState state, int length, Bytecodes: case Bytecodes::_invokedynamic: return _invokedynamic_return_entry[index]; default: - assert(!Bytecodes::is_invoke(code), err_msg("invoke instructions should be handled separately: %s", Bytecodes::name(code))); + assert(!Bytecodes::is_invoke(code), "invoke instructions should be handled separately: %s", Bytecodes::name(code)); return _return_entry[length].entry(state); } } diff --git a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp index 83a74d741dc..e229485ce96 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp @@ -59,6 +59,8 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator { address generate_safept_entry_for(TosState state, address runtime_entry); void generate_throw_exception(); + void lock_method(); + // Instruction generation void generate_and_dispatch (Template* t, TosState tos_out = ilgl); void set_vtos_entry_points (Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep); diff --git a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp b/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp new file mode 100644 index 00000000000..6481aaddca2 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" +#include "runtime/arguments.hpp" +#include "runtime/globals.hpp" +#include "utilities/defaultStream.hpp" + +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose) { + if (!EnableJVMCI) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); + } + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose) { + if (!EnableJVMCI) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); + } + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} diff --git a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp b/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp new file mode 100644 index 00000000000..35f47f9967d --- /dev/null +++ b/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP +#define SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP + +#include "runtime/globals.hpp" +#include "utilities/globalDefinitions.hpp" + +/* + * Here we have JVMCI arguments constraints functions, which are called automatically + * whenever flag's value changes. If the constraint fails the function should return + * an appropriate error value. + */ + +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose); +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose); + +#endif /* SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP */ diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp new file mode 100644 index 00000000000..bbf5e992f58 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp @@ -0,0 +1,1029 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "code/compiledIC.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/disassembler.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "asm/register.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/vmreg.hpp" + +#ifdef TARGET_ARCH_x86 +# include "vmreg_x86.inline.hpp" +#endif +#ifdef TARGET_ARCH_sparc +# include "vmreg_sparc.inline.hpp" +#endif +#ifdef TARGET_ARCH_zero +# include "vmreg_zero.inline.hpp" +#endif +#ifdef TARGET_ARCH_arm +# include "vmreg_arm.inline.hpp" +#endif +#ifdef TARGET_ARCH_ppc +# include "vmreg_ppc.inline.hpp" +#endif + + +// frequently used constants +// Allocate them with new so they are never destroyed (otherwise, a +// forced exit could destroy these objects while they are still in +// use). +ConstantOopWriteValue* CodeInstaller::_oop_null_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantOopWriteValue(NULL); +ConstantIntValue* CodeInstaller::_int_m1_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(-1); +ConstantIntValue* CodeInstaller::_int_0_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(0); +ConstantIntValue* CodeInstaller::_int_1_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(1); +ConstantIntValue* CodeInstaller::_int_2_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(2); +LocationValue* CodeInstaller::_illegal_value = new (ResourceObj::C_HEAP, mtCompiler) LocationValue(Location()); + +Method* getMethodFromHotSpotMethod(oop hotspot_method) { + assert(hotspot_method != NULL && hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass()), "sanity"); + return CompilerToVM::asMethod(hotspot_method); +} + +VMReg getVMRegFromLocation(oop location, int total_frame_size) { + oop reg = code_Location::reg(location); + jint offset = code_Location::offset(location); + + if (reg != NULL) { + // register + jint number = code_Register::number(reg); + VMReg vmReg = CodeInstaller::get_hotspot_reg(number); + assert(offset % 4 == 0, "must be aligned"); + return vmReg->next(offset / 4); + } else { + // stack slot + assert(offset % 4 == 0, "must be aligned"); + return VMRegImpl::stack2reg(offset / 4); + } +} + +// creates a HotSpot oop map out of the byte arrays provided by DebugInfo +OopMap* CodeInstaller::create_oop_map(oop debug_info) { + oop reference_map = DebugInfo::referenceMap(debug_info); + if (HotSpotReferenceMap::maxRegisterSize(reference_map) > 16) { + _has_wide_vector = true; + } + OopMap* map = new OopMap(_total_frame_size, _parameter_count); + objArrayOop objects = HotSpotReferenceMap::objects(reference_map); + objArrayOop derivedBase = HotSpotReferenceMap::derivedBase(reference_map); + typeArrayOop sizeInBytes = HotSpotReferenceMap::sizeInBytes(reference_map); + for (int i = 0; i < objects->length(); i++) { + oop location = objects->obj_at(i); + oop baseLocation = derivedBase->obj_at(i); + int bytes = sizeInBytes->int_at(i); + + VMReg vmReg = getVMRegFromLocation(location, _total_frame_size); + if (baseLocation != NULL) { + // derived oop + assert(bytes == 8, "derived oop can't be compressed"); + VMReg baseReg = getVMRegFromLocation(baseLocation, _total_frame_size); + map->set_derived_oop(vmReg, baseReg); + } else if (bytes == 8) { + // wide oop + map->set_oop(vmReg); + } else { + // narrow oop + assert(bytes == 4, "wrong size"); + map->set_narrowoop(vmReg); + } + } + + oop callee_save_info = (oop) DebugInfo::calleeSaveInfo(debug_info); + if (callee_save_info != NULL) { + objArrayOop registers = RegisterSaveLayout::registers(callee_save_info); + typeArrayOop slots = RegisterSaveLayout::slots(callee_save_info); + for (jint i = 0; i < slots->length(); i++) { + oop jvmci_reg = registers->obj_at(i); + jint jvmci_reg_number = code_Register::number(jvmci_reg); + VMReg hotspot_reg = CodeInstaller::get_hotspot_reg(jvmci_reg_number); + // HotSpot stack slots are 4 bytes + jint jvmci_slot = slots->int_at(i); + jint hotspot_slot = jvmci_slot * VMRegImpl::slots_per_word; + VMReg hotspot_slot_as_reg = VMRegImpl::stack2reg(hotspot_slot); + map->set_callee_saved(hotspot_slot_as_reg, hotspot_reg); +#ifdef _LP64 + // (copied from generate_oop_map() in c1_Runtime1_x86.cpp) + VMReg hotspot_slot_hi_as_reg = VMRegImpl::stack2reg(hotspot_slot + 1); + map->set_callee_saved(hotspot_slot_hi_as_reg, hotspot_reg->next()); +#endif + } + } + return map; +} + +static void record_metadata_reference(oop obj, jlong prim, jboolean compressed, OopRecorder* oop_recorder) { + if (obj->is_a(HotSpotResolvedObjectTypeImpl::klass())) { + Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(obj)); + if (compressed) { + assert(Klass::decode_klass((narrowKlass) prim) == klass, "%s @ " INTPTR_FORMAT " != " PTR64_FORMAT, klass->name()->as_C_string(), p2i(klass), prim); + } else { + assert((Klass*) prim == klass, "%s @ " INTPTR_FORMAT " != " PTR64_FORMAT, klass->name()->as_C_string(), p2i(klass), prim); + } + int index = oop_recorder->find_index(klass); + TRACE_jvmci_3("metadata[%d of %d] = %s", index, oop_recorder->metadata_count(), klass->name()->as_C_string()); + } else if (obj->is_a(HotSpotResolvedJavaMethodImpl::klass())) { + Method* method = (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(obj); + assert(!compressed, "unexpected compressed method pointer %s @ " INTPTR_FORMAT " = " PTR64_FORMAT, method->name()->as_C_string(), p2i(method), prim); + int index = oop_recorder->find_index(method); + TRACE_jvmci_3("metadata[%d of %d] = %s", index, oop_recorder->metadata_count(), method->name()->as_C_string()); + } else { + assert(java_lang_String::is_instance(obj), + "unexpected metadata reference (%s) for constant " JLONG_FORMAT " (" PTR64_FORMAT ")", obj->klass()->name()->as_C_string(), prim, prim); + } +} + +// Records any Metadata values embedded in a Constant (e.g., the value returned by HotSpotResolvedObjectTypeImpl.klass()). +static void record_metadata_in_constant(oop constant, OopRecorder* oop_recorder) { + if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { + oop obj = HotSpotMetaspaceConstantImpl::metaspaceObject(constant); + jlong prim = HotSpotMetaspaceConstantImpl::primitive(constant); + assert(obj != NULL, "must have an object"); + assert(prim != 0, "must have a primitive value"); + + record_metadata_reference(obj, prim, false, oop_recorder); + } +} + +static void record_metadata_in_patch(Handle& constant, OopRecorder* oop_recorder) { + record_metadata_reference(HotSpotMetaspaceConstantImpl::metaspaceObject(constant), HotSpotMetaspaceConstantImpl::primitive(constant), HotSpotMetaspaceConstantImpl::compressed(constant), oop_recorder); +} + +Location::Type CodeInstaller::get_oop_type(oop value) { + oop lirKind = Value::lirKind(value); + oop platformKind = LIRKind::platformKind(lirKind); + assert(LIRKind::referenceMask(lirKind) == 1, "unexpected referenceMask"); + + if (platformKind == word_kind()) { + return Location::oop; + } else { + return Location::narrowoop; + } +} + +ScopeValue* CodeInstaller::get_scope_value(oop value, BasicType type, GrowableArray* objects, ScopeValue* &second) { + second = NULL; + if (value == Value::ILLEGAL()) { + assert(type == T_ILLEGAL, "expected legal value"); + return _illegal_value; + } else if (value->is_a(RegisterValue::klass())) { + oop reg = RegisterValue::reg(value); + jint number = code_Register::number(reg); + VMReg hotspotRegister = get_hotspot_reg(number); + if (is_general_purpose_reg(hotspotRegister)) { + Location::Type locationType; + if (type == T_OBJECT) { + locationType = get_oop_type(value); + } else if (type == T_LONG) { + locationType = Location::lng; + } else { + assert(type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN, "unexpected type in cpu register"); + locationType = Location::int_in_long; + } + ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, hotspotRegister)); + if (type == T_LONG) { + second = value; + } + return value; + } else { + assert(type == T_FLOAT || type == T_DOUBLE, "only float and double expected in xmm register"); + Location::Type locationType; + if (type == T_FLOAT) { + // this seems weird, but the same value is used in c1_LinearScan + locationType = Location::normal; + } else { + locationType = Location::dbl; + } + ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, hotspotRegister)); + if (type == T_DOUBLE) { + second = value; + } + return value; + } + } else if (value->is_a(StackSlot::klass())) { + jint offset = StackSlot::offset(value); + if (StackSlot::addFrameSize(value)) { + offset += _total_frame_size; + } + + Location::Type locationType; + if (type == T_OBJECT) { + locationType = get_oop_type(value); + } else if (type == T_LONG) { + locationType = Location::lng; + } else if (type == T_DOUBLE) { + locationType = Location::dbl; + } else { + assert(type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN, "unexpected type in stack slot"); + locationType = Location::normal; + } + ScopeValue* value = new LocationValue(Location::new_stk_loc(locationType, offset)); + if (type == T_DOUBLE || type == T_LONG) { + second = value; + } + return value; + } else if (value->is_a(JavaConstant::klass())) { + record_metadata_in_constant(value, _oop_recorder); + if (value->is_a(PrimitiveConstant::klass())) { + if (value->is_a(RawConstant::klass())) { + jlong prim = PrimitiveConstant::primitive(value); + return new ConstantLongValue(prim); + } else { + assert(type == JVMCIRuntime::kindToBasicType(JavaKind::typeChar(PrimitiveConstant::kind(value))), "primitive constant type doesn't match"); + if (type == T_INT || type == T_FLOAT) { + jint prim = (jint)PrimitiveConstant::primitive(value); + switch (prim) { + case -1: return _int_m1_scope_value; + case 0: return _int_0_scope_value; + case 1: return _int_1_scope_value; + case 2: return _int_2_scope_value; + default: return new ConstantIntValue(prim); + } + } else { + assert(type == T_LONG || type == T_DOUBLE, "unexpected primitive constant type"); + jlong prim = PrimitiveConstant::primitive(value); + second = _int_1_scope_value; + return new ConstantLongValue(prim); + } + } + } else { + assert(type == T_OBJECT, "unexpected object constant"); + if (value->is_a(NullConstant::klass()) || value->is_a(HotSpotCompressedNullConstant::klass())) { + return _oop_null_scope_value; + } else { + assert(value->is_a(HotSpotObjectConstantImpl::klass()), "unexpected constant type"); + oop obj = HotSpotObjectConstantImpl::object(value); + assert(obj != NULL, "null value must be in NullConstant"); + return new ConstantOopWriteValue(JNIHandles::make_local(obj)); + } + } + } else if (value->is_a(VirtualObject::klass())) { + assert(type == T_OBJECT, "unexpected virtual object"); + int id = VirtualObject::id(value); + ScopeValue* object = objects->at(id); + assert(object != NULL, "missing value"); + return object; + } else { + value->klass()->print(); + value->print(); + } + ShouldNotReachHere(); + return NULL; +} + +void CodeInstaller::record_object_value(ObjectValue* sv, oop value, GrowableArray* objects) { + oop type = VirtualObject::type(value); + int id = VirtualObject::id(value); + oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type); + Klass* klass = java_lang_Class::as_Klass(javaMirror); + bool isLongArray = klass == Universe::longArrayKlassObj(); + + objArrayOop values = VirtualObject::values(value); + objArrayOop slotKinds = VirtualObject::slotKinds(value); + for (jint i = 0; i < values->length(); i++) { + ScopeValue* cur_second = NULL; + oop object = values->obj_at(i); + oop kind = slotKinds->obj_at(i); + BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); + ScopeValue* value = get_scope_value(object, type, objects, cur_second); + + if (isLongArray && cur_second == NULL) { + // we're trying to put ints into a long array... this isn't really valid, but it's used for some optimizations. + // add an int 0 constant + cur_second = _int_0_scope_value; + } + + if (cur_second != NULL) { + sv->field_values()->append(cur_second); + } + assert(value != NULL, "missing value"); + sv->field_values()->append(value); + } +} + +MonitorValue* CodeInstaller::get_monitor_value(oop value, GrowableArray* objects) { + guarantee(value->is_a(StackLockValue::klass()), "Monitors must be of type StackLockValue"); + + ScopeValue* second = NULL; + ScopeValue* owner_value = get_scope_value(StackLockValue::owner(value), T_OBJECT, objects, second); + assert(second == NULL, "monitor cannot occupy two stack slots"); + + ScopeValue* lock_data_value = get_scope_value(StackLockValue::slot(value), T_LONG, objects, second); + assert(second == lock_data_value, "monitor is LONG value that occupies two stack slots"); + assert(lock_data_value->is_location(), "invalid monitor location"); + Location lock_data_loc = ((LocationValue*)lock_data_value)->location(); + + bool eliminated = false; + if (StackLockValue::eliminated(value)) { + eliminated = true; + } + + return new MonitorValue(owner_value, lock_data_loc, eliminated); +} + +void CodeInstaller::initialize_dependencies(oop compiled_code, OopRecorder* recorder) { + JavaThread* thread = JavaThread::current(); + CompilerThread* compilerThread = thread->is_Compiler_thread() ? thread->as_CompilerThread() : NULL; + _oop_recorder = recorder; + _dependencies = new Dependencies(&_arena, _oop_recorder, compilerThread != NULL ? compilerThread->log() : NULL); + objArrayHandle assumptions = HotSpotCompiledCode::assumptions(compiled_code); + if (!assumptions.is_null()) { + int length = assumptions->length(); + for (int i = 0; i < length; ++i) { + Handle assumption = assumptions->obj_at(i); + if (!assumption.is_null()) { + if (assumption->klass() == Assumptions_NoFinalizableSubclass::klass()) { + assumption_NoFinalizableSubclass(assumption); + } else if (assumption->klass() == Assumptions_ConcreteSubtype::klass()) { + assumption_ConcreteSubtype(assumption); + } else if (assumption->klass() == Assumptions_LeafType::klass()) { + assumption_LeafType(assumption); + } else if (assumption->klass() == Assumptions_ConcreteMethod::klass()) { + assumption_ConcreteMethod(assumption); + } else if (assumption->klass() == Assumptions_CallSiteTargetValue::klass()) { + assumption_CallSiteTargetValue(assumption); + } else { + assumption->print(); + fatal("unexpected Assumption subclass"); + } + } + } + } + objArrayHandle methods = HotSpotCompiledCode::methods(compiled_code); + if (!methods.is_null()) { + int length = methods->length(); + for (int i = 0; i < length; ++i) { + Handle method_handle = methods->obj_at(i); + methodHandle method = getMethodFromHotSpotMethod(method_handle()); + + _dependencies->assert_evol_method(method()); + } + } +} + +RelocBuffer::~RelocBuffer() { + if (_buffer != NULL) { + FREE_C_HEAP_ARRAY(char, _buffer); + } +} + +address RelocBuffer::begin() const { + if (_buffer != NULL) { + return (address) _buffer; + } + return (address) _static_buffer; +} + +void RelocBuffer::set_size(size_t bytes) { + assert(bytes <= _size, "can't grow in size!"); + _size = bytes; +} + +void RelocBuffer::ensure_size(size_t bytes) { + assert(_buffer == NULL, "can only be used once"); + assert(_size == 0, "can only be used once"); + if (bytes >= RelocBuffer::stack_size) { + _buffer = NEW_C_HEAP_ARRAY(char, bytes, mtInternal); + } + _size = bytes; +} + +JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata) { + CodeBuffer buffer("JVMCI Compiler CodeBuffer for Metadata"); + jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); + initialize_dependencies(JNIHandles::resolve(compiled_code_obj), NULL); + + // Get instructions and constants CodeSections early because we need it. + _instructions = buffer.insts(); + _constants = buffer.consts(); + + initialize_fields(target(), JNIHandles::resolve(compiled_code_obj)); + if (!initialize_buffer(buffer)) { + return JVMCIEnv::code_too_large; + } + process_exception_handlers(); + + _debug_recorder->pcs_size(); // ehm, create the sentinel record + + assert(_debug_recorder->pcs_length() >= 2, "must be at least 2"); + + metadata.set_pc_desc(_debug_recorder->pcs(), _debug_recorder->pcs_length()); + metadata.set_scopes(_debug_recorder->stream()->buffer(), _debug_recorder->data_size()); + metadata.set_exception_table(&_exception_handler_table); + + RelocBuffer* reloc_buffer = metadata.get_reloc_buffer(); + + reloc_buffer->ensure_size(buffer.total_relocation_size()); + size_t size = (size_t) buffer.copy_relocations_to(reloc_buffer->begin(), (CodeBuffer::csize_t) reloc_buffer->size(), true); + reloc_buffer->set_size(size); + return JVMCIEnv::ok; +} + +// constructor used to create a method +JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log) { + CodeBuffer buffer("JVMCI Compiler CodeBuffer"); + jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); + OopRecorder* recorder = new OopRecorder(&_arena, true); + initialize_dependencies(JNIHandles::resolve(compiled_code_obj), recorder); + + // Get instructions and constants CodeSections early because we need it. + _instructions = buffer.insts(); + _constants = buffer.consts(); + + initialize_fields(target(), JNIHandles::resolve(compiled_code_obj)); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer); + if (result != JVMCIEnv::ok) { + return result; + } + process_exception_handlers(); + + int stack_slots = _total_frame_size / HeapWordSize; // conversion to words + + if (!compiled_code->is_a(HotSpotCompiledNmethod::klass())) { + oop stubName = HotSpotCompiledCode::name(compiled_code_obj); + char* name = strdup(java_lang_String::as_utf8_string(stubName)); + cb = RuntimeStub::new_runtime_stub(name, + &buffer, + CodeOffsets::frame_never_safe, + stack_slots, + _debug_recorder->_oopmaps, + false); + result = JVMCIEnv::ok; + } else { + nmethod* nm = NULL; + methodHandle method = getMethodFromHotSpotMethod(HotSpotCompiledNmethod::method(compiled_code)); + jint entry_bci = HotSpotCompiledNmethod::entryBCI(compiled_code); + jint id = HotSpotCompiledNmethod::id(compiled_code); + bool has_unsafe_access = HotSpotCompiledNmethod::hasUnsafeAccess(compiled_code) == JNI_TRUE; + JVMCIEnv* env = (JVMCIEnv*) (address) HotSpotCompiledNmethod::jvmciEnv(compiled_code); + if (id == -1) { + // Make sure a valid compile_id is associated with every compile + id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci); + } + result = JVMCIEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, + stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, + compiler, _debug_recorder, _dependencies, env, id, + has_unsafe_access, _has_wide_vector, installed_code, compiled_code, speculation_log); + cb = nm; + } + + if (cb != NULL) { + // Make sure the pre-calculated constants section size was correct. + guarantee((cb->code_begin() - cb->content_begin()) >= _constants_size, "%d < %d", (int)(cb->code_begin() - cb->content_begin()), _constants_size); + } + return result; +} + +void CodeInstaller::initialize_fields(oop target, oop compiled_code) { + if (compiled_code->is_a(HotSpotCompiledNmethod::klass())) { + Handle hotspotJavaMethod = HotSpotCompiledNmethod::method(compiled_code); + methodHandle method = getMethodFromHotSpotMethod(hotspotJavaMethod()); + _parameter_count = method->size_of_parameters(); + TRACE_jvmci_2("installing code for %s", method->name_and_sig_as_C_string()); + } else { + // Must be a HotSpotCompiledRuntimeStub. + // Only used in OopMap constructor for non-product builds + _parameter_count = 0; + } + _sites_handle = JNIHandles::make_local(HotSpotCompiledCode::sites(compiled_code)); + _exception_handlers_handle = JNIHandles::make_local(HotSpotCompiledCode::exceptionHandlers(compiled_code)); + + _code_handle = JNIHandles::make_local(HotSpotCompiledCode::targetCode(compiled_code)); + _code_size = HotSpotCompiledCode::targetCodeSize(compiled_code); + _total_frame_size = HotSpotCompiledCode::totalFrameSize(compiled_code); + _custom_stack_area_offset = HotSpotCompiledCode::customStackAreaOffset(compiled_code); + + // Pre-calculate the constants section size. This is required for PC-relative addressing. + _data_section_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSection(compiled_code)); + guarantee(HotSpotCompiledCode::dataSectionAlignment(compiled_code) <= _constants->alignment(), "Alignment inside constants section is restricted by alignment of section begin"); + _constants_size = data_section()->length(); + + _data_section_patches_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSectionPatches(compiled_code)); + +#ifndef PRODUCT + _comments_handle = JNIHandles::make_local(HotSpotCompiledCode::comments(compiled_code)); +#endif + + _next_call_type = INVOKE_INVALID; + + _has_wide_vector = false; + + oop arch = TargetDescription::arch(target); + _word_kind_handle = JNIHandles::make_local(Architecture::wordKind(arch)); +} + +int CodeInstaller::estimate_stubs_size() { + // Return size for all stubs. + int static_call_stubs = 0; + objArrayOop sites = this->sites(); + for (int i = 0; i < sites->length(); i++) { + oop site = sites->obj_at(i); + if (site->is_a(CompilationResult_Mark::klass())) { + oop id_obj = CompilationResult_Mark::id(site); + if (id_obj != NULL) { + assert(java_lang_boxing_object::is_instance(id_obj, T_INT), "Integer id expected"); + jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT)); + if (id == INVOKESTATIC || id == INVOKESPECIAL) { + static_call_stubs++; + } + } + } + } + return static_call_stubs * CompiledStaticCall::to_interp_stub_size(); +} + +// perform data and call relocation on the CodeBuffer +JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer) { + objArrayHandle sites = this->sites(); + int locs_buffer_size = sites->length() * (relocInfo::length_limit + sizeof(relocInfo)); + + // Allocate enough space in the stub section for the static call + // stubs. Stubs have extra relocs but they are managed by the stub + // section itself so they don't need to be accounted for in the + // locs_buffer above. + int stubs_size = estimate_stubs_size(); + int total_size = round_to(_code_size, buffer.insts()->alignment()) + round_to(_constants_size, buffer.consts()->alignment()) + round_to(stubs_size, buffer.stubs()->alignment()); + + if (total_size > JVMCINMethodSizeLimit) { + return JVMCIEnv::code_too_large; + } + + buffer.initialize(total_size, locs_buffer_size); + if (buffer.blob() == NULL) { + return JVMCIEnv::cache_full; + } + buffer.initialize_stubs_size(stubs_size); + buffer.initialize_consts_size(_constants_size); + + _debug_recorder = new DebugInformationRecorder(_oop_recorder); + _debug_recorder->set_oopmaps(new OopMapSet()); + + buffer.initialize_oop_recorder(_oop_recorder); + + // copy the constant data into the newly created CodeBuffer + address end_data = _constants->start() + _constants_size; + memcpy(_constants->start(), data_section()->base(T_BYTE), _constants_size); + _constants->set_end(end_data); + + // copy the code into the newly created CodeBuffer + address end_pc = _instructions->start() + _code_size; + guarantee(_instructions->allocates2(end_pc), "initialize should have reserved enough space for all the code"); + memcpy(_instructions->start(), code()->base(T_BYTE), _code_size); + _instructions->set_end(end_pc); + + for (int i = 0; i < data_section_patches()->length(); i++) { + Handle patch = data_section_patches()->obj_at(i); + Handle reference = CompilationResult_DataPatch::reference(patch); + assert(reference->is_a(CompilationResult_ConstantReference::klass()), "patch in data section must be a ConstantReference"); + Handle constant = CompilationResult_ConstantReference::constant(reference); + if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { + record_metadata_in_patch(constant, _oop_recorder); + } else if (constant->is_a(HotSpotObjectConstantImpl::klass())) { + Handle obj = HotSpotObjectConstantImpl::object(constant); + jobject value = JNIHandles::make_local(obj()); + int oop_index = _oop_recorder->find_index(value); + + address dest = _constants->start() + CompilationResult_Site::pcOffset(patch); + if (HotSpotObjectConstantImpl::compressed(constant)) { +#ifdef _LP64 + _constants->relocate(dest, oop_Relocation::spec(oop_index), relocInfo::narrow_oop_in_const); +#else + fatal("unexpected compressed oop in 32-bit mode"); +#endif + } else { + _constants->relocate(dest, oop_Relocation::spec(oop_index)); + } + } else { + ShouldNotReachHere(); + } + } + jint last_pc_offset = -1; + for (int i = 0; i < sites->length(); i++) { + { + No_Safepoint_Verifier no_safepoint; + oop site = sites->obj_at(i); + jint pc_offset = CompilationResult_Site::pcOffset(site); + + if (site->is_a(CompilationResult_Call::klass())) { + TRACE_jvmci_4("call at %i", pc_offset); + site_Call(buffer, pc_offset, site); + } else if (site->is_a(CompilationResult_Infopoint::klass())) { + // three reasons for infopoints denote actual safepoints + oop reason = CompilationResult_Infopoint::reason(site); + if (InfopointReason::SAFEPOINT() == reason || InfopointReason::CALL() == reason || InfopointReason::IMPLICIT_EXCEPTION() == reason) { + TRACE_jvmci_4("safepoint at %i", pc_offset); + site_Safepoint(buffer, pc_offset, site); + } else { + // if the infopoint is not an actual safepoint, it must have one of the other reasons + // (safeguard against new safepoint types that require handling above) + assert(InfopointReason::METHOD_START() == reason || InfopointReason::METHOD_END() == reason || InfopointReason::LINE_NUMBER() == reason, ""); + site_Infopoint(buffer, pc_offset, site); + } + } else if (site->is_a(CompilationResult_DataPatch::klass())) { + TRACE_jvmci_4("datapatch at %i", pc_offset); + site_DataPatch(buffer, pc_offset, site); + } else if (site->is_a(CompilationResult_Mark::klass())) { + TRACE_jvmci_4("mark at %i", pc_offset); + site_Mark(buffer, pc_offset, site); + } else { + fatal("unexpected Site subclass"); + } + last_pc_offset = pc_offset; + } + if (CodeInstallSafepointChecks && SafepointSynchronize::do_call_back()) { + // this is a hacky way to force a safepoint check but nothing else was jumping out at me. + ThreadToNativeFromVM ttnfv(JavaThread::current()); + } + } + +#ifndef PRODUCT + if (comments() != NULL) { + No_Safepoint_Verifier no_safepoint; + for (int i = 0; i < comments()->length(); i++) { + oop comment = comments()->obj_at(i); + assert(comment->is_a(HotSpotCompiledCode_Comment::klass()), "cce"); + jint offset = HotSpotCompiledCode_Comment::pcOffset(comment); + char* text = java_lang_String::as_utf8_string(HotSpotCompiledCode_Comment::text(comment)); + buffer.block_comment(offset, text); + } + } +#endif + return JVMCIEnv::ok; +} + +void CodeInstaller::assumption_NoFinalizableSubclass(Handle assumption) { + Handle receiverType_handle = Assumptions_NoFinalizableSubclass::receiverType(assumption()); + Klass* receiverType = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(receiverType_handle)); + _dependencies->assert_has_no_finalizable_subclasses(receiverType); +} + +void CodeInstaller::assumption_ConcreteSubtype(Handle assumption) { + Handle context_handle = Assumptions_ConcreteSubtype::context(assumption()); + Handle subtype_handle = Assumptions_ConcreteSubtype::subtype(assumption()); + Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); + Klass* subtype = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(subtype_handle)); + + assert(context->is_abstract(), ""); + _dependencies->assert_abstract_with_unique_concrete_subtype(context, subtype); +} + +void CodeInstaller::assumption_LeafType(Handle assumption) { + Handle context_handle = Assumptions_LeafType::context(assumption()); + Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); + + _dependencies->assert_leaf_type(context); +} + +void CodeInstaller::assumption_ConcreteMethod(Handle assumption) { + Handle impl_handle = Assumptions_ConcreteMethod::impl(assumption()); + Handle context_handle = Assumptions_ConcreteMethod::context(assumption()); + + methodHandle impl = getMethodFromHotSpotMethod(impl_handle()); + Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); + + _dependencies->assert_unique_concrete_method(context, impl()); +} + +void CodeInstaller::assumption_CallSiteTargetValue(Handle assumption) { + Handle callSite = Assumptions_CallSiteTargetValue::callSite(assumption()); + Handle methodHandle = Assumptions_CallSiteTargetValue::methodHandle(assumption()); + + _dependencies->assert_call_site_target_value(callSite(), methodHandle()); +} + +void CodeInstaller::process_exception_handlers() { + if (exception_handlers() != NULL) { + objArrayOop handlers = exception_handlers(); + for (int i = 0; i < handlers->length(); i++) { + oop exc = handlers->obj_at(i); + jint pc_offset = CompilationResult_Site::pcOffset(exc); + jint handler_offset = CompilationResult_ExceptionHandler::handlerPos(exc); + + // Subtable header + _exception_handler_table.add_entry(HandlerTableEntry(1, pc_offset, 0)); + + // Subtable entry + _exception_handler_table.add_entry(HandlerTableEntry(-1, handler_offset, 0)); + } + } +} + +// If deoptimization happens, the interpreter should reexecute these bytecodes. +// This function mainly helps the compilers to set up the reexecute bit. +static bool bytecode_should_reexecute(Bytecodes::Code code) { + switch (code) { + case Bytecodes::_invokedynamic: + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + return false; + default: + return true; + } + return true; +} + +GrowableArray* CodeInstaller::record_virtual_objects(oop debug_info) { + objArrayOop virtualObjects = DebugInfo::virtualObjectMapping(debug_info); + if (virtualObjects == NULL) { + return NULL; + } + GrowableArray* objects = new GrowableArray(virtualObjects->length(), virtualObjects->length(), NULL); + // Create the unique ObjectValues + for (int i = 0; i < virtualObjects->length(); i++) { + oop value = virtualObjects->obj_at(i); + int id = VirtualObject::id(value); + oop type = VirtualObject::type(value); + oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type); + ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror))); + assert(objects->at(id) == NULL, "once"); + objects->at_put(id, sv); + } + // All the values which could be referenced by the VirtualObjects + // exist, so now describe all the VirtualObjects themselves. + for (int i = 0; i < virtualObjects->length(); i++) { + oop value = virtualObjects->obj_at(i); + int id = VirtualObject::id(value); + record_object_value(objects->at(id)->as_ObjectValue(), value, objects); + } + _debug_recorder->dump_object_pool(objects); + return objects; +} + +void CodeInstaller::record_scope(jint pc_offset, oop debug_info) { + oop position = DebugInfo::bytecodePosition(debug_info); + if (position == NULL) { + // Stubs do not record scope info, just oop maps + return; + } + + GrowableArray* objectMapping = record_virtual_objects(debug_info); + record_scope(pc_offset, position, objectMapping); +} + +void CodeInstaller::record_scope(jint pc_offset, oop position, GrowableArray* objects) { + oop frame = NULL; + if (position->is_a(BytecodeFrame::klass())) { + frame = position; + } + oop caller_frame = BytecodePosition::caller(position); + if (caller_frame != NULL) { + record_scope(pc_offset, caller_frame, objects); + } + + oop hotspot_method = BytecodePosition::method(position); + Method* method = getMethodFromHotSpotMethod(hotspot_method); + jint bci = BytecodePosition::bci(position); + if (bci == BytecodeFrame::BEFORE_BCI()) { + bci = SynchronizationEntryBCI; + } + + TRACE_jvmci_2("Recording scope pc_offset=%d bci=%d method=%s", pc_offset, bci, method->name_and_sig_as_C_string()); + + bool reexecute = false; + if (frame != NULL) { + if (bci == SynchronizationEntryBCI){ + reexecute = false; + } else { + Bytecodes::Code code = Bytecodes::java_code_at(method, method->bcp_from(bci)); + reexecute = bytecode_should_reexecute(code); + if (frame != NULL) { + reexecute = (BytecodeFrame::duringCall(frame) == JNI_FALSE); + } + } + } + + DebugToken* locals_token = NULL; + DebugToken* expressions_token = NULL; + DebugToken* monitors_token = NULL; + bool throw_exception = false; + + if (frame != NULL) { + jint local_count = BytecodeFrame::numLocals(frame); + jint expression_count = BytecodeFrame::numStack(frame); + jint monitor_count = BytecodeFrame::numLocks(frame); + objArrayOop values = BytecodeFrame::values(frame); + objArrayOop slotKinds = BytecodeFrame::slotKinds(frame); + + assert(local_count + expression_count + monitor_count == values->length(), "unexpected values length"); + assert(local_count + expression_count == slotKinds->length(), "unexpected slotKinds length"); + + GrowableArray* locals = local_count > 0 ? new GrowableArray (local_count) : NULL; + GrowableArray* expressions = expression_count > 0 ? new GrowableArray (expression_count) : NULL; + GrowableArray* monitors = monitor_count > 0 ? new GrowableArray (monitor_count) : NULL; + + TRACE_jvmci_2("Scope at bci %d with %d values", bci, values->length()); + TRACE_jvmci_2("%d locals %d expressions, %d monitors", local_count, expression_count, monitor_count); + + for (jint i = 0; i < values->length(); i++) { + ScopeValue* second = NULL; + oop value = values->obj_at(i); + if (i < local_count) { + oop kind = slotKinds->obj_at(i); + BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); + ScopeValue* first = get_scope_value(value, type, objects, second); + if (second != NULL) { + locals->append(second); + } + locals->append(first); + } else if (i < local_count + expression_count) { + oop kind = slotKinds->obj_at(i); + BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); + ScopeValue* first = get_scope_value(value, type, objects, second); + if (second != NULL) { + expressions->append(second); + } + expressions->append(first); + } else { + monitors->append(get_monitor_value(value, objects)); + } + if (second != NULL) { + i++; + assert(i < values->length(), "double-slot value not followed by Value.ILLEGAL"); + assert(values->obj_at(i) == Value::ILLEGAL(), "double-slot value not followed by Value.ILLEGAL"); + } + } + + locals_token = _debug_recorder->create_scope_values(locals); + expressions_token = _debug_recorder->create_scope_values(expressions); + monitors_token = _debug_recorder->create_monitor_values(monitors); + + throw_exception = BytecodeFrame::rethrowException(frame) == JNI_TRUE; + } + + _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, false, + locals_token, expressions_token, monitors_token); +} + +void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site) { + oop debug_info = CompilationResult_Infopoint::debugInfo(site); + assert(debug_info != NULL, "debug info expected"); + + // address instruction = _instructions->start() + pc_offset; + // jint next_pc_offset = Assembler::locate_next_instruction(instruction) - _instructions->start(); + _debug_recorder->add_safepoint(pc_offset, create_oop_map(debug_info)); + record_scope(pc_offset, debug_info); + _debug_recorder->end_safepoint(pc_offset); +} + +void CodeInstaller::site_Infopoint(CodeBuffer& buffer, jint pc_offset, oop site) { + oop debug_info = CompilationResult_Infopoint::debugInfo(site); + assert(debug_info != NULL, "debug info expected"); + + _debug_recorder->add_non_safepoint(pc_offset); + record_scope(pc_offset, debug_info); + _debug_recorder->end_non_safepoint(pc_offset); +} + +void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, oop site) { + oop target = CompilationResult_Call::target(site); + InstanceKlass* target_klass = InstanceKlass::cast(target->klass()); + + oop hotspot_method = NULL; // JavaMethod + oop foreign_call = NULL; + + if (target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallTarget_klass())) { + foreign_call = target; + } else { + hotspot_method = target; + } + + oop debug_info = CompilationResult_Call::debugInfo(site); + + assert(!!hotspot_method ^ !!foreign_call, "Call site needs exactly one type"); + + NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset); + jint next_pc_offset = CodeInstaller::pd_next_offset(inst, pc_offset, hotspot_method); + + if (debug_info != NULL) { + _debug_recorder->add_safepoint(next_pc_offset, create_oop_map(debug_info)); + record_scope(next_pc_offset, debug_info); + } + + if (foreign_call != NULL) { + jlong foreign_call_destination = HotSpotForeignCallTarget::address(foreign_call); + CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination); + } else { // method != NULL + assert(hotspot_method != NULL, "unexpected JavaMethod"); + assert(debug_info != NULL, "debug info expected"); + + TRACE_jvmci_3("method call"); + CodeInstaller::pd_relocate_JavaMethod(hotspot_method, pc_offset); + if (_next_call_type == INVOKESTATIC || _next_call_type == INVOKESPECIAL) { + // Need a static call stub for transitions from compiled to interpreted. + CompiledStaticCall::emit_to_interp_stub(buffer, _instructions->start() + pc_offset); + } + } + + _next_call_type = INVOKE_INVALID; + + if (debug_info != NULL) { + _debug_recorder->end_safepoint(next_pc_offset); + } +} + +void CodeInstaller::site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site) { + oop reference = CompilationResult_DataPatch::reference(site); + if (reference->is_a(CompilationResult_ConstantReference::klass())) { + Handle constant = CompilationResult_ConstantReference::constant(reference); + if (constant->is_a(HotSpotObjectConstantImpl::klass())) { + pd_patch_OopConstant(pc_offset, constant); + } else if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { + record_metadata_in_patch(constant, _oop_recorder); + } else if (constant->is_a(HotSpotSentinelConstant::klass())) { + fatal("sentinel constant unsupported"); + } else { + fatal("unknown constant type in data patch"); + } + } else if (reference->is_a(CompilationResult_DataSectionReference::klass())) { + int data_offset = CompilationResult_DataSectionReference::offset(reference); + assert(0 <= data_offset && data_offset < _constants_size, "data offset 0x%X points outside data section (size 0x%X)", data_offset, _constants_size); + pd_patch_DataSectionReference(pc_offset, data_offset); + } else { + fatal("unknown data patch type"); + } +} + +void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, oop site) { + oop id_obj = CompilationResult_Mark::id(site); + + if (id_obj != NULL) { + assert(java_lang_boxing_object::is_instance(id_obj, T_INT), "Integer id expected"); + jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT)); + + address pc = _instructions->start() + pc_offset; + + switch (id) { + case UNVERIFIED_ENTRY: + _offsets.set_value(CodeOffsets::Entry, pc_offset); + break; + case VERIFIED_ENTRY: + _offsets.set_value(CodeOffsets::Verified_Entry, pc_offset); + break; + case OSR_ENTRY: + _offsets.set_value(CodeOffsets::OSR_Entry, pc_offset); + break; + case EXCEPTION_HANDLER_ENTRY: + _offsets.set_value(CodeOffsets::Exceptions, pc_offset); + break; + case DEOPT_HANDLER_ENTRY: + _offsets.set_value(CodeOffsets::Deopt, pc_offset); + break; + case INVOKEVIRTUAL: + case INVOKEINTERFACE: + case INLINE_INVOKE: + case INVOKESTATIC: + case INVOKESPECIAL: + _next_call_type = (MarkId) id; + _invoke_mark_pc = pc; + break; + case POLL_NEAR: + case POLL_FAR: + case POLL_RETURN_NEAR: + case POLL_RETURN_FAR: + pd_relocate_poll(pc, id); + break; + case CARD_TABLE_ADDRESS: + case HEAP_TOP_ADDRESS: + case HEAP_END_ADDRESS: + case NARROW_KLASS_BASE_ADDRESS: + case CRC_TABLE_ADDRESS: + break; + default: + ShouldNotReachHere(); + break; + } + } +} + diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp new file mode 100644 index 00000000000..b0d3016b645 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_CODE_INSTALLER_HPP +#define SHARE_VM_JVMCI_JVMCI_CODE_INSTALLER_HPP + +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "code/nativeInst.hpp" + +class RelocBuffer : public StackObj { + enum { stack_size = 1024 }; +public: + RelocBuffer() : _size(0), _buffer(0) {} + ~RelocBuffer(); + void ensure_size(size_t bytes); + void set_size(size_t bytes); + address begin() const; + size_t size() const { return _size; } +private: + size_t _size; + char _static_buffer[stack_size]; + char *_buffer; +}; + +class CodeMetadata { +public: + CodeMetadata() {} + + CodeBlob* get_code_blob() const { return _cb; } + + PcDesc* get_pc_desc() const { return _pc_desc; } + int get_nr_pc_desc() const { return _nr_pc_desc; } + + u_char* get_scopes_desc() const { return _scopes_desc; } + int get_scopes_size() const { return _nr_scopes_desc; } + + RelocBuffer* get_reloc_buffer() { return &_reloc_buffer; } + + ExceptionHandlerTable* get_exception_table() { return _exception_table; } + + void set_pc_desc(PcDesc* desc, int count) { + _pc_desc = desc; + _nr_pc_desc = count; + } + + void set_scopes(u_char* scopes, int size) { + _scopes_desc = scopes; + _nr_scopes_desc = size; + } + + void set_exception_table(ExceptionHandlerTable* table) { + _exception_table = table; + } + +private: + CodeBlob* _cb; + PcDesc* _pc_desc; + int _nr_pc_desc; + + u_char* _scopes_desc; + int _nr_scopes_desc; + + RelocBuffer _reloc_buffer; + ExceptionHandlerTable* _exception_table; +}; + +/* + * This class handles the conversion from a InstalledCode to a CodeBlob or an nmethod. + */ +class CodeInstaller : public StackObj { + friend class VMStructs; +private: + enum MarkId { + VERIFIED_ENTRY = 1, + UNVERIFIED_ENTRY = 2, + OSR_ENTRY = 3, + EXCEPTION_HANDLER_ENTRY = 4, + DEOPT_HANDLER_ENTRY = 5, + INVOKEINTERFACE = 6, + INVOKEVIRTUAL = 7, + INVOKESTATIC = 8, + INVOKESPECIAL = 9, + INLINE_INVOKE = 10, + POLL_NEAR = 11, + POLL_RETURN_NEAR = 12, + POLL_FAR = 13, + POLL_RETURN_FAR = 14, + CARD_TABLE_ADDRESS = 15, + HEAP_TOP_ADDRESS = 16, + HEAP_END_ADDRESS = 17, + NARROW_KLASS_BASE_ADDRESS = 18, + CRC_TABLE_ADDRESS = 19, + INVOKE_INVALID = -1 + }; + + Arena _arena; + + jobject _data_section_handle; + jobject _data_section_patches_handle; + jobject _sites_handle; + jobject _exception_handlers_handle; + CodeOffsets _offsets; + + jobject _code_handle; + jint _code_size; + jint _total_frame_size; + jint _custom_stack_area_offset; + jint _parameter_count; + jint _constants_size; +#ifndef PRODUCT + jobject _comments_handle; +#endif + + bool _has_wide_vector; + jobject _word_kind_handle; + + MarkId _next_call_type; + address _invoke_mark_pc; + + CodeSection* _instructions; + CodeSection* _constants; + + OopRecorder* _oop_recorder; + DebugInformationRecorder* _debug_recorder; + Dependencies* _dependencies; + ExceptionHandlerTable _exception_handler_table; + + static ConstantOopWriteValue* _oop_null_scope_value; + static ConstantIntValue* _int_m1_scope_value; + static ConstantIntValue* _int_0_scope_value; + static ConstantIntValue* _int_1_scope_value; + static ConstantIntValue* _int_2_scope_value; + static LocationValue* _illegal_value; + + jint pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method); + void pd_patch_OopConstant(int pc_offset, Handle& constant); + void pd_patch_DataSectionReference(int pc_offset, int data_offset); + void pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst); + void pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination); + void pd_relocate_JavaMethod(oop method, jint pc_offset); + void pd_relocate_poll(address pc, jint mark); + + objArrayOop sites() { return (objArrayOop) JNIHandles::resolve(_sites_handle); } + arrayOop code() { return (arrayOop) JNIHandles::resolve(_code_handle); } + arrayOop data_section() { return (arrayOop) JNIHandles::resolve(_data_section_handle); } + objArrayOop data_section_patches() { return (objArrayOop) JNIHandles::resolve(_data_section_patches_handle); } + objArrayOop exception_handlers() { return (objArrayOop) JNIHandles::resolve(_exception_handlers_handle); } +#ifndef PRODUCT + objArrayOop comments() { return (objArrayOop) JNIHandles::resolve(_comments_handle); } +#endif + + void record_resolved(oop obj); + + oop word_kind() { return (oop) JNIHandles::resolve(_word_kind_handle); } + +public: + CodeInstaller() : _arena(mtCompiler) {} + + JVMCIEnv::CodeInstallResult gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata); + JVMCIEnv::CodeInstallResult install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log); + + static address runtime_call_target_address(oop runtime_call); + static VMReg get_hotspot_reg(jint jvmciRegisterNumber); + static bool is_general_purpose_reg(VMReg hotspotRegister); + + const OopMapSet* oopMapSet() const { return _debug_recorder->_oopmaps; } + +protected: + Location::Type get_oop_type(oop value); + ScopeValue* get_scope_value(oop value, BasicType type, GrowableArray* objects, ScopeValue* &second); + MonitorValue* get_monitor_value(oop value, GrowableArray* objects); + + // extract the fields of the CompilationResult + void initialize_fields(oop target, oop target_method); + void initialize_dependencies(oop target_method, OopRecorder* oop_recorder); + + int estimate_stubs_size(); + + // perform data and call relocation on the CodeBuffer + JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer); + + void assumption_NoFinalizableSubclass(Handle assumption); + void assumption_ConcreteSubtype(Handle assumption); + void assumption_LeafType(Handle assumption); + void assumption_ConcreteMethod(Handle assumption); + void assumption_CallSiteTargetValue(Handle assumption); + + void site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site); + void site_Infopoint(CodeBuffer& buffer, jint pc_offset, oop site); + void site_Call(CodeBuffer& buffer, jint pc_offset, oop site); + void site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site); + void site_Mark(CodeBuffer& buffer, jint pc_offset, oop site); + + OopMap* create_oop_map(oop debug_info); + + void record_scope(jint pc_offset, oop debug_info); + void record_scope(jint pc_offset, oop code_pos, GrowableArray* objects); + void record_object_value(ObjectValue* sv, oop value, GrowableArray* objects); + + GrowableArray* record_virtual_objects(oop debug_info); + + void process_exception_handlers(); + int estimateStubSpace(int static_call_stubs); +}; + +/** + * Gets the Method metaspace object from a HotSpotResolvedJavaMethodImpl Java object. + */ +Method* getMethodFromHotSpotMethod(oop hotspot_method); + + + +#endif // SHARE_VM_JVMCI_JVMCI_CODE_INSTALLER_HPP diff --git a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp new file mode 100644 index 00000000000..ca747e6bc7c --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/handles.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "runtime/compilationPolicy.hpp" +#include "runtime/globals_extension.hpp" + +JVMCICompiler* JVMCICompiler::_instance = NULL; +elapsedTimer JVMCICompiler::_codeInstallTimer; + +JVMCICompiler::JVMCICompiler() : AbstractCompiler(jvmci) { + _bootstrapping = false; + _methodsCompiled = 0; + assert(_instance == NULL, "only one instance allowed"); + _instance = this; +} + +// Initialization +void JVMCICompiler::initialize() { + if (!UseCompiler || !EnableJVMCI || !UseJVMCICompiler || !should_perform_init()) { + return; + } + + set_state(initialized); + + // JVMCI is considered as application code so we need to + // stop the VM deferring compilation now. + CompilationPolicy::completed_vm_startup(); +} + +void JVMCICompiler::bootstrap() { +#ifndef PRODUCT + // We turn off CompileTheWorld so that compilation requests are not + // ignored during bootstrap or that JVMCI can be compiled by C1/C2. + FlagSetting ctwOff(CompileTheWorld, false); +#endif + + JavaThread* THREAD = JavaThread::current(); + _bootstrapping = true; + ResourceMark rm; + HandleMark hm; + if (PrintBootstrap) { + tty->print("Bootstrapping JVMCI"); + } + jlong start = os::javaTimeMillis(); + + Array* objectMethods = InstanceKlass::cast(SystemDictionary::Object_klass())->methods(); + // Initialize compile queue with a selected set of methods. + int len = objectMethods->length(); + for (int i = 0; i < len; i++) { + methodHandle mh = objectMethods->at(i); + if (!mh->is_native() && !mh->is_static() && !mh->is_initializer()) { + ResourceMark rm; + int hot_count = 10; // TODO: what's the appropriate value? + CompileBroker::compile_method(mh, InvocationEntryBci, CompLevel_full_optimization, mh, hot_count, "bootstrap", THREAD); + } + } + + int qsize; + bool first_round = true; + int z = 0; + do { + // Loop until there is something in the queue. + do { + os::sleep(THREAD, 100, true); + qsize = CompileBroker::queue_size(CompLevel_full_optimization); + } while (first_round && qsize == 0); + first_round = false; + if (PrintBootstrap) { + while (z < (_methodsCompiled / 100)) { + ++z; + tty->print_raw("."); + } + } + } while (qsize != 0); + + if (PrintBootstrap) { + tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)", os::javaTimeMillis() - start, _methodsCompiled); + } + _bootstrapping = false; +} + +void JVMCICompiler::compile_method(methodHandle method, int entry_bci, JVMCIEnv* env) { + JVMCI_EXCEPTION_CONTEXT + + bool is_osr = entry_bci != InvocationEntryBci; + if (_bootstrapping && is_osr) { + // no OSR compilations during bootstrap - the compiler is just too slow at this point, + // and we know that there are no endless loops + return; + } + + JVMCIRuntime::initialize_well_known_classes(CHECK_ABORT); + + HandleMark hm; + ResourceMark rm; + Handle receiver = JVMCIRuntime::get_HotSpotJVMCIRuntime(CHECK_ABORT); + + JavaValue method_result(T_OBJECT); + { + JavaCallArguments args; + args.push_long((jlong) (address) method()); + JavaCalls::call_static(&method_result, SystemDictionary::HotSpotResolvedJavaMethodImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::method_fromMetaspace_signature(), &args, CHECK_ABORT); + } + + JavaValue result(T_VOID); + JavaCallArguments args; + args.push_oop(receiver); + args.push_oop((oop)method_result.get_jobject()); + args.push_int(entry_bci); + args.push_long((jlong) (address) env); + args.push_int(env->task()->compile_id()); + JavaCalls::call_special(&result, receiver->klass(), vmSymbols::compileMethod_name(), vmSymbols::compileMethod_signature(), &args, CHECK_ABORT); + + _methodsCompiled++; +} + + +// Compilation entry point for methods +void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) { + ShouldNotReachHere(); +} + +// Print compilation timers and statistics +void JVMCICompiler::print_timers() { + print_compilation_timers(); +} + +// Print compilation timers and statistics +void JVMCICompiler::print_compilation_timers() { + TRACE_jvmci_1("JVMCICompiler::print_timers"); + tty->print_cr(" JVMCI code install time: %6.3f s", _codeInstallTimer.seconds()); +} diff --git a/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp new file mode 100644 index 00000000000..bf11cc528d4 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_COMPILER_HPP +#define SHARE_VM_JVMCI_JVMCI_COMPILER_HPP + +#include "compiler/abstractCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "utilities/exceptions.hpp" + +class JVMCICompiler : public AbstractCompiler { +private: + bool _bootstrapping; + + /** + * Number of methods compiled by JVMCI. This is not synchronized + * so may not be 100% accurate. + */ + volatile int _methodsCompiled; + + static JVMCICompiler* _instance; + + static elapsedTimer _codeInstallTimer; + +public: + JVMCICompiler(); + + static JVMCICompiler* instance(TRAPS) { + if (!EnableJVMCI) { + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled") + } + return _instance; + } + + virtual const char* name() { return "JVMCI"; } + + virtual bool supports_native() { return true; } + virtual bool supports_osr () { return true; } + + bool is_jvmci() { return true; } + bool is_c1 () { return false; } + bool is_c2 () { return false; } + + bool needs_stubs () { return false; } + + // Initialization + virtual void initialize(); + + void bootstrap(); + + // Compilation entry point for methods + virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci); + + void compile_method(methodHandle target, int entry_bci, JVMCIEnv* env); + + // Print compilation timers and statistics + virtual void print_timers(); + + // Print compilation statistics + void reset_compilation_stats(); + + // Print compilation timers and statistics + static void print_compilation_timers(); + + static elapsedTimer* codeInstallTimer() { return &_codeInstallTimer; } +}; + +#endif // SHARE_VM_JVMCI_JVMCI_COMPILER_HPP diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp new file mode 100644 index 00000000000..2430d33a3c8 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -0,0 +1,1370 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "code/codeCache.hpp" +#include "code/scopeDesc.hpp" +#include "interpreter/linkResolver.hpp" +#include "memory/oopFactory.hpp" +#include "oops/generateOopMap.hpp" +#include "oops/fieldStreams.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "runtime/fieldDescriptor.hpp" +#include "runtime/javaCalls.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "compiler/abstractCompiler.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/compilerOracle.hpp" +#include "compiler/disassembler.hpp" +#include "compiler/oopMap.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "gc/g1/heapRegion.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/deoptimization.hpp" +#include "runtime/vframe.hpp" +#include "runtime/vframe_hp.hpp" +#include "runtime/vmStructs.hpp" + + +// Entry to native method implementation that transitions current thread to '_thread_in_vm'. +#define C2V_VMENTRY(result_type, name, signature) \ + JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + TRACE_jvmci_1("CompilerToVM::" #name); \ + TRACE_CALL(result_type, jvmci_ ## name signature) \ + JVMCI_VM_ENTRY_MARK; \ + +#define C2V_END } + +oop CompilerToVM::get_jvmci_method(methodHandle method, TRAPS) { + if (method() != NULL) { + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_long((jlong) (address) method()); + JavaCalls::call_static(&result, SystemDictionary::HotSpotResolvedJavaMethodImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::method_fromMetaspace_signature(), &args, CHECK_NULL); + + return (oop)result.get_jobject(); + } + return NULL; +} + +oop CompilerToVM::get_jvmci_type(KlassHandle klass, TRAPS) { + if (klass() != NULL) { + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_oop(klass->java_mirror()); + JavaCalls::call_static(&result, SystemDictionary::HotSpotResolvedObjectTypeImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::klass_fromMetaspace_signature(), &args, CHECK_NULL); + + return (oop)result.get_jobject(); + } + return NULL; +} + +extern "C" { +extern VMStructEntry* gHotSpotVMStructs; +extern uint64_t gHotSpotVMStructEntryTypeNameOffset; +extern uint64_t gHotSpotVMStructEntryFieldNameOffset; +extern uint64_t gHotSpotVMStructEntryTypeStringOffset; +extern uint64_t gHotSpotVMStructEntryIsStaticOffset; +extern uint64_t gHotSpotVMStructEntryOffsetOffset; +extern uint64_t gHotSpotVMStructEntryAddressOffset; +extern uint64_t gHotSpotVMStructEntryArrayStride; + +extern VMTypeEntry* gHotSpotVMTypes; +extern uint64_t gHotSpotVMTypeEntryTypeNameOffset; +extern uint64_t gHotSpotVMTypeEntrySuperclassNameOffset; +extern uint64_t gHotSpotVMTypeEntryIsOopTypeOffset; +extern uint64_t gHotSpotVMTypeEntryIsIntegerTypeOffset; +extern uint64_t gHotSpotVMTypeEntryIsUnsignedOffset; +extern uint64_t gHotSpotVMTypeEntrySizeOffset; +extern uint64_t gHotSpotVMTypeEntryArrayStride; + +extern VMIntConstantEntry* gHotSpotVMIntConstants; +extern uint64_t gHotSpotVMIntConstantEntryNameOffset; +extern uint64_t gHotSpotVMIntConstantEntryValueOffset; +extern uint64_t gHotSpotVMIntConstantEntryArrayStride; + +extern VMLongConstantEntry* gHotSpotVMLongConstants; +extern uint64_t gHotSpotVMLongConstantEntryNameOffset; +extern uint64_t gHotSpotVMLongConstantEntryValueOffset; +extern uint64_t gHotSpotVMLongConstantEntryArrayStride; + +extern VMAddressEntry* gHotSpotVMAddresses; +extern uint64_t gHotSpotVMAddressEntryNameOffset; +extern uint64_t gHotSpotVMAddressEntryValueOffset; +extern uint64_t gHotSpotVMAddressEntryArrayStride; +} + +// FIXME This is only temporary until the GC code is changed. +bool CompilerToVM::_supports_inline_contig_alloc; +HeapWord** CompilerToVM::_heap_end_addr; +HeapWord** CompilerToVM::_heap_top_addr; + +/** + * We put all gHotSpotVM values in an array so we can read them easily from Java. + */ +static uintptr_t ciHotSpotVMData[28]; + +C2V_VMENTRY(jlong, initializeConfiguration, (JNIEnv *env, jobject)) + ciHotSpotVMData[0] = (uintptr_t) gHotSpotVMStructs; + ciHotSpotVMData[1] = gHotSpotVMStructEntryTypeNameOffset; + ciHotSpotVMData[2] = gHotSpotVMStructEntryFieldNameOffset; + ciHotSpotVMData[3] = gHotSpotVMStructEntryTypeStringOffset; + ciHotSpotVMData[4] = gHotSpotVMStructEntryIsStaticOffset; + ciHotSpotVMData[5] = gHotSpotVMStructEntryOffsetOffset; + ciHotSpotVMData[6] = gHotSpotVMStructEntryAddressOffset; + ciHotSpotVMData[7] = gHotSpotVMStructEntryArrayStride; + + ciHotSpotVMData[8] = (uintptr_t) gHotSpotVMTypes; + ciHotSpotVMData[9] = gHotSpotVMTypeEntryTypeNameOffset; + ciHotSpotVMData[10] = gHotSpotVMTypeEntrySuperclassNameOffset; + ciHotSpotVMData[11] = gHotSpotVMTypeEntryIsOopTypeOffset; + ciHotSpotVMData[12] = gHotSpotVMTypeEntryIsIntegerTypeOffset; + ciHotSpotVMData[13] = gHotSpotVMTypeEntryIsUnsignedOffset; + ciHotSpotVMData[14] = gHotSpotVMTypeEntrySizeOffset; + ciHotSpotVMData[15] = gHotSpotVMTypeEntryArrayStride; + + ciHotSpotVMData[16] = (uintptr_t) gHotSpotVMIntConstants; + ciHotSpotVMData[17] = gHotSpotVMIntConstantEntryNameOffset; + ciHotSpotVMData[18] = gHotSpotVMIntConstantEntryValueOffset; + ciHotSpotVMData[19] = gHotSpotVMIntConstantEntryArrayStride; + + ciHotSpotVMData[20] = (uintptr_t) gHotSpotVMLongConstants; + ciHotSpotVMData[21] = gHotSpotVMLongConstantEntryNameOffset; + ciHotSpotVMData[22] = gHotSpotVMLongConstantEntryValueOffset; + ciHotSpotVMData[23] = gHotSpotVMLongConstantEntryArrayStride; + + ciHotSpotVMData[24] = (uintptr_t) gHotSpotVMAddresses; + ciHotSpotVMData[25] = gHotSpotVMAddressEntryNameOffset; + ciHotSpotVMData[26] = gHotSpotVMAddressEntryValueOffset; + ciHotSpotVMData[27] = gHotSpotVMAddressEntryArrayStride; + + // FIXME This is only temporary until the GC code is changed. + CompilerToVM::_supports_inline_contig_alloc = Universe::heap()->supports_inline_contig_alloc(); + CompilerToVM::_heap_end_addr = CompilerToVM::_supports_inline_contig_alloc ? Universe::heap()->end_addr() : (HeapWord**) -1; + CompilerToVM::_heap_top_addr = CompilerToVM::_supports_inline_contig_alloc ? Universe::heap()->top_addr() : (HeapWord**) -1; + + return (jlong) (address) &ciHotSpotVMData; +C2V_END + +C2V_VMENTRY(jbyteArray, getBytecode, (JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + ResourceMark rm; + + int code_size = method->code_size(); + typeArrayOop reconstituted_code = oopFactory::new_byteArray(code_size, CHECK_NULL); + + guarantee(method->method_holder()->is_rewritten(), "Method's holder should be rewritten"); + // iterate over all bytecodes and replace non-Java bytecodes + + for (BytecodeStream s(method); s.next() != Bytecodes::_illegal; ) { + Bytecodes::Code code = s.code(); + Bytecodes::Code raw_code = s.raw_code(); + int bci = s.bci(); + int len = s.instruction_size(); + + // Restore original byte code. + reconstituted_code->byte_at_put(bci, (jbyte) (s.is_wide()? Bytecodes::_wide : code)); + if (len > 1) { + memcpy(reconstituted_code->byte_at_addr(bci + 1), s.bcp()+1, len-1); + } + + if (len > 1) { + // Restore the big-endian constant pool indexes. + // Cf. Rewriter::scan_method + switch (code) { + case Bytecodes::_getstatic: + case Bytecodes::_putstatic: + case Bytecodes::_getfield: + case Bytecodes::_putfield: + case Bytecodes::_invokevirtual: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokehandle: { + int cp_index = Bytes::get_native_u2((address) reconstituted_code->byte_at_addr(bci + 1)); + Bytes::put_Java_u2((address) reconstituted_code->byte_at_addr(bci + 1), (u2) cp_index); + break; + } + + case Bytecodes::_invokedynamic: + int cp_index = Bytes::get_native_u4((address) reconstituted_code->byte_at_addr(bci + 1)); + Bytes::put_Java_u4((address) reconstituted_code->byte_at_addr(bci + 1), (u4) cp_index); + break; + } + + // Not all ldc byte code are rewritten. + switch (raw_code) { + case Bytecodes::_fast_aldc: { + int cpc_index = reconstituted_code->byte_at(bci + 1) & 0xff; + int cp_index = method->constants()->object_to_cp_index(cpc_index); + assert(cp_index < method->constants()->length(), "sanity check"); + reconstituted_code->byte_at_put(bci + 1, (jbyte) cp_index); + break; + } + + case Bytecodes::_fast_aldc_w: { + int cpc_index = Bytes::get_native_u2((address) reconstituted_code->byte_at_addr(bci + 1)); + int cp_index = method->constants()->object_to_cp_index(cpc_index); + assert(cp_index < method->constants()->length(), "sanity check"); + Bytes::put_Java_u2((address) reconstituted_code->byte_at_addr(bci + 1), (u2) cp_index); + break; + } + } + } + } + + return (jbyteArray) JNIHandles::make_local(THREAD, reconstituted_code); +C2V_END + +C2V_VMENTRY(jint, getExceptionTableLength, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return method->exception_table_length(); +C2V_END + +C2V_VMENTRY(jlong, getExceptionTableStart, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + methodHandle method = CompilerToVM::asMethod(jvmci_method); + if (method->exception_table_length() == 0) { + return 0L; + } + return (jlong) (address) method->exception_table_start(); +C2V_END + +C2V_VMENTRY(jobject, getResolvedJavaMethodAtSlot, (JNIEnv *, jobject, jclass holder_handle, jint slot)) + oop java_class = JNIHandles::resolve(holder_handle); + Klass* holder = java_lang_Class::as_Klass(java_class); + methodHandle method = InstanceKlass::cast(holder)->method_with_idnum(slot); + oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +} + +C2V_VMENTRY(jobject, getResolvedJavaMethod, (JNIEnv *, jobject, jobject base, jlong offset)) + methodHandle method; + oop base_object = JNIHandles::resolve(base); + if (base_object == NULL) { + method = *((Method**)(offset)); + } else if (base_object->is_a(SystemDictionary::MemberName_klass())) { + method = (Method*) (intptr_t) base_object->long_field(offset); + } else if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + method = *((Method**)(HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object) + offset)); + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected type: %s", base_object->klass()->external_name())); + } + assert (method.is_null() || method->is_method(), "invalid read"); + oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +} + +C2V_VMENTRY(jobject, getConstantPool, (JNIEnv *, jobject, jobject base, jlong offset)) + constantPoolHandle cp; + oop base_object = JNIHandles::resolve(base); + jlong base_address = 0; + if (base_object != NULL) { + if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + base_address = HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotConstantPool_klass())) { + base_address = HotSpotConstantPool::metaspaceConstantPool(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { + base_address = (jlong) CompilerToVM::asKlass(base_object); + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected type: %s", base_object->klass()->external_name())); + } + } + cp = *((ConstantPool**) (intptr_t) (base_address + offset)); + if (!cp.is_null()) { + JavaValue method_result(T_OBJECT); + JavaCallArguments args; + args.push_long((jlong) (address) cp()); + JavaCalls::call_static(&method_result, SystemDictionary::HotSpotConstantPool_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::constantPool_fromMetaspace_signature(), &args, CHECK_NULL); + return JNIHandles::make_local(THREAD, (oop)method_result.get_jobject()); + } + return NULL; +} + +C2V_VMENTRY(jobject, getResolvedJavaType, (JNIEnv *, jobject, jobject base, jlong offset, jboolean compressed)) + KlassHandle klass; + oop base_object = JNIHandles::resolve(base); + jlong base_address = 0; + if (base_object != NULL && offset == oopDesc::klass_offset_in_bytes()) { + klass = base_object->klass(); + } else if (!compressed) { + if (base_object != NULL) { + if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + base_address = HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotConstantPool_klass())) { + base_address = HotSpotConstantPool::metaspaceConstantPool(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { + base_address = (jlong) CompilerToVM::asKlass(base_object); + } else if (base_object->is_a(SystemDictionary::Class_klass())) { + base_address = (jlong) (address) base_object; + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected arguments: %s " JLONG_FORMAT " %s", base_object->klass()->external_name(), offset, compressed ? "true" : "false")); + } + } + klass = *((Klass**) (intptr_t) (base_address + offset)); + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected arguments: %s " JLONG_FORMAT " %s", base_object->klass()->external_name(), offset, compressed ? "true" : "false")); + } + assert (klass.is_null() || klass->is_klass(), "invalid read"); + oop result = CompilerToVM::get_jvmci_type(klass, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +} + +C2V_VMENTRY(jobject, findUniqueConcreteMethod, (JNIEnv *, jobject, jobject jvmci_type, jobject jvmci_method)) + ResourceMark rm; + methodHandle method = CompilerToVM::asMethod(jvmci_method); + KlassHandle holder = CompilerToVM::asKlass(jvmci_type); + if (holder->is_interface()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Interface %s should be handled in Java code", holder->external_name())); + } + + methodHandle ucm; + { + MutexLocker locker(Compile_lock); + ucm = Dependencies::find_unique_concrete_method(holder(), method()); + } + oop result = CompilerToVM::get_jvmci_method(ucm, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jobject, getImplementor, (JNIEnv *, jobject, jobject jvmci_type)) + InstanceKlass* klass = (InstanceKlass*) CompilerToVM::asKlass(jvmci_type); + oop implementor = CompilerToVM::get_jvmci_type(klass->implementor(), CHECK_NULL); + return JNIHandles::make_local(THREAD, implementor); +C2V_END + +C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return method->is_ignored_by_security_stack_walk(); +C2V_END + +C2V_VMENTRY(jboolean, canInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return !method->is_not_compilable() && !CompilerOracle::should_not_inline(method) && !method->dont_inline(); +C2V_END + +C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return CompilerOracle::should_inline(method) || method->force_inline(); +C2V_END + +C2V_VMENTRY(jobject, lookupType, (JNIEnv*, jobject, jstring jname, jclass accessing_class, jboolean resolve)) + ResourceMark rm; + Handle name = JNIHandles::resolve(jname); + Symbol* class_name = java_lang_String::as_symbol(name, CHECK_0); + if (java_lang_String::length(name()) <= 1) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Primitive type %s should be handled in Java code", class_name->as_C_string())); + } + + Klass* resolved_klass = NULL; + Handle class_loader; + Handle protection_domain; + if (JNIHandles::resolve(accessing_class) == NULL) { + THROW_0(vmSymbols::java_lang_NullPointerException()); + } + Klass* accessing_klass = java_lang_Class::as_Klass(JNIHandles::resolve(accessing_class)); + class_loader = accessing_klass->class_loader(); + protection_domain = accessing_klass->protection_domain(); + + if (resolve) { + resolved_klass = SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, CHECK_0); + } else { + if (class_name->byte_at(0) == 'L' && + class_name->byte_at(class_name->utf8_length()-1) == ';') { + // This is a name from a signature. Strip off the trimmings. + // Call recursive to keep scope of strippedsym. + TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1, + class_name->utf8_length()-2, + CHECK_0); + resolved_klass = SystemDictionary::find(strippedsym, class_loader, protection_domain, CHECK_0); + } else if (FieldType::is_array(class_name)) { + FieldArrayInfo fd; + // dimension and object_key in FieldArrayInfo are assigned as a side-effect + // of this call + BasicType t = FieldType::get_array_info(class_name, fd, CHECK_0); + if (t == T_OBJECT) { + TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1+fd.dimension(), + class_name->utf8_length()-2-fd.dimension(), + CHECK_0); + // naked oop "k" is OK here -- we assign back into it + resolved_klass = SystemDictionary::find(strippedsym, + class_loader, + protection_domain, + CHECK_0); + if (resolved_klass != NULL) { + resolved_klass = resolved_klass->array_klass(fd.dimension(), CHECK_0); + } + } else { + resolved_klass = Universe::typeArrayKlassObj(t); + resolved_klass = TypeArrayKlass::cast(resolved_klass)->array_klass(fd.dimension(), CHECK_0); + } + } + } + Handle result = CompilerToVM::get_jvmci_type(resolved_klass, CHECK_NULL); + return JNIHandles::make_local(THREAD, result()); +C2V_END + +C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + oop result = cp->resolve_constant_at(index, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + return cp->name_and_type_ref_index_at(index); +C2V_END + +C2V_VMENTRY(jobject, lookupNameInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint which)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Handle sym = java_lang_String::create_from_symbol(cp->name_ref_at(which), CHECK_NULL); + return JNIHandles::make_local(THREAD, sym()); +C2V_END + +C2V_VMENTRY(jobject, lookupSignatureInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint which)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Handle sym = java_lang_String::create_from_symbol(cp->signature_ref_at(which), CHECK_NULL); + return JNIHandles::make_local(THREAD, sym()); +C2V_END + +C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + return cp->klass_ref_index_at(index); +C2V_END + +C2V_VMENTRY(jobject, resolveTypeInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Klass* resolved_klass = cp->klass_at(index, CHECK_NULL); + Handle klass = CompilerToVM::get_jvmci_type(resolved_klass, CHECK_NULL); + return JNIHandles::make_local(THREAD, klass()); +C2V_END + +C2V_VMENTRY(jobject, lookupKlassInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + KlassHandle loading_klass(cp->pool_holder()); + bool is_accessible = false; + KlassHandle klass = JVMCIEnv::get_klass_by_index(cp, index, is_accessible, loading_klass); + Symbol* symbol = NULL; + if (klass.is_null()) { + symbol = cp->klass_name_at(index); + } + Handle result; + if (!klass.is_null()) { + result = CompilerToVM::get_jvmci_type(klass, CHECK_NULL); + } else { + result = java_lang_String::create_from_symbol(symbol, CHECK_NULL); + } + return JNIHandles::make_local(THREAD, result()); +C2V_END + +C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, index); + return JNIHandles::make_local(THREAD, appendix_oop); +C2V_END + +C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + instanceKlassHandle pool_holder(cp->pool_holder()); + Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); + methodHandle method = JVMCIEnv::get_method_by_index(cp, index, bc, pool_holder); + oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + return cp->remap_instruction_operand_from_cache(index); +C2V_END + +C2V_VMENTRY(jobject, resolveFieldInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode, jlongArray info_handle)) + ResourceMark rm; + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF); + fieldDescriptor fd; + LinkInfo link_info(cp, index, CHECK_0); + LinkResolver::resolve_field(fd, link_info, Bytecodes::java_code(code), false, CHECK_0); + typeArrayOop info = (typeArrayOop) JNIHandles::resolve(info_handle); + assert(info != NULL && info->length() == 2, "must be"); + info->long_at_put(0, (jlong) fd.access_flags().as_int()); + info->long_at_put(1, (jlong) fd.offset()); + oop field_holder = CompilerToVM::get_jvmci_type(fd.field_holder(), CHECK_NULL); + return JNIHandles::make_local(THREAD, field_holder); +C2V_END + +C2V_VMENTRY(jint, getVtableIndexForInterfaceMethod, (JNIEnv *, jobject, jobject jvmci_type, jobject jvmci_method)) + ResourceMark rm; + Klass* klass = CompilerToVM::asKlass(jvmci_type); + Method* method = CompilerToVM::asMethod(jvmci_method); + if (klass->is_interface()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Interface %s should be handled in Java code", klass->external_name())); + } + if (!method->method_holder()->is_interface()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Method %s is not held by an interface, this case should be handled in Java code", method->name_and_sig_as_C_string())); + } + if (!InstanceKlass::cast(klass)->is_initialized()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Class %s must be initialized", klass->external_name())); + } + return LinkResolver::vtable_index_of_interface_method(klass, method); +C2V_END + +C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_type, jobject jvmci_method, jobject caller_jvmci_type)) + Klass* recv_klass = CompilerToVM::asKlass(receiver_jvmci_type); + Klass* caller_klass = CompilerToVM::asKlass(caller_jvmci_type); + Method* method = CompilerToVM::asMethod(jvmci_method); + + if (recv_klass->oop_is_array() || (InstanceKlass::cast(recv_klass)->is_linked())) { + Klass* holder_klass = method->method_holder(); + Symbol* method_name = method->name(); + Symbol* method_signature = method->signature(); + + if (holder_klass->is_interface()) { + // do link-time resolution to check all access rules. + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); + methodHandle resolved_method = LinkResolver::linktime_resolve_interface_method_or_null(link_info); + if (resolved_method.is_null() || resolved_method->is_private()) { + return NULL; + } + assert(recv_klass->is_subtype_of(holder_klass), ""); + // do actual lookup + methodHandle sel_method = LinkResolver::lookup_instance_method_in_klasses(recv_klass, resolved_method->name(), resolved_method->signature(), CHECK_AND_CLEAR_0); + oop result = CompilerToVM::get_jvmci_method(sel_method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); + } else { + // do link-time resolution to check all access rules. + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); + methodHandle resolved_method = LinkResolver::linktime_resolve_virtual_method_or_null(link_info); + if (resolved_method.is_null()) { + return NULL; + } + // do actual lookup (see LinkResolver::runtime_resolve_virtual_method) + int vtable_index = Method::invalid_vtable_index; + Method* selected_method; + + if (resolved_method->method_holder()->is_interface()) { // miranda method + vtable_index = LinkResolver::vtable_index_of_interface_method(holder_klass, resolved_method); + assert(vtable_index >= 0 , "we should have valid vtable index at this point"); + + InstanceKlass* inst = InstanceKlass::cast(recv_klass); + selected_method = inst->method_at_vtable(vtable_index); + } else { + // at this point we are sure that resolved_method is virtual and not + // a miranda method; therefore, it must have a valid vtable index. + assert(!resolved_method->has_itable_index(), ""); + vtable_index = resolved_method->vtable_index(); + // We could get a negative vtable_index for final methods, + // because as an optimization they are they are never put in the vtable, + // unless they override an existing method. + // If we do get a negative, it means the resolved method is the the selected + // method, and it can never be changed by an override. + if (vtable_index == Method::nonvirtual_vtable_index) { + assert(resolved_method->can_be_statically_bound(), "cannot override this method"); + selected_method = resolved_method(); + } else { + // recv_klass might be an arrayKlassOop but all vtables start at + // the same place. The cast is to avoid virtual call and assertion. + InstanceKlass* inst = (InstanceKlass*)recv_klass; + selected_method = inst->method_at_vtable(vtable_index); + } + } + oop result = CompilerToVM::get_jvmci_method(selected_method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); + } + } + return NULL; +C2V_END + +C2V_VMENTRY(jboolean, hasFinalizableSubclass,(JNIEnv *, jobject, jobject jvmci_type)) + Klass* klass = CompilerToVM::asKlass(jvmci_type); + assert(klass != NULL, "method must not be called for primitive types"); + return Dependencies::find_finalizable_subclass(klass) != NULL; +C2V_END + +C2V_VMENTRY(jobject, getClassInitializer, (JNIEnv *, jobject, jobject jvmci_type)) + InstanceKlass* klass = (InstanceKlass*) CompilerToVM::asKlass(jvmci_type); + oop result = CompilerToVM::get_jvmci_method(klass->class_initializer(), CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv*, jobject, jlong addr)) + address target_addr = (address) addr; + if (target_addr != 0x0) { + int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int)); + int64_t off_high = (int64_t)target_addr - ((int64_t)CodeCache::high_bound() + sizeof(int)); + return MAX2(ABS(off_low), ABS(off_high)); + } + return -1; +C2V_END + +C2V_VMENTRY(void, doNotInlineOrCompile,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + method->set_not_c1_compilable(); + method->set_not_c2_compilable(); + method->set_dont_inline(true); +C2V_END + +C2V_VMENTRY(jint, installCode, (JNIEnv *jniEnv, jobject, jobject target, jobject compiled_code, jobject installed_code, jobject speculation_log)) + ResourceMark rm; + HandleMark hm; + Handle target_handle = JNIHandles::resolve(target); + Handle compiled_code_handle = JNIHandles::resolve(compiled_code); + CodeBlob* cb = NULL; + Handle installed_code_handle = JNIHandles::resolve(installed_code); + Handle speculation_log_handle = JNIHandles::resolve(speculation_log); + + JVMCICompiler* compiler = JVMCICompiler::instance(CHECK_JNI_ERR); + + TraceTime install_time("installCode", JVMCICompiler::codeInstallTimer()); + CodeInstaller installer; + JVMCIEnv::CodeInstallResult result = installer.install(compiler, target_handle, compiled_code_handle, cb, installed_code_handle, speculation_log_handle); + + if (PrintCodeCacheOnCompilation) { + stringStream s; + // Dump code cache into a buffer before locking the tty, + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + CodeCache::print_summary(&s, false); + } + ttyLocker ttyl; + tty->print_raw_cr(s.as_string()); + } + + if (result != JVMCIEnv::ok) { + assert(cb == NULL, "should be"); + } else { + if (!installed_code_handle.is_null()) { + assert(installed_code_handle->is_a(InstalledCode::klass()), "wrong type"); + InstalledCode::set_address(installed_code_handle, (jlong) cb); + InstalledCode::set_version(installed_code_handle, InstalledCode::version(installed_code_handle) + 1); + if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { + HotSpotInstalledCode::set_size(installed_code_handle, cb->size()); + HotSpotInstalledCode::set_codeStart(installed_code_handle, (jlong) cb->code_begin()); + HotSpotInstalledCode::set_codeSize(installed_code_handle, cb->code_size()); + } + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL && installed_code_handle->is_scavengable()) { + assert(nm->detect_scavenge_root_oops(), "nm should be scavengable if installed_code is scavengable"); + if (!UseG1GC) { + assert(nm->on_scavenge_root_list(), "nm should be on scavengable list"); + } + } + } + } + return result; +C2V_END + +C2V_VMENTRY(jint, getMetadata, (JNIEnv *jniEnv, jobject, jobject target, jobject compiled_code, jobject metadata)) + ResourceMark rm; + HandleMark hm; + + Handle target_handle = JNIHandles::resolve(target); + Handle compiled_code_handle = JNIHandles::resolve(compiled_code); + Handle metadata_handle = JNIHandles::resolve(metadata); + + HotSpotOopMap::klass()->initialize(thread); + + CodeMetadata code_metadata; + CodeBlob *cb = NULL; + CodeInstaller installer; + + JVMCIEnv::CodeInstallResult result = installer.gather_metadata(target_handle, compiled_code_handle, code_metadata); //cb, pc_descs, nr_pc_descs, scopes_descs, scopes_size, reloc_buffer); + if (result != JVMCIEnv::ok) { + return result; + } + + if (code_metadata.get_nr_pc_desc() > 0) { + typeArrayHandle pcArrayOop = oopFactory::new_byteArray(sizeof(PcDesc) * code_metadata.get_nr_pc_desc(), CHECK_(JVMCIEnv::cache_full)); + memcpy(pcArrayOop->byte_at_addr(0), code_metadata.get_pc_desc(), sizeof(PcDesc) * code_metadata.get_nr_pc_desc()); + HotSpotMetaData::set_pcDescBytes(metadata_handle, pcArrayOop()); + } + + if (code_metadata.get_scopes_size() > 0) { + typeArrayHandle scopesArrayOop = oopFactory::new_byteArray(code_metadata.get_scopes_size(), CHECK_(JVMCIEnv::cache_full)); + memcpy(scopesArrayOop->byte_at_addr(0), code_metadata.get_scopes_desc(), code_metadata.get_scopes_size()); + HotSpotMetaData::set_scopesDescBytes(metadata_handle, scopesArrayOop()); + } + + RelocBuffer* reloc_buffer = code_metadata.get_reloc_buffer(); + typeArrayHandle relocArrayOop = oopFactory::new_byteArray((int) reloc_buffer->size(), CHECK_(JVMCIEnv::cache_full)); + if (reloc_buffer->size() > 0) { + memcpy(relocArrayOop->byte_at_addr(0), reloc_buffer->begin(), reloc_buffer->size()); + } + HotSpotMetaData::set_relocBytes(metadata_handle, relocArrayOop()); + + const OopMapSet* oopMapSet = installer.oopMapSet(); + { + ResourceMark mark; + ImmutableOopMapBuilder builder(oopMapSet); + int oopmap_size = builder.heap_size(); + typeArrayHandle oopMapArrayHandle = oopFactory::new_byteArray(oopmap_size, CHECK_(JVMCIEnv::cache_full)); + builder.generate_into((address) oopMapArrayHandle->byte_at_addr(0)); + HotSpotMetaData::set_oopMaps(metadata_handle, oopMapArrayHandle()); + } + + HotSpotMetaData::set_metadata(metadata_handle, NULL); + + ExceptionHandlerTable* handler = code_metadata.get_exception_table(); + int table_size = handler->size_in_bytes(); + typeArrayHandle exceptionArrayOop = oopFactory::new_byteArray(table_size, CHECK_(JVMCIEnv::cache_full)); + + if (table_size > 0) { + handler->copy_bytes_to((address) exceptionArrayOop->byte_at_addr(0)); + } + HotSpotMetaData::set_exceptionBytes(metadata_handle, exceptionArrayOop()); + + return result; +C2V_END + +C2V_VMENTRY(void, notifyCompilationStatistics, (JNIEnv *jniEnv, jobject, jint id, jobject hotspot_method, jboolean osr, jint processedBytecodes, jlong time, jlong timeUnitsPerSecond, jobject installed_code)) + JVMCICompiler* compiler = JVMCICompiler::instance(CHECK); + CompilerStatistics* stats = compiler->stats(); + + elapsedTimer timer = elapsedTimer(time, timeUnitsPerSecond); + if (osr) { + stats->_osr.update(timer, processedBytecodes); + } else { + stats->_standard.update(timer, processedBytecodes); + } + Handle installed_code_handle = JNIHandles::resolve(installed_code); + if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { + stats->_nmethods_size += HotSpotInstalledCode::size(installed_code_handle); + stats->_nmethods_code_size += HotSpotInstalledCode::codeSize(installed_code_handle); + } + + if (CITimeEach) { + methodHandle method = CompilerToVM::asMethod(hotspot_method); + float bytes_per_sec = 1.0 * processedBytecodes / timer.seconds(); + tty->print_cr("%3d seconds: %f bytes/sec: %f (bytes %d)", + id, timer.seconds(), bytes_per_sec, processedBytecodes); + } +C2V_END + +C2V_VMENTRY(void, resetCompilationStatistics, (JNIEnv *jniEnv, jobject)) + JVMCICompiler* compiler = JVMCICompiler::instance(CHECK); + CompilerStatistics* stats = compiler->stats(); + stats->_standard.reset(); + stats->_osr.reset(); +C2V_END + +C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv *jniEnv, jobject, jlong codeBlob)) + ResourceMark rm; + HandleMark hm; + + CodeBlob* cb = (CodeBlob*) (address) codeBlob; + if (cb == NULL) { + return NULL; + } + + // We don't want the stringStream buffer to resize during disassembly as it + // uses scoped resource memory. If a nested function called during disassembly uses + // a ResourceMark and the buffer expands within the scope of the mark, + // the buffer becomes garbage when that scope is exited. Experience shows that + // the disassembled code is typically about 10x the code size so a fixed buffer + // sized to 20x code size plus a fixed amount for header info should be sufficient. + int bufferSize = cb->code_size() * 20 + 1024; + char* buffer = NEW_RESOURCE_ARRAY(char, bufferSize); + stringStream st(buffer, bufferSize); + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + if (!nm->is_alive()) { + return NULL; + } + Disassembler::decode(nm, &st); + } else { + Disassembler::decode(cb, &st); + } + if (st.size() <= 0) { + return NULL; + } + + Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); + return JNIHandles::make_local(THREAD, result()); +C2V_END + +C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv*, jobject, jobject jvmci_method, int bci)) + ResourceMark rm; + HandleMark hm; + + methodHandle method = CompilerToVM::asMethod(jvmci_method); + oop element = java_lang_StackTraceElement::create(method, bci, CHECK_NULL); + return JNIHandles::make_local(THREAD, element); +C2V_END + +C2V_VMENTRY(jobject, executeInstalledCode, (JNIEnv*, jobject, jobject args, jobject hotspotInstalledCode)) + ResourceMark rm; + HandleMark hm; + + jlong nmethodValue = InstalledCode::address(hotspotInstalledCode); + if (nmethodValue == 0L) { + THROW_NULL(vmSymbols::jdk_vm_ci_code_InvalidInstalledCodeException()); + } + nmethod* nm = (nmethod*) (address) nmethodValue; + methodHandle mh = nm->method(); + Symbol* signature = mh->signature(); + JavaCallArguments jca(mh->size_of_parameters()); + + JavaArgumentUnboxer jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static()); + JavaValue result(jap.get_ret_type()); + jca.set_alternative_target(nm); + JavaCalls::call(&result, mh, &jca, CHECK_NULL); + + if (jap.get_ret_type() == T_VOID) { + return NULL; + } else if (jap.get_ret_type() == T_OBJECT || jap.get_ret_type() == T_ARRAY) { + return JNIHandles::make_local(THREAD, (oop) result.get_jobject()); + } else { + jvalue *value = (jvalue *) result.get_value_addr(); + // Narrow the value down if required (Important on big endian machines) + switch (jap.get_ret_type()) { + case T_BOOLEAN: + value->z = (jboolean) value->i; + break; + case T_BYTE: + value->b = (jbyte) value->i; + break; + case T_CHAR: + value->c = (jchar) value->i; + break; + case T_SHORT: + value->s = (jshort) value->i; + break; + } + oop o = java_lang_boxing_object::create(jap.get_ret_type(), value, CHECK_NULL); + return JNIHandles::make_local(THREAD, o); + } +C2V_END + +C2V_VMENTRY(jlongArray, getLineNumberTable, (JNIEnv *, jobject, jobject jvmci_method)) + Method* method = CompilerToVM::asMethod(jvmci_method); + if (!method->has_linenumber_table()) { + return NULL; + } + u2 num_entries = 0; + CompressedLineNumberReadStream streamForSize(method->compressed_linenumber_table()); + while (streamForSize.read_pair()) { + num_entries++; + } + + CompressedLineNumberReadStream stream(method->compressed_linenumber_table()); + typeArrayOop result = oopFactory::new_longArray(2 * num_entries, CHECK_NULL); + + int i = 0; + jlong value; + while (stream.read_pair()) { + value = ((long) stream.bci()); + result->long_at_put(i, value); + value = ((long) stream.line()); + result->long_at_put(i + 1, value); + i += 2; + } + + return (jlongArray) JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jlong, getLocalVariableTableStart, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + Method* method = CompilerToVM::asMethod(jvmci_method); + if (!method->has_localvariable_table()) { + return 0; + } + return (jlong) (address) method->localvariable_table_start(); +C2V_END + +C2V_VMENTRY(jint, getLocalVariableTableLength, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + Method* method = CompilerToVM::asMethod(jvmci_method); + return method->localvariable_table_length(); +C2V_END + +C2V_VMENTRY(void, reprofile, (JNIEnv*, jobject, jobject jvmci_method)) + Method* method = CompilerToVM::asMethod(jvmci_method); + MethodCounters* mcs = method->method_counters(); + if (mcs != NULL) { + mcs->clear_counters(); + } + NOT_PRODUCT(method->set_compiled_invocation_count(0)); + + nmethod* code = method->code(); + if (code != NULL) { + code->make_not_entrant(); + } + + MethodData* method_data = method->method_data(); + if (method_data == NULL) { + ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); + method_data = MethodData::allocate(loader_data, method, CHECK); + method->set_method_data(method_data); + } else { + method_data->initialize(); + } +C2V_END + + +C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv*, jobject, jobject hotspotInstalledCode)) + jlong nativeMethod = InstalledCode::address(hotspotInstalledCode); + nmethod* m = (nmethod*)nativeMethod; + if (m != NULL && !m->is_not_entrant()) { + m->mark_for_deoptimization(); + VM_Deoptimize op; + VMThread::execute(&op); + } + InstalledCode::set_address(hotspotInstalledCode, 0); +C2V_END + +C2V_VMENTRY(jobject, readUncompressedOop, (JNIEnv*, jobject, jlong addr)) + oop ret = oopDesc::load_decode_heap_oop((oop*)(address)addr); + return JNIHandles::make_local(THREAD, ret); +C2V_END + +C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv*, jobject)) + typeArrayOop arrayOop = oopFactory::new_longArray(JVMCICounterSize, CHECK_NULL); + JavaThread::collect_counters(arrayOop); + return (jlongArray) JNIHandles::make_local(THREAD, arrayOop); +C2V_END + +C2V_VMENTRY(int, allocateCompileId, (JNIEnv*, jobject, jobject jvmci_method, int entry_bci)) + HandleMark hm; + ResourceMark rm; + if (JNIHandles::resolve(jvmci_method) == NULL) { + THROW_0(vmSymbols::java_lang_NullPointerException()); + } + Method* method = CompilerToVM::asMethod(jvmci_method); + if (entry_bci >= method->code_size() || entry_bci < -1) { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Unexpected bci %d", entry_bci)); + } + return CompileBroker::assign_compile_id_unlocked(THREAD, method, entry_bci); +C2V_END + + +C2V_VMENTRY(jboolean, isMature, (JNIEnv*, jobject, jlong metaspace_method_data)) + MethodData* mdo = CompilerToVM::asMethodData(metaspace_method_data); + return mdo != NULL && mdo->is_mature(); +C2V_END + +C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv*, jobject, jobject jvmci_method, int entry_bci, int comp_level)) + Method* method = CompilerToVM::asMethod(jvmci_method); + return method->lookup_osr_nmethod_for(entry_bci, comp_level, true) != NULL; +C2V_END + +C2V_VMENTRY(jobject, getSymbol, (JNIEnv*, jobject, jlong symbol)) + Handle sym = java_lang_String::create_from_symbol((Symbol*)(address)symbol, CHECK_NULL); + return JNIHandles::make_local(THREAD, sym()); +C2V_END + +bool matches(jobjectArray methods, Method* method) { + objArrayOop methods_oop = (objArrayOop) JNIHandles::resolve(methods); + + for (int i = 0; i < methods_oop->length(); i++) { + if (CompilerToVM::asMethod(methods_oop->obj_at(i)) == method) { + return true; + } + } + return false; +} + +C2V_VMENTRY(jobject, getNextStackFrame, (JNIEnv*, jobject compilerToVM, jobject hs_frame, jobjectArray methods, jint initialSkip)) + ResourceMark rm; + + if (!thread->has_last_Java_frame()) return NULL; + Handle result = HotSpotStackFrameReference::klass()->allocate_instance(thread); + HotSpotStackFrameReference::klass()->initialize(thread); + + StackFrameStream fst(thread); + if (hs_frame != NULL) { + // look for the correct stack frame if one is given + intptr_t* stack_pointer = (intptr_t*) HotSpotStackFrameReference::stackPointer(hs_frame); + while (fst.current()->sp() != stack_pointer && !fst.is_done()) { + fst.next(); + } + if (fst.current()->sp() != stack_pointer) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "stack frame not found") + } + } + + int frame_number = 0; + vframe* vf = vframe::new_vframe(fst.current(), fst.register_map(), thread); + if (hs_frame != NULL) { + // look for the correct vframe within the stack frame if one is given + int last_frame_number = HotSpotStackFrameReference::frameNumber(hs_frame); + while (frame_number < last_frame_number) { + if (vf->is_top()) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "invalid frame number") + } + vf = vf->sender(); + frame_number ++; + } + // move one frame forward + if (vf->is_top()) { + if (fst.is_done()) { + return NULL; + } + fst.next(); + vf = vframe::new_vframe(fst.current(), fst.register_map(), thread); + frame_number = 0; + } else { + vf = vf->sender(); + frame_number++; + } + } + + while (true) { + // look for the given method + while (true) { + StackValueCollection* locals = NULL; + if (vf->is_compiled_frame()) { + // compiled method frame + compiledVFrame* cvf = compiledVFrame::cast(vf); + if (methods == NULL || matches(methods, cvf->method())) { + if (initialSkip > 0) { + initialSkip --; + } else { + ScopeDesc* scope = cvf->scope(); + // native wrapper do not have a scope + if (scope != NULL && scope->objects() != NULL) { + bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), scope->objects(), THREAD); + Deoptimization::reassign_fields(fst.current(), fst.register_map(), scope->objects(), realloc_failures, false); + + GrowableArray* local_values = scope->locals(); + typeArrayHandle array = oopFactory::new_boolArray(local_values->length(), thread); + for (int i = 0; i < local_values->length(); i++) { + ScopeValue* value = local_values->at(i); + if (value->is_object()) { + array->bool_at_put(i, true); + } + } + HotSpotStackFrameReference::set_localIsVirtual(result, array()); + } else { + HotSpotStackFrameReference::set_localIsVirtual(result, NULL); + } + + locals = cvf->locals(); + HotSpotStackFrameReference::set_bci(result, cvf->bci()); + oop method = CompilerToVM::get_jvmci_method(cvf->method(), CHECK_NULL); + HotSpotStackFrameReference::set_method(result, method); + } + } + } else if (vf->is_interpreted_frame()) { + // interpreted method frame + interpretedVFrame* ivf = interpretedVFrame::cast(vf); + if (methods == NULL || matches(methods, ivf->method())) { + if (initialSkip > 0) { + initialSkip --; + } else { + locals = ivf->locals(); + HotSpotStackFrameReference::set_bci(result, ivf->bci()); + oop method = CompilerToVM::get_jvmci_method(ivf->method(), CHECK_NULL); + HotSpotStackFrameReference::set_method(result, method); + HotSpotStackFrameReference::set_localIsVirtual(result, NULL); + } + } + } + + // locals != NULL means that we found a matching frame and result is already partially initialized + if (locals != NULL) { + HotSpotStackFrameReference::set_compilerToVM(result, JNIHandles::resolve(compilerToVM)); + HotSpotStackFrameReference::set_stackPointer(result, (jlong) fst.current()->sp()); + HotSpotStackFrameReference::set_frameNumber(result, frame_number); + + // initialize the locals array + objArrayHandle array = oopFactory::new_objectArray(locals->size(), thread); + for (int i = 0; i < locals->size(); i++) { + StackValue* var = locals->at(i); + if (var->type() == T_OBJECT) { + array->obj_at_put(i, locals->at(i)->get_obj()()); + } + } + HotSpotStackFrameReference::set_locals(result, array()); + + return JNIHandles::make_local(thread, result()); + } + + if (vf->is_top()) { + break; + } + frame_number++; + vf = vf->sender(); + } // end of vframe loop + + if (fst.is_done()) { + break; + } + fst.next(); + vf = vframe::new_vframe(fst.current(), fst.register_map(), thread); + frame_number = 0; + } // end of frame loop + + // the end was reached without finding a matching method + return NULL; +C2V_END + +C2V_VMENTRY(void, resolveInvokeDynamicInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + CallInfo callInfo; + LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, Bytecodes::_invokedynamic, CHECK); + ConstantPoolCacheEntry* cp_cache_entry = cp->invokedynamic_cp_cache_entry_at(index); + cp_cache_entry->set_dynamic_call(cp, callInfo); +C2V_END + +C2V_VMENTRY(void, resolveInvokeHandleInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + CallInfo callInfo; + LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, Bytecodes::_invokehandle, CHECK); + ConstantPoolCacheEntry* cp_cache_entry = cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index)); + cp_cache_entry->set_method_handle(cp, callInfo); +C2V_END + +C2V_VMENTRY(jboolean, shouldDebugNonSafepoints, (JNIEnv*, jobject)) + //see compute_recording_non_safepoints in debugInfroRec.cpp + if (JvmtiExport::should_post_compiled_method_load() && FLAG_IS_DEFAULT(DebugNonSafepoints)) { + return true; + } + return DebugNonSafepoints; +C2V_END + +// public native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate); +C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame, bool invalidate)) + ResourceMark rm; + + if (hs_frame == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), "stack frame is null") + } + + HotSpotStackFrameReference::klass()->initialize(thread); + + // look for the given stack frame + StackFrameStream fst(thread); + intptr_t* stack_pointer = (intptr_t*) HotSpotStackFrameReference::stackPointer(hs_frame); + while (fst.current()->sp() != stack_pointer && !fst.is_done()) { + fst.next(); + } + if (fst.current()->sp() != stack_pointer) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "stack frame not found") + } + + if (invalidate) { + if (!fst.current()->is_compiled_frame()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "compiled stack frame expected") + } + assert(fst.current()->cb()->is_nmethod(), "nmethod expected"); + ((nmethod*) fst.current()->cb())->make_not_entrant(); + } + Deoptimization::deoptimize(thread, *fst.current(), fst.register_map(), Deoptimization::Reason_none); + // look for the frame again as it has been updated by deopt (pc, deopt state...) + StackFrameStream fstAfterDeopt(thread); + while (fstAfterDeopt.current()->sp() != stack_pointer && !fstAfterDeopt.is_done()) { + fstAfterDeopt.next(); + } + if (fstAfterDeopt.current()->sp() != stack_pointer) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "stack frame not found after deopt") + } + + vframe* vf = vframe::new_vframe(fstAfterDeopt.current(), fstAfterDeopt.register_map(), thread); + if (!vf->is_compiled_frame()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "compiled stack frame expected") + } + + GrowableArray* virtualFrames = new GrowableArray(10); + while (true) { + assert(vf->is_compiled_frame(), "Wrong frame type"); + virtualFrames->push(compiledVFrame::cast(vf)); + if (vf->is_top()) { + break; + } + vf = vf->sender(); + } + + int last_frame_number = HotSpotStackFrameReference::frameNumber(hs_frame); + if (last_frame_number >= virtualFrames->length()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "invalid frame number") + } + + // Reallocate the non-escaping objects and restore their fields. + assert (virtualFrames->at(last_frame_number)->scope() != NULL,"invalid scope"); + GrowableArray* objects = virtualFrames->at(last_frame_number)->scope()->objects(); + + if (objects == NULL) { + // no objects to materialize + return; + } + + bool realloc_failures = Deoptimization::realloc_objects(thread, fstAfterDeopt.current(), objects, THREAD); + Deoptimization::reassign_fields(fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, realloc_failures, false); + + for (int frame_index = 0; frame_index < virtualFrames->length(); frame_index++) { + compiledVFrame* cvf = virtualFrames->at(frame_index); + + GrowableArray* scopeLocals = cvf->scope()->locals(); + StackValueCollection* locals = cvf->locals(); + + if (locals != NULL) { + for (int i2 = 0; i2 < locals->size(); i2++) { + StackValue* var = locals->at(i2); + if (var->type() == T_OBJECT && scopeLocals->at(i2)->is_object()) { + jvalue val; + val.l = (jobject) locals->at(i2)->get_obj()(); + cvf->update_local(T_OBJECT, i2, val); + } + } + } + } + + // all locals are materialized by now + HotSpotStackFrameReference::set_localIsVirtual(hs_frame, NULL); + + // update the locals array + objArrayHandle array = HotSpotStackFrameReference::locals(hs_frame); + StackValueCollection* locals = virtualFrames->at(last_frame_number)->locals(); + for (int i = 0; i < locals->size(); i++) { + StackValue* var = locals->at(i); + if (var->type() == T_OBJECT) { + array->obj_at_put(i, locals->at(i)->get_obj()()); + } + } +C2V_END + +C2V_VMENTRY(void, writeDebugOutput, (JNIEnv*, jobject, jbyteArray bytes, jint offset, jint length)) + if (bytes == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + typeArrayOop array = (typeArrayOop) JNIHandles::resolve(bytes); + + // Check if offset and length are non negative. + if (offset < 0 || length < 0) { + THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); + } + // Check if the range is valid. + if ((((unsigned int) length + (unsigned int) offset) > (unsigned int) array->length())) { + THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); + } + while (length > 0) { + jbyte* start = array->byte_at_addr(offset); + tty->write((char*) start, MIN2(length, O_BUFLEN)); + length -= O_BUFLEN; + offset += O_BUFLEN; + } +C2V_END + +C2V_VMENTRY(void, flushDebugOutput, (JNIEnv*, jobject)) + tty->flush(); +C2V_END + + +#define CC (char*) /*cast a literal from (const char*)*/ +#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) + +#define SPECULATION_LOG "Ljdk/vm/ci/meta/SpeculationLog;" +#define STRING "Ljava/lang/String;" +#define OBJECT "Ljava/lang/Object;" +#define CLASS "Ljava/lang/Class;" +#define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" +#define INSTALLED_CODE "Ljdk/vm/ci/code/InstalledCode;" +#define TARGET_DESCRIPTION "Ljdk/vm/ci/code/TargetDescription;" +#define RESOLVED_METHOD "Ljdk/vm/ci/meta/ResolvedJavaMethod;" +#define HS_RESOLVED_METHOD "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;" +#define HS_RESOLVED_KLASS "Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;" +#define HS_CONSTANT_POOL "Ljdk/vm/ci/hotspot/HotSpotConstantPool;" +#define HS_COMPILED_CODE "Ljdk/vm/ci/hotspot/HotSpotCompiledCode;" +#define HS_METADATA "Ljdk/vm/ci/hotspot/HotSpotMetaData;" +#define HS_STACK_FRAME_REF "Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;" +#define METASPACE_METHOD_DATA "J" + +JNINativeMethod CompilerToVM::methods[] = { + {CC"getBytecode", CC"("HS_RESOLVED_METHOD")[B", FN_PTR(getBytecode)}, + {CC"getExceptionTableStart", CC"("HS_RESOLVED_METHOD")J", FN_PTR(getExceptionTableStart)}, + {CC"getExceptionTableLength", CC"("HS_RESOLVED_METHOD")I", FN_PTR(getExceptionTableLength)}, + {CC"findUniqueConcreteMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD")"HS_RESOLVED_METHOD, FN_PTR(findUniqueConcreteMethod)}, + {CC"getImplementor", CC"("HS_RESOLVED_KLASS")"HS_RESOLVED_KLASS, FN_PTR(getImplementor)}, + {CC"getStackTraceElement", CC"("HS_RESOLVED_METHOD"I)"STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, + {CC"methodIsIgnoredBySecurityStackWalk", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, + {CC"doNotInlineOrCompile", CC"("HS_RESOLVED_METHOD")V", FN_PTR(doNotInlineOrCompile)}, + {CC"canInlineMethod", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(canInlineMethod)}, + {CC"shouldInlineMethod", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(shouldInlineMethod)}, + {CC"lookupType", CC"("STRING CLASS"Z)"HS_RESOLVED_KLASS, FN_PTR(lookupType)}, + {CC"lookupNameInPool", CC"("HS_CONSTANT_POOL"I)"STRING, FN_PTR(lookupNameInPool)}, + {CC"lookupNameAndTypeRefIndexInPool", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, + {CC"lookupSignatureInPool", CC"("HS_CONSTANT_POOL"I)"STRING, FN_PTR(lookupSignatureInPool)}, + {CC"lookupKlassRefIndexInPool", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(lookupKlassRefIndexInPool)}, + {CC"lookupKlassInPool", CC"("HS_CONSTANT_POOL"I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)}, + {CC"lookupAppendixInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(lookupAppendixInPool)}, + {CC"lookupMethodInPool", CC"("HS_CONSTANT_POOL"IB)"HS_RESOLVED_METHOD, FN_PTR(lookupMethodInPool)}, + {CC"constantPoolRemapInstructionOperandFromCache", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)}, + {CC"resolveConstantInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolveConstantInPool)}, + {CC"resolvePossiblyCachedConstantInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)}, + {CC"resolveTypeInPool", CC"("HS_CONSTANT_POOL"I)"HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)}, + {CC"resolveFieldInPool", CC"("HS_CONSTANT_POOL"IB[J)"HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)}, + {CC"resolveInvokeDynamicInPool", CC"("HS_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeDynamicInPool)}, + {CC"resolveInvokeHandleInPool", CC"("HS_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeHandleInPool)}, + {CC"resolveMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD HS_RESOLVED_KLASS")"HS_RESOLVED_METHOD, FN_PTR(resolveMethod)}, + {CC"getVtableIndexForInterfaceMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD")I", FN_PTR(getVtableIndexForInterfaceMethod)}, + {CC"getClassInitializer", CC"("HS_RESOLVED_KLASS")"HS_RESOLVED_METHOD, FN_PTR(getClassInitializer)}, + {CC"hasFinalizableSubclass", CC"("HS_RESOLVED_KLASS")Z", FN_PTR(hasFinalizableSubclass)}, + {CC"getMaxCallTargetOffset", CC"(J)J", FN_PTR(getMaxCallTargetOffset)}, + {CC"getResolvedJavaMethodAtSlot", CC"("CLASS"I)"HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethodAtSlot)}, + {CC"getResolvedJavaMethod", CC"(Ljava/lang/Object;J)"HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethod)}, + {CC"getConstantPool", CC"(Ljava/lang/Object;J)"HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, + {CC"getResolvedJavaType", CC"(Ljava/lang/Object;JZ)"HS_RESOLVED_KLASS, FN_PTR(getResolvedJavaType)}, + {CC"initializeConfiguration", CC"()J", FN_PTR(initializeConfiguration)}, + {CC"installCode", CC"("TARGET_DESCRIPTION HS_COMPILED_CODE INSTALLED_CODE SPECULATION_LOG")I", FN_PTR(installCode)}, + {CC"getMetadata", CC"("TARGET_DESCRIPTION HS_COMPILED_CODE HS_METADATA")I", FN_PTR(getMetadata)}, + {CC"notifyCompilationStatistics", CC"(I"HS_RESOLVED_METHOD"ZIJJ"INSTALLED_CODE")V", FN_PTR(notifyCompilationStatistics)}, + {CC"resetCompilationStatistics", CC"()V", FN_PTR(resetCompilationStatistics)}, + {CC"disassembleCodeBlob", CC"(J)"STRING, FN_PTR(disassembleCodeBlob)}, + {CC"executeInstalledCode", CC"(["OBJECT INSTALLED_CODE")"OBJECT, FN_PTR(executeInstalledCode)}, + {CC"getLineNumberTable", CC"("HS_RESOLVED_METHOD")[J", FN_PTR(getLineNumberTable)}, + {CC"getLocalVariableTableStart", CC"("HS_RESOLVED_METHOD")J", FN_PTR(getLocalVariableTableStart)}, + {CC"getLocalVariableTableLength", CC"("HS_RESOLVED_METHOD")I", FN_PTR(getLocalVariableTableLength)}, + {CC"reprofile", CC"("HS_RESOLVED_METHOD")V", FN_PTR(reprofile)}, + {CC"invalidateInstalledCode", CC"("INSTALLED_CODE")V", FN_PTR(invalidateInstalledCode)}, + {CC"readUncompressedOop", CC"(J)"OBJECT, FN_PTR(readUncompressedOop)}, + {CC"collectCounters", CC"()[J", FN_PTR(collectCounters)}, + {CC"allocateCompileId", CC"("HS_RESOLVED_METHOD"I)I", FN_PTR(allocateCompileId)}, + {CC"isMature", CC"("METASPACE_METHOD_DATA")Z", FN_PTR(isMature)}, + {CC"hasCompiledCodeForOSR", CC"("HS_RESOLVED_METHOD"II)Z", FN_PTR(hasCompiledCodeForOSR)}, + {CC"getSymbol", CC"(J)"STRING, FN_PTR(getSymbol)}, + {CC"getNextStackFrame", CC"("HS_STACK_FRAME_REF "["HS_RESOLVED_METHOD"I)"HS_STACK_FRAME_REF, FN_PTR(getNextStackFrame)}, + {CC"materializeVirtualObjects", CC"("HS_STACK_FRAME_REF"Z)V", FN_PTR(materializeVirtualObjects)}, + {CC"shouldDebugNonSafepoints", CC"()Z", FN_PTR(shouldDebugNonSafepoints)}, + {CC"writeDebugOutput", CC"([BII)V", FN_PTR(writeDebugOutput)}, + {CC"flushDebugOutput", CC"()V", FN_PTR(flushDebugOutput)}, +}; + +int CompilerToVM::methods_count() { + return sizeof(methods) / sizeof(JNINativeMethod); +} + diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp new file mode 100644 index 00000000000..bf6cc6bb3a0 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP +#define SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP + +#include "prims/jni.h" +#include "runtime/javaCalls.hpp" +#include "jvmci/jvmciJavaClasses.hpp" + +class CompilerToVM { +public: + /** + * Tag bits used by lookupKlassInPool to distinguish the types in Java. + */ + enum Tags { + KLASS_TAG = 0x0, + SYMBOL_TAG = 0x1 + }; + + // FIXME This is only temporary until the GC code is changed. + static bool _supports_inline_contig_alloc; + static HeapWord** _heap_end_addr; + static HeapWord** _heap_top_addr; + + static intptr_t tag_pointer(Klass* klass) { + return ((intptr_t) klass) | KLASS_TAG; + } + + static intptr_t tag_pointer(Symbol* symbol) { + return ((intptr_t) symbol) | SYMBOL_TAG; + } + + static JNINativeMethod methods[]; + static int methods_count(); + + static inline Method* asMethod(jobject jvmci_method) { + return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); + } + + static inline Method* asMethod(Handle jvmci_method) { + return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); + } + + static inline Method* asMethod(oop jvmci_method) { + return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); + } + + static inline ConstantPool* asConstantPool(jobject jvmci_constant_pool) { + return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); + } + + static inline ConstantPool* asConstantPool(Handle jvmci_constant_pool) { + return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); + } + + static inline ConstantPool* asConstantPool(oop jvmci_constant_pool) { + return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); + } + + static inline Klass* asKlass(jobject jvmci_type) { + return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); + } + + static inline Klass* asKlass(Handle jvmci_type) { + return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); + } + + static inline Klass* asKlass(oop jvmci_type) { + return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); + } + + static inline MethodData* asMethodData(jlong metaspaceMethodData) { + return (MethodData*) (address) metaspaceMethodData; + } + + static oop get_jvmci_method(methodHandle method, TRAPS); + + static oop get_jvmci_type(KlassHandle klass, TRAPS); +}; + +class JavaArgumentUnboxer : public SignatureIterator { + protected: + JavaCallArguments* _jca; + arrayOop _args; + int _index; + + oop next_arg(BasicType expectedType) { + assert(_index < _args->length(), "out of bounds"); + oop arg=((objArrayOop) (_args))->obj_at(_index++); + assert(expectedType == T_OBJECT || java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch"); + return arg; + } + + public: + JavaArgumentUnboxer(Symbol* signature, JavaCallArguments* jca, arrayOop args, bool is_static) : SignatureIterator(signature) { + this->_return_type = T_ILLEGAL; + _jca = jca; + _index = 0; + _args = args; + if (!is_static) { + _jca->push_oop(next_arg(T_OBJECT)); + } + iterate(); + assert(_index == args->length(), "arg count mismatch with signature"); + } + + inline void do_bool() { if (!is_return_type()) _jca->push_int(next_arg(T_BOOLEAN)->bool_field(java_lang_boxing_object::value_offset_in_bytes(T_BOOLEAN))); } + inline void do_char() { if (!is_return_type()) _jca->push_int(next_arg(T_CHAR)->char_field(java_lang_boxing_object::value_offset_in_bytes(T_CHAR))); } + inline void do_short() { if (!is_return_type()) _jca->push_int(next_arg(T_SHORT)->short_field(java_lang_boxing_object::value_offset_in_bytes(T_SHORT))); } + inline void do_byte() { if (!is_return_type()) _jca->push_int(next_arg(T_BYTE)->byte_field(java_lang_boxing_object::value_offset_in_bytes(T_BYTE))); } + inline void do_int() { if (!is_return_type()) _jca->push_int(next_arg(T_INT)->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT))); } + + inline void do_long() { if (!is_return_type()) _jca->push_long(next_arg(T_LONG)->long_field(java_lang_boxing_object::value_offset_in_bytes(T_LONG))); } + inline void do_float() { if (!is_return_type()) _jca->push_float(next_arg(T_FLOAT)->float_field(java_lang_boxing_object::value_offset_in_bytes(T_FLOAT))); } + inline void do_double() { if (!is_return_type()) _jca->push_double(next_arg(T_DOUBLE)->double_field(java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE))); } + + inline void do_object() { _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_object(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_array(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_void() { } +}; + +#endif // SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp new file mode 100644 index 00000000000..9758ce6d7bb --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp @@ -0,0 +1,595 @@ +/* + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "classfile/javaAssertions.hpp" +#include "classfile/systemDictionary.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/codeCache.hpp" +#include "code/scopeDesc.hpp" +#include "runtime/sweeper.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/compileLog.hpp" +#include "compiler/compilerOracle.hpp" +#include "interpreter/linkResolver.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/oopFactory.hpp" +#include "memory/universe.inline.hpp" +#include "oops/methodData.hpp" +#include "oops/objArrayKlass.hpp" +#include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "runtime/init.hpp" +#include "runtime/reflection.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/dtrace.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciJavaClasses.hpp" + +JVMCIEnv::JVMCIEnv(CompileTask* task, int system_dictionary_modification_counter) { + _task = task; + _system_dictionary_modification_counter = system_dictionary_modification_counter; + { + // Get Jvmti capabilities under lock to get consistent values. + MutexLocker mu(JvmtiThreadState_lock); + _jvmti_can_hotswap_or_post_breakpoint = JvmtiExport::can_hotswap_or_post_breakpoint(); + _jvmti_can_access_local_variables = JvmtiExport::can_access_local_variables(); + _jvmti_can_post_on_exceptions = JvmtiExport::can_post_on_exceptions(); + } +} + +// ------------------------------------------------------------------ +// Note: the logic of this method should mirror the logic of +// constantPoolOopDesc::verify_constant_pool_resolve. +bool JVMCIEnv::check_klass_accessibility(KlassHandle accessing_klass, KlassHandle resolved_klass) { + if (accessing_klass->oop_is_objArray()) { + accessing_klass = ObjArrayKlass::cast(accessing_klass())->bottom_klass(); + } + if (!accessing_klass->oop_is_instance()) { + return true; + } + + if (resolved_klass->oop_is_objArray()) { + // Find the element klass, if this is an array. + resolved_klass = ObjArrayKlass::cast(resolved_klass())->bottom_klass(); + } + if (resolved_klass->oop_is_instance()) { + return Reflection::verify_class_access(accessing_klass(), resolved_klass(), true); + } + return true; +} + +// ------------------------------------------------------------------ +KlassHandle JVMCIEnv::get_klass_by_name_impl(KlassHandle& accessing_klass, + constantPoolHandle& cpool, + Symbol* sym, + bool require_local) { + JVMCI_EXCEPTION_CONTEXT; + + // Now we need to check the SystemDictionary + if (sym->byte_at(0) == 'L' && + sym->byte_at(sym->utf8_length()-1) == ';') { + // This is a name from a signature. Strip off the trimmings. + // Call recursive to keep scope of strippedsym. + TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1, + sym->utf8_length()-2, + CHECK_(KlassHandle())); + return get_klass_by_name_impl(accessing_klass, cpool, strippedsym, require_local); + } + + Handle loader(THREAD, (oop)NULL); + Handle domain(THREAD, (oop)NULL); + if (!accessing_klass.is_null()) { + loader = Handle(THREAD, accessing_klass->class_loader()); + domain = Handle(THREAD, accessing_klass->protection_domain()); + } + + KlassHandle found_klass; + { + ttyUnlocker ttyul; // release tty lock to avoid ordering problems + MutexLocker ml(Compile_lock); + Klass* kls; + if (!require_local) { + kls = SystemDictionary::find_constrained_instance_or_array_klass(sym, loader, CHECK_(KlassHandle())); + } else { + kls = SystemDictionary::find_instance_or_array_klass(sym, loader, domain, CHECK_(KlassHandle())); + } + found_klass = KlassHandle(THREAD, kls); + } + + // If we fail to find an array klass, look again for its element type. + // The element type may be available either locally or via constraints. + // In either case, if we can find the element type in the system dictionary, + // we must build an array type around it. The CI requires array klasses + // to be loaded if their element klasses are loaded, except when memory + // is exhausted. + if (sym->byte_at(0) == '[' && + (sym->byte_at(1) == '[' || sym->byte_at(1) == 'L')) { + // We have an unloaded array. + // Build it on the fly if the element class exists. + TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1, + sym->utf8_length()-1, + CHECK_(KlassHandle())); + + // Get element Klass recursively. + KlassHandle elem_klass = + get_klass_by_name_impl(accessing_klass, + cpool, + elem_sym, + require_local); + if (!elem_klass.is_null()) { + // Now make an array for it + return elem_klass->array_klass(CHECK_(KlassHandle())); + } + } + + if (found_klass.is_null() && !cpool.is_null() && cpool->has_preresolution()) { + // Look inside the constant pool for pre-resolved class entries. + for (int i = cpool->length() - 1; i >= 1; i--) { + if (cpool->tag_at(i).is_klass()) { + Klass* kls = cpool->resolved_klass_at(i); + if (kls->name() == sym) { + return kls; + } + } + } + } + + return found_klass(); +} + +// ------------------------------------------------------------------ +KlassHandle JVMCIEnv::get_klass_by_name(KlassHandle& accessing_klass, + Symbol* klass_name, + bool require_local) { + ResourceMark rm; + constantPoolHandle cpool; + return get_klass_by_name_impl(accessing_klass, + cpool, + klass_name, + require_local); +} + +// ------------------------------------------------------------------ +// Implementation of get_klass_by_index. +KlassHandle JVMCIEnv::get_klass_by_index_impl(constantPoolHandle& cpool, + int index, + bool& is_accessible, + KlassHandle& accessor) { + JVMCI_EXCEPTION_CONTEXT; + KlassHandle klass (THREAD, ConstantPool::klass_at_if_loaded(cpool, index)); + Symbol* klass_name = NULL; + if (klass.is_null()) { + klass_name = cpool->klass_name_at(index); + } + + if (klass.is_null()) { + // Not found in constant pool. Use the name to do the lookup. + KlassHandle k = get_klass_by_name_impl(accessor, + cpool, + klass_name, + false); + // Calculate accessibility the hard way. + if (k.is_null()) { + is_accessible = false; + } else if (k->class_loader() != accessor->class_loader() && + get_klass_by_name_impl(accessor, cpool, k->name(), true).is_null()) { + // Loaded only remotely. Not linked yet. + is_accessible = false; + } else { + // Linked locally, and we must also check public/private, etc. + is_accessible = check_klass_accessibility(accessor, k); + } + if (!is_accessible) { + return KlassHandle(); + } + return k; + } + + // It is known to be accessible, since it was found in the constant pool. + is_accessible = true; + return klass; +} + +// ------------------------------------------------------------------ +// Get a klass from the constant pool. +KlassHandle JVMCIEnv::get_klass_by_index(constantPoolHandle& cpool, + int index, + bool& is_accessible, + KlassHandle& accessor) { + ResourceMark rm; + KlassHandle result = get_klass_by_index_impl(cpool, index, is_accessible, accessor); + return result; +} + +// ------------------------------------------------------------------ +// Implementation of get_field_by_index. +// +// Implementation note: the results of field lookups are cached +// in the accessor klass. +void JVMCIEnv::get_field_by_index_impl(instanceKlassHandle& klass, fieldDescriptor& field_desc, + int index) { + JVMCI_EXCEPTION_CONTEXT; + + assert(klass->is_linked(), "must be linked before using its constant-pool"); + + constantPoolHandle cpool(thread, klass->constants()); + + // Get the field's name, signature, and type. + Symbol* name = cpool->name_ref_at(index); + + int nt_index = cpool->name_and_type_ref_index_at(index); + int sig_index = cpool->signature_ref_index_at(nt_index); + Symbol* signature = cpool->symbol_at(sig_index); + + // Get the field's declared holder. + int holder_index = cpool->klass_ref_index_at(index); + bool holder_is_accessible; + KlassHandle declared_holder = get_klass_by_index(cpool, holder_index, + holder_is_accessible, + klass); + + // The declared holder of this field may not have been loaded. + // Bail out with partial field information. + if (!holder_is_accessible) { + return; + } + + + // Perform the field lookup. + Klass* canonical_holder = + InstanceKlass::cast(declared_holder())->find_field(name, signature, &field_desc); + if (canonical_holder == NULL) { + return; + } + + assert(canonical_holder == field_desc.field_holder(), "just checking"); +} + +// ------------------------------------------------------------------ +// Get a field by index from a klass's constant pool. +void JVMCIEnv::get_field_by_index(instanceKlassHandle& accessor, fieldDescriptor& fd, int index) { + ResourceMark rm; + return get_field_by_index_impl(accessor, fd, index); +} + +// ------------------------------------------------------------------ +// Perform an appropriate method lookup based on accessor, holder, +// name, signature, and bytecode. +methodHandle JVMCIEnv::lookup_method(instanceKlassHandle& h_accessor, + instanceKlassHandle& h_holder, + Symbol* name, + Symbol* sig, + Bytecodes::Code bc) { + JVMCI_EXCEPTION_CONTEXT; + LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); + methodHandle dest_method; + LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); + switch (bc) { + case Bytecodes::_invokestatic: + dest_method = + LinkResolver::resolve_static_call_or_null(link_info); + break; + case Bytecodes::_invokespecial: + dest_method = + LinkResolver::resolve_special_call_or_null(link_info); + break; + case Bytecodes::_invokeinterface: + dest_method = + LinkResolver::linktime_resolve_interface_method_or_null(link_info); + break; + case Bytecodes::_invokevirtual: + dest_method = + LinkResolver::linktime_resolve_virtual_method_or_null(link_info); + break; + default: ShouldNotReachHere(); + } + + return dest_method; +} + + +// ------------------------------------------------------------------ +methodHandle JVMCIEnv::get_method_by_index_impl(constantPoolHandle& cpool, + int index, Bytecodes::Code bc, + instanceKlassHandle& accessor) { + if (bc == Bytecodes::_invokedynamic) { + ConstantPoolCacheEntry* cpce = cpool->invokedynamic_cp_cache_entry_at(index); + bool is_resolved = !cpce->is_f1_null(); + if (is_resolved) { + // Get the invoker Method* from the constant pool. + // (The appendix argument, if any, will be noted in the method's signature.) + Method* adapter = cpce->f1_as_method(); + return methodHandle(adapter); + } + + return NULL; + } + + int holder_index = cpool->klass_ref_index_at(index); + bool holder_is_accessible; + KlassHandle holder = get_klass_by_index_impl(cpool, holder_index, holder_is_accessible, accessor); + + // Get the method's name and signature. + Symbol* name_sym = cpool->name_ref_at(index); + Symbol* sig_sym = cpool->signature_ref_at(index); + + if (cpool->has_preresolution() + || (holder() == SystemDictionary::MethodHandle_klass() && + MethodHandles::is_signature_polymorphic_name(holder(), name_sym))) { + // Short-circuit lookups for JSR 292-related call sites. + // That is, do not rely only on name-based lookups, because they may fail + // if the names are not resolvable in the boot class loader (7056328). + switch (bc) { + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + { + Method* m = ConstantPool::method_at_if_loaded(cpool, index); + if (m != NULL) { + return m; + } + } + break; + } + } + + if (holder_is_accessible) { // Our declared holder is loaded. + instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder); + methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc); + if (!m.is_null() && + (bc == Bytecodes::_invokestatic + ? InstanceKlass::cast(m->method_holder())->is_not_initialized() + : !InstanceKlass::cast(m->method_holder())->is_loaded())) { + m = NULL; + } + if (!m.is_null()) { + // We found the method. + return m; + } + } + + // Either the declared holder was not loaded, or the method could + // not be found. + + return NULL; +} + +// ------------------------------------------------------------------ +instanceKlassHandle JVMCIEnv::get_instance_klass_for_declared_method_holder(KlassHandle& method_holder) { + // For the case of .clone(), the method holder can be an ArrayKlass* + // instead of an InstanceKlass*. For that case simply pretend that the + // declared holder is Object.clone since that's where the call will bottom out. + if (method_holder->oop_is_instance()) { + return instanceKlassHandle(method_holder()); + } else if (method_holder->oop_is_array()) { + return instanceKlassHandle(SystemDictionary::Object_klass()); + } else { + ShouldNotReachHere(); + } + return NULL; +} + + +// ------------------------------------------------------------------ +methodHandle JVMCIEnv::get_method_by_index(constantPoolHandle& cpool, + int index, Bytecodes::Code bc, + instanceKlassHandle& accessor) { + ResourceMark rm; + return get_method_by_index_impl(cpool, index, bc, accessor); +} + +// ------------------------------------------------------------------ +// Check for changes to the system dictionary during compilation +// class loads, evolution, breakpoints +JVMCIEnv::CodeInstallResult JVMCIEnv::check_for_system_dictionary_modification(Dependencies* dependencies, Handle compiled_code, + JVMCIEnv* env, char** failure_detail) { + // If JVMTI capabilities were enabled during compile, the compilation is invalidated. + if (env != NULL) { + if (!env->_jvmti_can_hotswap_or_post_breakpoint && JvmtiExport::can_hotswap_or_post_breakpoint()) { + *failure_detail = (char*) "Hotswapping or breakpointing was enabled during compilation"; + return JVMCIEnv::dependencies_failed; + } + } + + // Dependencies must be checked when the system dictionary changes + // or if we don't know whether it has changed (i.e., env == NULL). + // In debug mode, always check dependencies. + bool counter_changed = env != NULL && env->_system_dictionary_modification_counter != SystemDictionary::number_of_modifications(); + bool verify_deps = env == NULL || trueInDebug || JavaAssertions::enabled(SystemDictionary::HotSpotInstalledCode_klass()->name()->as_C_string(), true); + if (!counter_changed && !verify_deps) { + return JVMCIEnv::ok; + } + + for (Dependencies::DepStream deps(dependencies); deps.next(); ) { + Klass* witness = deps.check_dependency(); + if (witness != NULL) { + // Use a fixed size buffer to prevent the string stream from + // resizing in the context of an inner resource mark. + char* buffer = NEW_RESOURCE_ARRAY(char, O_BUFLEN); + stringStream st(buffer, O_BUFLEN); + deps.print_dependency(witness, true, &st); + *failure_detail = st.as_string(); + if (env == NULL || counter_changed) { + return JVMCIEnv::dependencies_failed; + } else { + // The dependencies were invalid at the time of installation + // without any intervening modification of the system + // dictionary. That means they were invalidly constructed. + return JVMCIEnv::dependencies_invalid; + } + } + if (LogCompilation) { + deps.log_dependency(); + } + } + + return JVMCIEnv::ok; +} + +// ------------------------------------------------------------------ +JVMCIEnv::CodeInstallResult JVMCIEnv::register_method( + methodHandle& method, + nmethod*& nm, + int entry_bci, + CodeOffsets* offsets, + int orig_pc_offset, + CodeBuffer* code_buffer, + int frame_words, + OopMapSet* oop_map_set, + ExceptionHandlerTable* handler_table, + AbstractCompiler* compiler, + DebugInformationRecorder* debug_info, + Dependencies* dependencies, + JVMCIEnv* env, + int compile_id, + bool has_unsafe_access, + bool has_wide_vector, + Handle installed_code, + Handle compiled_code, + Handle speculation_log) { + JVMCI_EXCEPTION_CONTEXT; + nm = NULL; + int comp_level = CompLevel_full_optimization; + char* failure_detail = NULL; + JVMCIEnv::CodeInstallResult result; + { + // To prevent compile queue updates. + MutexLocker locker(MethodCompileQueue_lock, THREAD); + + // Prevent SystemDictionary::add_to_hierarchy from running + // and invalidating our dependencies until we install this method. + MutexLocker ml(Compile_lock); + + // Encode the dependencies now, so we can check them right away. + dependencies->encode_content_bytes(); + + // Check for {class loads, evolution, breakpoints} during compilation + result = check_for_system_dictionary_modification(dependencies, compiled_code, env, &failure_detail); + if (result != JVMCIEnv::ok) { + // While not a true deoptimization, it is a preemptive decompile. + MethodData* mdp = method()->method_data(); + if (mdp != NULL) { + mdp->inc_decompile_count(); + if (mdp->decompile_count() > (uint)PerMethodRecompilationCutoff) { + // TODO (chaeubl) enable this in the fastdebug build only once we are more stable + ResourceMark m; + tty->print_cr("WARN: endless recompilation of %s. Method was set to not compilable.", method()->name_and_sig_as_C_string()); + //ShouldNotReachHere(); + } + } + + // All buffers in the CodeBuffer are allocated in the CodeCache. + // If the code buffer is created on each compile attempt + // as in C2, then it must be freed. + //code_buffer->free_blob(); + } else { + ImplicitExceptionTable implicit_tbl; + nm = nmethod::new_nmethod(method, + compile_id, + entry_bci, + offsets, + orig_pc_offset, + debug_info, dependencies, code_buffer, + frame_words, oop_map_set, + handler_table, &implicit_tbl, + compiler, comp_level, installed_code, speculation_log); + + // Free codeBlobs + //code_buffer->free_blob(); + if (nm == NULL) { + // The CodeCache is full. Print out warning and disable compilation. + { + MutexUnlocker ml(Compile_lock); + MutexUnlocker locker(MethodCompileQueue_lock); + CompileBroker::handle_full_code_cache(CodeCache::get_code_blob_type(comp_level)); + } + } else { + nm->set_has_unsafe_access(has_unsafe_access); + nm->set_has_wide_vectors(has_wide_vector); + + // Record successful registration. + // (Put nm into the task handle *before* publishing to the Java heap.) + CompileTask* task = env == NULL ? NULL : env->task(); + if (task != NULL) task->set_code(nm); + + if (installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(installed_code())) { + if (entry_bci == InvocationEntryBci) { + if (TieredCompilation) { + // If there is an old version we're done with it + nmethod* old = method->code(); + if (TraceMethodReplacement && old != NULL) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + tty->print_cr("Replacing method %s", method_name); + } + if (old != NULL ) { + old->make_not_entrant(); + } + } + if (TraceNMethodInstalls) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + ttyLocker ttyl; + tty->print_cr("Installing method (%d) %s [entry point: %p]", + comp_level, + method_name, nm->entry_point()); + } + // Allow the code to be executed + method->set_code(method, nm); + } else { + if (TraceNMethodInstalls ) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + ttyLocker ttyl; + tty->print_cr("Installing osr method (%d) %s @ %d", + comp_level, + method_name, + entry_bci); + } + InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm); + } + } + } + result = nm != NULL ? JVMCIEnv::ok :JVMCIEnv::cache_full; + } + } + + // String creation must be done outside lock + if (failure_detail != NULL) { + // A failure to allocate the string is silently ignored. + Handle message = java_lang_String::create_from_str(failure_detail, THREAD); + HotSpotCompiledNmethod::set_installationFailureMessage(compiled_code, message()); + } + + // JVMTI -- compiled method notification (must be done outside lock) + if (nm != NULL) { + nm->post_compiled_method_load_event(); + } + + return result; +} + diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp new file mode 100644 index 00000000000..db88196310a --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_JVMCIENV_HPP +#define SHARE_VM_JVMCI_JVMCIENV_HPP + +#include "classfile/systemDictionary.hpp" +#include "code/debugInfoRec.hpp" +#include "code/dependencies.hpp" +#include "code/exceptionHandlerTable.hpp" +#include "compiler/oopMap.hpp" +#include "runtime/thread.hpp" + +class CompileTask; + +// Bring the JVMCI compiler thread into the VM state. +#define JVMCI_VM_ENTRY_MARK \ + JavaThread* thread = JavaThread::current(); \ + ThreadInVMfromNative __tiv(thread); \ + ResetNoHandleMark rnhm; \ + HandleMarkCleaner __hm(thread); \ + Thread* THREAD = thread; \ + debug_only(VMNativeEntryWrapper __vew;) + +#define JVMCI_EXCEPTION_CONTEXT \ + JavaThread* thread=JavaThread::current(); \ + Thread* THREAD = thread; + +// +// This class is the top level broker for requests from the compiler +// to the VM. +class JVMCIEnv : StackObj { + CI_PACKAGE_ACCESS_TO + + friend class CompileBroker; + friend class Dependencies; // for get_object, during logging + +public: + + enum CodeInstallResult { + ok, + dependencies_failed, + dependencies_invalid, + cache_full, + code_too_large + }; + + // Look up a klass by name from a particular class loader (the accessor's). + // If require_local, result must be defined in that class loader, or NULL. + // If !require_local, a result from remote class loader may be reported, + // if sufficient class loader constraints exist such that initiating + // a class loading request from the given loader is bound to return + // the class defined in the remote loader (or throw an error). + // + // Return an unloaded klass if !require_local and no class at all is found. + // + // The CI treats a klass as loaded if it is consistently defined in + // another loader, even if it hasn't yet been loaded in all loaders + // that could potentially see it via delegation. + static KlassHandle get_klass_by_name(KlassHandle& accessing_klass, + Symbol* klass_name, + bool require_local); + + // Constant pool access. + static KlassHandle get_klass_by_index(constantPoolHandle& cpool, + int klass_index, + bool& is_accessible, + KlassHandle& loading_klass); + static void get_field_by_index(instanceKlassHandle& loading_klass, fieldDescriptor& fd, + int field_index); + static methodHandle get_method_by_index(constantPoolHandle& cpool, + int method_index, Bytecodes::Code bc, + instanceKlassHandle& loading_klass); + + JVMCIEnv(CompileTask* task, int system_dictionary_modification_counter); + +private: + CompileTask* _task; + int _system_dictionary_modification_counter; + + // Cache JVMTI state + bool _jvmti_can_hotswap_or_post_breakpoint; + bool _jvmti_can_access_local_variables; + bool _jvmti_can_post_on_exceptions; + + // Implementation methods for loading and constant pool access. + static KlassHandle get_klass_by_name_impl(KlassHandle& accessing_klass, + constantPoolHandle& cpool, + Symbol* klass_name, + bool require_local); + static KlassHandle get_klass_by_index_impl(constantPoolHandle& cpool, + int klass_index, + bool& is_accessible, + KlassHandle& loading_klass); + static void get_field_by_index_impl(instanceKlassHandle& loading_klass, fieldDescriptor& fd, + int field_index); + static methodHandle get_method_by_index_impl(constantPoolHandle& cpool, + int method_index, Bytecodes::Code bc, + instanceKlassHandle& loading_klass); + + // Helper methods + static bool check_klass_accessibility(KlassHandle accessing_klass, KlassHandle resolved_klass); + static methodHandle lookup_method(instanceKlassHandle& accessor, + instanceKlassHandle& holder, + Symbol* name, + Symbol* sig, + Bytecodes::Code bc); + + private: + + // Is this thread currently in the VM state? + static bool is_in_vm(); + + // Helper routine for determining the validity of a compilation + // with respect to concurrent class loading. + static JVMCIEnv::CodeInstallResult check_for_system_dictionary_modification(Dependencies* target, Handle compiled_code, + JVMCIEnv* env, char** failure_detail); + +public: + CompileTask* task() { return _task; } + + // Register the result of a compilation. + static JVMCIEnv::CodeInstallResult register_method( + methodHandle& target, + nmethod*& nm, + int entry_bci, + CodeOffsets* offsets, + int orig_pc_offset, + CodeBuffer* code_buffer, + int frame_words, + OopMapSet* oop_map_set, + ExceptionHandlerTable* handler_table, + AbstractCompiler* compiler, + DebugInformationRecorder* debug_info, + Dependencies* dependencies, + JVMCIEnv* env, + int compile_id, + bool has_unsafe_access, + bool has_wide_vector, + Handle installed_code, + Handle compiled_code, + Handle speculation_log); + + // converts the Klass* representing the holder of a method into a + // InstanceKlass*. This is needed since the holder of a method in + // the bytecodes could be an array type. Basically this converts + // array types into java/lang/Object and other types stay as they are. + static instanceKlassHandle get_instance_klass_for_declared_method_holder(KlassHandle& klass); +}; + +#endif // SHARE_VM_JVMCI_JVMCIENV_HPP diff --git a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp new file mode 100644 index 00000000000..928fc1d1440 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "runtime/jniHandles.hpp" +#include "classfile/symbolTable.hpp" +#include "memory/resourceArea.hpp" + +// This function is similar to javaClasses.cpp, it computes the field offset of a (static or instance) field. +// It looks up the name and signature symbols without creating new ones, all the symbols of these classes need to be already loaded. + +void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field) { + InstanceKlass* ik = InstanceKlass::cast(klass); + Symbol* name_symbol = SymbolTable::probe(name, (int)strlen(name)); + Symbol* signature_symbol = SymbolTable::probe(signature, (int)strlen(signature)); + if (name_symbol == NULL || signature_symbol == NULL) { +#ifndef PRODUCT + ik->print_on(tty); +#endif + fatal("symbol with name %s and signature %s was not found in symbol table (klass=%s)", name, signature, klass->name()->as_C_string()); + } + + fieldDescriptor fd; + if (!ik->find_field(name_symbol, signature_symbol, &fd)) { + ResourceMark rm; + fatal("Invalid layout of %s at %s", name_symbol->as_C_string(), ik->external_name()); + } + guarantee(fd.is_static() == static_field, "static/instance mismatch"); + dest_offset = fd.offset(); + assert(dest_offset != 0, "must be valid offset"); +} + +// This piece of macro magic creates the contents of the jvmci_compute_offsets method that initializes the field indices of all the access classes. + +#define START_CLASS(name) { Klass* k = SystemDictionary::name##_klass(); assert(k != NULL, "Could not find class " #name ""); + +#define END_CLASS } + +#define FIELD(klass, name, signature, static_field) compute_offset(klass::_##name##_offset, k, #name, signature, static_field); +#define CHAR_FIELD(klass, name) FIELD(klass, name, "C", false) +#define INT_FIELD(klass, name) FIELD(klass, name, "I", false) +#define BOOLEAN_FIELD(klass, name) FIELD(klass, name, "Z", false) +#define LONG_FIELD(klass, name) FIELD(klass, name, "J", false) +#define FLOAT_FIELD(klass, name) FIELD(klass, name, "F", false) +#define OOP_FIELD(klass, name, signature) FIELD(klass, name, signature, false) +#define STATIC_OOP_FIELD(klass, name, signature) FIELD(klass, name, signature, true) +#define STATIC_INT_FIELD(klass, name) FIELD(klass, name, "I", true) +#define STATIC_BOOLEAN_FIELD(klass, name) FIELD(klass, name, "Z", true) + + +void JVMCIJavaClasses::compute_offsets() { + COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, OOP_FIELD, OOP_FIELD, STATIC_OOP_FIELD, STATIC_OOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD) + guarantee(InstalledCode::_address_offset == sizeof(oopDesc), "codeBlob must be first field!"); +} + +#define EMPTY0 +#define EMPTY1(x) +#define EMPTY2(x,y) +#define FIELD2(klass, name) int klass::_##name##_offset = 0; +#define FIELD3(klass, name, sig) FIELD2(klass, name) + +COMPILER_CLASSES_DO(EMPTY1, EMPTY0, FIELD2, FIELD2, FIELD2, FIELD2, FIELD2, FIELD3, FIELD3, FIELD3, FIELD3, FIELD3, FIELD2, FIELD2) + + + + + diff --git a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp new file mode 100644 index 00000000000..bfd81623cd8 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCIJAVACLASSES_HPP +#define SHARE_VM_JVMCI_JVMCIJAVACLASSES_HPP + +#include "classfile/systemDictionary.hpp" +#include "oops/instanceMirrorKlass.hpp" + +class JVMCIJavaClasses : AllStatic { + public: + static void compute_offsets(); +}; + +/* This macro defines the structure of the CompilationResult - classes. + * It will generate classes with accessors similar to javaClasses.hpp, but with specializations for oops, Handles and jni handles. + * + * The public interface of these classes will look like this: + + * class StackSlot : AllStatic { + * public: + * static Klass* klass(); + * static jint index(oop obj); + * static jint index(Handle obj); + * static jint index(jobject obj); + * static void set_index(oop obj, jint x); + * static void set_index(Handle obj, jint x); + * static void set_index(jobject obj, jint x); + * }; + * + */ + +#define COMPILER_CLASSES_DO(start_class, end_class, char_field, int_field, boolean_field, long_field, float_field, oop_field, typeArrayOop_field, objArrayOop_field, static_oop_field, static_objArrayOop_field, static_int_field, static_boolean_field) \ + start_class(Architecture) \ + oop_field(Architecture, wordKind, "Ljdk/vm/ci/meta/PlatformKind;") \ + end_class \ + start_class(TargetDescription) \ + oop_field(TargetDescription, arch, "Ljdk/vm/ci/code/Architecture;") \ + end_class \ + start_class(HotSpotResolvedObjectTypeImpl) \ + oop_field(HotSpotResolvedObjectTypeImpl, javaClass, "Ljava/lang/Class;") \ + end_class \ + start_class(HotSpotResolvedJavaMethodImpl) \ + long_field(HotSpotResolvedJavaMethodImpl, metaspaceMethod) \ + end_class \ + start_class(InstalledCode) \ + long_field(InstalledCode, address) \ + long_field(InstalledCode, version) \ + oop_field(InstalledCode, name, "Ljava/lang/String;") \ + end_class \ + start_class(HotSpotInstalledCode) \ + int_field(HotSpotInstalledCode, size) \ + long_field(HotSpotInstalledCode, codeStart) \ + int_field(HotSpotInstalledCode, codeSize) \ + end_class \ + start_class(HotSpotNmethod) \ + boolean_field(HotSpotNmethod, isDefault) \ + end_class \ + start_class(HotSpotCompiledCode) \ + oop_field(HotSpotCompiledCode, name, "Ljava/lang/String;") \ + objArrayOop_field(HotSpotCompiledCode, sites, "[Ljdk/vm/ci/code/CompilationResult$Site;") \ + objArrayOop_field(HotSpotCompiledCode, exceptionHandlers, "[Ljdk/vm/ci/code/CompilationResult$ExceptionHandler;") \ + objArrayOop_field(HotSpotCompiledCode, comments, "[Ljdk/vm/ci/hotspot/HotSpotCompiledCode$Comment;") \ + objArrayOop_field(HotSpotCompiledCode, assumptions, "[Ljdk/vm/ci/meta/Assumptions$Assumption;") \ + typeArrayOop_field(HotSpotCompiledCode, targetCode, "[B") \ + int_field(HotSpotCompiledCode, targetCodeSize) \ + typeArrayOop_field(HotSpotCompiledCode, dataSection, "[B") \ + int_field(HotSpotCompiledCode, dataSectionAlignment) \ + objArrayOop_field(HotSpotCompiledCode, dataSectionPatches, "[Ljdk/vm/ci/code/CompilationResult$DataPatch;") \ + boolean_field(HotSpotCompiledCode, isImmutablePIC) \ + int_field(HotSpotCompiledCode, totalFrameSize) \ + int_field(HotSpotCompiledCode, customStackAreaOffset) \ + objArrayOop_field(HotSpotCompiledCode, methods, "[Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + end_class \ + start_class(HotSpotCompiledCode_Comment) \ + oop_field(HotSpotCompiledCode_Comment, text, "Ljava/lang/String;") \ + int_field(HotSpotCompiledCode_Comment, pcOffset) \ + end_class \ + start_class(HotSpotCompiledNmethod) \ + oop_field(HotSpotCompiledNmethod, method, "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ + oop_field(HotSpotCompiledNmethod, installationFailureMessage, "Ljava/lang/String;") \ + int_field(HotSpotCompiledNmethod, entryBCI) \ + int_field(HotSpotCompiledNmethod, id) \ + long_field(HotSpotCompiledNmethod, jvmciEnv) \ + boolean_field(HotSpotCompiledNmethod, hasUnsafeAccess) \ + end_class \ + start_class(HotSpotJVMCIMetaAccessContext) \ + static_objArrayOop_field(HotSpotJVMCIMetaAccessContext, allContexts, "[Ljava/lang/ref/WeakReference;") \ + objArrayOop_field(HotSpotJVMCIMetaAccessContext, metadataRoots, "[Ljava/lang/Object;") \ + end_class \ + start_class(HotSpotForeignCallTarget) \ + long_field(HotSpotForeignCallTarget, address) \ + end_class \ + start_class(Assumptions_NoFinalizableSubclass) \ + oop_field(Assumptions_NoFinalizableSubclass, receiverType, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_ConcreteSubtype) \ + oop_field(Assumptions_ConcreteSubtype, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + oop_field(Assumptions_ConcreteSubtype, subtype, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_LeafType) \ + oop_field(Assumptions_LeafType, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_ConcreteMethod) \ + oop_field(Assumptions_ConcreteMethod, method, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + oop_field(Assumptions_ConcreteMethod, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + oop_field(Assumptions_ConcreteMethod, impl, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + end_class \ + start_class(Assumptions_CallSiteTargetValue) \ + oop_field(Assumptions_CallSiteTargetValue, callSite, "Ljava/lang/invoke/CallSite;") \ + oop_field(Assumptions_CallSiteTargetValue, methodHandle, "Ljava/lang/invoke/MethodHandle;") \ + end_class \ + start_class(CompilationResult_Site) \ + int_field(CompilationResult_Site, pcOffset) \ + end_class \ + start_class(CompilationResult_Call) \ + oop_field(CompilationResult_Call, target, "Ljdk/vm/ci/meta/InvokeTarget;") \ + oop_field(CompilationResult_Call, debugInfo, "Ljdk/vm/ci/code/DebugInfo;") \ + end_class \ + start_class(CompilationResult_DataPatch) \ + oop_field(CompilationResult_DataPatch, reference, "Ljdk/vm/ci/code/CompilationResult$Reference;") \ + end_class \ + start_class(CompilationResult_ConstantReference) \ + oop_field(CompilationResult_ConstantReference, constant, "Ljdk/vm/ci/meta/VMConstant;") \ + end_class \ + start_class(CompilationResult_DataSectionReference) \ + int_field(CompilationResult_DataSectionReference, offset) \ + end_class \ + start_class(InfopointReason) \ + static_oop_field(InfopointReason, UNKNOWN, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, SAFEPOINT, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, CALL, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, IMPLICIT_EXCEPTION, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, METHOD_START, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, METHOD_END, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, LINE_NUMBER, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, METASPACE_ACCESS, "Ljdk/vm/ci/code/InfopointReason;") \ + end_class \ + start_class(CompilationResult_Infopoint) \ + oop_field(CompilationResult_Infopoint, debugInfo, "Ljdk/vm/ci/code/DebugInfo;") \ + oop_field(CompilationResult_Infopoint, reason, "Ljdk/vm/ci/code/InfopointReason;") \ + end_class \ + start_class(CompilationResult_ExceptionHandler) \ + int_field(CompilationResult_ExceptionHandler, handlerPos) \ + end_class \ + start_class(CompilationResult_Mark) \ + oop_field(CompilationResult_Mark, id, "Ljava/lang/Object;") \ + end_class \ + start_class(DebugInfo) \ + oop_field(DebugInfo, bytecodePosition, "Ljdk/vm/ci/code/BytecodePosition;") \ + oop_field(DebugInfo, referenceMap, "Ljdk/vm/ci/code/ReferenceMap;") \ + oop_field(DebugInfo, calleeSaveInfo, "Ljdk/vm/ci/code/RegisterSaveLayout;") \ + objArrayOop_field(DebugInfo, virtualObjectMapping, "[Ljdk/vm/ci/code/VirtualObject;") \ + end_class \ + start_class(HotSpotReferenceMap) \ + objArrayOop_field(HotSpotReferenceMap, objects, "[Ljdk/vm/ci/code/Location;") \ + objArrayOop_field(HotSpotReferenceMap, derivedBase, "[Ljdk/vm/ci/code/Location;") \ + typeArrayOop_field(HotSpotReferenceMap, sizeInBytes, "[I") \ + int_field(HotSpotReferenceMap, maxRegisterSize) \ + end_class \ + start_class(RegisterSaveLayout) \ + objArrayOop_field(RegisterSaveLayout, registers, "[Ljdk/vm/ci/code/Register;") \ + typeArrayOop_field(RegisterSaveLayout, slots, "[I") \ + end_class \ + start_class(BytecodeFrame) \ + objArrayOop_field(BytecodeFrame, values, "[Ljdk/vm/ci/meta/JavaValue;") \ + objArrayOop_field(BytecodeFrame, slotKinds, "[Ljdk/vm/ci/meta/JavaKind;") \ + int_field(BytecodeFrame, numLocals) \ + int_field(BytecodeFrame, numStack) \ + int_field(BytecodeFrame, numLocks) \ + boolean_field(BytecodeFrame, rethrowException) \ + boolean_field(BytecodeFrame, duringCall) \ + static_int_field(BytecodeFrame, BEFORE_BCI) \ + end_class \ + start_class(BytecodePosition) \ + oop_field(BytecodePosition, caller, "Ljdk/vm/ci/code/BytecodePosition;") \ + oop_field(BytecodePosition, method, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + int_field(BytecodePosition, bci) \ + end_class \ + start_class(JavaConstant) \ + end_class \ + start_class(PrimitiveConstant) \ + oop_field(PrimitiveConstant, kind, "Ljdk/vm/ci/meta/JavaKind;") \ + long_field(PrimitiveConstant, primitive) \ + end_class \ + start_class(RawConstant) \ + long_field(RawConstant, primitive) \ + end_class \ + start_class(NullConstant) \ + end_class \ + start_class(HotSpotCompressedNullConstant) \ + end_class \ + start_class(HotSpotObjectConstantImpl) \ + oop_field(HotSpotObjectConstantImpl, object, "Ljava/lang/Object;") \ + boolean_field(HotSpotObjectConstantImpl, compressed) \ + end_class \ + start_class(HotSpotMetaspaceConstantImpl) \ + long_field(HotSpotMetaspaceConstantImpl, primitive) \ + oop_field(HotSpotMetaspaceConstantImpl, metaspaceObject, "Ljava/lang/Object;") \ + boolean_field(HotSpotMetaspaceConstantImpl, compressed) \ + end_class \ + start_class(HotSpotSentinelConstant) \ + end_class \ + start_class(JavaKind) \ + char_field(JavaKind, typeChar) \ + static_oop_field(JavaKind, Boolean, "Ljdk/vm/ci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Byte, "Ljdk/vm/ci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Char, "Ljdk/vm/ci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Short, "Ljdk/vm/ci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Int, "Ljdk/vm/ci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Long, "Ljdk/vm/ci/meta/JavaKind;"); \ + end_class \ + start_class(LIRKind) \ + oop_field(LIRKind, platformKind, "Ljdk/vm/ci/meta/PlatformKind;") \ + int_field(LIRKind, referenceMask) \ + end_class \ + start_class(Value) \ + oop_field(Value, lirKind, "Ljdk/vm/ci/meta/LIRKind;") \ + static_oop_field(Value, ILLEGAL, "Ljdk/vm/ci/meta/AllocatableValue;"); \ + end_class \ + start_class(RegisterValue) \ + oop_field(RegisterValue, reg, "Ljdk/vm/ci/code/Register;") \ + end_class \ + start_class(code_Location) \ + oop_field(code_Location, reg, "Ljdk/vm/ci/code/Register;") \ + int_field(code_Location, offset) \ + end_class \ + start_class(code_Register) \ + int_field(code_Register, number) \ + int_field(code_Register, encoding) \ + end_class \ + start_class(StackSlot) \ + int_field(StackSlot, offset) \ + boolean_field(StackSlot, addFrameSize) \ + end_class \ + start_class(VirtualObject) \ + int_field(VirtualObject, id) \ + oop_field(VirtualObject, type, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + objArrayOop_field(VirtualObject, values, "[Ljdk/vm/ci/meta/JavaValue;") \ + objArrayOop_field(VirtualObject, slotKinds, "[Ljdk/vm/ci/meta/JavaKind;") \ + end_class \ + start_class(StackLockValue) \ + oop_field(StackLockValue, owner, "Ljdk/vm/ci/meta/JavaValue;") \ + oop_field(StackLockValue, slot, "Ljdk/vm/ci/code/StackSlotValue;") \ + boolean_field(StackLockValue, eliminated) \ + end_class \ + start_class(SpeculationLog) \ + oop_field(SpeculationLog, lastFailed, "Ljava/lang/Object;") \ + end_class \ + start_class(HotSpotStackFrameReference) \ + oop_field(HotSpotStackFrameReference, compilerToVM, "Ljdk/vm/ci/hotspot/CompilerToVM;") \ + long_field(HotSpotStackFrameReference, stackPointer) \ + int_field(HotSpotStackFrameReference, frameNumber) \ + int_field(HotSpotStackFrameReference, bci) \ + oop_field(HotSpotStackFrameReference, method, "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ + objArrayOop_field(HotSpotStackFrameReference, locals, "[Ljava/lang/Object;") \ + typeArrayOop_field(HotSpotStackFrameReference, localIsVirtual, "[Z") \ + end_class \ + start_class(HotSpotMetaData) \ + typeArrayOop_field(HotSpotMetaData, pcDescBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, scopesDescBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, relocBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, exceptionBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, oopMaps, "[B") \ + objArrayOop_field(HotSpotMetaData, metadata, "[Ljava/lang/String;") \ + end_class \ + start_class(HotSpotOopMap) \ + int_field(HotSpotOopMap, offset) \ + int_field(HotSpotOopMap, count) \ + typeArrayOop_field(HotSpotOopMap, data, "[B") \ + end_class \ + start_class(HotSpotConstantPool) \ + long_field(HotSpotConstantPool, metaspaceConstantPool) \ + end_class \ + /* end*/ + + +#define START_CLASS(name) \ +class name : AllStatic { \ + private: \ + friend class JVMCICompiler; \ + static void check(oop obj, const char* field_name, int offset) { \ + assert(obj != NULL, "NULL field access of %s.%s", #name, field_name); \ + assert(obj->is_a(SystemDictionary::name##_klass()), "wrong class, " #name " expected, found %s", obj->klass()->external_name()); \ + assert(offset != 0, "must be valid offset"); \ + } \ + static void compute_offsets(); \ + public: \ + static InstanceKlass* klass() { return SystemDictionary::name##_klass() == NULL ? NULL : InstanceKlass::cast(SystemDictionary::name##_klass()); } + +#define END_CLASS }; + +#define FIELD(name, type, accessor, cast) \ + static int _##name##_offset; \ + static type name(oop obj) { check(obj, #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ + static type name(Handle& obj) { check(obj(), #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ + static type name(jobject obj) { check(JNIHandles::resolve(obj), #name, _##name##_offset); return cast JNIHandles::resolve(obj)->accessor(_##name##_offset); } \ + static void set_##name(oop obj, type x) { check(obj, #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ + static void set_##name(Handle& obj, type x) { check(obj(), #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ + static void set_##name(jobject obj, type x) { check(JNIHandles::resolve(obj), #name, _##name##_offset); JNIHandles::resolve(obj)->accessor##_put(_##name##_offset, x); } + +#define EMPTY_CAST +#define CHAR_FIELD(klass, name) FIELD(name, jchar, char_field, EMPTY_CAST) +#define INT_FIELD(klass, name) FIELD(name, jint, int_field, EMPTY_CAST) +#define BOOLEAN_FIELD(klass, name) FIELD(name, jboolean, bool_field, EMPTY_CAST) +#define LONG_FIELD(klass, name) FIELD(name, jlong, long_field, EMPTY_CAST) +#define FLOAT_FIELD(klass, name) FIELD(name, jfloat, float_field, EMPTY_CAST) +#define OOP_FIELD(klass, name, signature) FIELD(name, oop, obj_field, EMPTY_CAST) +#define OBJARRAYOOP_FIELD(klass, name, signature) FIELD(name, objArrayOop, obj_field, (objArrayOop)) +#define TYPEARRAYOOP_FIELD(klass, name, signature) FIELD(name, typeArrayOop, obj_field, (typeArrayOop)) +#define STATIC_OOP_FIELD(klassName, name, signature) STATIC_OOPISH_FIELD(klassName, name, oop, signature) +#define STATIC_OBJARRAYOOP_FIELD(klassName, name, signature) STATIC_OOPISH_FIELD(klassName, name, objArrayOop, signature) +#define STATIC_OOPISH_FIELD(klassName, name, type, signature) \ + static int _##name##_offset; \ + static type name() { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + if (UseCompressedOops) { \ + return (type) oopDesc::load_decode_heap_oop((narrowOop *)addr); \ + } else { \ + return (type) oopDesc::load_decode_heap_oop((oop*)addr); \ + } \ + } \ + static void set_##name(type x) { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + assert(klassName::klass() != NULL, "Class not yet loaded: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + if (UseCompressedOops) { \ + oop_store((narrowOop *)addr, x); \ + } else { \ + oop_store((oop*)addr, x); \ + } \ + } +#define STATIC_PRIMITIVE_FIELD(klassName, name, jtypename) \ + static int _##name##_offset; \ + static jtypename name() { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + return *((jtypename *)addr); \ + } \ + static void set_##name(jtypename x) { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + *((jtypename *)addr) = x; \ + } + +#define STATIC_INT_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jint) +#define STATIC_BOOLEAN_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jboolean) + +COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, TYPEARRAYOOP_FIELD, OBJARRAYOOP_FIELD, STATIC_OOP_FIELD, STATIC_OBJARRAYOOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD) +#undef START_CLASS +#undef END_CLASS +#undef FIELD +#undef CHAR_FIELD +#undef INT_FIELD +#undef BOOLEAN_FIELD +#undef LONG_FIELD +#undef FLOAT_FIELD +#undef OOP_FIELD +#undef TYPEARRAYOOP_FIELD +#undef OBJARRAYOOP_FIELD +#undef STATIC_OOPISH_FIELD +#undef STATIC_OOP_FIELD +#undef STATIC_OBJARRAYOOP_FIELD +#undef STATIC_INT_FIELD +#undef STATIC_BOOLEAN_FIELD +#undef EMPTY_CAST + +void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field); + +#endif // SHARE_VM_JVMCI_JVMCIJAVACLASSES_HPP diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp new file mode 100644 index 00000000000..d436a265cc7 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp @@ -0,0 +1,1014 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "asm/codeBuffer.hpp" +#include "code/codeCache.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/disassembler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "prims/jvm.h" +#include "runtime/biasedLocking.hpp" +#include "runtime/interfaceSupport.hpp" +#include "runtime/reflection.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/debug.hpp" +#include "utilities/defaultStream.hpp" + +#if defined(_MSC_VER) +#define strtoll _strtoi64 +#endif + +jobject JVMCIRuntime::_HotSpotJVMCIRuntime_instance = NULL; +bool JVMCIRuntime::_HotSpotJVMCIRuntime_initialized = false; +bool JVMCIRuntime::_well_known_classes_initialized = false; +const char* JVMCIRuntime::_compiler = NULL; +int JVMCIRuntime::_options_count = 0; +SystemProperty** JVMCIRuntime::_options = NULL; +bool JVMCIRuntime::_shutdown_called = false; + +static const char* OPTION_PREFIX = "jvmci.option."; +static const size_t OPTION_PREFIX_LEN = strlen(OPTION_PREFIX); + +BasicType JVMCIRuntime::kindToBasicType(jchar ch) { + switch(ch) { + case 'z': return T_BOOLEAN; + case 'b': return T_BYTE; + case 's': return T_SHORT; + case 'c': return T_CHAR; + case 'i': return T_INT; + case 'f': return T_FLOAT; + case 'j': return T_LONG; + case 'd': return T_DOUBLE; + case 'a': return T_OBJECT; + case '-': return T_ILLEGAL; + default: + fatal("unexpected Kind: %c", ch); + break; + } + return T_ILLEGAL; +} + +// Simple helper to see if the caller of a runtime stub which +// entered the VM has been deoptimized + +static bool caller_is_deopted() { + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, false); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + assert(caller_frame.is_compiled_frame(), "must be compiled"); + return caller_frame.is_deoptimized_frame(); +} + +// Stress deoptimization +static void deopt_caller() { + if ( !caller_is_deopted()) { + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, false); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); + assert(caller_is_deopted(), "Must be deoptimized"); + } +} + +JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance(JavaThread* thread, Klass* klass)) + JRT_BLOCK; + assert(klass->is_klass(), "not a class"); + instanceKlassHandle h(thread, klass); + h->check_valid_for_instantiation(true, CHECK); + // make sure klass is initialized + h->initialize(CHECK); + // allocate instance and return via TLS + oop obj = h->allocate_instance(CHECK); + thread->set_vm_result(obj); + JRT_BLOCK_END; + + if (ReduceInitialCardMarks) { + new_store_pre_barrier(thread); + } +JRT_END + +JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_klass, jint length)) + JRT_BLOCK; + // Note: no handle for klass needed since they are not used + // anymore after new_objArray() and no GC can happen before. + // (This may have to change if this code changes!) + assert(array_klass->is_klass(), "not a class"); + oop obj; + if (array_klass->oop_is_typeArray()) { + BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type(); + obj = oopFactory::new_typeArray(elt_type, length, CHECK); + } else { + Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); + obj = oopFactory::new_objArray(elem_klass, length, CHECK); + } + thread->set_vm_result(obj); + // This is pretty rare but this runtime patch is stressful to deoptimization + // if we deoptimize here so force a deopt to stress the path. + if (DeoptimizeALot) { + static int deopts = 0; + // Alternate between deoptimizing and raising an error (which will also cause a deopt) + if (deopts++ % 2 == 0) { + ResourceMark rm(THREAD); + THROW(vmSymbols::java_lang_OutOfMemoryError()); + } else { + deopt_caller(); + } + } + JRT_BLOCK_END; + + if (ReduceInitialCardMarks) { + new_store_pre_barrier(thread); + } +JRT_END + +void JVMCIRuntime::new_store_pre_barrier(JavaThread* thread) { + // After any safepoint, just before going back to compiled code, + // we inform the GC that we will be doing initializing writes to + // this object in the future without emitting card-marks, so + // GC may take any compensating steps. + // NOTE: Keep this code consistent with GraphKit::store_barrier. + + oop new_obj = thread->vm_result(); + if (new_obj == NULL) return; + + assert(Universe::heap()->can_elide_tlab_store_barriers(), + "compiler must check this first"); + // GC may decide to give back a safer copy of new_obj. + new_obj = Universe::heap()->new_store_pre_barrier(thread, new_obj); + thread->set_vm_result(new_obj); +} + +JRT_ENTRY(void, JVMCIRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims)) + assert(klass->is_klass(), "not a class"); + assert(rank >= 1, "rank must be nonzero"); + oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length)) + oop obj = Reflection::reflect_new_array(element_mirror, length, CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror)) + instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(type_mirror)); + + if (klass == NULL) { + ResourceMark rm(THREAD); + THROW(vmSymbols::java_lang_InstantiationException()); + } + + // Create new instance (the receiver) + klass->check_valid_for_instantiation(false, CHECK); + + // Make sure klass gets initialized + klass->initialize(CHECK); + + oop obj = klass->allocate_instance(CHECK); + thread->set_vm_result(obj); +JRT_END + +extern void vm_exit(int code); + +// Enter this method from compiled code handler below. This is where we transition +// to VM mode. This is done as a helper routine so that the method called directly +// from compiled code does not have to transition to VM. This allows the entry +// method to see if the nmethod that we have just looked up a handler for has +// been deoptimized while we were in the vm. This simplifies the assembly code +// cpu directories. +// +// We are entering here from exception stub (via the entry method below) +// If there is a compiled exception handler in this method, we will continue there; +// otherwise we will unwind the stack and continue at the caller of top frame method +// Note: we enter in Java using a special JRT wrapper. This wrapper allows us to +// control the area where we can allow a safepoint. After we exit the safepoint area we can +// check to see if the handler we are going to return is now in a nmethod that has +// been deoptimized. If that is the case we return the deopt blob +// unpack_with_exception entry instead. This makes life for the exception blob easier +// because making that same check and diverting is painful from assembly language. +JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, nmethod*& nm)) + // Reset method handle flag. + thread->set_is_method_handle_return(false); + + Handle exception(thread, ex); + nm = CodeCache::find_nmethod(pc); + assert(nm != NULL, "this is not a compiled method"); + // Adjust the pc as needed/ + if (nm->is_deopt_pc(pc)) { + RegisterMap map(thread, false); + frame exception_frame = thread->last_frame().sender(&map); + // if the frame isn't deopted then pc must not correspond to the caller of last_frame + assert(exception_frame.is_deoptimized_frame(), "must be deopted"); + pc = exception_frame.pc(); + } +#ifdef ASSERT + assert(exception.not_null(), "NULL exceptions should be handled by throw_exception"); + assert(exception->is_oop(), "just checking"); + // Check that exception is a subclass of Throwable, otherwise we have a VerifyError + if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { + if (ExitVMOnVerifyError) vm_exit(-1); + ShouldNotReachHere(); + } +#endif + + // Check the stack guard pages and reenable them if necessary and there is + // enough space on the stack to do so. Use fast exceptions only if the guard + // pages are enabled. + bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); + if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); + + if (JvmtiExport::can_post_on_exceptions()) { + // To ensure correct notification of exception catches and throws + // we have to deoptimize here. If we attempted to notify the + // catches and throws during this exception lookup it's possible + // we could deoptimize on the way out of the VM and end back in + // the interpreter at the throw site. This would result in double + // notifications since the interpreter would also notify about + // these same catches and throws as it unwound the frame. + + RegisterMap reg_map(thread); + frame stub_frame = thread->last_frame(); + frame caller_frame = stub_frame.sender(®_map); + + // We don't really want to deoptimize the nmethod itself since we + // can actually continue in the exception handler ourselves but I + // don't see an easy way to have the desired effect. + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); + assert(caller_is_deopted(), "Must be deoptimized"); + + return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + + // ExceptionCache is used only for exceptions at call sites and not for implicit exceptions + if (guard_pages_enabled) { + address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); + if (fast_continuation != NULL) { + // Set flag if return address is a method handle call site. + thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); + return fast_continuation; + } + } + + // If the stack guard pages are enabled, check whether there is a handler in + // the current method. Otherwise (guard pages disabled), force an unwind and + // skip the exception cache update (i.e., just leave continuation==NULL). + address continuation = NULL; + if (guard_pages_enabled) { + + // New exception handling mechanism can support inlined methods + // with exception handlers since the mappings are from PC to PC + + // debugging support + // tracing + if (TraceExceptions) { + ttyLocker ttyl; + ResourceMark rm; + tty->print_cr("Exception <%s> (" INTPTR_FORMAT ") thrown in compiled method <%s> at PC " INTPTR_FORMAT " for thread " INTPTR_FORMAT "", + exception->print_value_string(), p2i((address)exception()), nm->method()->print_value_string(), p2i(pc), p2i(thread)); + } + // for AbortVMOnException flag + NOT_PRODUCT(Exceptions::debug_check_abort(exception)); + + // Clear out the exception oop and pc since looking up an + // exception handler can cause class loading, which might throw an + // exception and those fields are expected to be clear during + // normal bytecode execution. + thread->clear_exception_oop_and_pc(); + + continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false); + // If an exception was thrown during exception dispatch, the exception oop may have changed + thread->set_exception_oop(exception()); + thread->set_exception_pc(pc); + + // the exception cache is used only by non-implicit exceptions + if (continuation != NULL && !SharedRuntime::deopt_blob()->contains(continuation)) { + nm->add_handler_for_exception_and_pc(exception, pc, continuation); + } + } + + // Set flag if return address is a method handle call site. + thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); + + if (TraceExceptions) { + ttyLocker ttyl; + ResourceMark rm; + tty->print_cr("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT " for exception thrown at PC " PTR_FORMAT, + p2i(thread), p2i(continuation), p2i(pc)); + } + + return continuation; +JRT_END + +// Enter this method from compiled code only if there is a Java exception handler +// in the method handling the exception. +// We are entering here from exception stub. We don't do a normal VM transition here. +// We do it in a helper. This is so we can check to see if the nmethod we have just +// searched for an exception handler has been deoptimized in the meantime. +address JVMCIRuntime::exception_handler_for_pc(JavaThread* thread) { + oop exception = thread->exception_oop(); + address pc = thread->exception_pc(); + // Still in Java mode + DEBUG_ONLY(ResetNoHandleMark rnhm); + nmethod* nm = NULL; + address continuation = NULL; + { + // Enter VM mode by calling the helper + ResetNoHandleMark rnhm; + continuation = exception_handler_for_pc_helper(thread, exception, pc, nm); + } + // Back in JAVA, use no oops DON'T safepoint + + // Now check to see if the compiled method we were called from is now deoptimized. + // If so we must return to the deopt blob and deoptimize the nmethod + if (nm != NULL && caller_is_deopted()) { + continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + + assert(continuation != NULL, "no handler found"); + return continuation; +} + +JRT_ENTRY(void, JVMCIRuntime::create_null_exception(JavaThread* thread)) + SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_NullPointerException()); + thread->set_vm_result(PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::create_out_of_bounds_exception(JavaThread* thread, jint index)) + char message[jintAsStringSize]; + sprintf(message, "%d", index); + SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message); + thread->set_vm_result(PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; +JRT_END + +JRT_ENTRY_NO_ASYNC(void, JVMCIRuntime::monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock)) + IF_TRACE_jvmci_3 { + char type[O_BUFLEN]; + obj->klass()->name()->as_C_string(type, O_BUFLEN); + markOop mark = obj->mark(); + TRACE_jvmci_3("%s: entered locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(mark), p2i(lock)); + tty->flush(); + } +#ifdef ASSERT + if (PrintBiasedLockingStatistics) { + Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); + } +#endif + Handle h_obj(thread, obj); + assert(h_obj()->is_oop(), "must be NULL or an object"); + if (UseBiasedLocking) { + // Retry fast entry if bias is revoked to avoid unnecessary inflation + ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); + } else { + if (JVMCIUseFastLocking) { + // When using fast locking, the compiled code has already tried the fast case + ObjectSynchronizer::slow_enter(h_obj, lock, THREAD); + } else { + ObjectSynchronizer::fast_enter(h_obj, lock, false, THREAD); + } + } + TRACE_jvmci_3("%s: exiting locking slow with obj=" INTPTR_FORMAT, thread->name(), p2i(obj)); +JRT_END + +JRT_LEAF(void, JVMCIRuntime::monitorexit(JavaThread* thread, oopDesc* obj, BasicLock* lock)) + assert(thread == JavaThread::current(), "threads must correspond"); + assert(thread->last_Java_sp(), "last_Java_sp must be set"); + // monitorexit is non-blocking (leaf routine) => no exceptions can be thrown + EXCEPTION_MARK; + +#ifdef DEBUG + if (!obj->is_oop()) { + ResetNoHandleMark rhm; + nmethod* method = thread->last_frame().cb()->as_nmethod_or_null(); + if (method != NULL) { + tty->print_cr("ERROR in monitorexit in method %s wrong obj " INTPTR_FORMAT, method->name(), p2i(obj)); + } + thread->print_stack_on(tty); + assert(false, "invalid lock object pointer dected"); + } +#endif + + if (JVMCIUseFastLocking) { + // When using fast locking, the compiled code has already tried the fast case + ObjectSynchronizer::slow_exit(obj, lock, THREAD); + } else { + ObjectSynchronizer::fast_exit(obj, lock, THREAD); + } + IF_TRACE_jvmci_3 { + char type[O_BUFLEN]; + obj->klass()->name()->as_C_string(type, O_BUFLEN); + TRACE_jvmci_3("%s: exited locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(obj->mark()), p2i(lock)); + tty->flush(); + } +JRT_END + +JRT_LEAF(void, JVMCIRuntime::log_object(JavaThread* thread, oopDesc* obj, jint flags)) + bool string = mask_bits_are_true(flags, LOG_OBJECT_STRING); + bool addr = mask_bits_are_true(flags, LOG_OBJECT_ADDRESS); + bool newline = mask_bits_are_true(flags, LOG_OBJECT_NEWLINE); + if (!string) { + if (!addr && obj->is_oop_or_null(true)) { + char buf[O_BUFLEN]; + tty->print("%s@" INTPTR_FORMAT, obj->klass()->name()->as_C_string(buf, O_BUFLEN), p2i(obj)); + } else { + tty->print(INTPTR_FORMAT, p2i(obj)); + } + } else { + ResourceMark rm; + assert(obj != NULL && java_lang_String::is_instance(obj), "must be"); + char *buf = java_lang_String::as_utf8_string(obj); + tty->print_raw(buf); + } + if (newline) { + tty->cr(); + } +JRT_END + +JRT_LEAF(void, JVMCIRuntime::write_barrier_pre(JavaThread* thread, oopDesc* obj)) + thread->satb_mark_queue().enqueue(obj); +JRT_END + +JRT_LEAF(void, JVMCIRuntime::write_barrier_post(JavaThread* thread, void* card_addr)) + thread->dirty_card_queue().enqueue(card_addr); +JRT_END + +JRT_LEAF(jboolean, JVMCIRuntime::validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child)) + bool ret = true; + if(!Universe::heap()->is_in_closed_subset(parent)) { + tty->print_cr("Parent Object " INTPTR_FORMAT " not in heap", p2i(parent)); + parent->print(); + ret=false; + } + if(!Universe::heap()->is_in_closed_subset(child)) { + tty->print_cr("Child Object " INTPTR_FORMAT " not in heap", p2i(child)); + child->print(); + ret=false; + } + return (jint)ret; +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::vm_error(JavaThread* thread, jlong where, jlong format, jlong value)) + ResourceMark rm; + const char *error_msg = where == 0L ? "" : (char*) (address) where; + char *detail_msg = NULL; + if (format != 0L) { + const char* buf = (char*) (address) format; + size_t detail_msg_length = strlen(buf) * 2; + detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length); + jio_snprintf(detail_msg, detail_msg_length, buf, value); + report_vm_error(__FILE__, __LINE__, error_msg, "%s", detail_msg); + } else { + report_vm_error(__FILE__, __LINE__, error_msg); + } +JRT_END + +JRT_LEAF(oopDesc*, JVMCIRuntime::load_and_clear_exception(JavaThread* thread)) + oop exception = thread->exception_oop(); + assert(exception != NULL, "npe"); + thread->set_exception_oop(NULL); + thread->set_exception_pc(0); + return exception; +JRT_END + +PRAGMA_DIAG_PUSH +PRAGMA_FORMAT_NONLITERAL_IGNORED +JRT_LEAF(void, JVMCIRuntime::log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3)) + ResourceMark rm; + assert(format != NULL && java_lang_String::is_instance(format), "must be"); + char *buf = java_lang_String::as_utf8_string(format); + tty->print((const char*)buf, v1, v2, v3); +JRT_END +PRAGMA_DIAG_POP + +static void decipher(jlong v, bool ignoreZero) { + if (v != 0 || !ignoreZero) { + void* p = (void *)(address) v; + CodeBlob* cb = CodeCache::find_blob(p); + if (cb) { + if (cb->is_nmethod()) { + char buf[O_BUFLEN]; + tty->print("%s [" INTPTR_FORMAT "+" JLONG_FORMAT "]", cb->as_nmethod_or_null()->method()->name_and_sig_as_C_string(buf, O_BUFLEN), p2i(cb->code_begin()), (jlong)((address)v - cb->code_begin())); + return; + } + cb->print_value_on(tty); + return; + } + if (Universe::heap()->is_in(p)) { + oop obj = oop(p); + obj->print_value_on(tty); + return; + } + tty->print(INTPTR_FORMAT " [long: " JLONG_FORMAT ", double %lf, char %c]",p2i((void *)v), (jlong)v, (jdouble)v, (char)v); + } +} + +PRAGMA_DIAG_PUSH +PRAGMA_FORMAT_NONLITERAL_IGNORED +JRT_LEAF(void, JVMCIRuntime::vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3)) + ResourceMark rm; + const char *buf = (const char*) (address) format; + if (vmError) { + if (buf != NULL) { + fatal(buf, v1, v2, v3); + } else { + fatal(""); + } + } else if (buf != NULL) { + tty->print(buf, v1, v2, v3); + } else { + assert(v2 == 0, "v2 != 0"); + assert(v3 == 0, "v3 != 0"); + decipher(v1, false); + } +JRT_END +PRAGMA_DIAG_POP + +JRT_LEAF(void, JVMCIRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) + union { + jlong l; + jdouble d; + jfloat f; + } uu; + uu.l = value; + switch (typeChar) { + case 'z': tty->print(value == 0 ? "false" : "true"); break; + case 'b': tty->print("%d", (jbyte) value); break; + case 'c': tty->print("%c", (jchar) value); break; + case 's': tty->print("%d", (jshort) value); break; + case 'i': tty->print("%d", (jint) value); break; + case 'f': tty->print("%f", uu.f); break; + case 'j': tty->print(JLONG_FORMAT, value); break; + case 'd': tty->print("%lf", uu.d); break; + default: assert(false, "unknown typeChar"); break; + } + if (newline) { + tty->cr(); + } +JRT_END + +JRT_ENTRY(jint, JVMCIRuntime::identity_hash_code(JavaThread* thread, oopDesc* obj)) + return (jint) obj->identity_hash(); +JRT_END + +JRT_ENTRY(jboolean, JVMCIRuntime::thread_is_interrupted(JavaThread* thread, oopDesc* receiver, jboolean clear_interrupted)) + // Ensure that the C++ Thread and OSThread structures aren't freed before we operate. + // This locking requires thread_in_vm which is why this method cannot be JRT_LEAF. + Handle receiverHandle(thread, receiver); + MutexLockerEx ml(thread->threadObj() == (void*)receiver ? NULL : Threads_lock); + JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle()); + if (receiverThread == NULL) { + // The other thread may exit during this process, which is ok so return false. + return JNI_FALSE; + } else { + return (jint) Thread::is_interrupted(receiverThread, clear_interrupted != 0); + } +JRT_END + +JRT_ENTRY(jint, JVMCIRuntime::test_deoptimize_call_int(JavaThread* thread, int value)) + deopt_caller(); + return value; +JRT_END + +// private static JVMCIRuntime JVMCI.initializeRuntime() +JVM_ENTRY(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) + if (!EnableJVMCI) { + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled") + } + JVMCIRuntime::initialize_HotSpotJVMCIRuntime(CHECK_NULL); + jobject ret = JVMCIRuntime::get_HotSpotJVMCIRuntime_jobject(CHECK_NULL); + return ret; +JVM_END + +Handle JVMCIRuntime::callStatic(const char* className, const char* methodName, const char* signature, JavaCallArguments* args, TRAPS) { + guarantee(!_HotSpotJVMCIRuntime_initialized, "cannot reinitialize HotSpotJVMCIRuntime"); + + TempNewSymbol name = SymbolTable::new_symbol(className, CHECK_(Handle())); + KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, CHECK_(Handle())); + TempNewSymbol runtime = SymbolTable::new_symbol(methodName, CHECK_(Handle())); + TempNewSymbol sig = SymbolTable::new_symbol(signature, CHECK_(Handle())); + JavaValue result(T_OBJECT); + if (args == NULL) { + JavaCalls::call_static(&result, klass, runtime, sig, CHECK_(Handle())); + } else { + JavaCalls::call_static(&result, klass, runtime, sig, args, CHECK_(Handle())); + } + return Handle((oop)result.get_jobject()); +} + +static bool jvmci_options_file_exists() { + const char* home = Arguments::get_java_home(); + size_t path_len = strlen(home) + strlen("/lib/jvmci/options") + 1; + char path[JVM_MAXPATHLEN]; + char sep = os::file_separator()[0]; + jio_snprintf(path, JVM_MAXPATHLEN, "%s%clib%cjvmci%coptions", home, sep, sep, sep); + struct stat st; + return os::stat(path, &st) == 0; +} + +void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(TRAPS) { + if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) { +#ifdef ASSERT + // This should only be called in the context of the JVMCI class being initialized + TempNewSymbol name = SymbolTable::new_symbol("jdk/vm/ci/runtime/JVMCI", CHECK); + Klass* k = SystemDictionary::resolve_or_null(name, CHECK); + instanceKlassHandle klass = InstanceKlass::cast(k); + assert(klass->is_being_initialized() && klass->is_reentrant_initialization(THREAD), + "HotSpotJVMCIRuntime initialization should only be triggered through JVMCI initialization"); +#endif + + bool parseOptionsFile = jvmci_options_file_exists(); + if (_options != NULL || parseOptionsFile) { + JavaCallArguments args; + objArrayOop options; + if (_options != NULL) { + options = oopFactory::new_objArray(SystemDictionary::String_klass(), _options_count * 2, CHECK); + for (int i = 0; i < _options_count; i++) { + SystemProperty* prop = _options[i]; + oop name = java_lang_String::create_oop_from_str(prop->key() + OPTION_PREFIX_LEN, CHECK); + oop value = java_lang_String::create_oop_from_str(prop->value(), CHECK); + options->obj_at_put(i * 2, name); + options->obj_at_put((i * 2) + 1, value); + } + } else { + options = NULL; + } + args.push_oop(options); + args.push_int(parseOptionsFile); + callStatic("jdk/vm/ci/options/OptionsParser", + "parseOptionsFromVM", + "([Ljava/lang/String;Z)Ljava/lang/Boolean;", &args, CHECK); + } + + if (_compiler != NULL) { + JavaCallArguments args; + oop compiler = java_lang_String::create_oop_from_str(_compiler, CHECK); + args.push_oop(compiler); + callStatic("jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig", + "selectCompiler", + "(Ljava/lang/String;)Ljava/lang/Boolean;", &args, CHECK); + } + + Handle result = callStatic("jdk/vm/ci/hotspot/HotSpotJVMCIRuntime", + "runtime", + "()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;", NULL, CHECK); + _HotSpotJVMCIRuntime_initialized = true; + _HotSpotJVMCIRuntime_instance = JNIHandles::make_global(result()); + } +} + +void JVMCIRuntime::initialize_JVMCI(TRAPS) { + if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) { + callStatic("jdk/vm/ci/runtime/JVMCI", + "getRuntime", + "()Ljdk/vm/ci/runtime/JVMCIRuntime;", NULL, CHECK); + } + assert(_HotSpotJVMCIRuntime_initialized == true, "what?"); +} + +void JVMCIRuntime::initialize_well_known_classes(TRAPS) { + if (JVMCIRuntime::_well_known_classes_initialized == false) { + SystemDictionary::WKID scan = SystemDictionary::FIRST_JVMCI_WKID; + SystemDictionary::initialize_wk_klasses_through(SystemDictionary::LAST_JVMCI_WKID, scan, CHECK); + JVMCIJavaClasses::compute_offsets(); + JVMCIRuntime::_well_known_classes_initialized = true; + } +} + +void JVMCIRuntime::metadata_do(void f(Metadata*)) { + // For simplicity, the existence of HotSpotJVMCIMetaAccessContext in + // the SystemDictionary well known classes should ensure the other + // classes have already been loaded, so make sure their order in the + // table enforces that. + assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl) < + SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); + assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotConstantPool) < + SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); + assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl) < + SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); + + if (HotSpotJVMCIMetaAccessContext::klass() == NULL || + !HotSpotJVMCIMetaAccessContext::klass()->is_linked()) { + // Nothing could be registered yet + return; + } + + // WeakReference[] + objArrayOop allContexts = HotSpotJVMCIMetaAccessContext::allContexts(); + if (allContexts == NULL) { + return; + } + + // These must be loaded at this point but the linking state doesn't matter. + assert(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass() != NULL, "must be loaded"); + assert(SystemDictionary::HotSpotConstantPool_klass() != NULL, "must be loaded"); + assert(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass() != NULL, "must be loaded"); + + for (int i = 0; i < allContexts->length(); i++) { + oop ref = allContexts->obj_at(i); + if (ref != NULL) { + oop referent = java_lang_ref_Reference::referent(ref); + if (referent != NULL) { + // Chunked Object[] with last element pointing to next chunk + objArrayOop metadataRoots = HotSpotJVMCIMetaAccessContext::metadataRoots(referent); + while (metadataRoots != NULL) { + for (int typeIndex = 0; typeIndex < metadataRoots->length() - 1; typeIndex++) { + oop reference = metadataRoots->obj_at(typeIndex); + if (reference == NULL) { + continue; + } + oop metadataRoot = java_lang_ref_Reference::referent(reference); + if (metadataRoot == NULL) { + continue; + } + if (metadataRoot->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + Method* method = CompilerToVM::asMethod(metadataRoot); + f(method); + } else if (metadataRoot->is_a(SystemDictionary::HotSpotConstantPool_klass())) { + ConstantPool* constantPool = CompilerToVM::asConstantPool(metadataRoot); + f(constantPool); + } else if (metadataRoot->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { + Klass* klass = CompilerToVM::asKlass(metadataRoot); + f(klass); + } else { + metadataRoot->print(); + ShouldNotReachHere(); + } + } + metadataRoots = (objArrayOop)metadataRoots->obj_at(metadataRoots->length() - 1); + assert(metadataRoots == NULL || metadataRoots->is_objArray(), "wrong type"); + } + } + } + } +} + +// private static void CompilerToVM.registerNatives() +JVM_ENTRY(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass)) + if (!EnableJVMCI) { + THROW_MSG(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled"); + } + +#ifdef _LP64 +#ifndef TARGET_ARCH_sparc + uintptr_t heap_end = (uintptr_t) Universe::heap()->reserved_region().end(); + uintptr_t allocation_end = heap_end + ((uintptr_t)16) * 1024 * 1024 * 1024; + guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)"); +#endif // TARGET_ARCH_sparc +#else + fatal("check TLAB allocation code for address space conflicts"); +#endif + + JVMCIRuntime::initialize_well_known_classes(CHECK); + + { + ThreadToNativeFromVM trans(thread); + + // Ensure _non_oop_bits is initialized + Universe::non_oop_word(); + + env->RegisterNatives(c2vmClass, CompilerToVM::methods, CompilerToVM::methods_count()); + } +JVM_END + +/** + * Closure for parsing a line from a *.properties file in jre/lib/jvmci/properties. + * The line must match the regular expression "[^=]+=.*". That is one or more + * characters other than '=' followed by '=' followed by zero or more characters. + * Everything before the '=' is the property name and everything after '=' is the value. + * Lines that start with '#' are treated as comments and ignored. + * No special processing of whitespace or any escape characters is performed. + * The last definition of a property "wins" (i.e., it overrides all earlier + * definitions of the property). + */ +class JVMCIPropertiesFileClosure : public ParseClosure { + SystemProperty** _plist; +public: + JVMCIPropertiesFileClosure(SystemProperty** plist) : _plist(plist) {} + void do_line(char* line) { + if (line[0] == '#') { + // skip comment + return; + } + size_t len = strlen(line); + char* sep = strchr(line, '='); + if (sep == NULL) { + warn_and_abort("invalid format: could not find '=' character"); + return; + } + if (sep == line) { + warn_and_abort("invalid format: name cannot be empty"); + return; + } + *sep = '\0'; + const char* name = line; + char* value = sep + 1; + Arguments::PropertyList_unique_add(_plist, name, value); + } +}; + +void JVMCIRuntime::init_system_properties(SystemProperty** plist) { + char jvmciDir[JVM_MAXPATHLEN]; + const char* fileSep = os::file_separator(); + jio_snprintf(jvmciDir, sizeof(jvmciDir), "%s%slib%sjvmci", + Arguments::get_java_home(), fileSep, fileSep, fileSep); + DIR* dir = os::opendir(jvmciDir); + if (dir != NULL) { + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(jvmciDir), mtInternal); + JVMCIPropertiesFileClosure closure(plist); + const unsigned suffix_len = (unsigned)strlen(".properties"); + while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL && !closure.is_aborted()) { + const char* name = entry->d_name; + if (strlen(name) > suffix_len && strcmp(name + strlen(name) - suffix_len, ".properties") == 0) { + char propertiesFilePath[JVM_MAXPATHLEN]; + jio_snprintf(propertiesFilePath, sizeof(propertiesFilePath), "%s%s%s",jvmciDir, fileSep, name); + JVMCIRuntime::parse_lines(propertiesFilePath, &closure, false); + } + } + FREE_C_HEAP_ARRAY(char, dbuf); + os::closedir(dir); + } +} + +#define CHECK_WARN_ABORT_(message) THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + warning(message); \ + char buf[512]; \ + jio_snprintf(buf, 512, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ + return; \ + } \ + (void)(0 + +void JVMCIRuntime::save_compiler(const char* compiler) { + assert(compiler != NULL, "npe"); + assert(_compiler == NULL, "cannot reassign JVMCI compiler"); + _compiler = compiler; +} + +jint JVMCIRuntime::save_options(SystemProperty* props) { + int count = 0; + SystemProperty* first = NULL; + for (SystemProperty* p = props; p != NULL; p = p->next()) { + if (strncmp(p->key(), OPTION_PREFIX, OPTION_PREFIX_LEN) == 0) { + if (p->value() == NULL || strlen(p->value()) == 0) { + jio_fprintf(defaultStream::output_stream(), "JVMCI option %s must have non-zero length value\n", p->key()); + return JNI_ERR; + } + if (first == NULL) { + first = p; + } + count++; + } + } + if (count != 0) { + _options_count = count; + _options = NEW_C_HEAP_ARRAY(SystemProperty*, count, mtCompiler); + _options[0] = first; + SystemProperty** insert_pos = _options + 1; + for (SystemProperty* p = first->next(); p != NULL; p = p->next()) { + if (strncmp(p->key(), OPTION_PREFIX, OPTION_PREFIX_LEN) == 0) { + *insert_pos = p; + insert_pos++; + } + } + assert (insert_pos - _options == count, "must be"); + } + return JNI_OK; +} + +void JVMCIRuntime::shutdown() { + if (_HotSpotJVMCIRuntime_instance != NULL) { + _shutdown_called = true; + JavaThread* THREAD = JavaThread::current(); + HandleMark hm(THREAD); + Handle receiver = get_HotSpotJVMCIRuntime(CHECK_ABORT); + JavaValue result(T_VOID); + JavaCallArguments args; + args.push_oop(receiver); + JavaCalls::call_special(&result, receiver->klass(), vmSymbols::shutdown_method_name(), vmSymbols::void_method_signature(), &args, CHECK_ABORT); + } +} + +void JVMCIRuntime::call_printStackTrace(Handle exception, Thread* thread) { + assert(exception->is_a(SystemDictionary::Throwable_klass()), "Throwable instance expected"); + JavaValue result(T_VOID); + JavaCalls::call_virtual(&result, + exception, + KlassHandle(thread, + SystemDictionary::Throwable_klass()), + vmSymbols::printStackTrace_name(), + vmSymbols::void_method_signature(), + thread); +} + +void JVMCIRuntime::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) { + Thread* THREAD = Thread::current(); + CLEAR_PENDING_EXCEPTION; + tty->print_raw_cr(message); + call_printStackTrace(exception, THREAD); + + // Give other aborting threads to also print their stack traces. + // This can be very useful when debugging class initialization + // failures. + os::sleep(THREAD, 200, false); + + vm_abort(dump_core); +} + +void JVMCIRuntime::parse_lines(char* path, ParseClosure* closure, bool warnStatFailure) { + struct stat st; + if (os::stat(path, &st) == 0 && (st.st_mode & S_IFREG) == S_IFREG) { // exists & is regular file + int file_handle = os::open(path, 0, 0); + if (file_handle != -1) { + char* buffer = NEW_C_HEAP_ARRAY(char, st.st_size + 1, mtInternal); + int num_read; + num_read = (int) os::read(file_handle, (char*) buffer, st.st_size); + if (num_read == -1) { + warning("Error reading file %s due to %s", path, strerror(errno)); + } else if (num_read != st.st_size) { + warning("Only read %d of " SIZE_FORMAT " bytes from %s", num_read, (size_t) st.st_size, path); + } + os::close(file_handle); + closure->set_filename(path); + if (num_read == st.st_size) { + buffer[num_read] = '\0'; + + char* line = buffer; + while (line - buffer < num_read && !closure->is_aborted()) { + // find line end (\r, \n or \r\n) + char* nextline = NULL; + char* cr = strchr(line, '\r'); + char* lf = strchr(line, '\n'); + if (cr != NULL && lf != NULL) { + char* min = MIN2(cr, lf); + *min = '\0'; + if (lf == cr + 1) { + nextline = lf + 1; + } else { + nextline = min + 1; + } + } else if (cr != NULL) { + *cr = '\0'; + nextline = cr + 1; + } else if (lf != NULL) { + *lf = '\0'; + nextline = lf + 1; + } + // trim left + while (*line == ' ' || *line == '\t') line++; + char* end = line + strlen(line); + // trim right + while (end > line && (*(end -1) == ' ' || *(end -1) == '\t')) end--; + *end = '\0'; + // skip comments and empty lines + if (*line != '#' && strlen(line) > 0) { + closure->parse_line(line); + } + if (nextline != NULL) { + line = nextline; + } else { + // File without newline at the end + break; + } + } + } + FREE_C_HEAP_ARRAY(char, buffer); + } else { + warning("Error opening file %s due to %s", path, strerror(errno)); + } + } else if (warnStatFailure) { + warning("Could not stat file %s due to %s", path, strerror(errno)); + } +} diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp new file mode 100644 index 00000000000..df41d67688e --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_RUNTIME_HPP +#define SHARE_VM_JVMCI_JVMCI_RUNTIME_HPP + +#include "interpreter/interpreter.hpp" +#include "memory/allocation.hpp" +#include "runtime/arguments.hpp" +#include "runtime/deoptimization.hpp" + +class ParseClosure : public StackObj { + int _lineNo; + char* _filename; + bool _abort; +protected: + void abort() { _abort = true; } + void warn_and_abort(const char* message) { + warn(message); + abort(); + } + void warn(const char* message) { + warning("Error at line %d while parsing %s: %s", _lineNo, _filename == NULL ? "?" : _filename, message); + } + public: + ParseClosure() : _lineNo(0), _filename(NULL), _abort(false) {} + void parse_line(char* line) { + _lineNo++; + do_line(line); + } + virtual void do_line(char* line) = 0; + int lineNo() { return _lineNo; } + bool is_aborted() { return _abort; } + void set_filename(char* path) {_filename = path; _lineNo = 0;} +}; + +#define CHECK_ABORT THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ + return; \ + } \ + (void)(0 + +#define CHECK_ABORT_(result) THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ + return result; \ + } \ + (void)(0 + +class JVMCIRuntime: public AllStatic { + private: + static jobject _HotSpotJVMCIRuntime_instance; + static bool _HotSpotJVMCIRuntime_initialized; + static bool _well_known_classes_initialized; + static const char* _compiler; + static int _options_count; + static SystemProperty** _options; + + static bool _shutdown_called; + + /** + * Instantiates a service object, calls its default constructor and returns it. + * + * @param name the name of a class implementing jdk.vm.ci.service.Service + */ + static Handle create_Service(const char* name, TRAPS); + + public: + + /** + * Parses *.properties files in jre/lib/jvmci/ and adds the properties to plist. + */ + static void init_system_properties(SystemProperty** plist); + + /** + * Saves the value of the "jvmci.compiler" system property for processing + * when JVMCI is initialized. + */ + static void save_compiler(const char* compiler); + + /** + * Saves the value of the system properties starting with "jvmci.option." for processing + * when JVMCI is initialized. + * + * @param props the head of the system property list + * @return JNI_ERR if a JVMCI option has a zero length value, JNI_OK otherwise + */ + static jint save_options(SystemProperty* props); + + static bool is_HotSpotJVMCIRuntime_initialized() { return _HotSpotJVMCIRuntime_initialized; } + + /** + * Gets the singleton HotSpotJVMCIRuntime instance, initializing it if necessary + */ + static Handle get_HotSpotJVMCIRuntime(TRAPS) { + initialize_JVMCI(CHECK_(Handle())); + return Handle(JNIHandles::resolve_non_null(_HotSpotJVMCIRuntime_instance)); + } + + static jobject get_HotSpotJVMCIRuntime_jobject(TRAPS) { + initialize_JVMCI(CHECK_NULL); + assert(_HotSpotJVMCIRuntime_initialized, "must be"); + return _HotSpotJVMCIRuntime_instance; + } + + static Handle callStatic(const char* className, const char* methodName, const char* returnType, JavaCallArguments* args, TRAPS); + + /** + * Trigger initialization of HotSpotJVMCIRuntime through JVMCI.getRuntime() + */ + static void initialize_JVMCI(TRAPS); + + /** + * Explicitly initialize HotSpotJVMCIRuntime itself + */ + static void initialize_HotSpotJVMCIRuntime(TRAPS); + + static void initialize_well_known_classes(TRAPS); + + static void metadata_do(void f(Metadata*)); + + static void shutdown(); + + static bool shutdown_called() { + return _shutdown_called; + } + + static void parse_lines(char* path, ParseClosure* closure, bool warnStatFailure); + + /** + * Aborts the VM due to an unexpected exception. + */ + static void abort_on_pending_exception(Handle exception, const char* message, bool dump_core = false); + + /** + * Calls Throwable.printStackTrace() on a given exception. + */ + static void call_printStackTrace(Handle exception, Thread* thread); + + static BasicType kindToBasicType(jchar ch); + + // The following routines are all called from compiled JVMCI code + + static void new_instance(JavaThread* thread, Klass* klass); + static void new_array(JavaThread* thread, Klass* klass, jint length); + static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims); + static void dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length); + static void dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror); + static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupted); + static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3); + static jint identity_hash_code(JavaThread* thread, oopDesc* obj); + static address exception_handler_for_pc(JavaThread* thread); + static void monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void create_null_exception(JavaThread* thread); + static void create_out_of_bounds_exception(JavaThread* thread, jint index); + static void vm_error(JavaThread* thread, jlong where, jlong format, jlong value); + static oopDesc* load_and_clear_exception(JavaThread* thread); + static void log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3); + static void log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline); + // Note: Must be kept in sync with constants in com.oracle.graal.replacements.Log + enum { + LOG_OBJECT_NEWLINE = 0x01, + LOG_OBJECT_STRING = 0x02, + LOG_OBJECT_ADDRESS = 0x04 + }; + static void log_object(JavaThread* thread, oopDesc* msg, jint flags); + static void write_barrier_pre(JavaThread* thread, oopDesc* obj); + static void write_barrier_post(JavaThread* thread, void* card); + static jboolean validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child); + static void new_store_pre_barrier(JavaThread* thread); + + // Test only function + static int test_deoptimize_call_int(JavaThread* thread, int value); +}; + +// Tracing macros. + +#define IF_TRACE_jvmci_1 if (!(JVMCITraceLevel >= 1)) ; else +#define IF_TRACE_jvmci_2 if (!(JVMCITraceLevel >= 2)) ; else +#define IF_TRACE_jvmci_3 if (!(JVMCITraceLevel >= 3)) ; else +#define IF_TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4)) ; else +#define IF_TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5)) ; else + +#define TRACE_jvmci_1 if (!(JVMCITraceLevel >= 1 && (tty->print("JVMCITrace-1: "), true))) ; else tty->print_cr +#define TRACE_jvmci_2 if (!(JVMCITraceLevel >= 2 && (tty->print(" JVMCITrace-2: "), true))) ; else tty->print_cr +#define TRACE_jvmci_3 if (!(JVMCITraceLevel >= 3 && (tty->print(" JVMCITrace-3: "), true))) ; else tty->print_cr +#define TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4 && (tty->print(" JVMCITrace-4: "), true))) ; else tty->print_cr +#define TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5 && (tty->print(" JVMCITrace-5: "), true))) ; else tty->print_cr + +#endif // SHARE_VM_JVMCI_JVMCI_RUNTIME_HPP diff --git a/hotspot/src/share/vm/gc/shared/watermark.hpp b/hotspot/src/share/vm/jvmci/jvmci_globals.cpp similarity index 51% rename from hotspot/src/share/vm/gc/shared/watermark.hpp rename to hotspot/src/share/vm/jvmci/jvmci_globals.cpp index af33e7b94c8..f555863ed0d 100644 --- a/hotspot/src/share/vm/gc/shared/watermark.hpp +++ b/hotspot/src/share/vm/jvmci/jvmci_globals.cpp @@ -22,40 +22,15 @@ * */ -#ifndef SHARE_VM_GC_SHARED_WATERMARK_HPP -#define SHARE_VM_GC_SHARED_WATERMARK_HPP +#include "precompiled.hpp" +#include "jvmci/jvmci_globals.hpp" -#include "memory/allocation.hpp" -#include "utilities/globalDefinitions.hpp" - -// A water mark points into a space and is used during GC to keep track of -// progress. - -class Space; - -class WaterMark VALUE_OBJ_CLASS_SPEC { - friend class VMStructs; - private: - HeapWord* _point; - Space* _space; - public: - // Accessors - Space* space() const { return _space; } - void set_space(Space* s) { _space = s; } - HeapWord* point() const { return _point; } - void set_point(HeapWord* p) { _point = p; } - - // Constructors - WaterMark(Space* s, HeapWord* p) : _space(s), _point(p) {}; - WaterMark() : _space(NULL), _point(NULL) {}; -}; - -inline bool operator==(const WaterMark& x, const WaterMark& y) { - return (x.point() == y.point()) && (x.space() == y.space()); -} - -inline bool operator!=(const WaterMark& x, const WaterMark& y) { - return !(x == y); -} - -#endif // SHARE_VM_GC_SHARED_WATERMARK_HPP +JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ + MATERIALIZE_PD_DEVELOPER_FLAG, \ + MATERIALIZE_PRODUCT_FLAG, \ + MATERIALIZE_PD_PRODUCT_FLAG, \ + MATERIALIZE_DIAGNOSTIC_FLAG, \ + MATERIALIZE_EXPERIMENTAL_FLAG, \ + MATERIALIZE_NOTPRODUCT_FLAG, + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) diff --git a/hotspot/src/share/vm/jvmci/jvmci_globals.hpp b/hotspot/src/share/vm/jvmci/jvmci_globals.hpp new file mode 100644 index 00000000000..ac1bfd119e6 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/jvmci_globals.hpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_JVMCIGLOBALS_HPP +#define SHARE_VM_JVMCI_JVMCIGLOBALS_HPP + +#include "runtime/globals.hpp" + +// +// Defines all global flags used by the JVMCI compiler. Only flags that need +// to be accessible to the JVMCI C++ code should be defined here. All other +// JVMCI flags should be defined in JVMCIOptions.java. +// +#define JVMCI_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, range, constraint) \ + \ + experimental(bool, EnableJVMCI, false, \ + "Enable JVMCI") \ + \ + experimental(bool, UseJVMCICompiler, false, \ + "Use JVMCI as the default compiler") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, BootstrapJVMCI, false, \ + "Bootstrap JVMCI before running Java main method") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, PrintBootstrap, true, \ + "Print JVMCI bootstrap progress and summary") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCIThreads, 1, \ + "Force number of JVMCI compiler threads to use") \ + range(1, max_jint) \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCIHostThreads, 1, \ + "Force number of compiler threads for JVMCI host compiler") \ + range(1, max_jint) \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, CodeInstallSafepointChecks, true, \ + "Perform explicit safepoint checks while installing code") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + NOT_COMPILER2(product(intx, MaxVectorSize, 64, \ + "Max vector size in bytes, " \ + "actual size could be less depending on elements type")) \ + \ + NOT_COMPILER2(product(bool, ReduceInitialCardMarks, true, \ + "Defer write barriers of young objects")) \ + \ + experimental(intx, JVMCITraceLevel, 0, \ + "Trace level for JVMCI: " \ + "1 means emit a message for each CompilerToVM call," \ + "levels greater than 1 provide progressively greater detail") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCICounterSize, 0, \ + "Reserved size for benchmark counters") \ + range(0, max_jint) \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, JVMCICountersExcludeCompiler, true, \ + "Exclude JVMCI compiler threads from benchmark counters") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + develop(bool, JVMCIUseFastLocking, true, \ + "Use fast inlined locking code") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCINMethodSizeLimit, (80*K)*wordSize, \ + "Maximum size of a compiled method.") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + develop(bool, TraceUncollectedSpeculations, false, \ + "Print message when a failed speculation was not collected") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + + +// Read default values for JVMCI globals + +JVMCI_FLAGS(DECLARE_DEVELOPER_FLAG, \ + DECLARE_PD_DEVELOPER_FLAG, \ + DECLARE_PRODUCT_FLAG, \ + DECLARE_PD_PRODUCT_FLAG, \ + DECLARE_DIAGNOSTIC_FLAG, \ + DECLARE_EXPERIMENTAL_FLAG, \ + DECLARE_NOTPRODUCT_FLAG, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + +#endif // SHARE_VM_JVMCI_JVMCIGLOBALS_HPP diff --git a/hotspot/src/share/vm/jvmci/systemDictionary_jvmci.hpp b/hotspot/src/share/vm/jvmci/systemDictionary_jvmci.hpp new file mode 100644 index 00000000000..931dcaffb9c --- /dev/null +++ b/hotspot/src/share/vm/jvmci/systemDictionary_jvmci.hpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP +#define SHARE_VM_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP + +#if !INCLUDE_JVMCI +#define JVMCI_WK_KLASSES_DO(do_klass) +#else +#define JVMCI_WK_KLASSES_DO(do_klass) \ + /* JVMCI classes. These are loaded on-demand. */ \ + do_klass(HotSpotCompiledCode_klass, jdk_vm_ci_hotspot_HotSpotCompiledCode, Jvmci) \ + do_klass(HotSpotCompiledCode_Comment_klass, jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment, Jvmci) \ + do_klass(HotSpotCompiledNmethod_klass, jdk_vm_ci_hotspot_HotSpotCompiledNmethod, Jvmci) \ + do_klass(HotSpotForeignCallTarget_klass, jdk_vm_ci_hotspot_HotSpotForeignCallTarget, Jvmci) \ + do_klass(HotSpotReferenceMap_klass, jdk_vm_ci_hotspot_HotSpotReferenceMap, Jvmci) \ + do_klass(HotSpotInstalledCode_klass, jdk_vm_ci_hotspot_HotSpotInstalledCode, Jvmci) \ + do_klass(HotSpotNmethod_klass, jdk_vm_ci_hotspot_HotSpotNmethod, Jvmci) \ + do_klass(HotSpotResolvedJavaMethodImpl_klass, jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl, Jvmci) \ + do_klass(HotSpotResolvedObjectTypeImpl_klass, jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl, Jvmci) \ + do_klass(HotSpotCompressedNullConstant_klass, jdk_vm_ci_hotspot_HotSpotCompressedNullConstant, Jvmci) \ + do_klass(HotSpotObjectConstantImpl_klass, jdk_vm_ci_hotspot_HotSpotObjectConstantImpl, Jvmci) \ + do_klass(HotSpotMetaspaceConstantImpl_klass, jdk_vm_ci_hotspot_HotSpotMetaspaceConstantImpl, Jvmci) \ + do_klass(HotSpotSentinelConstant_klass, jdk_vm_ci_hotspot_HotSpotSentinelConstant, Jvmci) \ + do_klass(HotSpotStackFrameReference_klass, jdk_vm_ci_hotspot_HotSpotStackFrameReference, Jvmci) \ + do_klass(HotSpotMetaData_klass, jdk_vm_ci_hotspot_HotSpotMetaData, Jvmci) \ + do_klass(HotSpotOopMap_klass, jdk_vm_ci_hotspot_HotSpotOopMap, Jvmci) \ + do_klass(HotSpotConstantPool_klass, jdk_vm_ci_hotspot_HotSpotConstantPool, Jvmci) \ + do_klass(HotSpotJVMCIMetaAccessContext_klass, jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext, Jvmci) \ + do_klass(Assumptions_ConcreteMethod_klass, jdk_vm_ci_meta_Assumptions_ConcreteMethod, Jvmci) \ + do_klass(Assumptions_NoFinalizableSubclass_klass, jdk_vm_ci_meta_Assumptions_NoFinalizableSubclass, Jvmci) \ + do_klass(Assumptions_ConcreteSubtype_klass, jdk_vm_ci_meta_Assumptions_ConcreteSubtype, Jvmci) \ + do_klass(Assumptions_LeafType_klass, jdk_vm_ci_meta_Assumptions_LeafType, Jvmci) \ + do_klass(Assumptions_CallSiteTargetValue_klass, jdk_vm_ci_meta_Assumptions_CallSiteTargetValue, Jvmci) \ + do_klass(Architecture_klass, jdk_vm_ci_code_Architecture, Jvmci) \ + do_klass(TargetDescription_klass, jdk_vm_ci_code_TargetDescription, Jvmci) \ + do_klass(BytecodePosition_klass, jdk_vm_ci_code_BytecodePosition, Jvmci) \ + do_klass(DebugInfo_klass, jdk_vm_ci_code_DebugInfo, Jvmci) \ + do_klass(RegisterSaveLayout_klass, jdk_vm_ci_code_RegisterSaveLayout, Jvmci) \ + do_klass(BytecodeFrame_klass, jdk_vm_ci_code_BytecodeFrame, Jvmci) \ + do_klass(CompilationResult_Call_klass, jdk_vm_ci_code_CompilationResult_Call, Jvmci) \ + do_klass(CompilationResult_ConstantReference_klass, jdk_vm_ci_code_CompilationResult_ConstantReference, Jvmci) \ + do_klass(CompilationResult_DataPatch_klass, jdk_vm_ci_code_CompilationResult_DataPatch, Jvmci) \ + do_klass(CompilationResult_DataSectionReference_klass, jdk_vm_ci_code_CompilationResult_DataSectionReference, Jvmci) \ + do_klass(CompilationResult_ExceptionHandler_klass, jdk_vm_ci_code_CompilationResult_ExceptionHandler, Jvmci) \ + do_klass(CompilationResult_Mark_klass, jdk_vm_ci_code_CompilationResult_Mark, Jvmci) \ + do_klass(CompilationResult_Infopoint_klass, jdk_vm_ci_code_CompilationResult_Infopoint, Jvmci) \ + do_klass(CompilationResult_Site_klass, jdk_vm_ci_code_CompilationResult_Site, Jvmci) \ + do_klass(InfopointReason_klass, jdk_vm_ci_code_InfopointReason, Jvmci) \ + do_klass(InstalledCode_klass, jdk_vm_ci_code_InstalledCode, Jvmci) \ + do_klass(code_Location_klass, jdk_vm_ci_code_Location, Jvmci) \ + do_klass(code_Register_klass, jdk_vm_ci_code_Register, Jvmci) \ + do_klass(RegisterValue_klass, jdk_vm_ci_code_RegisterValue, Jvmci) \ + do_klass(StackSlot_klass, jdk_vm_ci_code_StackSlot, Jvmci) \ + do_klass(StackLockValue_klass, jdk_vm_ci_code_StackLockValue, Jvmci) \ + do_klass(VirtualObject_klass, jdk_vm_ci_code_VirtualObject, Jvmci) \ + do_klass(SpeculationLog_klass, jdk_vm_ci_meta_SpeculationLog, Jvmci) \ + do_klass(JavaConstant_klass, jdk_vm_ci_meta_JavaConstant, Jvmci) \ + do_klass(PrimitiveConstant_klass, jdk_vm_ci_meta_PrimitiveConstant, Jvmci) \ + do_klass(RawConstant_klass, jdk_vm_ci_meta_RawConstant, Jvmci) \ + do_klass(NullConstant_klass, jdk_vm_ci_meta_NullConstant, Jvmci) \ + do_klass(ExceptionHandler_klass, jdk_vm_ci_meta_ExceptionHandler, Jvmci) \ + do_klass(JavaKind_klass, jdk_vm_ci_meta_JavaKind, Jvmci) \ + do_klass(LIRKind_klass, jdk_vm_ci_meta_LIRKind, Jvmci) \ + do_klass(Value_klass, jdk_vm_ci_meta_Value, Jvmci) +#endif + +#endif // SHARE_VM_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp new file mode 100644 index 00000000000..97ef4466fd9 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP +#define SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP + +#include "compiler/abstractCompiler.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciRuntime.hpp" + +#define VM_STRUCTS_JVMCI(nonstatic_field, static_field) \ + nonstatic_field(JavaThread, _pending_deoptimization, int) \ + nonstatic_field(JavaThread, _pending_failed_speculation, oop) \ + nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \ + nonstatic_field(JavaThread, _jvmci_counters, jlong*) \ + nonstatic_field(MethodData, _jvmci_ir_size, int) \ + nonstatic_field(JVMCIEnv, _task, CompileTask*) \ + nonstatic_field(JVMCIEnv, _jvmti_can_hotswap_or_post_breakpoint, bool) \ + nonstatic_field(DeoptimizationBlob, _uncommon_trap_offset, int) \ + \ + static_field(CompilerToVM, _supports_inline_contig_alloc, bool) \ + static_field(CompilerToVM, _heap_end_addr, HeapWord**) \ + static_field(CompilerToVM, _heap_top_addr, HeapWord**) + +#define VM_TYPES_JVMCI(declare_type, declare_toplevel_type) \ + declare_toplevel_type(CompilerToVM) \ + declare_toplevel_type(JVMCIEnv) \ + +#define VM_INT_CONSTANTS_JVMCI(declare_constant, declare_preprocessor_constant) \ + declare_constant(Deoptimization::Reason_unreached0) \ + declare_constant(Deoptimization::Reason_type_checked_inlining) \ + declare_constant(Deoptimization::Reason_optimized_type_check) \ + declare_constant(Deoptimization::Reason_aliasing) \ + declare_constant(Deoptimization::Reason_transfer_to_interpreter) \ + declare_constant(Deoptimization::Reason_not_compiled_exception_handler) \ + declare_constant(Deoptimization::Reason_unresolved) \ + declare_constant(Deoptimization::Reason_jsr_mismatch) \ + declare_constant(JVMCIEnv::ok) \ + declare_constant(JVMCIEnv::dependencies_failed) \ + declare_constant(JVMCIEnv::dependencies_invalid) \ + declare_constant(JVMCIEnv::cache_full) \ + declare_constant(JVMCIEnv::code_too_large) \ + \ + declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ + declare_preprocessor_constant("JVM_RECOGNIZED_FIELD_MODIFIERS", JVM_RECOGNIZED_FIELD_MODIFIERS) \ + \ + declare_constant(CompilerToVM::KLASS_TAG) \ + declare_constant(CompilerToVM::SYMBOL_TAG) \ + \ + declare_constant(CodeInstaller::VERIFIED_ENTRY) \ + declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ + declare_constant(CodeInstaller::OSR_ENTRY) \ + declare_constant(CodeInstaller::EXCEPTION_HANDLER_ENTRY) \ + declare_constant(CodeInstaller::DEOPT_HANDLER_ENTRY) \ + declare_constant(CodeInstaller::INVOKEINTERFACE) \ + declare_constant(CodeInstaller::INVOKEVIRTUAL) \ + declare_constant(CodeInstaller::INVOKESTATIC) \ + declare_constant(CodeInstaller::INVOKESPECIAL) \ + declare_constant(CodeInstaller::INLINE_INVOKE) \ + declare_constant(CodeInstaller::POLL_NEAR) \ + declare_constant(CodeInstaller::POLL_RETURN_NEAR) \ + declare_constant(CodeInstaller::POLL_FAR) \ + declare_constant(CodeInstaller::POLL_RETURN_FAR) \ + declare_constant(CodeInstaller::CARD_TABLE_ADDRESS) \ + declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \ + declare_constant(CodeInstaller::HEAP_END_ADDRESS) \ + declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \ + declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \ + declare_constant(CodeInstaller::INVOKE_INVALID) \ + \ + declare_constant(Method::invalid_vtable_index) \ + +#define VM_ADDRESSES_JVMCI(declare_address, declare_preprocessor_address, declare_function) \ + declare_function(JVMCIRuntime::new_instance) \ + declare_function(JVMCIRuntime::new_array) \ + declare_function(JVMCIRuntime::new_multi_array) \ + declare_function(JVMCIRuntime::dynamic_new_array) \ + declare_function(JVMCIRuntime::dynamic_new_instance) \ + \ + declare_function(JVMCIRuntime::thread_is_interrupted) \ + declare_function(JVMCIRuntime::vm_message) \ + declare_function(JVMCIRuntime::identity_hash_code) \ + declare_function(JVMCIRuntime::exception_handler_for_pc) \ + declare_function(JVMCIRuntime::monitorenter) \ + declare_function(JVMCIRuntime::monitorexit) \ + declare_function(JVMCIRuntime::create_null_exception) \ + declare_function(JVMCIRuntime::create_out_of_bounds_exception) \ + declare_function(JVMCIRuntime::log_primitive) \ + declare_function(JVMCIRuntime::log_object) \ + declare_function(JVMCIRuntime::log_printf) \ + declare_function(JVMCIRuntime::vm_error) \ + declare_function(JVMCIRuntime::load_and_clear_exception) \ + declare_function(JVMCIRuntime::write_barrier_pre) \ + declare_function(JVMCIRuntime::write_barrier_post) \ + declare_function(JVMCIRuntime::validate_object) \ + \ + declare_function(JVMCIRuntime::test_deoptimize_call_int) + +#endif // SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP diff --git a/hotspot/src/share/vm/jvmci/vmSymbols_jvmci.hpp b/hotspot/src/share/vm/jvmci/vmSymbols_jvmci.hpp new file mode 100644 index 00000000000..eedc51b6e86 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/vmSymbols_jvmci.hpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_VMSYMBOLS_JVMCI_HPP +#define SHARE_VM_JVMCI_VMSYMBOLS_JVMCI_HPP + + +#if !INCLUDE_JVMCI +#define JVMCI_VM_SYMBOLS_DO(template, do_alias) +#else +#define JVMCI_VM_SYMBOLS_DO(template, do_alias) \ + template(jdk_vm_ci_hotspot_HotSpotCompiledCode, "jdk/vm/ci/hotspot/HotSpotCompiledCode") \ + template(jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment, "jdk/vm/ci/hotspot/HotSpotCompiledCode$Comment") \ + template(jdk_vm_ci_hotspot_HotSpotCompiledNmethod, "jdk/vm/ci/hotspot/HotSpotCompiledNmethod") \ + template(jdk_vm_ci_hotspot_HotSpotForeignCallTarget, "jdk/vm/ci/hotspot/HotSpotForeignCallTarget") \ + template(jdk_vm_ci_hotspot_HotSpotReferenceMap, "jdk/vm/ci/hotspot/HotSpotReferenceMap") \ + template(jdk_vm_ci_hotspot_CompilerToVM, "jdk/vm/ci/hotspot/CompilerToVM") \ + template(jdk_vm_ci_hotspot_HotSpotInstalledCode, "jdk/vm/ci/hotspot/HotSpotInstalledCode") \ + template(jdk_vm_ci_hotspot_HotSpotNmethod, "jdk/vm/ci/hotspot/HotSpotNmethod") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl, "jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl, "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl") \ + template(jdk_vm_ci_hotspot_HotSpotCompressedNullConstant, "jdk/vm/ci/hotspot/HotSpotCompressedNullConstant") \ + template(jdk_vm_ci_hotspot_HotSpotObjectConstantImpl, "jdk/vm/ci/hotspot/HotSpotObjectConstantImpl") \ + template(jdk_vm_ci_hotspot_HotSpotMetaspaceConstantImpl, "jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl") \ + template(jdk_vm_ci_hotspot_HotSpotSentinelConstant, "jdk/vm/ci/hotspot/HotSpotSentinelConstant") \ + template(jdk_vm_ci_hotspot_HotSpotStackFrameReference, "jdk/vm/ci/hotspot/HotSpotStackFrameReference") \ + template(jdk_vm_ci_hotspot_HotSpotMetaData, "jdk/vm/ci/hotspot/HotSpotMetaData") \ + template(jdk_vm_ci_hotspot_HotSpotOopMap, "jdk/vm/ci/hotspot/HotSpotOopMap") \ + template(jdk_vm_ci_hotspot_HotSpotConstantPool, "jdk/vm/ci/hotspot/HotSpotConstantPool") \ + template(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext, "jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext") \ + template(jdk_vm_ci_meta_JavaConstant, "jdk/vm/ci/meta/JavaConstant") \ + template(jdk_vm_ci_meta_PrimitiveConstant, "jdk/vm/ci/meta/PrimitiveConstant") \ + template(jdk_vm_ci_meta_RawConstant, "jdk/vm/ci/meta/RawConstant") \ + template(jdk_vm_ci_meta_NullConstant, "jdk/vm/ci/meta/NullConstant") \ + template(jdk_vm_ci_meta_ExceptionHandler, "jdk/vm/ci/meta/ExceptionHandler") \ + template(jdk_vm_ci_meta_JavaKind, "jdk/vm/ci/meta/JavaKind") \ + template(jdk_vm_ci_meta_LIRKind, "jdk/vm/ci/meta/LIRKind") \ + template(jdk_vm_ci_meta_Value, "jdk/vm/ci/meta/Value") \ + template(jdk_vm_ci_meta_Assumptions_ConcreteSubtype, "jdk/vm/ci/meta/Assumptions$ConcreteSubtype") \ + template(jdk_vm_ci_meta_Assumptions_LeafType, "jdk/vm/ci/meta/Assumptions$LeafType") \ + template(jdk_vm_ci_meta_Assumptions_NoFinalizableSubclass, "jdk/vm/ci/meta/Assumptions$NoFinalizableSubclass") \ + template(jdk_vm_ci_meta_Assumptions_ConcreteMethod, "jdk/vm/ci/meta/Assumptions$ConcreteMethod") \ + template(jdk_vm_ci_meta_Assumptions_CallSiteTargetValue, "jdk/vm/ci/meta/Assumptions$CallSiteTargetValue") \ + template(jdk_vm_ci_meta_SpeculationLog, "jdk/vm/ci/meta/SpeculationLog") \ + template(jdk_vm_ci_code_Architecture, "jdk/vm/ci/code/Architecture") \ + template(jdk_vm_ci_code_TargetDescription, "jdk/vm/ci/code/TargetDescription") \ + template(jdk_vm_ci_code_CompilationResult_Call, "jdk/vm/ci/code/CompilationResult$Call") \ + template(jdk_vm_ci_code_CompilationResult_ConstantReference, "jdk/vm/ci/code/CompilationResult$ConstantReference") \ + template(jdk_vm_ci_code_CompilationResult_DataPatch, "jdk/vm/ci/code/CompilationResult$DataPatch") \ + template(jdk_vm_ci_code_CompilationResult_DataSectionReference, "jdk/vm/ci/code/CompilationResult$DataSectionReference") \ + template(jdk_vm_ci_code_CompilationResult_ExceptionHandler, "jdk/vm/ci/code/CompilationResult$ExceptionHandler") \ + template(jdk_vm_ci_code_CompilationResult_Mark, "jdk/vm/ci/code/CompilationResult$Mark") \ + template(jdk_vm_ci_code_CompilationResult_Infopoint, "jdk/vm/ci/code/CompilationResult$Infopoint") \ + template(jdk_vm_ci_code_CompilationResult_Site, "jdk/vm/ci/code/CompilationResult$Site") \ + template(jdk_vm_ci_code_InfopointReason, "jdk/vm/ci/code/InfopointReason") \ + template(jdk_vm_ci_code_InstalledCode, "jdk/vm/ci/code/InstalledCode") \ + template(jdk_vm_ci_code_BytecodeFrame, "jdk/vm/ci/code/BytecodeFrame") \ + template(jdk_vm_ci_code_BytecodePosition, "jdk/vm/ci/code/BytecodePosition") \ + template(jdk_vm_ci_code_DebugInfo, "jdk/vm/ci/code/DebugInfo") \ + template(jdk_vm_ci_code_Location, "jdk/vm/ci/code/Location") \ + template(jdk_vm_ci_code_Register, "jdk/vm/ci/code/Register") \ + template(jdk_vm_ci_code_RegisterValue, "jdk/vm/ci/code/RegisterValue") \ + template(jdk_vm_ci_code_StackSlot, "jdk/vm/ci/code/StackSlot") \ + template(jdk_vm_ci_code_StackLockValue, "jdk/vm/ci/code/StackLockValue") \ + template(jdk_vm_ci_code_VirtualObject, "jdk/vm/ci/code/VirtualObject") \ + template(jdk_vm_ci_code_RegisterSaveLayout, "jdk/vm/ci/code/RegisterSaveLayout") \ + template(jdk_vm_ci_code_InvalidInstalledCodeException, "jdk/vm/ci/code/InvalidInstalledCodeException") \ + template(compileMethod_name, "compileMethod") \ + template(compileMethod_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;IJI)V") \ + template(fromMetaspace_name, "fromMetaspace") \ + template(method_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ + template(constantPool_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotConstantPool;") \ + template(klass_fromMetaspace_signature, "(Ljava/lang/Class;)Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;") \ + template(jdk_vm_ci_hotspot_Stable_signature, "Ljdk/vm/ci/hotspot/Stable;") +#endif + +#endif // SHARE_VM_JVMCI_VMSYMBOLS_JVMCI_HPP diff --git a/hotspot/src/share/vm/libadt/dict.cpp b/hotspot/src/share/vm/libadt/dict.cpp index bbed6795e65..9ad56fa657a 100644 --- a/hotspot/src/share/vm/libadt/dict.cpp +++ b/hotspot/src/share/vm/libadt/dict.cpp @@ -31,8 +31,6 @@ #include -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - //------------------------------data----------------------------------------- // String hash tables #define MAXID 20 @@ -288,9 +286,9 @@ int32_t Dict::operator ==(const Dict &d2) const { // Handier print routine void Dict::print() { DictI i(this); // Moved definition in iterator here because of g++. - tty->print("Dict@0x%lx[%d] = {", this, _cnt); + tty->print("Dict@" INTPTR_FORMAT "[%d] = {", p2i(this), _cnt); for( ; i.test(); ++i ) { - tty->print("(0x%lx,0x%lx),", i._key, i._value); + tty->print("(" INTPTR_FORMAT "," INTPTR_FORMAT "),", p2i(i._key), p2i(i._value)); } tty->print_cr("}"); } diff --git a/hotspot/src/share/vm/logging/log.hpp b/hotspot/src/share/vm/logging/log.hpp new file mode 100644 index 00000000000..8b1f7c63c2f --- /dev/null +++ b/hotspot/src/share/vm/logging/log.hpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOG_HPP +#define SHARE_VM_LOGGING_LOG_HPP + +#include "logging/logLevel.hpp" +#include "logging/logPrefix.hpp" +#include "logging/logTagSet.hpp" +#include "logging/logTag.hpp" +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" +#include "utilities/ostream.hpp" + +// +// Logging macros +// +// Usage: +// log_()(); +// e.g. +// log_debug(logging)("message %d", i); +// +// Note that these macros will not evaluate the arguments unless the logging is enabled. +// +#define log_error(...) (!log_is_enabled(Error, __VA_ARGS__)) ? (void)0 : Log::write +#define log_warning(...) (!log_is_enabled(Warning, __VA_ARGS__)) ? (void)0 : Log::write +#define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log::write +#define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log::write +#define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log::write +#ifndef PRODUCT +#define log_develop(...) (!log_is_enabled(Develop, __VA_ARGS__)) ? (void)0 : Log::write +#else +#define DUMMY_ARGUMENT_CONSUMER(...) +#define log_develop(...) DUMMY_ARGUMENT_CONSUMER +#endif + +// Convenience macro to test if the logging is enabled on the specified level for given tags. +#define log_is_enabled(level, ...) (Log::is_level(LogLevel::level)) + +// +// Log class for more advanced logging scenarios. +// Has printf-style member functions for each log level (trace(), debug(), etc). +// +// Also has outputStream compatible API for the different log-levels. +// The streams are resource allocated when requested and are accessed through +// calls to _stream() functions (trace_stream(), debug_stream(), etc). +// +// Example usage: +// LogHandle(logging) log; +// if (log.is_debug()) { +// ... +// log.debug("result = %d", result).trace(" tracing info"); +// obj->print_on(log.debug_stream()); +// } +// +#define LogHandle(...) Log + +template +class Log VALUE_OBJ_CLASS_SPEC { + private: + static const size_t LogBufferSize = 512; + public: + // Make sure no more than the maximum number of tags have been given. + // The GuardTag allows this to be detected if/when it happens. If the GuardTag + // is not __NO_TAG, the number of tags given exceeds the maximum allowed. + STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); // Number of logging tags exceeds maximum supported! + + static bool is_level(LogLevelType level) { + return LogTagSetMapping::tagset().is_level(level); + } + + template + ATTRIBUTE_PRINTF(1, 2) + static void write(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vwrite(fmt, args); + va_end(args); + }; + + template + ATTRIBUTE_PRINTF(1, 0) + static void vwrite(const char* fmt, va_list args) { + char buf[LogBufferSize]; + size_t prefix_len = LogPrefix::prefix(buf, sizeof(buf)); + int ret = vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, fmt, args); + assert(ret >= 0 && (size_t)ret < sizeof(buf), "Log message too long"); + puts(buf); + } + + template + static void puts(const char* string) { + LogTagSetMapping::tagset().log(Level, string); + } + +#define LOG_LEVEL(level, name) ATTRIBUTE_PRINTF(2, 0) \ + Log& v##name(const char* fmt, va_list args) { \ + vwrite(fmt, args); \ + return *this; \ + } \ + Log& name(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { \ + va_list args; \ + va_start(args, fmt); \ + vwrite(fmt, args); \ + va_end(args); \ + return *this; \ + } \ + static bool is_##name() { \ + return is_level(LogLevel::level); \ + } \ + static outputStream* name##_stream() { \ + return new logStream(write); \ + } + LOG_LEVEL_LIST +#undef LOG_LEVEL +}; + +#endif // SHARE_VM_LOGGING_LOG_HPP diff --git a/hotspot/src/share/vm/logging/logConfiguration.cpp b/hotspot/src/share/vm/logging/logConfiguration.cpp new file mode 100644 index 00000000000..d575a458249 --- /dev/null +++ b/hotspot/src/share/vm/logging/logConfiguration.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/log.hpp" +#include "logging/logConfiguration.hpp" +#include "logging/logDecorations.hpp" +#include "logging/logDecorators.hpp" +#include "logging/logDiagnosticCommand.hpp" +#include "logging/logFileOutput.hpp" +#include "logging/logOutput.hpp" +#include "logging/logTagLevelExpression.hpp" +#include "logging/logTagSet.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/os.inline.hpp" +#include "utilities/globalDefinitions.hpp" + +LogOutput** LogConfiguration::_outputs = NULL; +size_t LogConfiguration::_n_outputs = 0; + +void LogConfiguration::post_initialize() { + assert(LogConfiguration_lock != NULL, "Lock must be initialized before post-initialization"); + LogDiagnosticCommand::registerCommand(); + LogHandle(logging) log; + log.info("Log configuration fully initialized."); + if (log.is_trace()) { + ResourceMark rm; + MutexLocker ml(LogConfiguration_lock); + describe(log.trace_stream()); + } +} + +void LogConfiguration::initialize(jlong vm_start_time) { + LogFileOutput::set_file_name_parameters(vm_start_time); + LogDecorations::set_vm_start_time_millis(vm_start_time); + + assert(_outputs == NULL, "Should not initialize _outputs before this function, initialize called twice?"); + _outputs = NEW_C_HEAP_ARRAY(LogOutput*, 2, mtLogging); + _outputs[0] = LogOutput::Stdout; + _outputs[1] = LogOutput::Stderr; + _n_outputs = 2; +} + +void LogConfiguration::finalize() { + for (size_t i = 2; i < _n_outputs; i++) { + delete _outputs[i]; + } + FREE_C_HEAP_ARRAY(LogOutput*, _outputs); +} + +size_t LogConfiguration::find_output(const char* name) { + for (size_t i = 0; i < _n_outputs; i++) { + if (strcmp(_outputs[i]->name(), name) == 0) { + return i; + } + } + return SIZE_MAX; +} + +LogOutput* LogConfiguration::new_output(char* name, const char* options) { + const char* type; + char* equals_pos = strchr(name, '='); + if (equals_pos == NULL) { + type = "file"; + } else { + *equals_pos = '\0'; + type = name; + name = equals_pos + 1; + } + + LogOutput* output; + if (strcmp(type, "file") == 0) { + output = new LogFileOutput(name); + } else { + // unsupported log output type + return NULL; + } + + bool success = output->initialize(options); + if (!success) { + delete output; + return NULL; + } + return output; +} + +size_t LogConfiguration::add_output(LogOutput* output) { + size_t idx = _n_outputs++; + _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging); + _outputs[idx] = output; + return idx; +} + +void LogConfiguration::delete_output(size_t idx) { + assert(idx > 1 && idx < _n_outputs, + "idx must be in range 1 < idx < _n_outputs, but idx = " SIZE_FORMAT + " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs); + LogOutput* output = _outputs[idx]; + // Swap places with the last output and shrink the array + _outputs[idx] = _outputs[--_n_outputs]; + _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging); + delete output; +} + +void LogConfiguration::configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators) { + assert(idx < _n_outputs, "Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs); + LogOutput* output = _outputs[idx]; + output->set_decorators(decorators); + output->set_config_string(tag_level_expression.to_string()); + bool enabled = false; + for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { + LogLevelType level = tag_level_expression.level_for(*ts); + if (level != LogLevel::Off) { + enabled = true; + } + ts->update_decorators(decorators); + ts->set_output_level(output, level); + } + + // If the output is not used by any tagset it should be removed, unless it is stdout/stderr. + if (!enabled && idx > 1) { + delete_output(idx); + } +} + +void LogConfiguration::disable_output(size_t idx) { + LogOutput* out = _outputs[idx]; + LogDecorators empty_decorators; + empty_decorators.clear(); + + // Remove the output from all tagsets. + for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { + ts->set_output_level(out, LogLevel::Off); + ts->update_decorators(empty_decorators); + } + + // Delete the output unless stdout/stderr + if (out != LogOutput::Stderr && out != LogOutput::Stdout) { + delete_output(find_output(out->name())); + } else { + out->set_config_string("all=off"); + } +} + +void LogConfiguration::disable_logging() { + assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), + "LogConfiguration lock must be held when calling this function"); + for (size_t i = 0; i < _n_outputs; i++) { + disable_output(i); + } +} + +bool LogConfiguration::parse_command_line_arguments(const char* opts) { + char* copy = os::strdup_check_oom(opts, mtLogging); + + // Split the option string to its colon separated components. + char* what = NULL; + char* output_str = NULL; + char* decorators_str = NULL; + char* output_options = NULL; + + what = copy; + char* colon = strchr(what, ':'); + if (colon != NULL) { + *colon = '\0'; + output_str = colon + 1; + colon = strchr(output_str, ':'); + if (colon != NULL) { + *colon = '\0'; + decorators_str = colon + 1; + colon = strchr(decorators_str, ':'); + if (colon != NULL) { + *colon = '\0'; + output_options = colon + 1; + } + } + } + + // Parse each argument + char errbuf[512]; + stringStream ss(errbuf, sizeof(errbuf)); + bool success = parse_log_arguments(output_str, what, decorators_str, output_options, &ss); + if (!success) { + errbuf[strlen(errbuf) - 1] = '\0'; // Strip trailing newline. + log_error(logging)("%s", errbuf); + } + + os::free(copy); + return success; +} + +bool LogConfiguration::parse_log_arguments(const char* outputstr, + const char* what, + const char* decoratorstr, + const char* output_options, + outputStream* errstream) { + assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), + "LogConfiguration lock must be held when calling this function"); + if (outputstr == NULL || strlen(outputstr) == 0) { + outputstr = "stdout"; + } + + size_t idx; + if (outputstr[0] == '#') { + int ret = sscanf(outputstr+1, SIZE_FORMAT, &idx); + if (ret != 1 || idx >= _n_outputs) { + errstream->print_cr("Invalid output index '%s'", outputstr); + return false; + } + } else { + idx = find_output(outputstr); + if (idx == SIZE_MAX) { + char* tmp = os::strdup_check_oom(outputstr, mtLogging); + LogOutput* output = new_output(tmp, output_options); + os::free(tmp); + if (output == NULL) { + errstream->print("Unable to add output '%s'", outputstr); + if (output_options != NULL && strlen(output_options) > 0) { + errstream->print(" with options '%s'", output_options); + } + errstream->cr(); + return false; + } + idx = add_output(output); + } else if (output_options != NULL && strlen(output_options) > 0) { + errstream->print_cr("Output options for existing outputs are ignored."); + } + } + + LogTagLevelExpression expr; + if (!expr.parse(what, errstream)) { + return false; + } + + LogDecorators decorators; + if (!decorators.parse(decoratorstr, errstream)) { + return false; + } + + configure_output(idx, expr, decorators); + return true; +} + +void LogConfiguration::describe(outputStream* out) { + assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), + "LogConfiguration lock must be held when calling this function"); + + out->print("Available log levels:"); + for (size_t i = 0; i < LogLevel::Count; i++) { + out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast(i))); + } + out->cr(); + + out->print("Available log decorators:"); + for (size_t i = 0; i < LogDecorators::Count; i++) { + LogDecorators::Decorator d = static_cast(i); + out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d)); + } + out->cr(); + + out->print("Available log tags:"); + for (size_t i = 1; i < LogTag::Count; i++) { + out->print("%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast(i))); + } + out->cr(); + + out->print_cr("Log output configuration:"); + for (size_t i = 0; i < _n_outputs; i++) { + out->print("#" SIZE_FORMAT ": %s %s ", i, _outputs[i]->name(), _outputs[i]->config_string()); + for (size_t d = 0; d < LogDecorators::Count; d++) { + LogDecorators::Decorator decorator = static_cast(d); + if (_outputs[i]->decorators().is_decorator(decorator)) { + out->print("%s,", LogDecorators::name(decorator)); + } + } + out->cr(); + } +} + +void LogConfiguration::print_command_line_help(FILE* out) { + jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n" + "\t where 'what' is a combination of tags and levels on the form tag1[+tag2...][*][=level][,...]\n" + "\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n"); + + jio_fprintf(out, "Available log levels:\n"); + for (size_t i = 0; i < LogLevel::Count; i++) { + jio_fprintf(out, "%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast(i))); + } + + jio_fprintf(out, "\n\nAvailable log decorators: \n"); + for (size_t i = 0; i < LogDecorators::Count; i++) { + LogDecorators::Decorator d = static_cast(i); + jio_fprintf(out, "%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d)); + } + jio_fprintf(out, "\n Decorators can also be specified as 'none' for no decoration.\n\n"); + + jio_fprintf(out, "Available log tags:\n"); + for (size_t i = 1; i < LogTag::Count; i++) { + jio_fprintf(out, "%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast(i))); + } + jio_fprintf(out, "\n Specifying 'all' instead of a tag combination matches all tag combinations.\n\n"); + + jio_fprintf(out, "Available log outputs:\n" + " stdout, stderr, file=\n" + " Specifying %%p and/or %%t in the filename will expand to the JVM's PID and startup timestamp, respectively.\n\n" + + "Some examples:\n" + " -Xlog\n" + "\t Log all messages using 'info' level to stdout with 'uptime', 'levels' and 'tags' decorations.\n" + "\t (Equivalent to -Xlog:all=info:stdout:uptime,levels,tags).\n\n" + + " -Xlog:gc\n" + "\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n" + + " -Xlog:gc=debug:file=gc.txt:none\n" + "\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n" + + " -Xlog:gc=trace:file=gctrace.txt:uptimemillis,pids:filecount=5,filesize=1024\n" + "\t Log messages tagged with 'gc' tag using 'trace' level to a rotating fileset of 5 files of size 1MB,\n" + "\t using the base name 'gctrace.txt', with 'uptimemillis' and 'pid' decorations.\n\n" + + " -Xlog:gc::uptime,tid\n" + "\t Log messages tagged with 'gc' tag using 'info' level to output 'stdout', using 'uptime' and 'tid' decorations.\n\n" + + " -Xlog:gc*=info,rt*=off\n" + "\t Log messages tagged with at least 'gc' using 'info' level, but turn off logging of messages tagged with 'rt'.\n" + "\t (Messages tagged with both 'gc' and 'rt' will not be logged.)\n\n" + + " -Xlog:disable -Xlog:rt=trace:rttrace.txt\n" + "\t Turn off all logging, including warnings and errors,\n" + "\t and then enable messages tagged with 'rt' using 'trace' level to file 'rttrace.txt'.\n"); +} diff --git a/hotspot/src/share/vm/logging/logConfiguration.hpp b/hotspot/src/share/vm/logging/logConfiguration.hpp new file mode 100644 index 00000000000..06f7dd5c6e9 --- /dev/null +++ b/hotspot/src/share/vm/logging/logConfiguration.hpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGCONFIGURATION_HPP +#define SHARE_VM_LOGGING_LOGCONFIGURATION_HPP + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogOutput; +class LogDecorators; +class LogTagLevelExpression; + +// Global configuration of logging. Handles parsing and configuration of the logging framework, +// and manages the list of configured log outputs. The actual tag and level configuration is +// kept implicitly in the LogTagSets and their LogOutputLists. During configuration the tagsets +// are iterated over and updated accordingly. +class LogConfiguration : public AllStatic { + private: + static LogOutput** _outputs; + static size_t _n_outputs; + + // Create a new output. Returns NULL if failed. + static LogOutput* new_output(char* name, const char* options = NULL); + + // Add an output to the list of configured outputs. Returns the assigned index. + static size_t add_output(LogOutput* out); + + // Delete a configured output. The stderr/stdout outputs can not be removed. + // Output should be completely disabled before it is deleted. + static void delete_output(size_t idx); + + // Disable all logging to the specified output and then delete it (unless it is stdout/stderr). + static void disable_output(size_t idx); + + // Get output index by name. Returns SIZE_MAX if output not found. + static size_t find_output(const char* name); + + // Configure output (add or update existing configuration) to log on tag-level combination using specified decorators. + static void configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators); + + public: + // Initialization and finalization of log configuration, to be run at vm startup and shutdown respectively. + static void initialize(jlong vm_start_time); + static void finalize(); + + // Perform necessary post-initialization after VM startup. Enables reconfiguration of logging. + static void post_initialize(); + + // Disable all logging, equivalent to -Xlog:disable. + static void disable_logging(); + + // Parse command line configuration. Parameter 'opts' is the string immediately following the -Xlog: argument ("gc" for -Xlog:gc). + static bool parse_command_line_arguments(const char* opts = "all"); + + // Parse separated configuration arguments (from JCmd/MBean and command line). + static bool parse_log_arguments(const char* outputstr, + const char* what, + const char* decoratorstr, + const char* output_options, + outputStream* errstream); + + // Prints log configuration to outputStream, used by JCmd/MBean. + static void describe(outputStream* out); + + // Prints usage help for command line log configuration. + static void print_command_line_help(FILE* out); +}; + +#endif // SHARE_VM_LOGGING_LOGCONFIGURATION_HPP diff --git a/hotspot/src/share/vm/logging/logDecorations.cpp b/hotspot/src/share/vm/logging/logDecorations.cpp new file mode 100644 index 00000000000..ec8013e3ada --- /dev/null +++ b/hotspot/src/share/vm/logging/logDecorations.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logConfiguration.hpp" +#include "logging/logDecorations.hpp" +#include "runtime/os.inline.hpp" +#include "runtime/thread.inline.hpp" +#include "services/management.hpp" + +jlong LogDecorations::_vm_start_time_millis = 0; + +LogDecorations::LogDecorations(LogLevelType level, const LogTagSet &tagset, const LogDecorators &decorators) + : _level(level), _tagset(tagset), _millis(-1) { + create_decorations(decorators); +} + +void LogDecorations::create_decorations(const LogDecorators &decorators) { + char* position = _decorations_buffer; + #define DECORATOR(full_name, abbr) \ + if (decorators.is_decorator(LogDecorators::full_name##_decorator)) { \ + _decoration_offset[LogDecorators::full_name##_decorator] = position; \ + position = create_##full_name##_decoration(position) + 1; \ + } + DECORATOR_LIST +#undef DECORATOR +} + +jlong LogDecorations::java_millis() { + if (_millis < 0) { + _millis = os::javaTimeMillis(); + } + return _millis; +} + +#define ASSERT_AND_RETURN(written, pos) \ + assert(written >= 0, "Decorations buffer overflow"); \ + return pos + written; + +char* LogDecorations::create_time_decoration(char* pos) { + char* buf = os::iso8601_time(pos, 29); + int written = buf == NULL ? -1 : 29; + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_uptime_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%.3fs", os::elapsedTime()); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_timemillis_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ms", java_millis()); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_uptimemillis_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), + INT64_FORMAT "ms", java_millis() - _vm_start_time_millis); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_timenanos_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ns", os::javaTimeNanos()); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_uptimenanos_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ns", os::elapsed_counter()); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_pid_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%d", os::current_process_id()); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_tid_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), + INTX_FORMAT, Thread::current()->osthread()->thread_id()); + ASSERT_AND_RETURN(written, pos) +} + +char* LogDecorations::create_level_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%s", LogLevel::name(_level)); + ASSERT_AND_RETURN(written, pos) +} + +char* LogDecorations::create_tags_decoration(char* pos) { + int written = _tagset.label(pos, DecorationsBufferSize - (pos - _decorations_buffer)); + ASSERT_AND_RETURN(written, pos) +} diff --git a/hotspot/src/share/vm/logging/logDecorations.hpp b/hotspot/src/share/vm/logging/logDecorations.hpp new file mode 100644 index 00000000000..08a675f225b --- /dev/null +++ b/hotspot/src/share/vm/logging/logDecorations.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGDECORATIONS_HPP +#define SHARE_VM_LOGGING_LOGDECORATIONS_HPP + +#include "logging/logDecorators.hpp" +#include "logging/logTagSet.hpp" +#include "memory/allocation.hpp" + +// Temporary object containing the necessary data for a log call's decorations (timestamps, etc). +class LogDecorations VALUE_OBJ_CLASS_SPEC { + public: + static const int DecorationsBufferSize = 256; + private: + char _decorations_buffer[DecorationsBufferSize]; + char* _decoration_offset[LogDecorators::Count]; + LogLevelType _level; + LogTagSet _tagset; + jlong _millis; + static jlong _vm_start_time_millis; + + jlong java_millis(); + void create_decorations(const LogDecorators& decorators); + +#define DECORATOR(name, abbr) char* create_##name##_decoration(char* pos); + DECORATOR_LIST +#undef DECORATOR + + public: + LogDecorations(LogLevelType level, const LogTagSet& tagset, const LogDecorators& decorators); + + const char* decoration(LogDecorators::Decorator decorator) const { + return _decoration_offset[decorator]; + } + + static void set_vm_start_time_millis(jlong start_time) { + _vm_start_time_millis = start_time; + } +}; + +#endif // SHARE_VM_LOGGING_LOGDECORATIONS_HPP diff --git a/hotspot/src/share/vm/logging/logDecorators.cpp b/hotspot/src/share/vm/logging/logDecorators.cpp new file mode 100644 index 00000000000..69e36b4bba8 --- /dev/null +++ b/hotspot/src/share/vm/logging/logDecorators.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logDecorators.hpp" +#include "runtime/os.inline.hpp" + +const char* LogDecorators::_name[][2] = { +#define DECORATOR(n, a) {#n, #a}, + DECORATOR_LIST +#undef DECORATOR +}; + +LogDecorators::Decorator LogDecorators::from_string(const char* str) { + for (size_t i = 0; i < Count; i++) { + Decorator d = static_cast(i); + if (strcasecmp(str, name(d)) == 0 || strcasecmp(str, abbreviation(d)) == 0) { + return d; + } + } + return Invalid; +} + +bool LogDecorators::parse(const char* decorator_args, outputStream* errstream) { + if (decorator_args == NULL || strlen(decorator_args) == 0) { + _decorators = DefaultDecoratorsMask; + return true; + } + + if (strcasecmp(decorator_args, "none") == 0 ) { + _decorators = 0; + return true; + } + + bool result = true; + uint tmp_decorators = 0; + char* args_copy = os::strdup_check_oom(decorator_args, mtLogging); + char* token = args_copy; + char* comma_pos; + do { + comma_pos = strchr(token, ','); + if (comma_pos != NULL) { + *comma_pos = '\0'; + } + Decorator d = from_string(token); + if (d == Invalid) { + if (errstream != NULL) { + errstream->print_cr("Invalid decorator '%s'.", token); + } + result = false; + break; + } + tmp_decorators |= mask(d); + token = comma_pos + 1; + } while (comma_pos != NULL); + os::free(args_copy); + if (result) { + _decorators = tmp_decorators; + } + return result; +} diff --git a/hotspot/src/share/vm/logging/logDecorators.hpp b/hotspot/src/share/vm/logging/logDecorators.hpp new file mode 100644 index 00000000000..0946c62bf56 --- /dev/null +++ b/hotspot/src/share/vm/logging/logDecorators.hpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGDECORATORS_HPP +#define SHARE_VM_LOGGING_LOGDECORATORS_HPP + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +// The list of available decorators: +// time - Current time and date in ISO-8601 format +// uptime - Time since the start of the JVM in seconds and milliseconds (e.g., 6.567s) +// timemillis - The same value as generated by System.currentTimeMillis() +// uptimemillis - Milliseconds since the JVM started +// timenanos - The same value as generated by System.nanoTime() +// uptimenanos - Nanoseconds since the JVM started +// pid - The process identifier +// tid - The thread identifier +// level - The level associated with the log message +// tags - The tag-set associated with the log message +#define DECORATOR_LIST \ + DECORATOR(time, t) \ + DECORATOR(uptime, u) \ + DECORATOR(timemillis, tm) \ + DECORATOR(uptimemillis, um) \ + DECORATOR(timenanos, tn) \ + DECORATOR(uptimenanos, un) \ + DECORATOR(pid, p) \ + DECORATOR(tid, ti) \ + DECORATOR(level, l) \ + DECORATOR(tags, tg) + +// LogDecorators represents a selection of decorators that should be prepended to +// each log message for a given output. Decorators are always prepended in the order +// declared above. For example, logging with 'uptime, level, tags' decorators results in: +// [0,943s][info ][logging] message. +class LogDecorators VALUE_OBJ_CLASS_SPEC { + public: + enum Decorator { +#define DECORATOR(name, abbr) name##_decorator, + DECORATOR_LIST +#undef DECORATOR + Count, + Invalid + }; + + private: + uint _decorators; + static const char* _name[][2]; + static const uint DefaultDecoratorsMask = (1 << uptime_decorator) | (1 << level_decorator) | (1 << tags_decorator); + + static uint mask(LogDecorators::Decorator decorator) { + return 1 << decorator; + } + + public: + LogDecorators() : _decorators(DefaultDecoratorsMask) { + }; + + void clear() { + _decorators = 0; + } + + static const char* name(LogDecorators::Decorator decorator) { + return _name[decorator][0]; + } + + static const char* abbreviation(LogDecorators::Decorator decorator) { + return _name[decorator][1]; + } + + static LogDecorators::Decorator from_string(const char* str); + + void combine_with(const LogDecorators &source) { + _decorators |= source._decorators; + } + + bool is_decorator(LogDecorators::Decorator decorator) const { + return (_decorators & mask(decorator)) != 0; + } + + bool parse(const char* decorator_args, outputStream* errstream = NULL); +}; + +#endif // SHARE_VM_LOGGING_LOGDECORATORS_HPP diff --git a/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp b/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp new file mode 100644 index 00000000000..982f5f3e348 --- /dev/null +++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logConfiguration.hpp" +#include "logging/logDiagnosticCommand.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/mutexLocker.hpp" +#include "utilities/globalDefinitions.hpp" + +LogDiagnosticCommand::LogDiagnosticCommand(outputStream* output, bool heap_allocated) + : DCmdWithParser(output, heap_allocated), + _output("output", "The name or index (#) of output to configure.", "STRING", false), + _output_options("output_options", "Options for the output.", "STRING", false), + _what("what", "Configures what tags to log.", "STRING", false), + _decorators("decorators", "Configures which decorators to use. Use 'none' or an empty value to remove all.", "STRING", false), + _disable("disable", "Turns off all logging and clears the log configuration.", "BOOLEAN", false), + _list("list", "Lists current log configuration.", "BOOLEAN", false) { + _dcmdparser.add_dcmd_option(&_output); + _dcmdparser.add_dcmd_option(&_output_options); + _dcmdparser.add_dcmd_option(&_what); + _dcmdparser.add_dcmd_option(&_decorators); + _dcmdparser.add_dcmd_option(&_disable); + _dcmdparser.add_dcmd_option(&_list); +} + +int LogDiagnosticCommand::num_arguments() { + ResourceMark rm; + LogDiagnosticCommand* dcmd = new LogDiagnosticCommand(NULL, false); + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } +} + +void LogDiagnosticCommand::registerCommand() { + uint32_t full_visibility = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean; + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_visibility, true, false)); +} + +void LogDiagnosticCommand::execute(DCmdSource source, TRAPS) { + bool any_command = false; + if (_disable.has_value()) { + MutexLocker ml(LogConfiguration_lock); + LogConfiguration::disable_logging(); + any_command = true; + } + + if (_output.has_value() || _what.has_value() || _decorators.has_value()) { + MutexLocker ml(LogConfiguration_lock); + if (!LogConfiguration::parse_log_arguments(_output.value(), + _what.value(), + _decorators.value(), + _output_options.value(), + output())) { + return; + } + any_command = true; + } + + if (_list.has_value()) { + MutexLocker ml(LogConfiguration_lock); + LogConfiguration::describe(output()); + any_command = true; + } + + if (!any_command) { + // If no argument was provided, print usage + print_help(LogDiagnosticCommand::name()); + } + +} diff --git a/hotspot/src/share/vm/logging/logDiagnosticCommand.hpp b/hotspot/src/share/vm/logging/logDiagnosticCommand.hpp new file mode 100644 index 00000000000..56b738a02fb --- /dev/null +++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP +#define SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP + +#include "services/diagnosticCommand.hpp" + +// The LogDiagnosticCommand represents the 'VM.log' DCMD +// that allows configuration of the logging at runtime. +// It can be used to view or modify the current log configuration. +// VM.log without additional arguments prints the usage description. +// The 'list' argument will list all available log tags, +// levels, decorators and currently configured log outputs. +// Specifying 'disable' will disable logging completely. +// The remaining arguments are used to set a log output to log everything +// with the specified tags and levels using the given decorators. +class LogDiagnosticCommand : public DCmdWithParser { + protected: + DCmdArgument _output; + DCmdArgument _output_options; + DCmdArgument _what; + DCmdArgument _decorators; + DCmdArgument _disable; + DCmdArgument _list; + + public: + LogDiagnosticCommand(outputStream* output, bool heap_allocated); + void execute(DCmdSource source, TRAPS); + static void registerCommand(); + static int num_arguments(); + + static const char* name() { + return "VM.log"; + } + + static const char* description() { + return "Lists, enables, disables or changes a log output configuration."; + } + + // Used by SecurityManager. This DCMD requires ManagementPermission = control. + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", "control", NULL}; + return p; + } +}; + +#endif // SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP diff --git a/hotspot/src/share/vm/logging/logFileOutput.cpp b/hotspot/src/share/vm/logging/logFileOutput.cpp new file mode 100644 index 00000000000..5eeef844856 --- /dev/null +++ b/hotspot/src/share/vm/logging/logFileOutput.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/log.hpp" +#include "logging/logConfiguration.hpp" +#include "logging/logFileOutput.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/os.inline.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/defaultStream.hpp" + +const char* LogFileOutput::FileOpenMode = "a"; +const char* LogFileOutput::PidFilenamePlaceholder = "%p"; +const char* LogFileOutput::TimestampFilenamePlaceholder = "%t"; +const char* LogFileOutput::TimestampFormat = "%Y-%m-%d_%H-%M-%S"; +const char* LogFileOutput::FileSizeOptionKey = "filesize"; +const char* LogFileOutput::FileCountOptionKey = "filecount"; +char LogFileOutput::_pid_str[PidBufferSize]; +char LogFileOutput::_vm_start_time_str[StartTimeBufferSize]; + +LogFileOutput::LogFileOutput(const char* name) + : LogFileStreamOutput(NULL), _name(os::strdup_check_oom(name, mtLogging)), + _file_name(NULL), _archive_name(NULL), _archive_name_len(0), _current_size(0), + _rotate_size(0), _current_file(1), _file_count(0), + _rotation_lock(Mutex::leaf, "LogFileOutput rotation lock", true, Mutex::_safepoint_check_sometimes) { + _file_name = make_file_name(name, _pid_str, _vm_start_time_str); +} + +void LogFileOutput::set_file_name_parameters(jlong vm_start_time) { + int res = jio_snprintf(_pid_str, sizeof(_pid_str), "%d", os::current_process_id()); + assert(res > 0, "PID buffer too small"); + + struct tm local_time; + time_t utc_time = vm_start_time / 1000; + os::localtime_pd(&utc_time, &local_time); + res = (int)strftime(_vm_start_time_str, sizeof(_vm_start_time_str), TimestampFormat, &local_time); + assert(res > 0, "VM start time buffer too small."); +} + +LogFileOutput::~LogFileOutput() { + if (_stream != NULL) { + if (_archive_name != NULL) { + archive(); + } + if (fclose(_stream) != 0) { + jio_fprintf(defaultStream::error_stream(), "Could not close log file '%s' (%s).\n", + _file_name, strerror(errno)); + } + } + os::free(_archive_name); + os::free(_file_name); + os::free(const_cast(_name)); +} + +size_t LogFileOutput::parse_value(const char* value_str) { + char* end; + unsigned long long value = strtoull(value_str, &end, 10); + if (!isdigit(*value_str) || end != value_str + strlen(value_str) || value >= SIZE_MAX) { + return SIZE_MAX; + } + return value; +} + +bool LogFileOutput::configure_rotation(const char* options) { + if (options == NULL || strlen(options) == 0) { + return true; + } + bool success = true; + char* opts = os::strdup_check_oom(options, mtLogging); + + char* comma_pos; + char* pos = opts; + do { + comma_pos = strchr(pos, ','); + if (comma_pos != NULL) { + *comma_pos = '\0'; + } + + char* equals_pos = strchr(pos, '='); + if (equals_pos == NULL) { + success = false; + break; + } + char* key = pos; + char* value_str = equals_pos + 1; + *equals_pos = '\0'; + + if (strcmp(FileCountOptionKey, key) == 0) { + size_t value = parse_value(value_str); + if (value == SIZE_MAX || value >= UINT_MAX) { + success = false; + break; + } + _file_count = static_cast(value); + _file_count_max_digits = static_cast(log10(static_cast(_file_count)) + 1); + _archive_name_len = 2 + strlen(_file_name) + _file_count_max_digits; + _archive_name = NEW_C_HEAP_ARRAY(char, _archive_name_len, mtLogging); + } else if (strcmp(FileSizeOptionKey, key) == 0) { + size_t value = parse_value(value_str); + if (value == SIZE_MAX || value > SIZE_MAX / K) { + success = false; + break; + } + _rotate_size = value * K; + } else { + success = false; + break; + } + pos = comma_pos + 1; + } while (comma_pos != NULL); + + os::free(opts); + return success; +} + +bool LogFileOutput::initialize(const char* options) { + if (!configure_rotation(options)) { + return false; + } + _stream = fopen(_file_name, FileOpenMode); + if (_stream == NULL) { + log_error(logging)("Could not open log file '%s' (%s).\n", _file_name, strerror(errno)); + return false; + } + return true; +} + +int LogFileOutput::write(const LogDecorations& decorations, const char* msg) { + if (_stream == NULL) { + // An error has occurred with this output, avoid writing to it. + return 0; + } + int written = LogFileStreamOutput::write(decorations, msg); + _current_size += written; + + if (should_rotate()) { + MutexLockerEx ml(&_rotation_lock, true /* no safepoint check */); + if (should_rotate()) { + rotate(); + } + } + + return written; +} + +void LogFileOutput::archive() { + assert(_archive_name != NULL && _archive_name_len > 0, "Rotation must be configured before using this function."); + int ret = jio_snprintf(_archive_name, _archive_name_len, "%s.%0*u", + _file_name, _file_count_max_digits, _current_file); + assert(ret >= 0, "Buffer should always be large enough"); + + // Attempt to remove possibly existing archived log file before we rename. + // Don't care if it fails, we really only care about the rename that follows. + remove(_archive_name); + + // Rename the file from ex hotspot.log to hotspot.log.2 + if (rename(_file_name, _archive_name) == -1) { + jio_fprintf(defaultStream::error_stream(), "Could not rename log file '%s' to '%s' (%s).\n", + _file_name, _archive_name, strerror(errno)); + } +} + +void LogFileOutput::rotate() { + // Archive the current log file + archive(); + + // Open the active log file using the same stream as before + _stream = freopen(_file_name, FileOpenMode, _stream); + if (_stream == NULL) { + jio_fprintf(defaultStream::error_stream(), "Could not reopen file '%s' during log rotation (%s).\n", + _file_name, strerror(errno)); + return; + } + + // Reset accumulated size, increase current file counter, and check for file count wrap-around. + _current_size = 0; + _current_file = (_current_file >= _file_count ? 1 : _current_file + 1); +} + +char* LogFileOutput::make_file_name(const char* file_name, + const char* pid_string, + const char* timestamp_string) { + char* result = NULL; + + // Lets start finding out if we have any %d and/or %t in the name. + // We will only replace the first occurrence of any placeholder + const char* pid = strstr(file_name, PidFilenamePlaceholder); + const char* timestamp = strstr(file_name, TimestampFilenamePlaceholder); + + if (pid == NULL && timestamp == NULL) { + // We found no place-holders, return the simple filename + return os::strdup_check_oom(file_name, mtLogging); + } + + // At least one of the place-holders were found in the file_name + const char* first = ""; + size_t first_pos = SIZE_MAX; + size_t first_replace_len = 0; + + const char* second = ""; + size_t second_pos = SIZE_MAX; + size_t second_replace_len = 0; + + // If we found a %p, then setup our variables accordingly + if (pid != NULL) { + if (timestamp == NULL || pid < timestamp) { + first = pid_string; + first_pos = pid - file_name; + first_replace_len = strlen(PidFilenamePlaceholder); + } else { + second = pid_string; + second_pos = pid - file_name; + second_replace_len = strlen(PidFilenamePlaceholder); + } + } + + if (timestamp != NULL) { + if (pid == NULL || timestamp < pid) { + first = timestamp_string; + first_pos = timestamp - file_name; + first_replace_len = strlen(TimestampFilenamePlaceholder); + } else { + second = timestamp_string; + second_pos = timestamp - file_name; + second_replace_len = strlen(TimestampFilenamePlaceholder); + } + } + + size_t first_len = strlen(first); + size_t second_len = strlen(second); + + // Allocate the new buffer, size it to hold all we want to put in there +1. + size_t result_len = strlen(file_name) + first_len - first_replace_len + second_len - second_replace_len; + result = NEW_C_HEAP_ARRAY(char, result_len + 1, mtLogging); + + // Assemble the strings + size_t file_name_pos = 0; + size_t i = 0; + while (i < result_len) { + if (file_name_pos == first_pos) { + // We are in the range of the first placeholder + strcpy(result + i, first); + // Bump output buffer position with length of replacing string + i += first_len; + // Bump source buffer position to skip placeholder + file_name_pos += first_replace_len; + } else if (file_name_pos == second_pos) { + // We are in the range of the second placeholder + strcpy(result + i, second); + i += second_len; + file_name_pos += second_replace_len; + } else { + // Else, copy char by char of the original file + result[i] = file_name[file_name_pos++]; + i++; + } + } + // Add terminating char + result[result_len] = '\0'; + return result; +} diff --git a/hotspot/src/share/vm/logging/logFileOutput.hpp b/hotspot/src/share/vm/logging/logFileOutput.hpp new file mode 100644 index 00000000000..7419454e069 --- /dev/null +++ b/hotspot/src/share/vm/logging/logFileOutput.hpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP +#define SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP + +#include "logging/logFileStreamOutput.hpp" +#include "runtime/mutex.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogDecorations; + +// The log file output, with support for file rotation based on a target size. +class LogFileOutput : public LogFileStreamOutput { + private: + static const char* FileOpenMode; + static const char* FileCountOptionKey; + static const char* FileSizeOptionKey; + static const char* PidFilenamePlaceholder; + static const char* TimestampFilenamePlaceholder; + static const char* TimestampFormat; + static const size_t StartTimeBufferSize = 20; + static const size_t PidBufferSize = 21; + static char _pid_str[PidBufferSize]; + static char _vm_start_time_str[StartTimeBufferSize]; + + Mutex _rotation_lock; + const char* _name; + char* _file_name; + char* _archive_name; + + uint _current_file; + uint _file_count; + uint _file_count_max_digits; + + size_t _archive_name_len; + size_t _rotate_size; + size_t _current_size; + + void archive(); + void rotate(); + bool configure_rotation(const char* options); + char *make_file_name(const char* file_name, const char* pid_string, const char* timestamp_string); + static size_t parse_value(const char* value_str); + + bool should_rotate() const { + return _file_count > 0 && _rotate_size > 0 && _current_size >= _rotate_size; + } + + public: + LogFileOutput(const char *name); + virtual ~LogFileOutput(); + virtual bool initialize(const char* options); + virtual int write(const LogDecorations& decorations, const char* msg); + + virtual const char* name() const { + return _name; + } + + static void set_file_name_parameters(jlong start_time); +}; + +#endif // SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP diff --git a/hotspot/src/share/vm/logging/logFileStreamOutput.cpp b/hotspot/src/share/vm/logging/logFileStreamOutput.cpp new file mode 100644 index 00000000000..00dfcc5b76b --- /dev/null +++ b/hotspot/src/share/vm/logging/logFileStreamOutput.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logDecorators.hpp" +#include "logging/logDecorations.hpp" +#include "logging/logFileStreamOutput.hpp" +#include "memory/allocation.inline.hpp" + +LogStdoutOutput LogStdoutOutput::_instance; +LogStderrOutput LogStderrOutput::_instance; + +int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) { + char decoration_buf[LogDecorations::DecorationsBufferSize]; + char* position = decoration_buf; + int total_written = 0; + + for (uint i = 0; i < LogDecorators::Count; i++) { + LogDecorators::Decorator decorator = static_cast(i); + if (!_decorators.is_decorator(decorator)) { + continue; + } + int written = jio_snprintf(position, sizeof(decoration_buf) - total_written, "[%-*s]", + _decorator_padding[decorator], + decorations.decoration(decorator)); + if (written <= 0) { + return -1; + } else if (static_cast(written - 2) > _decorator_padding[decorator]) { + _decorator_padding[decorator] = written - 2; + } + position += written; + total_written += written; + } + + if (total_written == 0) { + total_written = jio_fprintf(_stream, "%s\n", msg); + } else { + total_written = jio_fprintf(_stream, "%s %s\n", decoration_buf, msg); + } + fflush(_stream); + return total_written; +} diff --git a/hotspot/src/share/vm/logging/logFileStreamOutput.hpp b/hotspot/src/share/vm/logging/logFileStreamOutput.hpp new file mode 100644 index 00000000000..757d644bf32 --- /dev/null +++ b/hotspot/src/share/vm/logging/logFileStreamOutput.hpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP +#define SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP + +#include "logging/logDecorators.hpp" +#include "logging/logOutput.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogDecorations; + +// Base class for all FileStream-based log outputs. +class LogFileStreamOutput : public LogOutput { + protected: + FILE* _stream; + size_t _decorator_padding[LogDecorators::Count]; + + LogFileStreamOutput(FILE *stream) : _stream(stream) { + for (size_t i = 0; i < LogDecorators::Count; i++) { + _decorator_padding[i] = 0; + } + _decorator_padding[LogDecorators::level_decorator] = 7; + } + + public: + virtual int write(const LogDecorations &decorations, const char* msg); +}; + +class LogStdoutOutput : public LogFileStreamOutput { + friend class LogOutput; + private: + static LogStdoutOutput _instance; + LogStdoutOutput() : LogFileStreamOutput(stdout) { + set_config_string("all=off"); + } + virtual bool initialize(const char* options) { + return false; + } + public: + virtual const char* name() const { + return "stdout"; + } +}; + +class LogStderrOutput : public LogFileStreamOutput { + friend class LogOutput; + private: + static LogStderrOutput _instance; + LogStderrOutput() : LogFileStreamOutput(stderr) { + set_config_string("all=warning"); + } + virtual bool initialize(const char* options) { + return false; + } + public: + virtual const char* name() const { + return "stderr"; + } +}; + +#endif // SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP diff --git a/hotspot/src/share/vm/logging/logLevel.cpp b/hotspot/src/share/vm/logging/logLevel.cpp new file mode 100644 index 00000000000..f33653e6dda --- /dev/null +++ b/hotspot/src/share/vm/logging/logLevel.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logLevel.hpp" +#include "utilities/globalDefinitions.hpp" + +const char* LogLevel::_name[] = { + "off", +#define LOG_LEVEL(name, printname) #printname, + LOG_LEVEL_LIST +#undef LOG_LEVEL +}; + +LogLevelType LogLevel::from_string(const char* str) { + for (uint i = 0; i < Count; i++) { + if (strcasecmp(str, _name[i]) == 0) { + return static_cast(i); + } + } + return Invalid; +} diff --git a/hotspot/src/share/vm/logging/logLevel.hpp b/hotspot/src/share/vm/logging/logLevel.hpp new file mode 100644 index 00000000000..55ac3564d2c --- /dev/null +++ b/hotspot/src/share/vm/logging/logLevel.hpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGLEVEL_HPP +#define SHARE_VM_LOGGING_LOGLEVEL_HPP + +#include "memory/allocation.hpp" +#include "utilities/macros.hpp" + +// The list of log levels: +// +// develop - A non-product level that is finer than trace. +// Should be used for really expensive and/or +// extensive logging, or logging that shouldn't +// or can't be included in a product build. +// +// trace - Finest level of logging in product builds. +// Use for extensive/noisy logging that can +// give slow-down when enabled. +// +// debug - A finer level of logging. Use for semi-noisy +// logging that is does not fit the info level. +// +// info - General level of logging. Use for significant +// events and/or informative summaries. +// +// warning - Important messages that are not strictly errors. +// +// error - Critical messages caused by errors. +// +#define LOG_LEVEL_LIST \ + NOT_PRODUCT(LOG_LEVEL(Develop, develop)) \ + LOG_LEVEL(Trace, trace) \ + LOG_LEVEL(Debug, debug) \ + LOG_LEVEL(Info, info) \ + LOG_LEVEL(Warning, warning) \ + LOG_LEVEL(Error, error) + +class LogLevel : public AllStatic { + public: + enum type { + Off, +#define LOG_LEVEL(name, printname) name, + LOG_LEVEL_LIST +#undef LOG_LEVEL + Count, + Invalid, + First = Off + 1, + Last = Error, + Default = Warning, + Unspecified = Info + }; + + static const char *name(LogLevel::type level) { + return _name[level]; + } + + static LogLevel::type from_string(const char* str); + + private: + static const char* _name[]; +}; + +typedef LogLevel::type LogLevelType; + +#endif // SHARE_VM_LOGGING_LOGLEVEL_HPP diff --git a/hotspot/src/share/vm/logging/logOutput.cpp b/hotspot/src/share/vm/logging/logOutput.cpp new file mode 100644 index 00000000000..ee59d587d8b --- /dev/null +++ b/hotspot/src/share/vm/logging/logOutput.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logFileStreamOutput.hpp" +#include "logging/logOutput.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/os.inline.hpp" + +LogOutput* const LogOutput::Stdout = &LogStdoutOutput::_instance; +LogOutput* const LogOutput::Stderr = &LogStderrOutput::_instance; + +LogOutput::~LogOutput() { + os::free(_config_string); +} + +void LogOutput::set_config_string(const char* string) { + os::free(_config_string); + _config_string = os::strdup_check_oom(string, mtLogging); +} diff --git a/hotspot/src/share/vm/logging/logOutput.hpp b/hotspot/src/share/vm/logging/logOutput.hpp new file mode 100644 index 00000000000..cb9d52ef933 --- /dev/null +++ b/hotspot/src/share/vm/logging/logOutput.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGOUTPUT_HPP +#define SHARE_VM_LOGGING_LOGOUTPUT_HPP + +#include "logging/logDecorators.hpp" +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogDecorations; + +// The base class/interface for log outputs. +// Keeps track of the latest configuration string, +// and its selected decorators. +class LogOutput : public CHeapObj { + protected: + LogDecorators _decorators; + char* _config_string; + + public: + static LogOutput* const Stdout; + static LogOutput* const Stderr; + + void set_decorators(const LogDecorators &decorators) { + _decorators = decorators; + } + + const LogDecorators& decorators() const { + return _decorators; + } + + const char* config_string() const { + return _config_string; + } + + LogOutput() : _config_string(NULL) { + } + + virtual ~LogOutput(); + void set_config_string(const char* string); + + virtual const char* name() const = 0; + virtual bool initialize(const char* options) = 0; + virtual int write(const LogDecorations &decorations, const char* msg) = 0; +}; + +#endif // SHARE_VM_LOGGING_LOGOUTPUT_HPP diff --git a/hotspot/src/share/vm/logging/logOutputList.cpp b/hotspot/src/share/vm/logging/logOutputList.cpp new file mode 100644 index 00000000000..e30f077293c --- /dev/null +++ b/hotspot/src/share/vm/logging/logOutputList.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logLevel.hpp" +#include "logging/logOutputList.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/atomic.inline.hpp" +#include "runtime/orderAccess.inline.hpp" +#include "utilities/globalDefinitions.hpp" + +jint LogOutputList::increase_readers() { + jint result = Atomic::add(1, &_active_readers); + assert(_active_readers > 0, "Ensure we have consistent state"); + return result; +} + +jint LogOutputList::decrease_readers() { + jint result = Atomic::add(-1, &_active_readers); + assert(result >= 0, "Ensure we have consistent state"); + return result; +} + +void LogOutputList::wait_until_no_readers() const { + OrderAccess::storeload(); + while (_active_readers != 0) { + // Busy wait + } +} + +void LogOutputList::set_output_level(LogOutput* output, LogLevelType level) { + LogOutputNode* node = find(output); + if (level == LogLevel::Off && node != NULL) { + remove_output(node); + } else if (level != LogLevel::Off && node == NULL) { + add_output(output, level); + } else if (node != NULL) { + update_output_level(node, level); + } +} + +LogOutputList::LogOutputNode* LogOutputList::find(LogOutput* output) { + for (LogOutputNode* node = _level_start[LogLevel::Last]; node != NULL; node = node->_next) { + if (output == node->_value) { + return node; + } + } + return NULL; +} + +void LogOutputList::remove_output(LogOutputList::LogOutputNode* node) { + assert(node != NULL, "Node must be non-null"); + + // Remove node from _level_start first + bool found = false; + for (uint level = LogLevel::First; level < LogLevel::Count; level++) { + if (_level_start[level] == node) { + found = true; + _level_start[level] = node->_next; + } + } + + // Now remove it from the linked list + for (LogOutputNode* cur = _level_start[LogLevel::Last]; cur != NULL; cur = cur->_next) { + if (cur->_next == node) { + found = true; + cur->_next = node->_next; + break; + } + } + assert(found, "Node to be removed should always be found"); + + wait_until_no_readers(); + delete node; +} + +void LogOutputList::add_output(LogOutput* output, LogLevelType level) { + LogOutputNode* node = new LogOutputNode(); + node->_value = output; + node->_level = level; + + // Set the next pointer to the first node of a lower level + for (node->_next = _level_start[level]; + node->_next != NULL && node->_next->_level == level; + node->_next = node->_next->_next) { + } + + // Update the _level_start index + for (int l = LogLevel::Last; l >= level; l--) { + if (_level_start[l] == NULL || _level_start[l]->_level < level) { + _level_start[l] = node; + } + } + + // Add the node the list + for (LogOutputNode* cur = _level_start[LogLevel::Last]; cur != NULL; cur = cur->_next) { + if (cur != node && cur->_next == node->_next) { + cur->_next = node; + break; + } + } +} + +void LogOutputList::update_output_level(LogOutputList::LogOutputNode* node, LogLevelType level) { + add_output(node->_value, level); + wait_until_no_readers(); + remove_output(node); +} diff --git a/hotspot/src/share/vm/logging/logOutputList.hpp b/hotspot/src/share/vm/logging/logOutputList.hpp new file mode 100644 index 00000000000..900b7d9fcdb --- /dev/null +++ b/hotspot/src/share/vm/logging/logOutputList.hpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP +#define SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP + +#include "logging/logLevel.hpp" +#include "memory/allocation.hpp" +#include "runtime/atomic.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogOutput; + +// Data structure to keep track of log outputs for a given tagset. +// Essentially a sorted linked list going from error level outputs +// to outputs of finer levels. Keeps an index from each level to +// the first node in the list for the corresponding level. +// This allows a log message on, for example, info level to jump +// straight into the list where the first info level output can +// be found. The log message will then be printed on that output, +// as well as all outputs in nodes that follow in the list (which +// can be additional info level outputs and/or debug and trace outputs). +// +// Each instance keeps track of the number of current readers of the list. +// To remove a node from the list the node must first be unlinked, +// and the memory for that node can be freed whenever the removing +// thread observes an active reader count of 0 (after unlinking it). +class LogOutputList VALUE_OBJ_CLASS_SPEC { + private: + struct LogOutputNode : public CHeapObj { + LogOutput* _value; + LogOutputNode* _next; + LogLevelType _level; + }; + + LogOutputNode* _level_start[LogLevel::Count]; + volatile jint _active_readers; + + LogOutputNode* find(LogOutput* output); + void remove_output(LogOutputNode* node); + void add_output(LogOutput* output, LogLevelType level); + void update_output_level(LogOutputNode* node, LogLevelType level); + + public: + LogOutputList() : _active_readers(0) { + for (size_t i = 0; i < LogLevel::Count; i++) { + _level_start[i] = NULL; + } + } + + // Test if the outputlist has an output for the given level. + bool is_level(LogLevelType level) { + return _level_start[level] != NULL; + } + + // Set (add/update/remove) the output to the specified level. + void set_output_level(LogOutput* output, LogLevelType level); + + // Bookkeeping functions to keep track of number of active readers/iterators for the list. + jint increase_readers(); + jint decrease_readers(); + void wait_until_no_readers() const; + + class Iterator VALUE_OBJ_CLASS_SPEC { + friend class LogOutputList; + private: + LogOutputNode* _current; + LogOutputList* _list; + Iterator(LogOutputList* list, LogOutputNode* start) : _current(start), _list(list) { + } + + public: + ~Iterator() { + _list->decrease_readers(); + } + + LogOutput* operator*() { + return _current->_value; + } + + void operator++(int) { + _current = _current->_next; + } + + bool operator!=(const LogOutputNode *ref) const { + return _current != ref; + } + }; + + Iterator iterator(LogLevelType level = LogLevel::Last) { + increase_readers(); + return Iterator(this, _level_start[level]); + } + + LogOutputNode* end() const { + return NULL; + } +}; + +#endif // SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP diff --git a/hotspot/src/share/vm/logging/logPrefix.hpp b/hotspot/src/share/vm/logging/logPrefix.hpp new file mode 100644 index 00000000000..2bdd290c7e0 --- /dev/null +++ b/hotspot/src/share/vm/logging/logPrefix.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGPREFIX_HPP +#define SHARE_VM_LOGGING_LOGPREFIX_HPP + +#include "gc/shared/gcId.hpp" +#include "logging/logTag.hpp" + +// Prefixes prepend each log message for a specified tagset with the given prefix. +// A prefix consists of a format string and a value or callback. Prefixes are added +// after the decorations but before the log message. +// +// List of prefixes for specific tags and/or tagsets. +// Syntax: LOG_PREFIX(, , LOG_TAGS()) +#define LOG_PREFIX_LIST // Currently unused/empty + +// The empty prefix, used when there's no prefix defined. +template +struct LogPrefix : public AllStatic { + STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); + static size_t prefix(char* buf, size_t len) { + return 0; + } +}; + +#define LOG_PREFIX(fmt, fn, ...) \ +template <> struct LogPrefix<__VA_ARGS__> { \ + static size_t prefix(char* buf, size_t len) { \ + int ret = jio_snprintf(buf, len, fmt, fn); \ + assert(ret >= 0, \ + "Failed to prefix log message using prefix ('%s', '%s'), log buffer too small?", fmt, #fn); \ + return ret; \ + } \ +}; +LOG_PREFIX_LIST +#undef LOG_PREFIX + +#endif // SHARE_VM_LOGGING_LOGPREFIX_HPP diff --git a/hotspot/src/share/vm/logging/logTag.cpp b/hotspot/src/share/vm/logging/logTag.cpp new file mode 100644 index 00000000000..9694ede5270 --- /dev/null +++ b/hotspot/src/share/vm/logging/logTag.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logTag.hpp" +#include "utilities/globalDefinitions.hpp" + +const char* LogTag::_name[] = { + "", // __NO_TAG +#define LOG_TAG(name) #name, + LOG_TAG_LIST +#undef LOG_TAG +}; + +LogTagType LogTag::from_string(const char* str) { + for (uint i = 0; i < LogTag::Count; i++) { + if (strcasecmp(str, _name[i]) == 0) { + return static_cast(i); + } + } + return __NO_TAG; +} diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp new file mode 100644 index 00000000000..0989af3401c --- /dev/null +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGTAG_HPP +#define SHARE_VM_LOGGING_LOGTAG_HPP + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +// List of available logging tags. New tags should be added here. +// (The tags 'all', 'disable' and 'help' are special tags that can +// not be used in log calls, and should not be listed below.) +#define LOG_TAG_LIST \ + LOG_TAG(logging) + +#define PREFIX_LOG_TAG(T) (LogTag::T) + +// Expand a set of log tags to their prefixed names. +// For error detection purposes, the macro passes one more tag than what is supported. +// If too many tags are given, a static assert in the log class will fail. +#define LOG_TAGS_EXPANDED(T0, T1, T2, T3, T4, T5, ...) PREFIX_LOG_TAG(T0), PREFIX_LOG_TAG(T1), PREFIX_LOG_TAG(T2), \ + PREFIX_LOG_TAG(T3), PREFIX_LOG_TAG(T4), PREFIX_LOG_TAG(T5) +// The EXPAND_VARARGS macro is required for MSVC, or it will resolve the LOG_TAGS_EXPANDED macro incorrectly. +#define EXPAND_VARARGS(x) x +#define LOG_TAGS(...) EXPAND_VARARGS(LOG_TAGS_EXPANDED(__VA_ARGS__, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG)) + +// Log tags are used to classify log messages. +// Each log message can be assigned between 1 to LogTag::MaxTags number of tags. +// Specifying multiple tags for a log message means that only outputs configured +// for those exact tags, or a subset of the tags with a wildcard, will see the logging. +// Multiple tags should be comma separated, e.g. log_error(tag1, tag2)("msg"). +class LogTag : public AllStatic { + public: + // The maximum number of tags that a single log message can have. + // E.g. there might be hundreds of different tags available, + // but a specific log message can only be tagged with up to MaxTags of those. + static const size_t MaxTags = 5; + + enum type { + __NO_TAG, +#define LOG_TAG(name) name, + LOG_TAG_LIST +#undef LOG_TAG + Count + }; + + static const char* name(LogTag::type tag) { + return _name[tag]; + } + + static LogTag::type from_string(const char *str); + + private: + static const char* _name[]; +}; + +typedef LogTag::type LogTagType; + +#endif // SHARE_VM_LOGGING_LOGTAG_HPP diff --git a/hotspot/src/share/vm/logging/logTagLevelExpression.cpp b/hotspot/src/share/vm/logging/logTagLevelExpression.cpp new file mode 100644 index 00000000000..d3dd9b283f0 --- /dev/null +++ b/hotspot/src/share/vm/logging/logTagLevelExpression.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logTagLevelExpression.hpp" +#include "logging/logTagSet.hpp" +#include "runtime/arguments.hpp" +#include "runtime/os.inline.hpp" + +const char* LogTagLevelExpression::DefaultExpressionString = "all"; + +LogTagLevelExpression::~LogTagLevelExpression() { + os::free(_string); +} + +void LogTagLevelExpression::clear() { + _ntags = 0; + _ncombinations = 0; + for (size_t combination = 0; combination < MaxCombinations; combination++) { + _level[combination] = LogLevel::Invalid; + _allow_other_tags[combination] = false; + for (size_t tag = 0; tag < LogTag::MaxTags; tag++) { + _tags[combination][tag] = LogTag::__NO_TAG; + } + } + os::free(_string); + _string = NULL; +} + +bool LogTagLevelExpression::parse(const char* str, outputStream* errstream) { + bool success = true; + clear(); + if (str == NULL || strcmp(str, "") == 0) { + str = DefaultExpressionString; + } + char* copy = os::strdup_check_oom(str, mtLogging); + // Split string on commas + for (char *comma_pos = copy, *cur = copy; success && comma_pos != NULL; cur = comma_pos + 1) { + if (_ncombinations == MaxCombinations) { + if (errstream != NULL) { + errstream->print_cr("Can not have more than " SIZE_FORMAT " tag combinations in a what-expression.", + MaxCombinations); + } + success = false; + break; + } + + comma_pos = strchr(cur, ','); + if (comma_pos != NULL) { + *comma_pos = '\0'; + } + + // Parse the level, if specified + LogLevelType level = LogLevel::Unspecified; + char* equals = strchr(cur, '='); + if (equals != NULL) { + level = LogLevel::from_string(equals + 1); + if (level == LogLevel::Invalid) { + if (errstream != NULL) { + errstream->print_cr("Invalid level '%s' in what-expression.", equals + 1); + } + success = false; + break; + } + *equals = '\0'; // now ignore "=level" part of substr + } + set_level(level); + + // Parse special tags such as 'all' + if (strcmp(cur, "all") == 0) { + set_allow_other_tags(); + new_combination(); + continue; + } + + // Check for '*' suffix + char* asterisk_pos = strchr(cur, '*'); + if (asterisk_pos != NULL && asterisk_pos[1] == '\0') { + set_allow_other_tags(); + *asterisk_pos = '\0'; + } + + // Parse the tag expression (t1+t2+...+tn) + char* plus_pos; + char* cur_tag = cur; + do { + plus_pos = strchr(cur_tag, '+'); + if (plus_pos != NULL) { + *plus_pos = '\0'; + } + LogTagType tag = LogTag::from_string(cur_tag); + if (tag == LogTag::__NO_TAG) { + if (errstream != NULL) { + errstream->print_cr("Invalid tag '%s' in what-expression.", cur_tag); + } + success = false; + break; + } + if (_ntags == LogTag::MaxTags) { + if (errstream != NULL) { + errstream->print_cr("Tag combination exceeds the maximum of " SIZE_FORMAT " tags.", + LogTag::MaxTags); + } + success = false; + break; + } + add_tag(tag); + cur_tag = plus_pos + 1; + } while (plus_pos != NULL); + + new_combination(); + } + + // Save the (unmodified) string for printing purposes. + _string = copy; + strcpy(_string, str); + + return success; +} + +LogLevelType LogTagLevelExpression::level_for(const LogTagSet& ts) const { + LogLevelType level = LogLevel::Off; + for (size_t combination = 0; combination < _ncombinations; combination++) { + bool contains_all = true; + size_t tag_idx; + for (tag_idx = 0; tag_idx < LogTag::MaxTags && _tags[combination][tag_idx] != LogTag::__NO_TAG; tag_idx++) { + if (!ts.contains(_tags[combination][tag_idx])) { + contains_all = false; + break; + } + } + // All tags in the expression must be part of the tagset, + // and either the expression allows other tags (has a wildcard), + // or the number of tags in the expression and tagset must match. + if (contains_all && (_allow_other_tags[combination] || tag_idx == ts.ntags())) { + level = _level[combination]; + } + } + return level; +} diff --git a/hotspot/src/share/vm/logging/logTagLevelExpression.hpp b/hotspot/src/share/vm/logging/logTagLevelExpression.hpp new file mode 100644 index 00000000000..5fae414e5a1 --- /dev/null +++ b/hotspot/src/share/vm/logging/logTagLevelExpression.hpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP +#define SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP + +#include "logging/logLevel.hpp" +#include "logging/logTag.hpp" +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogTagSet; + +// Class used to temporary encode a 'what'-expression during log configuration. +// Consists of a combination of tags and levels, e.g. "tag1+tag2=level1,tag3*=level2". +class LogTagLevelExpression : public StackObj { + private: + static const size_t MaxCombinations = 32; + static const char* DefaultExpressionString; + + size_t _ntags, _ncombinations; + LogTagType _tags[MaxCombinations][LogTag::MaxTags]; + LogLevelType _level[MaxCombinations]; + bool _allow_other_tags[MaxCombinations]; + char* _string; + + void new_combination() { + _ncombinations++; + _ntags = 0; + } + + void add_tag(LogTagType tag) { + assert(_ntags < LogTag::MaxTags, "Can't have more tags than MaxTags!"); + _tags[_ncombinations][_ntags++] = tag; + } + + void set_level(LogLevelType level) { + _level[_ncombinations] = level; + } + + void set_allow_other_tags() { + _allow_other_tags[_ncombinations] = true; + } + + void clear(); + + public: + LogTagLevelExpression() : _ntags(0), _ncombinations(0), _string(NULL) { + } + + const char* to_string() const { + return _string; + } + + ~LogTagLevelExpression(); + bool parse(const char* str, outputStream* errstream = NULL); + LogLevelType level_for(const LogTagSet& ts) const; +}; + +#endif // SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP diff --git a/hotspot/src/share/vm/logging/logTagSet.cpp b/hotspot/src/share/vm/logging/logTagSet.cpp new file mode 100644 index 00000000000..5a975c58073 --- /dev/null +++ b/hotspot/src/share/vm/logging/logTagSet.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logDecorations.hpp" +#include "logging/logLevel.hpp" +#include "logging/logOutput.hpp" +#include "logging/logTag.hpp" +#include "logging/logTagSet.hpp" + +LogTagSet* LogTagSet::_list = NULL; +size_t LogTagSet::_ntagsets = 0; + +// This constructor is called only during static initialization. +// See the declaration in logTagSet.hpp for more information. +LogTagSet::LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4) + : _next(_list) { + _tag[0] = t0; + _tag[1] = t1; + _tag[2] = t2; + _tag[3] = t3; + _tag[4] = t4; + for (_ntags = 0; _ntags < LogTag::MaxTags && _tag[_ntags] != LogTag::__NO_TAG; _ntags++) { + } + _list = this; + _ntagsets++; + + // Set the default output to warning and error level for all new tagsets. + _output_list.set_output_level(LogOutput::Stderr, LogLevel::Default); +} + +bool LogTagSet::is_level(LogLevelType level) { + return _output_list.is_level(level); +} + +void LogTagSet::update_decorators(const LogDecorators& decorator) { + LogDecorators new_decorators = decorator; + for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) { + new_decorators.combine_with((*it)->decorators()); + } + _decorators = new_decorators; +} + +bool LogTagSet::has_output(const LogOutput* output) { + for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) { + if (*it == output) { + return true; + } + } + return false; +} + +void LogTagSet::log(LogLevelType level, const char* msg) { + LogDecorations decorations(level, *this, _decorators); + for (LogOutputList::Iterator it = _output_list.iterator(level); it != _output_list.end(); it++) { + (*it)->write(decorations, msg); + } +} + +int LogTagSet::label(char* buf, size_t len) { + int tot_written = 0; + for (size_t i = 0; i < _ntags; i++) { + int written = jio_snprintf(buf + tot_written, len - tot_written, "%s%s", + (i == 0 ? "" : ","), + LogTag::name(_tag[i])); + if (written < 0) { + return -1; + } + tot_written += written; + } + return tot_written; +} diff --git a/hotspot/src/share/vm/logging/logTagSet.hpp b/hotspot/src/share/vm/logging/logTagSet.hpp new file mode 100644 index 00000000000..e25512f7630 --- /dev/null +++ b/hotspot/src/share/vm/logging/logTagSet.hpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGTAGSET_HPP +#define SHARE_VM_LOGGING_LOGTAGSET_HPP + +#include "logging/logDecorators.hpp" +#include "logging/logLevel.hpp" +#include "logging/logOutputList.hpp" +#include "logging/logTag.hpp" +#include "utilities/globalDefinitions.hpp" + +// The tagset represents a combination of tags that occur in a log call somewhere. +// Tagsets are created automatically by the LogTagSetMappings and should never be +// instantiated directly somewhere else. +class LogTagSet VALUE_OBJ_CLASS_SPEC { + private: + static LogTagSet* _list; + static size_t _ntagsets; + + LogTagSet* const _next; + size_t _ntags; + LogTagType _tag[LogTag::MaxTags]; + + LogOutputList _output_list; + LogDecorators _decorators; + + // Keep constructor private to prevent incorrect instantiations of this class. + // Only LogTagSetMappings can create/contain instances of this class. + // The constructor links all tagsets together in a global list of tagsets. + // This list is used during configuration to be able to update all tagsets + // and their configurations to reflect the new global log configuration. + LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4); + + template + friend class LogTagSetMapping; + + public: + static LogTagSet* first() { + return _list; + } + + LogTagSet* next() { + return _next; + } + + size_t ntags() const { + return _ntags; + } + + bool contains(LogTagType tag) const { + for (size_t i = 0; _tag[i] != LogTag::__NO_TAG; i++) { + if (tag == _tag[i]) { + return true; + } + } + return false; + } + + void set_output_level(LogOutput* output, LogLevelType level) { + _output_list.set_output_level(output, level); + } + + // Refresh the decorators for this tagset to contain the decorators for all + // of its current outputs combined with the given decorators. + void update_decorators(const LogDecorators& decorator); + + int label(char *buf, size_t len); + bool has_output(const LogOutput* output); + bool is_level(LogLevelType level); + void log(LogLevelType level, const char* msg); +}; + +template +class LogTagSetMapping : public AllStatic { +private: + static LogTagSet _tagset; + +public: + static LogTagSet& tagset() { + return _tagset; + } +}; + +// Instantiate the static field _tagset for all tagsets that are used for logging somewhere. +// (This must be done here rather than the .cpp file because it's a template.) +// Each combination of tags used as template arguments to the Log class somewhere (via macro or not) +// will instantiate the LogTagSetMapping template, which in turn creates the static field for that +// tagset. This _tagset contains the configuration for those tags. +template +LogTagSet LogTagSetMapping::_tagset(T0, T1, T2, T3, T4); + +#endif // SHARE_VM_LOGGING_LOGTAGSET_HPP diff --git a/hotspot/src/share/vm/memory/allocation.cpp b/hotspot/src/share/vm/memory/allocation.cpp index 25889e9e2d1..5f846d3c245 100644 --- a/hotspot/src/share/vm/memory/allocation.cpp +++ b/hotspot/src/share/vm/memory/allocation.cpp @@ -125,7 +125,7 @@ void ResourceObj::operator delete [](void* p) { void ResourceObj::set_allocation_type(address res, allocation_type type) { // Set allocation type in the resource object uintptr_t allocation = (uintptr_t)res; - assert((allocation & allocation_mask) == 0, err_msg("address should be aligned to 4 bytes at least: " INTPTR_FORMAT, p2i(res))); + assert((allocation & allocation_mask) == 0, "address should be aligned to 4 bytes at least: " INTPTR_FORMAT, p2i(res)); assert(type <= allocation_mask, "incorrect allocation type"); ResourceObj* resobj = (ResourceObj *)res; resobj->_allocation_t[0] = ~(allocation + type); @@ -161,8 +161,8 @@ ResourceObj::ResourceObj() { // default constructor } else if (is_type_set()) { // Operator new() was called and type was set. assert(!allocated_on_stack(), - err_msg("not embedded or stack, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", - p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1])); + "not embedded or stack, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", + p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1]); } else { // Operator new() was not called. // Assume that it is embedded or stack object. @@ -175,8 +175,8 @@ ResourceObj::ResourceObj(const ResourceObj& r) { // default copy constructor // Used in ClassFileParser::parse_constant_pool_entries() for ClassFileStream. // Note: garbage may resembles valid value. assert(~(_allocation_t[0] | allocation_mask) != (uintptr_t)this || !is_type_set(), - err_msg("embedded or stack only, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", - p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1])); + "embedded or stack only, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", + p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1]); set_allocation_type((address)this, STACK_OR_EMBEDDED); _allocation_t[1] = 0; // Zap verification value } @@ -184,8 +184,8 @@ ResourceObj::ResourceObj(const ResourceObj& r) { // default copy constructor ResourceObj& ResourceObj::operator=(const ResourceObj& r) { // default copy assignment // Used in InlineTree::ok_to_inline() for WarmCallInfo. assert(allocated_on_stack(), - err_msg("copy only into local, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", - p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1])); + "copy only into local, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", + p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1]); // Keep current _allocation_t value; return *this; } @@ -533,7 +533,7 @@ size_t Arena::used() const { } void Arena::signal_out_of_memory(size_t sz, const char* whence) const { - vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR, whence); + vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR, "%s", whence); } // Grow a new Chunk diff --git a/hotspot/src/share/vm/memory/allocation.hpp b/hotspot/src/share/vm/memory/allocation.hpp index c5207414b64..e7cb81947af 100644 --- a/hotspot/src/share/vm/memory/allocation.hpp +++ b/hotspot/src/share/vm/memory/allocation.hpp @@ -154,8 +154,9 @@ enum MemoryType { mtChunk = 0x0C, // chunk that holds content of arenas mtTest = 0x0D, // Test type for verifying NMT mtTracing = 0x0E, // memory used for Tracing - mtNone = 0x0F, // undefined - mt_number_of_types = 0x10 // number of memory types (mtDontTrack + mtLogging = 0x0F, // memory for logging + mtNone = 0x10, // undefined + mt_number_of_types = 0x11 // number of memory types (mtDontTrack // is not included as validate type) }; diff --git a/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp b/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp index d97547c4116..8837c8a6e2d 100644 --- a/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp +++ b/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp @@ -708,8 +708,8 @@ void BinaryTreeDictionary::insert_chunk_in_tree(Chunk_t* fc size_t size = fc->size(); assert((size >= min_size()), - err_msg(SIZE_FORMAT " is too small to be a TreeChunk " SIZE_FORMAT, - size, min_size())); + SIZE_FORMAT " is too small to be a TreeChunk " SIZE_FORMAT, + size, min_size()); if (FLSVerifyDictionary) { verify_tree(); } diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 030f8a30d3a..c152f6ab525 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -50,7 +50,6 @@ #define O_BINARY 0 // otherwise do nothing. #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC extern address JVM_FunctionAtStart(); extern address JVM_FunctionAtEnd(); @@ -443,8 +442,8 @@ void FileMapInfo::write_region(int region, char* base, size_t size, if (_file_open) { guarantee(si->_file_offset == _file_offset, "file offset mismatch."); if (PrintSharedSpaces) { - tty->print_cr("Shared file region %d: 0x%6x bytes, addr " INTPTR_FORMAT - " file offset 0x%6x", region, size, base, _file_offset); + tty->print_cr("Shared file region %d: " SIZE_FORMAT_HEX_W(6) " bytes, addr " INTPTR_FORMAT + " file offset " SIZE_FORMAT_HEX_W(6), region, size, p2i(base), _file_offset); } } else { si->_file_offset = _file_offset; @@ -602,7 +601,8 @@ ReservedSpace FileMapInfo::reserve_shared_memory() { // other reserved memory (like the code cache). ReservedSpace rs(size, os::vm_allocation_granularity(), false, requested_addr); if (!rs.is_reserved()) { - fail_continue("Unable to reserve shared space at required address " INTPTR_FORMAT, requested_addr); + fail_continue("Unable to reserve shared space at required address " + INTPTR_FORMAT, p2i(requested_addr)); return rs; } // the reserved virtual memory is for mapping class data sharing archive @@ -659,7 +659,7 @@ bool FileMapInfo::map_string_regions() { tty->print_cr("Shared string data from the CDS archive is being ignored. " "The current CompressedOops/CompressedClassPointers encoding differs from " "that archived due to heap size change. The archive was dumped using max heap " - "size %dM.", max_heap_size()/M); + "size " UINTX_FORMAT "M.", max_heap_size()/M); } } else { string_ranges = new MemRegion[MetaspaceShared::max_strings]; @@ -896,7 +896,7 @@ bool FileMapInfo::FileMapHeader::validate() { } if (_obj_alignment != ObjectAlignmentInBytes) { FileMapInfo::fail_continue("The shared archive file's ObjectAlignmentInBytes of %d" - " does not equal the current ObjectAlignmentInBytes of %d.", + " does not equal the current ObjectAlignmentInBytes of " INTX_FORMAT ".", _obj_alignment, ObjectAlignmentInBytes); return false; } @@ -951,7 +951,7 @@ void FileMapInfo::print_shared_spaces() { char *base = _header->region_addr(i); gclog_or_tty->print(" %s " INTPTR_FORMAT "-" INTPTR_FORMAT, shared_region_name[i], - base, base + si->_used); + p2i(base), p2i(base + si->_used)); } } diff --git a/hotspot/src/share/vm/memory/iterator.hpp b/hotspot/src/share/vm/memory/iterator.hpp index e498c0721e2..e455419c0c5 100644 --- a/hotspot/src/share/vm/memory/iterator.hpp +++ b/hotspot/src/share/vm/memory/iterator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,10 +51,18 @@ class OopClosure : public Closure { // This is needed by the GC and is extracted to a separate type to not // pollute the OopClosure interface. class ExtendedOopClosure : public OopClosure { - public: + private: ReferenceProcessor* _ref_processor; + + protected: ExtendedOopClosure(ReferenceProcessor* rp) : _ref_processor(rp) { } - ExtendedOopClosure() : OopClosure(), _ref_processor(NULL) { } + ExtendedOopClosure() : _ref_processor(NULL) { } + ~ExtendedOopClosure() { } + + void set_ref_processor_internal(ReferenceProcessor* rp) { _ref_processor = rp; } + + public: + ReferenceProcessor* ref_processor() const { return _ref_processor; } // If the do_metadata functions return "true", // we invoke the following when running oop_iterate(): diff --git a/hotspot/src/share/vm/memory/iterator.inline.hpp b/hotspot/src/share/vm/memory/iterator.inline.hpp index 51cb429f3e7..cf2a1f679ec 100644 --- a/hotspot/src/share/vm/memory/iterator.inline.hpp +++ b/hotspot/src/share/vm/memory/iterator.inline.hpp @@ -58,7 +58,7 @@ void ExtendedOopClosure::verify(T* p) { if (!oopDesc::is_null(heap_oop)) { oop o = oopDesc::decode_heap_oop_not_null(heap_oop); assert(Universe::heap()->is_in_closed_subset(o), - err_msg("should be in closed *p " PTR_FORMAT " " PTR_FORMAT, p2i(p), p2i(o))); + "should be in closed *p " PTR_FORMAT " " PTR_FORMAT, p2i(p), p2i(o)); } } } diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 3d26659d49a..f4e40db3193 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -189,7 +189,7 @@ class ChunkManager : public CHeapObj { assert(index == SpecializedIndex || \ index == SmallIndex || \ index == MediumIndex || \ - index == HumongousIndex, err_msg("Bad index: %d", (int) index)) + index == HumongousIndex, "Bad index: %d", (int) index) size_t num_free_chunks(ChunkIndex index) const { index_bounds_check(index); @@ -378,13 +378,13 @@ class VirtualSpaceNode : public CHeapObj { #define assert_is_ptr_aligned(ptr, alignment) \ assert(is_ptr_aligned(ptr, alignment), \ - err_msg(PTR_FORMAT " is not aligned to " \ - SIZE_FORMAT, p2i(ptr), alignment)) + PTR_FORMAT " is not aligned to " \ + SIZE_FORMAT, p2i(ptr), alignment) #define assert_is_size_aligned(size, alignment) \ assert(is_size_aligned(size, alignment), \ - err_msg(SIZE_FORMAT " is not aligned to " \ - SIZE_FORMAT, size, alignment)) + SIZE_FORMAT " is not aligned to " \ + SIZE_FORMAT, size, alignment) // Decide if large pages should be committed when the memory is reserved. @@ -801,8 +801,8 @@ void VirtualSpaceNode::dec_container_count() { #ifdef ASSERT void VirtualSpaceNode::verify_container_count() { assert(_container_count == container_count_slow(), - err_msg("Inconsistency in container_count _container_count " UINTX_FORMAT - " container_count_slow() " UINTX_FORMAT, _container_count, container_count_slow())); + "Inconsistency in container_count _container_count " UINTX_FORMAT + " container_count_slow() " UINTX_FORMAT, _container_count, container_count_slow()); } #endif @@ -965,12 +965,12 @@ bool VirtualSpaceNode::initialize() { (HeapWord*)(_rs.base() + _rs.size()))); assert(reserved()->start() == (HeapWord*) _rs.base(), - err_msg("Reserved start was not set properly " PTR_FORMAT - " != " PTR_FORMAT, p2i(reserved()->start()), p2i(_rs.base()))); + "Reserved start was not set properly " PTR_FORMAT + " != " PTR_FORMAT, p2i(reserved()->start()), p2i(_rs.base())); assert(reserved()->word_size() == _rs.size() / BytesPerWord, - err_msg("Reserved size was not set properly " SIZE_FORMAT - " != " SIZE_FORMAT, reserved()->word_size(), - _rs.size() / BytesPerWord)); + "Reserved size was not set properly " SIZE_FORMAT + " != " SIZE_FORMAT, reserved()->word_size(), + _rs.size() / BytesPerWord); } return result; @@ -1016,11 +1016,11 @@ void VirtualSpaceList::dec_reserved_words(size_t v) { _reserved_words = _reserved_words - v; } -#define assert_committed_below_limit() \ - assert(MetaspaceAux::committed_bytes() <= MaxMetaspaceSize, \ - err_msg("Too much committed memory. Committed: " SIZE_FORMAT \ - " limit (MaxMetaspaceSize): " SIZE_FORMAT, \ - MetaspaceAux::committed_bytes(), MaxMetaspaceSize)); +#define assert_committed_below_limit() \ + assert(MetaspaceAux::committed_bytes() <= MaxMetaspaceSize, \ + "Too much committed memory. Committed: " SIZE_FORMAT \ + " limit (MaxMetaspaceSize): " SIZE_FORMAT, \ + MetaspaceAux::committed_bytes(), MaxMetaspaceSize); void VirtualSpaceList::inc_committed_words(size_t v) { assert_lock_strong(SpaceManager::expand_lock()); @@ -1461,8 +1461,8 @@ size_t MetaspaceGC::allowed_expansion() { size_t capacity_until_gc = capacity_until_GC(); assert(capacity_until_gc >= committed_bytes, - err_msg("capacity_until_gc: " SIZE_FORMAT " < committed_bytes: " SIZE_FORMAT, - capacity_until_gc, committed_bytes)); + "capacity_until_gc: " SIZE_FORMAT " < committed_bytes: " SIZE_FORMAT, + capacity_until_gc, committed_bytes); size_t left_until_max = MaxMetaspaceSize - committed_bytes; size_t left_until_GC = capacity_until_gc - committed_bytes; @@ -1543,8 +1543,8 @@ void MetaspaceGC::compute_new_size() { // No expansion, now see if we want to shrink // We would never want to shrink more than this assert(capacity_until_GC >= minimum_desired_capacity, - err_msg(SIZE_FORMAT " >= " SIZE_FORMAT, - capacity_until_GC, minimum_desired_capacity)); + SIZE_FORMAT " >= " SIZE_FORMAT, + capacity_until_GC, minimum_desired_capacity); size_t max_shrink_bytes = capacity_until_GC - minimum_desired_capacity; // Should shrinking be considered? @@ -1585,8 +1585,8 @@ void MetaspaceGC::compute_new_size() { shrink_bytes = align_size_down(shrink_bytes, Metaspace::commit_alignment()); assert(shrink_bytes <= max_shrink_bytes, - err_msg("invalid shrink size " SIZE_FORMAT " not <= " SIZE_FORMAT, - shrink_bytes, max_shrink_bytes)); + "invalid shrink size " SIZE_FORMAT " not <= " SIZE_FORMAT, + shrink_bytes, max_shrink_bytes); if (current_shrink_factor == 0) { _shrink_factor = 10; } else { @@ -1676,9 +1676,9 @@ size_t ChunkManager::free_chunks_count() { void ChunkManager::locked_verify_free_chunks_total() { assert_lock_strong(SpaceManager::expand_lock()); assert(sum_free_chunks() == _free_chunks_total, - err_msg("_free_chunks_total " SIZE_FORMAT " is not the" - " same as sum " SIZE_FORMAT, _free_chunks_total, - sum_free_chunks())); + "_free_chunks_total " SIZE_FORMAT " is not the" + " same as sum " SIZE_FORMAT, _free_chunks_total, + sum_free_chunks()); } void ChunkManager::verify_free_chunks_total() { @@ -1690,9 +1690,9 @@ void ChunkManager::verify_free_chunks_total() { void ChunkManager::locked_verify_free_chunks_count() { assert_lock_strong(SpaceManager::expand_lock()); assert(sum_free_chunks_count() == _free_chunks_count, - err_msg("_free_chunks_count " SIZE_FORMAT " is not the" - " same as sum " SIZE_FORMAT, _free_chunks_count, - sum_free_chunks_count())); + "_free_chunks_count " SIZE_FORMAT " is not the" + " same as sum " SIZE_FORMAT, _free_chunks_count, + sum_free_chunks_count()); } void ChunkManager::verify_free_chunks_count() { @@ -1891,9 +1891,9 @@ void SpaceManager::get_initial_chunk_sizes(Metaspace::MetaspaceType type, break; } assert(*chunk_word_size != 0 && *class_chunk_word_size != 0, - err_msg("Initial chunks sizes bad: data " SIZE_FORMAT - " class " SIZE_FORMAT, - *chunk_word_size, *class_chunk_word_size)); + "Initial chunks sizes bad: data " SIZE_FORMAT + " class " SIZE_FORMAT, + *chunk_word_size, *class_chunk_word_size); } size_t SpaceManager::sum_free_in_chunks_in_use() const { @@ -2036,9 +2036,9 @@ size_t SpaceManager::calc_chunk_size(size_t word_size) { assert(!SpaceManager::is_humongous(word_size) || chunk_word_size == if_humongous_sized_chunk, - err_msg("Size calculation is wrong, word_size " SIZE_FORMAT - " chunk_word_size " SIZE_FORMAT, - word_size, chunk_word_size)); + "Size calculation is wrong, word_size " SIZE_FORMAT + " chunk_word_size " SIZE_FORMAT, + word_size, chunk_word_size); if (TraceMetadataHumongousAllocation && SpaceManager::is_humongous(word_size)) { gclog_or_tty->print_cr("Metadata humongous allocation:"); @@ -2202,9 +2202,9 @@ void ChunkManager::return_chunks(ChunkIndex index, Metachunk* chunks) { SpaceManager::~SpaceManager() { // This call this->_lock which can't be done while holding expand_lock() assert(sum_capacity_in_chunks_in_use() == allocated_chunks_words(), - err_msg("sum_capacity_in_chunks_in_use() " SIZE_FORMAT - " allocated_chunks_words() " SIZE_FORMAT, - sum_capacity_in_chunks_in_use(), allocated_chunks_words())); + "sum_capacity_in_chunks_in_use() " SIZE_FORMAT + " allocated_chunks_words() " SIZE_FORMAT, + sum_capacity_in_chunks_in_use(), allocated_chunks_words()); MutexLockerEx fcl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); @@ -2275,9 +2275,9 @@ SpaceManager::~SpaceManager() { assert(humongous_chunks->word_size() == (size_t) align_size_up(humongous_chunks->word_size(), smallest_chunk_size()), - err_msg("Humongous chunk size is wrong: word size " SIZE_FORMAT - " granularity " SIZE_FORMAT, - humongous_chunks->word_size(), smallest_chunk_size())); + "Humongous chunk size is wrong: word size " SIZE_FORMAT + " granularity " SIZE_FORMAT, + humongous_chunks->word_size(), smallest_chunk_size()); Metachunk* next_humongous_chunks = humongous_chunks->next(); humongous_chunks->container()->dec_container_count(); chunk_manager()->humongous_dictionary()->return_chunk(humongous_chunks); @@ -2331,7 +2331,7 @@ void SpaceManager::deallocate(MetaWord* p, size_t word_size) { size_t raw_word_size = get_raw_word_size(word_size); size_t min_size = TreeChunk >::min_size(); assert(raw_word_size >= min_size, - err_msg("Should not deallocate dark matter " SIZE_FORMAT "<" SIZE_FORMAT, word_size, min_size)); + "Should not deallocate dark matter " SIZE_FORMAT "<" SIZE_FORMAT, word_size, min_size); block_freelists()->return_block(p, raw_word_size); } @@ -2541,9 +2541,9 @@ void SpaceManager::verify_allocated_blocks_words() { assert(SafepointSynchronize::is_at_safepoint() || !Universe::is_fully_initialized(), "Verification can fail if the applications is running"); assert(allocated_blocks_words() == sum_used_in_chunks_in_use(), - err_msg("allocation total is not consistent " SIZE_FORMAT - " vs " SIZE_FORMAT, - allocated_blocks_words(), sum_used_in_chunks_in_use())); + "allocation total is not consistent " SIZE_FORMAT + " vs " SIZE_FORMAT, + allocated_blocks_words(), sum_used_in_chunks_in_use()); } #endif @@ -2616,9 +2616,9 @@ size_t MetaspaceAux::free_bytes() { void MetaspaceAux::dec_capacity(Metaspace::MetadataType mdtype, size_t words) { assert_lock_strong(SpaceManager::expand_lock()); assert(words <= capacity_words(mdtype), - err_msg("About to decrement below 0: words " SIZE_FORMAT - " is greater than _capacity_words[%u] " SIZE_FORMAT, - words, mdtype, capacity_words(mdtype))); + "About to decrement below 0: words " SIZE_FORMAT + " is greater than _capacity_words[%u] " SIZE_FORMAT, + words, mdtype, capacity_words(mdtype)); _capacity_words[mdtype] -= words; } @@ -2630,9 +2630,9 @@ void MetaspaceAux::inc_capacity(Metaspace::MetadataType mdtype, size_t words) { void MetaspaceAux::dec_used(Metaspace::MetadataType mdtype, size_t words) { assert(words <= used_words(mdtype), - err_msg("About to decrement below 0: words " SIZE_FORMAT - " is greater than _used_words[%u] " SIZE_FORMAT, - words, mdtype, used_words(mdtype))); + "About to decrement below 0: words " SIZE_FORMAT + " is greater than _used_words[%u] " SIZE_FORMAT, + words, mdtype, used_words(mdtype)); // For CMS deallocation of the Metaspaces occurs during the // sweep which is a concurrent phase. Protection by the expand_lock() // is not enough since allocation is on a per Metaspace basis @@ -2699,11 +2699,11 @@ size_t MetaspaceAux::capacity_bytes_slow() { size_t class_capacity = capacity_bytes_slow(Metaspace::ClassType); size_t non_class_capacity = capacity_bytes_slow(Metaspace::NonClassType); assert(capacity_bytes() == class_capacity + non_class_capacity, - err_msg("bad accounting: capacity_bytes() " SIZE_FORMAT - " class_capacity + non_class_capacity " SIZE_FORMAT - " class_capacity " SIZE_FORMAT " non_class_capacity " SIZE_FORMAT, - capacity_bytes(), class_capacity + non_class_capacity, - class_capacity, non_class_capacity)); + "bad accounting: capacity_bytes() " SIZE_FORMAT + " class_capacity + non_class_capacity " SIZE_FORMAT + " class_capacity " SIZE_FORMAT " non_class_capacity " SIZE_FORMAT, + capacity_bytes(), class_capacity + non_class_capacity, + class_capacity, non_class_capacity); return class_capacity + non_class_capacity; } @@ -2904,17 +2904,17 @@ void MetaspaceAux::verify_capacity() { // For purposes of the running sum of capacity, verify against capacity size_t capacity_in_use_bytes = capacity_bytes_slow(); assert(running_sum_capacity_bytes == capacity_in_use_bytes, - err_msg("capacity_words() * BytesPerWord " SIZE_FORMAT - " capacity_bytes_slow()" SIZE_FORMAT, - running_sum_capacity_bytes, capacity_in_use_bytes)); + "capacity_words() * BytesPerWord " SIZE_FORMAT + " capacity_bytes_slow()" SIZE_FORMAT, + running_sum_capacity_bytes, capacity_in_use_bytes); for (Metaspace::MetadataType i = Metaspace::ClassType; i < Metaspace:: MetadataTypeCount; i = (Metaspace::MetadataType)(i + 1)) { size_t capacity_in_use_bytes = capacity_bytes_slow(i); assert(capacity_bytes(i) == capacity_in_use_bytes, - err_msg("capacity_bytes(%u) " SIZE_FORMAT - " capacity_bytes_slow(%u)" SIZE_FORMAT, - i, capacity_bytes(i), i, capacity_in_use_bytes)); + "capacity_bytes(%u) " SIZE_FORMAT + " capacity_bytes_slow(%u)" SIZE_FORMAT, + i, capacity_bytes(i), i, capacity_in_use_bytes); } #endif } @@ -2925,17 +2925,17 @@ void MetaspaceAux::verify_used() { // For purposes of the running sum of used, verify against used size_t used_in_use_bytes = used_bytes_slow(); assert(used_bytes() == used_in_use_bytes, - err_msg("used_bytes() " SIZE_FORMAT - " used_bytes_slow()" SIZE_FORMAT, - used_bytes(), used_in_use_bytes)); + "used_bytes() " SIZE_FORMAT + " used_bytes_slow()" SIZE_FORMAT, + used_bytes(), used_in_use_bytes); for (Metaspace::MetadataType i = Metaspace::ClassType; i < Metaspace:: MetadataTypeCount; i = (Metaspace::MetadataType)(i + 1)) { size_t used_in_use_bytes = used_bytes_slow(i); assert(used_bytes(i) == used_in_use_bytes, - err_msg("used_bytes(%u) " SIZE_FORMAT - " used_bytes_slow(%u)" SIZE_FORMAT, - i, used_bytes(i), i, used_in_use_bytes)); + "used_bytes(%u) " SIZE_FORMAT + " used_bytes_slow(%u)" SIZE_FORMAT, + i, used_bytes(i), i, used_in_use_bytes); } #endif } @@ -3157,7 +3157,7 @@ void Metaspace::print_compressed_class_space(outputStream* st, const char* reque void Metaspace::initialize_class_space(ReservedSpace rs) { // The reserved space size may be bigger because of alignment, esp with UseLargePages assert(rs.size() >= CompressedClassSpaceSize, - err_msg(SIZE_FORMAT " != " SIZE_FORMAT, rs.size(), CompressedClassSpaceSize)); + SIZE_FORMAT " != " SIZE_FORMAT, rs.size(), CompressedClassSpaceSize); assert(using_class_space(), "Must be using class space"); _class_space_list = new VirtualSpaceList(rs); _chunk_manager_class = new ChunkManager(SpecializedChunk, ClassSmallChunk, ClassMediumChunk); @@ -3688,7 +3688,7 @@ const char* Metaspace::metadata_type_name(Metaspace::MetadataType mdtype) { case Metaspace::ClassType: return "Class"; case Metaspace::NonClassType: return "Metadata"; default: - assert(false, err_msg("Got bad mdtype: %d", (int) mdtype)); + assert(false, "Got bad mdtype: %d", (int) mdtype); return NULL; } } @@ -3970,15 +3970,15 @@ class TestVirtualSpaceNodeTest { #define assert_is_available_positive(word_size) \ assert(vsn.is_available(word_size), \ - err_msg(#word_size ": " PTR_FORMAT " bytes were not available in " \ - "VirtualSpaceNode [" PTR_FORMAT ", " PTR_FORMAT ")", \ - (uintptr_t)(word_size * BytesPerWord), p2i(vsn.bottom()), p2i(vsn.end()))); + #word_size ": " PTR_FORMAT " bytes were not available in " \ + "VirtualSpaceNode [" PTR_FORMAT ", " PTR_FORMAT ")", \ + (uintptr_t)(word_size * BytesPerWord), p2i(vsn.bottom()), p2i(vsn.end())); #define assert_is_available_negative(word_size) \ assert(!vsn.is_available(word_size), \ - err_msg(#word_size ": " PTR_FORMAT " bytes should not be available in " \ - "VirtualSpaceNode [" PTR_FORMAT ", " PTR_FORMAT ")", \ - (uintptr_t)(word_size * BytesPerWord), p2i(vsn.bottom()), p2i(vsn.end()))); + #word_size ": " PTR_FORMAT " bytes should not be available in " \ + "VirtualSpaceNode [" PTR_FORMAT ", " PTR_FORMAT ")", \ + (uintptr_t)(word_size * BytesPerWord), p2i(vsn.bottom()), p2i(vsn.end())); static void test_is_available_positive() { // Reserve some memory. diff --git a/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp b/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp index d692ccb7e85..9a38c9da242 100644 --- a/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp +++ b/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp @@ -43,7 +43,7 @@ class MetaspaceGCThresholdUpdater : public AllStatic { case ExpandAndAllocate: return "expand_and_allocate"; default: - assert(false, err_msg("Got bad updater: %d", (int) updater)); + assert(false, "Got bad updater: %d", (int) updater); return NULL; }; } diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 7589712a247..71507120a70 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -44,8 +44,6 @@ #include "runtime/vm_operations.hpp" #include "utilities/hashtable.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - int MetaspaceShared::_max_alignment = 0; ReservedSpace* MetaspaceShared::_shared_rs = NULL; @@ -578,7 +576,7 @@ void VM_PopulateDumpSharedSpace::doit() { // Print shared spaces all the time // To make fmt_space be a syntactic constant (for format warnings), use #define. -#define fmt_space "%s space: %9d [ %4.1f%% of total] out of %9d bytes [%4.1f%% used] at " INTPTR_FORMAT +#define fmt_space "%s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%4.1f%% used] at " INTPTR_FORMAT Metaspace* ro_space = _loader_data->ro_metaspace(); Metaspace* rw_space = _loader_data->rw_metaspace(); @@ -611,12 +609,12 @@ void VM_PopulateDumpSharedSpace::doit() { const double mc_u_perc = mc_bytes / double(mc_alloced) * 100.0; const double total_u_perc = total_bytes / double(total_alloced) * 100.0; - tty->print_cr(fmt_space, "ro", ro_bytes, ro_t_perc, ro_alloced, ro_u_perc, ro_space->bottom()); - tty->print_cr(fmt_space, "rw", rw_bytes, rw_t_perc, rw_alloced, rw_u_perc, rw_space->bottom()); - tty->print_cr(fmt_space, "md", md_bytes, md_t_perc, md_alloced, md_u_perc, md_low); - tty->print_cr(fmt_space, "mc", mc_bytes, mc_t_perc, mc_alloced, mc_u_perc, mc_low); - tty->print_cr(fmt_space, "st", ss_bytes, ss_t_perc, ss_bytes, 100.0, ss_low); - tty->print_cr("total : %9d [100.0%% of total] out of %9d bytes [%4.1f%% used]", + tty->print_cr(fmt_space, "ro", ro_bytes, ro_t_perc, ro_alloced, ro_u_perc, p2i(ro_space->bottom())); + tty->print_cr(fmt_space, "rw", rw_bytes, rw_t_perc, rw_alloced, rw_u_perc, p2i(rw_space->bottom())); + tty->print_cr(fmt_space, "md", md_bytes, md_t_perc, md_alloced, md_u_perc, p2i(md_low)); + tty->print_cr(fmt_space, "mc", mc_bytes, mc_t_perc, mc_alloced, mc_u_perc, p2i(mc_low)); + tty->print_cr(fmt_space, "st", ss_bytes, ss_t_perc, ss_bytes, 100.0, p2i(ss_low)); + tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%4.1f%% used]", total_bytes, total_alloced, total_u_perc); // Update the vtable pointers in all of the Klass objects in the @@ -738,9 +736,9 @@ void MetaspaceShared::preload_and_dump(TRAPS) { TraceTime timer("Dump Shared Spaces", TraceStartupTime); ResourceMark rm; - tty->print_cr("Allocated shared space: %d bytes at " PTR_FORMAT, + tty->print_cr("Allocated shared space: " SIZE_FORMAT " bytes at " PTR_FORMAT, MetaspaceShared::shared_rs()->size(), - MetaspaceShared::shared_rs()->base()); + p2i(MetaspaceShared::shared_rs()->base())); // Preload classes to be shared. // Should use some os:: method rather than fopen() here. aB. diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index f386dc46dc0..fa22f5bfdcc 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -35,7 +35,6 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/genRemSet.hpp" #include "gc/shared/generation.hpp" #include "gc/shared/space.hpp" #include "interpreter/interpreter.hpp" @@ -143,6 +142,10 @@ debug_only(int Universe::_fullgc_alot_dummy_next = 0;) // Heap int Universe::_verify_count = 0; +// Oop verification (see MacroAssembler::verify_oop) +uintptr_t Universe::_verify_oop_mask = 0; +uintptr_t Universe::_verify_oop_bits = (uintptr_t) -1; + int Universe::_base_vtable_size = 0; bool Universe::_bootstrapping = false; bool Universe::_fully_initialized = false; @@ -812,8 +815,8 @@ void Universe::print_compressed_oops_mode(outputStream* st) { ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { assert(alignment <= Arguments::conservative_max_heap_alignment(), - err_msg("actual alignment " SIZE_FORMAT " must be within maximum heap alignment " SIZE_FORMAT, - alignment, Arguments::conservative_max_heap_alignment())); + "actual alignment " SIZE_FORMAT " must be within maximum heap alignment " SIZE_FORMAT, + alignment, Arguments::conservative_max_heap_alignment()); size_t total_reserved = align_size_up(heap_size, alignment); assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), @@ -1171,17 +1174,9 @@ void Universe::verify(VerifyOption option, const char* prefix, bool silent) { _verify_in_progress = false; } -// Oop verification (see MacroAssembler::verify_oop) - -static uintptr_t _verify_oop_data[2] = {0, (uintptr_t)-1}; -static uintptr_t _verify_klass_data[2] = {0, (uintptr_t)-1}; - #ifndef PRODUCT - -static void calculate_verify_data(uintptr_t verify_data[2], - HeapWord* low_boundary, - HeapWord* high_boundary) { +void Universe::calculate_verify_data(HeapWord* low_boundary, HeapWord* high_boundary) { assert(low_boundary < high_boundary, "bad interval"); // decide which low-order bits we require to be clear: @@ -1206,28 +1201,25 @@ static void calculate_verify_data(uintptr_t verify_data[2], // require address alignment, too: mask |= (alignSize - 1); - if (!(verify_data[0] == 0 && verify_data[1] == (uintptr_t)-1)) { - assert(verify_data[0] == mask && verify_data[1] == bits, "mask stability"); + if (!(_verify_oop_mask == 0 && _verify_oop_bits == (uintptr_t)-1)) { + assert(_verify_oop_mask == mask && _verify_oop_bits == bits, "mask stability"); } - verify_data[0] = mask; - verify_data[1] = bits; + _verify_oop_mask = mask; + _verify_oop_bits = bits; } // Oop verification (see MacroAssembler::verify_oop) uintptr_t Universe::verify_oop_mask() { MemRegion m = heap()->reserved_region(); - calculate_verify_data(_verify_oop_data, - m.start(), - m.end()); - return _verify_oop_data[0]; + calculate_verify_data(m.start(), m.end()); + return _verify_oop_mask; } - - uintptr_t Universe::verify_oop_bits() { - verify_oop_mask(); - return _verify_oop_data[1]; + MemRegion m = heap()->reserved_region(); + calculate_verify_data(m.start(), m.end()); + return _verify_oop_bits; } uintptr_t Universe::verify_mark_mask() { diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 56c2fca89e6..854a818883c 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -248,9 +248,14 @@ class Universe: AllStatic { // Debugging static int _verify_count; // number of verifies done + // True during call to verify(). Should only be set/cleared in verify(). static bool _verify_in_progress; + static uintptr_t _verify_oop_mask; + static uintptr_t _verify_oop_bits; + + static void calculate_verify_data(HeapWord* low_boundary, HeapWord* high_boundary) PRODUCT_RETURN; static void compute_verify_oop_data(); public: @@ -269,7 +274,7 @@ class Universe: AllStatic { } static Klass* typeArrayKlassObj(BasicType t) { - assert((uint)t < T_VOID+1, err_msg("range check for type: %s", type2name(t))); + assert((uint)t < T_VOID+1, "range check for type: %s", type2name(t)); assert(_typeArrayKlassObjs[t] != NULL, "domain check"); return _typeArrayKlassObjs[t]; } diff --git a/hotspot/src/share/vm/memory/virtualspace.cpp b/hotspot/src/share/vm/memory/virtualspace.cpp index 2131cae1dec..433904eed00 100644 --- a/hotspot/src/share/vm/memory/virtualspace.cpp +++ b/hotspot/src/share/vm/memory/virtualspace.cpp @@ -29,8 +29,6 @@ #include "oops/oop.inline.hpp" #include "services/memTracker.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // ReservedSpace // Dummy constructor @@ -82,7 +80,7 @@ static bool failed_to_reserve_as_requested(char* base, char* requested_address, assert(UseCompressedOops, "currently requested address used only for compressed oops"); if (PrintCompressedOopsMode) { tty->cr(); - tty->print_cr("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, base, requested_address); + tty->print_cr("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, p2i(base), p2i(requested_address)); } // OS ignored requested address. Try different address. if (special) { @@ -137,9 +135,9 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, } // Check alignment constraints. assert((uintptr_t) base % alignment == 0, - err_msg("Large pages returned a non-aligned address, base: " - PTR_FORMAT " alignment: " PTR_FORMAT, - base, (void*)(uintptr_t)alignment)); + "Large pages returned a non-aligned address, base: " + PTR_FORMAT " alignment: " SIZE_FORMAT_HEX, + p2i(base), alignment); _special = true; } else { // failed; try to reserve regular memory below @@ -291,7 +289,7 @@ void ReservedHeapSpace::establish_noaccess_prefix() { if (PrintCompressedOopsMode) { tty->cr(); tty->print_cr("Protected page at the reserved heap base: " - PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix); + PTR_FORMAT " / " INTX_FORMAT " bytes", p2i(_base), _noaccess_prefix); } assert(Universe::narrow_oop_use_implicit_null_checks() == true, "not initialized?"); } else { @@ -324,8 +322,8 @@ void ReservedHeapSpace::try_reserve_heap(size_t size, char* base = NULL; if (PrintCompressedOopsMode && Verbose) { - tty->print("Trying to allocate at address " PTR_FORMAT " heap of size " PTR_FORMAT ".\n", - requested_address, (address)size); + tty->print("Trying to allocate at address " PTR_FORMAT " heap of size " SIZE_FORMAT_HEX ".\n", + p2i(requested_address), size); } if (special) { @@ -334,9 +332,9 @@ void ReservedHeapSpace::try_reserve_heap(size_t size, if (base != NULL) { // Check alignment constraints. assert((uintptr_t) base % alignment == 0, - err_msg("Large pages returned a non-aligned address, base: " - PTR_FORMAT " alignment: " PTR_FORMAT, - base, (void*)(uintptr_t)alignment)); + "Large pages returned a non-aligned address, base: " + PTR_FORMAT " alignment: " SIZE_FORMAT_HEX, + p2i(base), alignment); _special = true; } } @@ -561,7 +559,7 @@ void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t ali // Last, desperate try without any placement. if (_base == NULL) { if (PrintCompressedOopsMode && Verbose) { - tty->print("Trying to allocate at address NULL heap of size " PTR_FORMAT ".\n", (address)size + noaccess_prefix); + tty->print("Trying to allocate at address NULL heap of size " SIZE_FORMAT_HEX ".\n", size + noaccess_prefix); } initialize(size + noaccess_prefix, alignment, large, NULL, false); } @@ -853,7 +851,7 @@ bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { if (!os::commit_memory(lower_high(), lower_needs, _executable)) { debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT ", lower_needs=" SIZE_FORMAT ", %d) failed", - lower_high(), lower_needs, _executable);) + p2i(lower_high()), lower_needs, _executable);) return false; } else { _lower_high += lower_needs; @@ -867,7 +865,7 @@ bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { _executable)) { debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT ", middle_needs=" SIZE_FORMAT ", " SIZE_FORMAT - ", %d) failed", middle_high(), middle_needs, + ", %d) failed", p2i(middle_high()), middle_needs, middle_alignment(), _executable);) return false; } @@ -880,7 +878,7 @@ bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { if (!os::commit_memory(upper_high(), upper_needs, _executable)) { debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT ", upper_needs=" SIZE_FORMAT ", %d) failed", - upper_high(), upper_needs, _executable);) + p2i(upper_high()), upper_needs, _executable);) return false; } else { _upper_high += upper_needs; @@ -1017,8 +1015,8 @@ void VirtualSpace::print_on(outputStream* out) { out->cr(); out->print_cr(" - committed: " SIZE_FORMAT, committed_size()); out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size()); - out->print_cr(" - [low, high]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low(), high()); - out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low_boundary(), high_boundary()); + out->print_cr(" - [low, high]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", p2i(low()), p2i(high())); + out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", p2i(low_boundary()), p2i(high_boundary())); } void VirtualSpace::print() { @@ -1205,20 +1203,20 @@ void TestReservedSpace_test() { TestReservedSpace::test_reserved_space(); } -#define assert_equals(actual, expected) \ - assert(actual == expected, \ - err_msg("Got " SIZE_FORMAT " expected " \ - SIZE_FORMAT, actual, expected)); +#define assert_equals(actual, expected) \ + assert(actual == expected, \ + "Got " SIZE_FORMAT " expected " \ + SIZE_FORMAT, actual, expected); #define assert_ge(value1, value2) \ assert(value1 >= value2, \ - err_msg("'" #value1 "': " SIZE_FORMAT " '" \ - #value2 "': " SIZE_FORMAT, value1, value2)); + "'" #value1 "': " SIZE_FORMAT " '" \ + #value2 "': " SIZE_FORMAT, value1, value2); #define assert_lt(value1, value2) \ assert(value1 < value2, \ - err_msg("'" #value1 "': " SIZE_FORMAT " '" \ - #value2 "': " SIZE_FORMAT, value1, value2)); + "'" #value1 "': " SIZE_FORMAT " '" \ + #value2 "': " SIZE_FORMAT, value1, value2); class TestVirtualSpace : AllStatic { diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index c301a245bc7..5d3c61d2a41 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -45,8 +45,6 @@ #include "runtime/vframe.hpp" #include "utilities/copy.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) { // Tags are RW but comment below applies to tags also. Array* tags = MetadataFactory::new_writeable_array(loader_data, length, 0, CHECK_NULL); @@ -113,7 +111,7 @@ objArrayOop ConstantPool::resolved_references() const { // to map it back for resolving and some unlikely miscellaneous uses. // The objects created by invokedynamic are appended to this list. void ConstantPool::initialize_resolved_references(ClassLoaderData* loader_data, - intStack reference_map, + const intStack& reference_map, int constant_pool_map_length, TRAPS) { // Initialized the resolved object cache. @@ -1826,9 +1824,9 @@ void ConstantPool::patch_resolved_references(GrowableArray* cp_patches) // Ensure that all the patches have been used. for (int index = 0; index < cp_patches->length(); index++) { assert(cp_patches->at(index).is_null(), - err_msg("Unused constant pool patch at %d in class file %s", - index, - pool_holder()->external_name())); + "Unused constant pool patch at %d in class file %s", + index, + pool_holder()->external_name()); } #endif // ASSERT } @@ -1868,11 +1866,11 @@ void ConstantPool::print_on(outputStream* st) const { st->cr(); } if (pool_holder() != NULL) { - st->print_cr(" - holder: " INTPTR_FORMAT, pool_holder()); + st->print_cr(" - holder: " INTPTR_FORMAT, p2i(pool_holder())); } - st->print_cr(" - cache: " INTPTR_FORMAT, cache()); - st->print_cr(" - resolved_references: " INTPTR_FORMAT, (void *)resolved_references()); - st->print_cr(" - reference_map: " INTPTR_FORMAT, reference_map()); + st->print_cr(" - cache: " INTPTR_FORMAT, p2i(cache())); + st->print_cr(" - resolved_references: " INTPTR_FORMAT, p2i(resolved_references())); + st->print_cr(" - reference_map: " INTPTR_FORMAT, p2i(reference_map())); for (int index = 1; index < length(); index++) { // Index 0 is unused ((ConstantPool*)this)->print_entry_on(index, st); @@ -1897,7 +1895,7 @@ void ConstantPool::print_entry_on(const int index, outputStream* st) { { Klass* k = klass_at(index, CATCH); guarantee(k != NULL, "need klass"); k->print_value_on(st); - st->print(" {0x%lx}", (address)k); + st->print(" {" PTR_FORMAT "}", p2i(k)); } break; case JVM_CONSTANT_Fieldref : @@ -1910,7 +1908,7 @@ void ConstantPool::print_entry_on(const int index, outputStream* st) { if (is_pseudo_string_at(index)) { oop anObj = pseudo_string_at(index); anObj->print_value_on(st); - st->print(" {0x%lx}", (address)anObj); + st->print(" {" PTR_FORMAT "}", p2i(anObj)); } else { unresolved_string_at(index)->print_value_on(st); } @@ -1987,7 +1985,7 @@ void ConstantPool::print_value_on(outputStream* st) const { if (extra) st->print(" (extra)"); } if (cache() != NULL) { - st->print(" cache=" PTR_FORMAT, cache()); + st->print(" cache=" PTR_FORMAT, p2i(cache())); } } diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 538c78fe8fb..dca3a2f4d31 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -185,7 +185,7 @@ class ConstantPool : public Metadata { // Create object cache in the constant pool void initialize_resolved_references(ClassLoaderData* loader_data, - intStack reference_map, + const intStack& reference_map, int constant_pool_map_length, TRAPS); @@ -662,6 +662,8 @@ class ConstantPool : public Metadata { int klass_ref_index_at(int which) { return impl_klass_ref_index_at(which, false); } int name_and_type_ref_index_at(int which) { return impl_name_and_type_ref_index_at(which, false); } + int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG + // Lookup for entries consisting of (name_index, signature_index) int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt) int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt) @@ -783,8 +785,6 @@ class ConstantPool : public Metadata { int impl_klass_ref_index_at(int which, bool uncached); int impl_name_and_type_ref_index_at(int which, bool uncached); - int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG - // Used while constructing constant pool (only by ClassFileParser) jint klass_index_at(int which) { assert(tag_at(which).is_klass_index(), "Corrupted constant pool"); diff --git a/hotspot/src/share/vm/oops/cpCache.cpp b/hotspot/src/share/vm/oops/cpCache.cpp index 996dc55cf7a..db65df2172c 100644 --- a/hotspot/src/share/vm/oops/cpCache.cpp +++ b/hotspot/src/share/vm/oops/cpCache.cpp @@ -36,8 +36,6 @@ #include "runtime/orderAccess.inline.hpp" #include "utilities/macros.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Implementation of ConstantPoolCacheEntry void ConstantPoolCacheEntry::initialize_entry(int index) { @@ -126,7 +124,7 @@ void ConstantPoolCacheEntry::set_parameter_size(int value) { // This routine is called only in corner cases where the CPCE is not yet initialized. // See AbstractInterpreter::deopt_continue_after_entry. assert(_flags == 0 || parameter_size() == 0 || parameter_size() == value, - err_msg("size must not change: parameter_size=%d, value=%d", parameter_size(), value)); + "size must not change: parameter_size=%d, value=%d", parameter_size(), value); // Setting the parameter size by itself is only safe if the // current value of _flags is 0, otherwise another thread may have // updated it and we don't want to overwrite that value. Don't @@ -136,7 +134,7 @@ void ConstantPoolCacheEntry::set_parameter_size(int value) { Atomic::cmpxchg_ptr((value & parameter_size_mask), &_flags, 0); } guarantee(parameter_size() == value, - err_msg("size must not change: parameter_size=%d, value=%d", parameter_size(), value)); + "size must not change: parameter_size=%d, value=%d", parameter_size(), value); } void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_code, @@ -310,9 +308,9 @@ void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool, if (TraceInvokeDynamic) { tty->print_cr("set_method_handle bc=%d appendix=" PTR_FORMAT "%s method_type=" PTR_FORMAT "%s method=" PTR_FORMAT " ", invoke_code, - (void *)appendix(), (has_appendix ? "" : " (unused)"), - (void *)method_type(), (has_method_type ? "" : " (unused)"), - (intptr_t)adapter()); + p2i(appendix()), (has_appendix ? "" : " (unused)"), + p2i(method_type()), (has_method_type ? "" : " (unused)"), + p2i(adapter())); adapter->print(); if (has_appendix) appendix()->print(); } @@ -593,7 +591,7 @@ void ConstantPoolCache::initialize(const intArray& inverse_index_map, // all point to the same constant pool cache entry. for (int entry = 1; entry < ConstantPoolCacheEntry::_indy_resolved_references_entries; entry++) { const int cpci_next = invokedynamic_references_map[ref + entry]; - assert(cpci == cpci_next, err_msg_res("%d == %d", cpci, cpci_next)); + assert(cpci == cpci_next, "%d == %d", cpci, cpci_next); } #endif entry_at(cpci)->initialize_resolved_reference_index(ref); diff --git a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp index ce1cb6b570f..a20a9db2318 100644 --- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp @@ -41,11 +41,10 @@ class InstanceClassLoaderKlass: public InstanceKlass { // Constructor InstanceClassLoaderKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous) - : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous) {} + : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, + InstanceKlass::_misc_kind_class_loader, rt, access_flags, is_anonymous) {} public: - virtual bool oop_is_instanceClassLoader() const { return true; } - InstanceClassLoaderKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } // GC specific object visitors diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 0aa1c431bbb..f01521cc009 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -66,8 +66,6 @@ #include "c1/c1_Compiler.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef DTRACE_ENABLED @@ -147,8 +145,8 @@ InstanceKlass* InstanceKlass::allocate_instance_klass( } else { // normal class ik = new (loader_data, size, THREAD) InstanceKlass( - vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, - access_flags, is_anonymous); + vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, + InstanceKlass::_misc_kind_other, rt, access_flags, is_anonymous); } } else { // reference klass @@ -197,6 +195,7 @@ InstanceKlass::InstanceKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, + unsigned kind, ReferenceType rt, AccessFlags access_flags, bool is_anonymous) { @@ -211,6 +210,7 @@ InstanceKlass::InstanceKlass(int vtable_len, set_nonstatic_oop_map_size(nonstatic_oop_map_size); set_access_flags(access_flags); _misc_flags = 0; // initialize to zero + set_kind(kind); set_is_anonymous(is_anonymous); assert(size() == iksize, "wrong size for object"); @@ -1028,7 +1028,7 @@ instanceOop InstanceKlass::register_finalizer(instanceOop i, TRAPS) { if (TraceFinalizerRegistration) { tty->print("Registered "); i->print_value_on(tty); - tty->print_cr(" (" INTPTR_FORMAT ") as finalizable", (address)i); + tty->print_cr(" (" INTPTR_FORMAT ") as finalizable", p2i(i)); } instanceHandle h_i(THREAD, i); // Pass the handle as argument, JavaCalls::call expects oop as jobjects @@ -1131,7 +1131,7 @@ void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_k, TRAP if (TraceClassInitialization) { tty->print("%d Initializing ", call_class_initializer_impl_counter++); this_k->name()->print_value(); - tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", (address)this_k()); + tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", p2i(this_k())); } if (h_method() != NULL) { JavaCallArguments args; // No arguments @@ -1499,7 +1499,7 @@ int InstanceKlass::find_method_index( // not found #ifdef ASSERT int index = (skipping_overpass || skipping_static || skipping_private) ? -1 : linear_search(methods, name, signature); - assert(index == -1, err_msg("binary search should have found entry %d", index)); + assert(index == -1, "binary search should have found entry %d", index); #endif } return -1; @@ -1915,7 +1915,7 @@ bool nmethodBucket::remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { for (nmethodBucket* b = deps; b != NULL; b = b->next()) { if (nm == b->get_nmethod()) { int val = b->decrement(); - guarantee(val >= 0, err_msg("Underflow: %d", val)); + guarantee(val >= 0, "Underflow: %d", val); return (val == 0); } } @@ -1936,7 +1936,7 @@ nmethodBucket* nmethodBucket::clean_dependent_nmethods(nmethodBucket* deps) { nmethodBucket* b = first; while (b != NULL) { - assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); + assert(b->count() >= 0, "bucket count: %d", b->count()); nmethodBucket* next = b->next(); if (b->count() == 0) { if (last == NULL) { @@ -1976,7 +1976,7 @@ bool nmethodBucket::is_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { if (nm == b->get_nmethod()) { #ifdef ASSERT int count = b->count(); - assert(count >= 0, err_msg("count shouldn't be negative: %d", count)); + assert(count >= 0, "count shouldn't be negative: %d", count); #endif return true; } @@ -2001,7 +2001,7 @@ void InstanceKlass::clean_dependent_nmethods() { else { // Verification for (nmethodBucket* b = _dependencies; b != NULL; b = b->next()) { - assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); + assert(b->count() >= 0, "bucket count: %d", b->count()); assert(b->count() != 0, "empty buckets need to be cleaned"); } } @@ -2797,7 +2797,7 @@ void InstanceKlass::print_on(outputStream* st) const { st->print(" "); } } - if (n >= MaxSubklassPrintSize) st->print("(%d more klasses...)", n - MaxSubklassPrintSize); + if (n >= MaxSubklassPrintSize) st->print("(" INTX_FORMAT " more klasses...)", n - MaxSubklassPrintSize); st->cr(); if (is_interface()) { @@ -2873,9 +2873,9 @@ void InstanceKlass::print_on(outputStream* st) const { } st->print(BULLET"inner classes: "); inner_classes()->print_value_on(st); st->cr(); st->print(BULLET"java mirror: "); java_mirror()->print_value_on(st); st->cr(); - st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", vtable_length(), start_of_vtable()); st->cr(); + st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", vtable_length(), p2i(start_of_vtable())); st->cr(); if (vtable_length() > 0 && (Verbose || WizardMode)) print_vtable(start_of_vtable(), vtable_length(), st); - st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", itable_length(), start_of_itable()); st->cr(); + st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", itable_length(), p2i(start_of_itable())); st->cr(); if (itable_length() > 0 && (Verbose || WizardMode)) print_vtable(start_of_itable(), itable_length(), st); st->print_cr(BULLET"---- static fields (%d words):", static_field_size()); FieldPrinter print_static_field(st); @@ -3068,7 +3068,7 @@ class VerifyFieldClosure: public OopClosure { template void do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); if (!obj->is_oop_or_null()) { - tty->print_cr("Failed: " PTR_FORMAT " -> " PTR_FORMAT, p, (address)obj); + tty->print_cr("Failed: " PTR_FORMAT " -> " PTR_FORMAT, p2i(p), p2i(obj)); Universe::print(); guarantee(false, "boom"); } @@ -3110,7 +3110,7 @@ void InstanceKlass::verify_on(outputStream* st) { Klass* sib = next_sibling(); if (sib != NULL) { if (sib == this) { - fatal(err_msg("subclass points to itself " PTR_FORMAT, sib)); + fatal("subclass points to itself " PTR_FORMAT, p2i(sib)); } guarantee(sib->is_klass(), "should be klass"); @@ -3310,7 +3310,7 @@ void InstanceKlass::purge_previous_versions(InstanceKlass* ik) { // The previous version InstanceKlass is on the ClassLoaderData deallocate list // so will be deallocated during the next phase of class unloading. RC_TRACE(0x00000200, ("purge: previous version " INTPTR_FORMAT " is dead", - pv_node)); + p2i(pv_node))); // For debugging purposes. pv_node->set_is_scratch_class(); pv_node->class_loader_data()->add_to_deallocate_list(pv_node); @@ -3321,7 +3321,7 @@ void InstanceKlass::purge_previous_versions(InstanceKlass* ik) { continue; } else { RC_TRACE(0x00000200, ("purge: previous version " INTPTR_FORMAT " is alive", - pv_node)); + p2i(pv_node))); assert(pvcp->pool_holder() != NULL, "Constant pool with no holder"); guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack"); live_count++; @@ -3472,10 +3472,10 @@ void InstanceKlass::add_previous_version(instanceKlassHandle scratch_class, // is never reached, but this won't be noticeable to the programmer. old_method->set_running_emcp(true); RC_TRACE(0x00000400, ("add: EMCP method %s is on_stack " INTPTR_FORMAT, - old_method->name_and_sig_as_C_string(), old_method)); + old_method->name_and_sig_as_C_string(), p2i(old_method))); } else if (!old_method->is_obsolete()) { RC_TRACE(0x00000400, ("add: EMCP method %s is NOT on_stack " INTPTR_FORMAT, - old_method->name_and_sig_as_C_string(), old_method)); + old_method->name_and_sig_as_C_string(), p2i(old_method))); } } } diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 69dc88dca05..be9501089b6 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -117,6 +117,7 @@ class InstanceKlass: public Klass { int itable_len, int static_field_size, int nonstatic_oop_map_size, + unsigned kind, ReferenceType rt, AccessFlags access_flags, bool is_anonymous); @@ -199,16 +200,30 @@ class InstanceKlass: public Klass { bool _is_marked_dependent; // used for marking during flushing and deoptimization bool _has_unloaded_dependent; + // The low two bits of _misc_flags contains the kind field. + // This can be used to quickly discriminate among the four kinds of + // InstanceKlass. + + static const unsigned _misc_kind_field_size = 2; + static const unsigned _misc_kind_field_pos = 0; + static const unsigned _misc_kind_field_mask = (1u << _misc_kind_field_size) - 1u; + + static const unsigned _misc_kind_other = 0; // concrete InstanceKlass + static const unsigned _misc_kind_reference = 1; // InstanceRefKlass + static const unsigned _misc_kind_class_loader = 2; // InstanceClassLoaderKlass + static const unsigned _misc_kind_mirror = 3; // InstanceMirrorKlass + + // Start after _misc_kind field. enum { - _misc_rewritten = 1 << 0, // methods rewritten. - _misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops - _misc_should_verify_class = 1 << 2, // allow caching of preverification - _misc_is_anonymous = 1 << 3, // has embedded _host_klass field - _misc_is_contended = 1 << 4, // marked with contended annotation - _misc_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods - _misc_declares_default_methods = 1 << 6, // directly declares default methods (any access) - _misc_has_been_redefined = 1 << 7, // class has been redefined - _misc_is_scratch_class = 1 << 8 // class is the redefined scratch class + _misc_rewritten = 1 << 2, // methods rewritten. + _misc_has_nonstatic_fields = 1 << 3, // for sizing with UseCompressedOops + _misc_should_verify_class = 1 << 4, // allow caching of preverification + _misc_is_anonymous = 1 << 5, // has embedded _host_klass field + _misc_is_contended = 1 << 6, // marked with contended annotation + _misc_has_default_methods = 1 << 7, // class/superclass/implemented interfaces has default methods + _misc_declares_default_methods = 1 << 8, // directly declares default methods (any access) + _misc_has_been_redefined = 1 << 9, // class has been redefined + _misc_is_scratch_class = 1 << 10 // class is the redefined scratch class }; u2 _misc_flags; u2 _minor_version; // minor version number of class file @@ -667,6 +682,28 @@ class InstanceKlass: public Klass { _misc_flags |= _misc_is_scratch_class; } +private: + + void set_kind(unsigned kind) { + assert(kind <= _misc_kind_field_mask, "Invalid InstanceKlass kind"); + unsigned fmask = _misc_kind_field_mask << _misc_kind_field_pos; + unsigned flags = _misc_flags & ~fmask; + _misc_flags = (flags | (kind << _misc_kind_field_pos)); + } + + bool is_kind(unsigned desired) const { + unsigned kind = (_misc_flags >> _misc_kind_field_pos) & _misc_kind_field_mask; + return kind == desired; + } + +public: + + // Other is anything that is not one of the more specialized kinds of InstanceKlass. + bool is_other_instance_klass() const { return is_kind(_misc_kind_other); } + bool is_reference_instance_klass() const { return is_kind(_misc_kind_reference); } + bool is_mirror_instance_klass() const { return is_kind(_misc_kind_mirror); } + bool is_class_loader_instance_klass() const { return is_kind(_misc_kind_class_loader); } + void init_previous_versions() { _previous_versions = NULL; } @@ -885,9 +922,8 @@ class InstanceKlass: public Klass { // Casting from Klass* static InstanceKlass* cast(Klass* k) { - assert(k == NULL || k->is_klass(), "must be"); assert(k == NULL || k->oop_is_instance(), "cast to InstanceKlass"); - return (InstanceKlass*) k; + return static_cast(k); } InstanceKlass* java_super() const { diff --git a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp index 74bf924303f..fb518454761 100644 --- a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp @@ -48,17 +48,17 @@ class InstanceMirrorKlass: public InstanceKlass { // Constructor InstanceMirrorKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous) - : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous) {} + : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, + InstanceKlass::_misc_kind_mirror, rt, access_flags, is_anonymous) {} public: InstanceMirrorKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } - // Type testing - bool oop_is_instanceMirror() const { return true; } // Casting from Klass* static InstanceMirrorKlass* cast(Klass* k) { - assert(k->oop_is_instanceMirror(), "cast to InstanceMirrorKlass"); - return (InstanceMirrorKlass*) k; + assert(InstanceKlass::cast(k)->is_mirror_instance_klass(), + "cast to InstanceMirrorKlass"); + return static_cast(k); } // Returns the size of the instance including the extra static fields. diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.cpp b/hotspot/src/share/vm/oops/instanceRefKlass.cpp index 8e31ef851b5..31da264eeff 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp @@ -33,8 +33,6 @@ #include "utilities/macros.hpp" #include "utilities/preserveException.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void InstanceRefKlass::update_nonstatic_oop_maps(Klass* k) { // Clear the nonstatic oop-map entries corresponding to referent // and nextPending field. They are treated specially by the diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.hpp b/hotspot/src/share/vm/oops/instanceRefKlass.hpp index fd86e47a149..de7aca618f6 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp @@ -51,18 +51,11 @@ class InstanceRefKlass: public InstanceKlass { // Constructor InstanceRefKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous) - : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous) {} + : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, + InstanceKlass::_misc_kind_reference, rt, access_flags, is_anonymous) {} public: InstanceRefKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } - // Type testing - bool oop_is_instanceRef() const { return true; } - - // Casting from Klass* - static InstanceRefKlass* cast(Klass* k) { - assert(k->oop_is_instanceRef(), "cast to InstanceRefKlass"); - return (InstanceRefKlass*) k; - } // GC specific object visitors // diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp b/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp index 97f42758c15..4581a23e8c7 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp @@ -43,7 +43,7 @@ void InstanceRefKlass::oop_oop_iterate_ref_processing_specialized(oop obj, OopCl T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); T heap_oop = oopDesc::load_heap_oop(referent_addr); - ReferenceProcessor* rp = closure->_ref_processor; + ReferenceProcessor* rp = closure->ref_processor(); if (!oopDesc::is_null(heap_oop)) { oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); if (!referent->is_gc_marked() && (rp != NULL) && diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index e6c7e3e4f01..30bdc14cd2a 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -690,11 +690,11 @@ void Klass::oop_verify_on(oop obj, outputStream* st) { bool Klass::verify_vtable_index(int i) { if (oop_is_instance()) { int limit = ((InstanceKlass*)this)->vtable_length()/vtableEntry::size(); - assert(i >= 0 && i < limit, err_msg("index %d out of bounds %d", i, limit)); + assert(i >= 0 && i < limit, "index %d out of bounds %d", i, limit); } else { assert(oop_is_array(), "Must be"); int limit = ((ArrayKlass*)this)->vtable_length()/vtableEntry::size(); - assert(i >= 0 && i < limit, err_msg("index %d out of bounds %d", i, limit)); + assert(i >= 0 && i < limit, "index %d out of bounds %d", i, limit); } return true; } @@ -715,8 +715,14 @@ bool Klass::verify_itable_index(int i) { class TestKlass { public: static void test_oop_is_instanceClassLoader() { - assert(SystemDictionary::ClassLoader_klass()->oop_is_instanceClassLoader(), "assert"); - assert(!SystemDictionary::String_klass()->oop_is_instanceClassLoader(), "assert"); + Klass* klass = SystemDictionary::ClassLoader_klass(); + guarantee(klass->oop_is_instance(), "assert"); + guarantee(InstanceKlass::cast(klass)->is_class_loader_instance_klass(), "test failed"); + + klass = SystemDictionary::String_klass(); + guarantee(!klass->oop_is_instance() || + !InstanceKlass::cast(klass)->is_class_loader_instance_klass(), + "test failed"); } }; diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 3ed523a0677..aa8aabb61fa 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -341,7 +341,7 @@ protected: assert(lh < (jint)_lh_neutral_value, "must be array"); int l2esz = (lh >> _lh_log2_element_size_shift) & _lh_log2_element_size_mask; assert(l2esz <= LogBitsPerLong, - err_msg("sanity. l2esz: 0x%x for lh: 0x%x", (uint)l2esz, (uint)lh)); + "sanity. l2esz: 0x%x for lh: 0x%x", (uint)l2esz, (uint)lh); return l2esz; } static jint array_layout_helper(jint tag, int hsize, BasicType etype, int log2_esize) { @@ -480,9 +480,6 @@ protected: virtual bool oop_is_objArray_slow() const { return false; } virtual bool oop_is_typeArray_slow() const { return false; } public: - virtual bool oop_is_instanceClassLoader() const { return false; } - virtual bool oop_is_instanceMirror() const { return false; } - virtual bool oop_is_instanceRef() const { return false; } // Fast non-virtual versions #ifndef ASSERT diff --git a/hotspot/src/share/vm/oops/klass.inline.hpp b/hotspot/src/share/vm/oops/klass.inline.hpp index 8b05c3c2945..5c820f574c1 100644 --- a/hotspot/src/share/vm/oops/klass.inline.hpp +++ b/hotspot/src/share/vm/oops/klass.inline.hpp @@ -63,7 +63,7 @@ inline Klass* Klass::decode_klass_not_null(narrowKlass v) { assert(!is_null(v), "narrow klass value can never be zero"); int shift = Universe::narrow_klass_shift(); Klass* result = (Klass*)(void*)((uintptr_t)Universe::narrow_klass_base() + ((uintptr_t)v << shift)); - assert(check_klass_alignment(result), err_msg("address not aligned: " INTPTR_FORMAT, p2i((void*) result))); + assert(check_klass_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result)); return result; } diff --git a/hotspot/src/share/vm/oops/klassVtable.cpp b/hotspot/src/share/vm/oops/klassVtable.cpp index 545dbd467ae..9872b3fca55 100644 --- a/hotspot/src/share/vm/oops/klassVtable.cpp +++ b/hotspot/src/share/vm/oops/klassVtable.cpp @@ -38,8 +38,6 @@ #include "runtime/handles.inline.hpp" #include "utilities/copy.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - inline InstanceKlass* klassVtable::ik() const { Klass* k = _klass(); assert(k->oop_is_instance(), "not an InstanceKlass"); @@ -1461,8 +1459,8 @@ void klassVtable::verify(outputStream* st, bool forced) { oop* end_of_obj = (oop*)_klass() + _klass()->size(); oop* end_of_vtable = (oop *)&table()[_length]; if (end_of_vtable > end_of_obj) { - fatal(err_msg("klass %s: klass object too short (vtable extends beyond " - "end)", _klass->internal_name())); + fatal("klass %s: klass object too short (vtable extends beyond end)", + _klass->internal_name()); } for (int i = 0; i < _length; i++) table()[i].verify(this, st); @@ -1505,7 +1503,7 @@ void vtableEntry::verify(klassVtable* vt, outputStream* st) { #ifndef PRODUCT print(); #endif - fatal(err_msg("vtableEntry " PTR_FORMAT ": method is from subclass", this)); + fatal("vtableEntry " PTR_FORMAT ": method is from subclass", p2i(this)); } } @@ -1515,7 +1513,7 @@ void vtableEntry::print() { ResourceMark rm; tty->print("vtableEntry %s: ", method()->name()->as_C_string()); if (Verbose) { - tty->print("m %#lx ", (address)method()); + tty->print("m " PTR_FORMAT " ", p2i(method())); } } @@ -1586,7 +1584,7 @@ long klassItable::_total_size; // Total no. of bytes used for itables void klassItable::print_statistics() { tty->print_cr("itable statistics:"); tty->print_cr("%6d classes with itables", _total_classes); - tty->print_cr("%6d K uses for itables (average by class: %d bytes)", _total_size / K, _total_size / _total_classes); + tty->print_cr("%6lu K uses for itables (average by class: %ld bytes)", _total_size / K, _total_size / _total_classes); } #endif // PRODUCT diff --git a/hotspot/src/share/vm/oops/markOop.cpp b/hotspot/src/share/vm/oops/markOop.cpp index e7ce60eef7d..0224ca7597b 100644 --- a/hotspot/src/share/vm/oops/markOop.cpp +++ b/hotspot/src/share/vm/oops/markOop.cpp @@ -27,8 +27,6 @@ #include "runtime/thread.inline.hpp" #include "runtime/objectMonitor.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void markOopDesc::print_on(outputStream* st) const { if (is_marked()) { st->print(" marked(" INTPTR_FORMAT ")", value()); @@ -39,7 +37,7 @@ void markOopDesc::print_on(outputStream* st) const { if (mon == NULL) { st->print("NULL (this should never be seen!)"); } else { - st->print("{count=" INTPTR_FORMAT ",waiters=" INTPTR_FORMAT + st->print("{count=0x%08x,waiters=0x%08x" ",recursions=" INTPTR_FORMAT ",owner=" INTPTR_FORMAT "}", mon->count(), mon->waiters(), mon->recursions(), p2i(mon->owner())); @@ -65,7 +63,7 @@ void markOopDesc::print_on(outputStream* st) const { assert(is_unlocked() || has_bias_pattern(), "just checking"); st->print("mark("); if (has_bias_pattern()) st->print("biased,"); - st->print("hash %#lx,", hash()); + st->print("hash " INTPTR_FORMAT ",", hash()); st->print("age %d)", age()); } } diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 089d3896459..192769f7226 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -57,8 +57,6 @@ #include "utilities/quickSort.hpp" #include "utilities/xmlstream.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Implementation of Method Method* Method::allocate(ClassLoaderData* loader_data, @@ -74,17 +72,14 @@ Method* Method::allocate(ClassLoaderData* loader_data, sizes, method_type, CHECK_NULL); - int size = Method::size(access_flags.is_native()); - - return new (loader_data, size, false, MetaspaceObj::MethodType, THREAD) Method(cm, access_flags, size); + return new (loader_data, size, false, MetaspaceObj::MethodType, THREAD) Method(cm, access_flags); } -Method::Method(ConstMethod* xconst, AccessFlags access_flags, int size) { +Method::Method(ConstMethod* xconst, AccessFlags access_flags) { No_Safepoint_Verifier no_safepoint; set_constMethod(xconst); set_access_flags(access_flags); - set_method_size(size); #ifdef CC_INTERP set_result_index(T_VOID); #endif @@ -220,7 +215,7 @@ void Method::mask_for(int bci, InterpreterOopMap* mask) { Thread* myThread = Thread::current(); methodHandle h_this(myThread, this); -#ifdef ASSERT +#if defined(ASSERT) && !INCLUDE_JVMCI bool has_capability = myThread->is_VM_thread() || myThread->is_ConcurrentGC_thread() || myThread->is_GC_task_thread(); @@ -246,9 +241,11 @@ int Method::bci_from(address bcp) const { return 0; } #ifdef ASSERT - { ResourceMark rm; - assert(is_native() && bcp == code_base() || contains(bcp) || is_error_reported(), - err_msg("bcp doesn't belong to this method: bcp: " INTPTR_FORMAT ", method: %s", bcp, name_and_sig_as_C_string())); + { + ResourceMark rm; + assert(is_native() && bcp == code_base() || contains(bcp) || is_error_reported(), + "bcp doesn't belong to this method: bcp: " INTPTR_FORMAT ", method: %s", + p2i(bcp), name_and_sig_as_C_string()); } #endif return bcp - code_base(); @@ -279,7 +276,7 @@ int Method::validate_bci_from_bcp(address bcp) const { } address Method::bcp_from(int bci) const { - assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()), err_msg("illegal bci: %d", bci)); + assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()), "illegal bci: %d", bci); address bcp = code_base() + bci; assert(is_native() && bcp == code_base() || contains(bcp), "bcp doesn't belong to this method"); return bcp; @@ -573,7 +570,7 @@ bool Method::can_be_statically_bound(AccessFlags class_access_flags) const { ResourceMark rm; bool is_nonv = (vtable_index() == nonvirtual_vtable_index); if (class_access_flags.is_interface()) { - assert(is_nonv == is_static(), err_msg("is_nonv=%s", name_and_sig_as_C_string())); + assert(is_nonv == is_static(), "is_nonv=%s", name_and_sig_as_C_string()); } #endif assert(valid_vtable_index() || valid_itable_index(), "method must be linked before we ask this question"); @@ -1227,7 +1224,6 @@ methodHandle Method::clone_with_new_data(methodHandle m, u_char* new_code, int n m->method_type(), CHECK_(methodHandle())); methodHandle newm (THREAD, newm_oop); - int new_method_size = newm->method_size(); // Create a shallow copy of Method part, but be careful to preserve the new ConstMethod* ConstMethod* newcm = newm->constMethod(); @@ -1242,7 +1238,6 @@ methodHandle Method::clone_with_new_data(methodHandle m, u_char* new_code, int n newm->set_constMethod(newcm); newm->constMethod()->set_code_size(new_code_length); newm->constMethod()->set_constMethod_size(new_const_method_size); - newm->set_method_size(new_method_size); assert(newm->code_size() == new_code_length, "check"); assert(newm->method_parameters_length() == method_parameters_len, "check"); assert(newm->checked_exceptions_length() == checked_exceptions_len, "check"); @@ -1373,7 +1368,7 @@ void Method::init_intrinsic_id() { // These two methods are static since a GC may move the Method bool Method::load_signature_classes(methodHandle m, TRAPS) { - if (THREAD->is_Compiler_thread()) { + if (!THREAD->can_call_java()) { // There is nothing useful this routine can do from within the Compile thread. // Hopefully, the signature contains only well-known classes. // We could scan for this and return true/false, but the caller won't care. @@ -1491,14 +1486,20 @@ class SignatureTypePrinter : public SignatureTypeNames { void Method::print_name(outputStream* st) { Thread *thread = Thread::current(); ResourceMark rm(thread); - SignatureTypePrinter sig(signature(), st); st->print("%s ", is_static() ? "static" : "virtual"); - sig.print_returntype(); - st->print(" %s.", method_holder()->internal_name()); - name()->print_symbol_on(st); - st->print("("); - sig.print_parameters(); - st->print(")"); + if (WizardMode) { + st->print("%s.", method_holder()->internal_name()); + name()->print_symbol_on(st); + signature()->print_symbol_on(st); + } else { + SignatureTypePrinter sig(signature(), st); + sig.print_returntype(); + st->print(" %s.", method_holder()->internal_name()); + name()->print_symbol_on(st); + st->print("("); + sig.print_parameters(); + st->print(")"); + } } #endif // !PRODUCT || INCLUDE_JVMTI @@ -1572,7 +1573,7 @@ Bytecodes::Code Method::orig_bytecode_at(int bci) const { } { ResourceMark rm; - fatal(err_msg("no original bytecode found in %s at bci %d", name_and_sig_as_C_string(), bci)); + fatal("no original bytecode found in %s at bci %d", name_and_sig_as_C_string(), bci); } return Bytecodes::_shouldnotreachhere; } @@ -2024,9 +2025,9 @@ void Method::print_on(outputStream* st) const { assert(is_method(), "must be method"); st->print_cr("%s", internal_name()); // get the effect of PrintOopAddress, always, for methods: - st->print_cr(" - this oop: " INTPTR_FORMAT, (intptr_t)this); + st->print_cr(" - this oop: " INTPTR_FORMAT, p2i(this)); st->print (" - method holder: "); method_holder()->print_value_on(st); st->cr(); - st->print (" - constants: " INTPTR_FORMAT " ", (address)constants()); + st->print (" - constants: " INTPTR_FORMAT " ", p2i(constants())); constants()->print_value_on(st); st->cr(); st->print (" - access: 0x%x ", access_flags().as_int()); access_flags().print_on(st); st->cr(); st->print (" - name: "); name()->print_value_on(st); st->cr(); @@ -2040,26 +2041,26 @@ void Method::print_on(outputStream* st) const { if (highest_comp_level() != CompLevel_none) st->print_cr(" - highest level: %d", highest_comp_level()); st->print_cr(" - vtable index: %d", _vtable_index); - st->print_cr(" - i2i entry: " INTPTR_FORMAT, interpreter_entry()); + st->print_cr(" - i2i entry: " INTPTR_FORMAT, p2i(interpreter_entry())); st->print( " - adapters: "); AdapterHandlerEntry* a = ((Method*)this)->adapter(); if (a == NULL) - st->print_cr(INTPTR_FORMAT, a); + st->print_cr(INTPTR_FORMAT, p2i(a)); else a->print_adapter_on(st); - st->print_cr(" - compiled entry " INTPTR_FORMAT, from_compiled_entry()); + st->print_cr(" - compiled entry " INTPTR_FORMAT, p2i(from_compiled_entry())); st->print_cr(" - code size: %d", code_size()); if (code_size() != 0) { - st->print_cr(" - code start: " INTPTR_FORMAT, code_base()); - st->print_cr(" - code end (excl): " INTPTR_FORMAT, code_base() + code_size()); + st->print_cr(" - code start: " INTPTR_FORMAT, p2i(code_base())); + st->print_cr(" - code end (excl): " INTPTR_FORMAT, p2i(code_base() + code_size())); } if (method_data() != NULL) { - st->print_cr(" - method data: " INTPTR_FORMAT, (address)method_data()); + st->print_cr(" - method data: " INTPTR_FORMAT, p2i(method_data())); } st->print_cr(" - checked ex length: %d", checked_exceptions_length()); if (checked_exceptions_length() > 0) { CheckedExceptionElement* table = checked_exceptions_start(); - st->print_cr(" - checked ex start: " INTPTR_FORMAT, table); + st->print_cr(" - checked ex start: " INTPTR_FORMAT, p2i(table)); if (Verbose) { for (int i = 0; i < checked_exceptions_length(); i++) { st->print_cr(" - throws %s", constants()->printable_name_at(table[i].class_cp_index)); @@ -2068,7 +2069,7 @@ void Method::print_on(outputStream* st) const { } if (has_linenumber_table()) { u_char* table = compressed_linenumber_table(); - st->print_cr(" - linenumber start: " INTPTR_FORMAT, table); + st->print_cr(" - linenumber start: " INTPTR_FORMAT, p2i(table)); if (Verbose) { CompressedLineNumberReadStream stream(table); while (stream.read_pair()) { @@ -2079,7 +2080,7 @@ void Method::print_on(outputStream* st) const { st->print_cr(" - localvar length: %d", localvariable_table_length()); if (localvariable_table_length() > 0) { LocalVariableTableElement* table = localvariable_table_start(); - st->print_cr(" - localvar start: " INTPTR_FORMAT, table); + st->print_cr(" - localvar start: " INTPTR_FORMAT, p2i(table)); if (Verbose) { for (int i = 0; i < localvariable_table_length(); i++) { int bci = table[i].start_bci; @@ -2096,8 +2097,8 @@ void Method::print_on(outputStream* st) const { code()->print_value_on(st); } if (is_native()) { - st->print_cr(" - native function: " INTPTR_FORMAT, native_function()); - st->print_cr(" - signature handler: " INTPTR_FORMAT, signature_handler()); + st->print_cr(" - native function: " INTPTR_FORMAT, p2i(native_function())); + st->print_cr(" - signature handler: " INTPTR_FORMAT, p2i(signature_handler())); } } diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 2cec504aba9..f1a2e916f7d 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -71,7 +71,6 @@ class Method : public Metadata { #ifdef CC_INTERP int _result_index; // C++ interpreter needs for converting results to/from stack #endif - u2 _method_size; // size of this object u2 _intrinsic_id; // vmSymbols::intrinsic_id (0 == _none) // Flags @@ -106,7 +105,7 @@ class Method : public Metadata { volatile address _from_interpreted_entry; // Cache of _code ? _adapter->i2c_entry() : _i2i_entry // Constructor - Method(ConstMethod* xconst, AccessFlags access_flags, int size); + Method(ConstMethod* xconst, AccessFlags access_flags); public: static Method* allocate(ClassLoaderData* loader_data, @@ -241,12 +240,8 @@ class Method : public Metadata { // code size int code_size() const { return constMethod()->code_size(); } - // method size - int method_size() const { return _method_size; } - void set_method_size(int size) { - assert(0 <= size && size < (1 << 16), "invalid method size"); - _method_size = size; - } + // method size in words + int method_size() const { return sizeof(Method)/wordSize + is_native() ? 2 : 0; } // constant pool for Klass* holding this method ConstantPool* constants() const { return constMethod()->constants(); } @@ -685,8 +680,10 @@ class Method : public Metadata { TRAPS); static Klass* check_non_bcp_klass(Klass* klass); - // How many extra stack entries for invokedynamic when it's enabled - static const int extra_stack_entries_for_jsr292 = 1; + enum { + // How many extra stack entries for invokedynamic + extra_stack_entries_for_jsr292 = 1 + }; // this operates only on invoke methods: // presize interpreter frames for extra interpreter stack entries, if needed diff --git a/hotspot/src/share/vm/oops/methodCounters.hpp b/hotspot/src/share/vm/oops/methodCounters.hpp index 7d042bf72a1..039271b1c10 100644 --- a/hotspot/src/share/vm/oops/methodCounters.hpp +++ b/hotspot/src/share/vm/oops/methodCounters.hpp @@ -42,7 +42,7 @@ class MethodCounters: public MetaspaceObj { // The counter is reset by the sweeper and is decremented by some of the compiled // code. The counter values are interpreted as follows: // 1. (HotMethodDetection..INT_MAX] - initial value, no counters inserted - // 2. (1..HotMethodDetectionLimit) - the method is warm, the counter is used + // 2. [1..HotMethodDetectionLimit) - the method is warm, the counter is used // to figure out which methods can be flushed. // 3. (INT_MIN..0] - method is hot and will deopt and get // recompiled without the counters diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index 0700c51040b..c74a611ffe1 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -38,8 +38,6 @@ #include "runtime/orderAccess.inline.hpp" #include "utilities/copy.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // ================================================================== // DataLayout // @@ -110,7 +108,7 @@ char* ProfileData::print_data_on_helper(const MethodData* md) const { return ss.as_string(); break; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } } return NULL; @@ -413,13 +411,39 @@ void ReceiverTypeData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { } } +#if INCLUDE_JVMCI +void VirtualCallData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { + ReceiverTypeData::clean_weak_klass_links(is_alive_cl); + for (uint row = 0; row < method_row_limit(); row++) { + Method* p = method(row); + if (p != NULL && !p->method_holder()->is_loader_alive(is_alive_cl)) { + clear_method_row(row); + } + } +} + +void VirtualCallData::clean_weak_method_links() { + ReceiverTypeData::clean_weak_method_links(); + for (uint row = 0; row < method_row_limit(); row++) { + Method* p = method(row); + if (p != NULL && !p->on_stack()) { + clear_method_row(row); + } + } +} +#endif // INCLUDE_JVMCI + void ReceiverTypeData::print_receiver_data_on(outputStream* st) const { uint row; int entries = 0; for (row = 0; row < row_limit(); row++) { if (receiver(row) != NULL) entries++; } +#if INCLUDE_JVMCI + st->print_cr("count(%u) nonprofiled_count(%u) entries(%u)", count(), nonprofiled_count(), entries); +#else st->print_cr("count(%u) entries(%u)", count(), entries); +#endif int total = count(); for (row = 0; row < row_limit(); row++) { if (receiver(row) != NULL) { @@ -438,9 +462,36 @@ void ReceiverTypeData::print_data_on(outputStream* st, const char* extra) const print_shared(st, "ReceiverTypeData", extra); print_receiver_data_on(st); } + +#if INCLUDE_JVMCI +void VirtualCallData::print_method_data_on(outputStream* st) const { + uint row; + int entries = 0; + for (row = 0; row < method_row_limit(); row++) { + if (method(row) != NULL) entries++; + } + tab(st); + st->print_cr("method_entries(%u)", entries); + int total = count(); + for (row = 0; row < method_row_limit(); row++) { + if (method(row) != NULL) { + total += method_count(row); + } + } + for (row = 0; row < method_row_limit(); row++) { + if (method(row) != NULL) { + tab(st); + method(row)->print_value_on(st); + st->print_cr("(%u %4.2f)", method_count(row), (float) method_count(row) / (float) total); + } + } +} +#endif // INCLUDE_JVMCI + void VirtualCallData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "VirtualCallData", extra); print_receiver_data_on(st); + print_method_data_on(st); } // ================================================================== @@ -665,7 +716,7 @@ MethodData* MethodData::allocate(ClassLoaderData* loader_data, methodHandle meth } int MethodData::bytecode_cell_count(Bytecodes::Code code) { -#if defined(COMPILER1) && !defined(COMPILER2) +#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) return no_profile_data; #else switch (code) { @@ -797,6 +848,26 @@ bool MethodData::is_speculative_trap_bytecode(Bytecodes::Code code) { } int MethodData::compute_extra_data_count(int data_size, int empty_bc_count, bool needs_speculative_traps) { +#if INCLUDE_JVMCI + if (ProfileTraps) { + // Assume that up to 30% of the possibly trapping BCIs with no MDP will need to allocate one. + int extra_data_count = MIN2(empty_bc_count, MAX2(4, (empty_bc_count * 30) / 100)); + + // Make sure we have a minimum number of extra data slots to + // allocate SpeculativeTrapData entries. We would want to have one + // entry per compilation that inlines this method and for which + // some type speculation assumption fails. So the room we need for + // the SpeculativeTrapData entries doesn't directly depend on the + // size of the method. Because it's hard to estimate, we reserve + // space for an arbitrary number of entries. + int spec_data_count = (needs_speculative_traps ? SpecTrapLimitExtraEntries : 0) * + (SpeculativeTrapData::static_cell_count() + DataLayout::header_size_in_cells()); + + return MAX2(extra_data_count, spec_data_count); + } else { + return 0; + } +#else // INCLUDE_JVMCI if (ProfileTraps) { // Assume that up to 3% of BCIs with no MDP will need to allocate one. int extra_data_count = (uint)(empty_bc_count * 3) / 128 + 1; @@ -822,6 +893,7 @@ int MethodData::compute_extra_data_count(int data_size, int empty_bc_count, bool } else { return 0; } +#endif // INCLUDE_JVMCI } // Compute the size of the MethodData* necessary to store @@ -835,7 +907,7 @@ int MethodData::compute_allocation_size_in_bytes(methodHandle method) { while ((c = stream.next()) >= 0) { int size_in_bytes = compute_data_size(&stream); data_size += size_in_bytes; - if (size_in_bytes == 0) empty_bc_count += 1; + if (size_in_bytes == 0 JVMCI_ONLY(&& Bytecodes::can_trap(c))) empty_bc_count += 1; needs_speculative_traps = needs_speculative_traps || is_speculative_trap_bytecode(c); } int object_size = in_bytes(data_offset()) + data_size; @@ -869,7 +941,7 @@ int MethodData::compute_allocation_size_in_words(methodHandle method) { // the segment in bytes. int MethodData::initialize_data(BytecodeStream* stream, int data_index) { -#if defined(COMPILER1) && !defined(COMPILER2) +#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) return 0; #else int cell_count = -1; @@ -1060,10 +1132,14 @@ void MethodData::post_initialize(BytecodeStream* stream) { MethodData::MethodData(methodHandle method, int size, TRAPS) : _extra_data_lock(Monitor::leaf, "MDO extra data lock"), _parameters_type_data_di(parameters_uninitialized) { - No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC - ResourceMark rm; // Set the method back-pointer. _method = method(); + initialize(); +} + +void MethodData::initialize() { + No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC + ResourceMark rm; init(); set_creation_mileage(mileage_of(method())); @@ -1073,13 +1149,13 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) int data_size = 0; int empty_bc_count = 0; // number of bytecodes lacking data _data[0] = 0; // apparently not set below. - BytecodeStream stream(method); + BytecodeStream stream(method()); Bytecodes::Code c; bool needs_speculative_traps = false; while ((c = stream.next()) >= 0) { int size_in_bytes = initialize_data(&stream, data_size); data_size += size_in_bytes; - if (size_in_bytes == 0) empty_bc_count += 1; + if (size_in_bytes == 0 JVMCI_ONLY(&& Bytecodes::can_trap(c))) empty_bc_count += 1; needs_speculative_traps = needs_speculative_traps || is_speculative_trap_bytecode(c); } _data_size = data_size; @@ -1097,7 +1173,7 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) // the code for traps cells works. DataLayout *dp = data_layout_at(data_size + extra_size); - int arg_size = method->size_of_parameters(); + int arg_size = method()->size_of_parameters(); dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1); int arg_data_size = DataLayout::compute_size_in_bytes(arg_size+1); @@ -1126,6 +1202,7 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) post_initialize(&stream); + assert(object_size == compute_allocation_size_in_bytes(methodHandle(_method)), "MethodData: computed size != initialized size"); set_size(object_size); } @@ -1146,6 +1223,10 @@ void MethodData::init() { _num_blocks = 0; _would_profile = unknown; +#if INCLUDE_JVMCI + _jvmci_ir_size = 0; +#endif + #if INCLUDE_RTM_OPT _rtm_state = NoRTM; // No RTM lock eliding by default if (UseRTMLocking && @@ -1239,7 +1320,7 @@ DataLayout* MethodData::next_extra(DataLayout* dp) { nb_cells = SpeculativeTrapData::static_cell_count(); break; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } return (DataLayout*)((address)dp + DataLayout::compute_size_in_bytes(nb_cells)); } @@ -1279,7 +1360,7 @@ ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout } break; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } } return NULL; @@ -1400,7 +1481,7 @@ void MethodData::print_data_on(outputStream* st) const { dp = end; // ArgInfoData is at the end of extra data section. break; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } st->print("%d", dp_to_di(data->dp())); st->fill_to(6); @@ -1612,7 +1693,7 @@ void MethodData::clean_extra_data(CleanExtraDataClosure* cl) { clean_extra_data_helper(dp, shift, true); return; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } } } @@ -1638,7 +1719,7 @@ void MethodData::verify_extra_data_clean(CleanExtraDataClosure* cl) { case DataLayout::arg_info_data_tag: return; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } } #endif diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index b80ac6b1d80..ac58123f8b7 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -539,7 +539,11 @@ protected: enum { // null_seen: // saw a null operand (cast/aastore/instanceof) - null_seen_flag = DataLayout::first_flag + 0 + null_seen_flag = DataLayout::first_flag + 0 +#if INCLUDE_JVMCI + // bytecode threw any exception + , exception_seen_flag = null_seen_flag + 1 +#endif }; enum { bit_cell_count = 0 }; // no additional data fields needed. public: @@ -563,6 +567,11 @@ public: bool null_seen() { return flag_at(null_seen_flag); } void set_null_seen() { set_flag_at(null_seen_flag); } +#if INCLUDE_JVMCI + // true if an exception was thrown at the specific BCI + bool exception_seen() { return flag_at(exception_seen_flag); } + void set_exception_seen() { set_flag_at(exception_seen_flag); } +#endif // Code generation support static int null_seen_byte_constant() { @@ -1166,7 +1175,22 @@ public: class ReceiverTypeData : public CounterData { protected: enum { +#if INCLUDE_JVMCI + // Description of the different counters + // ReceiverTypeData for instanceof/checkcast/aastore: + // C1/C2: count is incremented on type overflow and decremented for failed type checks + // JVMCI: count decremented for failed type checks and nonprofiled_count is incremented on type overflow + // TODO (chaeubl): in fact, JVMCI should also increment the count for failed type checks to mimic the C1/C2 behavior + // VirtualCallData for invokevirtual/invokeinterface: + // C1/C2: count is incremented on type overflow + // JVMCI: count is incremented on type overflow, nonprofiled_count is incremented on method overflow + + // JVMCI is interested in knowing the percentage of type checks involving a type not explicitly in the profile + nonprofiled_count_off_set = counter_cell_count, + receiver0_offset, +#else receiver0_offset = counter_cell_count, +#endif count0_offset, receiver_type_row_cell_count = (count0_offset + 1) - receiver0_offset }; @@ -1181,7 +1205,7 @@ public: virtual bool is_ReceiverTypeData() const { return true; } static int static_cell_count() { - return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count; + return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count JVMCI_ONLY(+ 1); } virtual int cell_count() const { @@ -1243,6 +1267,13 @@ public: set_count(0); set_receiver(row, NULL); set_receiver_count(row, 0); +#if INCLUDE_JVMCI + if (!this->is_VirtualCallData()) { + // if this is a ReceiverTypeData for JVMCI, the nonprofiled_count + // must also be reset (see "Description of the different counters" above) + set_nonprofiled_count(0); + } +#endif } // Code generation support @@ -1252,6 +1283,17 @@ public: static ByteSize receiver_count_offset(uint row) { return cell_offset(receiver_count_cell_index(row)); } +#if INCLUDE_JVMCI + static ByteSize nonprofiled_receiver_count_offset() { + return cell_offset(nonprofiled_count_off_set); + } + uint nonprofiled_count() const { + return uint_at(nonprofiled_count_off_set); + } + void set_nonprofiled_count(uint count) { + set_uint_at(nonprofiled_count_off_set, count); + } +#endif // INCLUDE_JVMCI static ByteSize receiver_type_data_size() { return cell_offset(static_cell_count()); } @@ -1316,7 +1358,7 @@ public: static int static_cell_count() { // At this point we could add more profile state, e.g., for arguments. // But for now it's the same size as the base record type. - return ReceiverTypeData::static_cell_count(); + return ReceiverTypeData::static_cell_count() JVMCI_ONLY(+ (uint) MethodProfileWidth * receiver_type_row_cell_count); } virtual int cell_count() const { @@ -1338,6 +1380,62 @@ public: } #endif // CC_INTERP +#if INCLUDE_JVMCI + static ByteSize method_offset(uint row) { + return cell_offset(method_cell_index(row)); + } + static ByteSize method_count_offset(uint row) { + return cell_offset(method_count_cell_index(row)); + } + static int method_cell_index(uint row) { + return receiver0_offset + (row + TypeProfileWidth) * receiver_type_row_cell_count; + } + static int method_count_cell_index(uint row) { + return count0_offset + (row + TypeProfileWidth) * receiver_type_row_cell_count; + } + static uint method_row_limit() { + return MethodProfileWidth; + } + + Method* method(uint row) const { + assert(row < method_row_limit(), "oob"); + + Method* method = (Method*)intptr_at(method_cell_index(row)); + assert(method == NULL || method->is_method(), "must be"); + return method; + } + + uint method_count(uint row) const { + assert(row < method_row_limit(), "oob"); + return uint_at(method_count_cell_index(row)); + } + + void set_method(uint row, Method* m) { + assert((uint)row < method_row_limit(), "oob"); + set_intptr_at(method_cell_index(row), (uintptr_t)m); + } + + void set_method_count(uint row, uint count) { + assert(row < method_row_limit(), "oob"); + set_uint_at(method_count_cell_index(row), count); + } + + void clear_method_row(uint row) { + assert(row < method_row_limit(), "oob"); + // Clear total count - indicator of polymorphic call site (see comment for clear_row() in ReceiverTypeData). + set_nonprofiled_count(0); + set_method(row, NULL); + set_method_count(row, 0); + } + + // GC support + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); + + // Redefinition support + virtual void clean_weak_method_links(); +#endif // INCLUDE_JVMCI + + void print_method_data_on(outputStream* st) const NOT_JVMCI_RETURN; void print_data_on(outputStream* st, const char* extra = NULL) const; }; @@ -2053,10 +2151,11 @@ public: MethodData() : _extra_data_lock(Monitor::leaf, "MDO extra data lock") {}; // For ciMethodData bool is_methodData() const volatile { return true; } + void initialize(); // Whole-method sticky bits and flags enum { - _trap_hist_limit = 22, // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 22 JVMCI_ONLY(+5), // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values @@ -2104,6 +2203,11 @@ private: enum WouldProfile {unknown, no_profile, profile}; WouldProfile _would_profile; +#if INCLUDE_JVMCI + // Support for HotSpotMethodData.setCompiledIRSize(int) + int _jvmci_ir_size; +#endif + // Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size; @@ -2382,7 +2486,7 @@ public: // Return (uint)-1 for overflow. uint trap_count(int reason) const { - assert((uint)reason < _trap_hist_limit, "oob"); + assert((uint)reason < JVMCI_ONLY(2*) _trap_hist_limit, "oob"); return (int)((_trap_hist._array[reason]+1) & _trap_hist_mask) - 1; } // For loops: @@ -2391,17 +2495,13 @@ public: uint inc_trap_count(int reason) { // Count another trap, anywhere in this method. assert(reason >= 0, "must be single trap"); - if ((uint)reason < _trap_hist_limit) { - uint cnt1 = 1 + _trap_hist._array[reason]; - if ((cnt1 & _trap_hist_mask) != 0) { // if no counter overflow... - _trap_hist._array[reason] = cnt1; - return cnt1; - } else { - return _trap_hist_mask + (++_nof_overflow_traps); - } + assert((uint)reason < JVMCI_ONLY(2*) _trap_hist_limit, "oob"); + uint cnt1 = 1 + _trap_hist._array[reason]; + if ((cnt1 & _trap_hist_mask) != 0) { // if no counter overflow... + _trap_hist._array[reason] = cnt1; + return cnt1; } else { - // Could not represent the count in the histogram. - return (++_nof_overflow_traps); + return _trap_hist_mask + (++_nof_overflow_traps); } } @@ -2446,6 +2546,10 @@ public: return byte_offset_of(MethodData, _data[0]); } + static ByteSize trap_history_offset() { + return byte_offset_of(MethodData, _trap_hist._array); + } + static ByteSize invocation_counter_offset() { return byte_offset_of(MethodData, _invocation_counter); } diff --git a/hotspot/src/share/vm/oops/oop.cpp b/hotspot/src/share/vm/oops/oop.cpp index 83d24b06b77..e801ae30229 100644 --- a/hotspot/src/share/vm/oops/oop.cpp +++ b/hotspot/src/share/vm/oops/oop.cpp @@ -31,8 +31,6 @@ #include "runtime/thread.inline.hpp" #include "utilities/copy.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - bool always_do_update_barrier = false; BarrierSet* oopDesc::_bs = NULL; @@ -47,7 +45,7 @@ void oopDesc::print_on(outputStream* st) const { void oopDesc::print_address_on(outputStream* st) const { if (PrintOopAddress) { - st->print("{" INTPTR_FORMAT "}", this); + st->print("{" INTPTR_FORMAT "}", p2i(this)); } } @@ -123,7 +121,7 @@ VerifyOopClosure VerifyOopClosure::verify_oop; template void VerifyOopClosure::do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); - guarantee(obj->is_oop_or_null(), err_msg("invalid oop: " INTPTR_FORMAT, p2i((oopDesc*) obj))); + guarantee(obj->is_oop_or_null(), "invalid oop: " INTPTR_FORMAT, p2i((oopDesc*) obj)); } void VerifyOopClosure::do_oop(oop* p) { VerifyOopClosure::do_oop_work(p); } diff --git a/hotspot/src/share/vm/oops/oop.inline.hpp b/hotspot/src/share/vm/oops/oop.inline.hpp index 593ac92dd39..4ab957dbd26 100644 --- a/hotspot/src/share/vm/oops/oop.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.inline.hpp @@ -126,10 +126,25 @@ inline void oopDesc::init_mark() { set_mark(markOopDesc::proto inline bool oopDesc::is_a(Klass* k) const { return klass()->is_subtype_of(k); } -inline bool oopDesc::is_instance() const { return klass()->oop_is_instance(); } -inline bool oopDesc::is_instanceClassLoader() const { return klass()->oop_is_instanceClassLoader(); } -inline bool oopDesc::is_instanceMirror() const { return klass()->oop_is_instanceMirror(); } -inline bool oopDesc::is_instanceRef() const { return klass()->oop_is_instanceRef(); } +inline bool oopDesc::is_instance() const { + return klass()->oop_is_instance(); +} + +inline bool oopDesc::is_instanceClassLoader() const { + Klass* k = klass(); + return k->oop_is_instance() && InstanceKlass::cast(k)->is_class_loader_instance_klass(); +} + +inline bool oopDesc::is_instanceMirror() const { + Klass* k = klass(); + return k->oop_is_instance() && InstanceKlass::cast(k)->is_mirror_instance_klass(); +} + +inline bool oopDesc::is_instanceRef() const { + Klass* k = klass(); + return k->oop_is_instance() && InstanceKlass::cast(k)->is_reference_instance_klass(); +} + inline bool oopDesc::is_array() const { return klass()->oop_is_array(); } inline bool oopDesc::is_objArray() const { return klass()->oop_is_objArray(); } inline bool oopDesc::is_typeArray() const { return klass()->oop_is_typeArray(); } @@ -189,7 +204,7 @@ inline oop oopDesc::decode_heap_oop_not_null(narrowOop v) { address base = Universe::narrow_oop_base(); int shift = Universe::narrow_oop_shift(); oop result = (oop)(void*)((uintptr_t)base + ((uintptr_t)v << shift)); - assert(check_obj_alignment(result), err_msg("address not aligned: " INTPTR_FORMAT, p2i((void*) result))); + assert(check_obj_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result)); return result; } diff --git a/hotspot/src/share/vm/opto/block.cpp b/hotspot/src/share/vm/opto/block.cpp index ded60f22583..3be4e7e6ac0 100644 --- a/hotspot/src/share/vm/opto/block.cpp +++ b/hotspot/src/share/vm/opto/block.cpp @@ -358,6 +358,8 @@ void Block::dump(const PhaseCFG* cfg) const { PhaseCFG::PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher) : Phase(CFG) , _block_arena(arena) +, _regalloc(NULL) +, _scheduling_for_pressure(false) , _root(root) , _matcher(matcher) , _node_to_block_mapping(arena) diff --git a/hotspot/src/share/vm/opto/block.hpp b/hotspot/src/share/vm/opto/block.hpp index 48aa6eeb25d..501495e0513 100644 --- a/hotspot/src/share/vm/opto/block.hpp +++ b/hotspot/src/share/vm/opto/block.hpp @@ -37,6 +37,7 @@ class MachCallNode; class Matcher; class RootNode; class VectorSet; +class PhaseChaitin; struct Tarjan; //------------------------------Block_Array------------------------------------ @@ -383,6 +384,12 @@ class PhaseCFG : public Phase { // Arena for the blocks to be stored in Arena* _block_arena; + // Info used for scheduling + PhaseChaitin* _regalloc; + + // Register pressure heuristic used? + bool _scheduling_for_pressure; + // The matcher for this compilation Matcher& _matcher; @@ -433,12 +440,14 @@ class PhaseCFG : public Phase { // to late. Helper for schedule_late. Block* hoist_to_cheaper_block(Block* LCA, Block* early, Node* self); - bool schedule_local(Block* block, GrowableArray& ready_cnt, VectorSet& next_call); + bool schedule_local(Block* block, GrowableArray& ready_cnt, VectorSet& next_call, intptr_t* recacl_pressure_nodes); void set_next_call(Block* block, Node* n, VectorSet& next_call); void needed_for_next_call(Block* block, Node* this_call, VectorSet& next_call); // Perform basic-block local scheduling - Node* select(Block* block, Node_List& worklist, GrowableArray& ready_cnt, VectorSet& next_call, uint sched_slot); + Node* select(Block* block, Node_List& worklist, GrowableArray& ready_cnt, VectorSet& next_call, uint sched_slot, + intptr_t* recacl_pressure_nodes); + void adjust_register_pressure(Node* n, Block* block, intptr_t *recalc_pressure_nodes, bool finalize_mode); // Schedule a call next in the block uint sched_call(Block* block, uint node_cnt, Node_List& worklist, GrowableArray& ready_cnt, MachCallNode* mcall, VectorSet& next_call); diff --git a/hotspot/src/share/vm/opto/bytecodeInfo.cpp b/hotspot/src/share/vm/opto/bytecodeInfo.cpp index fa476d62401..3d4a54f173e 100644 --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp @@ -114,7 +114,7 @@ bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined method is hot: "); } - set_msg("force inline by CompilerOracle"); + set_msg("force inline by CompileCommand"); _forced_inline = true; return true; } @@ -223,12 +223,12 @@ bool InlineTree::should_not_inline(ciMethod *callee_method, // ignore heuristic controls on inlining if (callee_method->should_inline()) { - set_msg("force inline by CompilerOracle"); + set_msg("force inline by CompileCommand"); return false; } if (callee_method->should_not_inline()) { - set_msg("disallowed by CompilerOracle"); + set_msg("disallowed by CompileCommand"); return true; } @@ -470,11 +470,6 @@ bool pass_initial_checks(ciMethod* caller_method, int caller_bci, ciMethod* call } } } - // We will attempt to see if a class/field/etc got properly loaded. If it - // did not, it may attempt to throw an exception during our probing. Catch - // and ignore such exceptions and do not attempt to compile the method. - if( callee_method->should_exclude() ) return false; - return true; } diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 61abb9c0893..fb4e2dd8f26 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -69,43 +69,32 @@ develop(bool, StressGCM, false, \ "Randomize instruction scheduling in GCM") \ \ - notproduct(intx, CompileZapFirst, 0, \ - "If +ZapDeadCompiledLocals, " \ - "skip this many before compiling in zap calls") \ - \ - notproduct(intx, CompileZapLast, -1, \ - "If +ZapDeadCompiledLocals, " \ - "compile this many after skipping (incl. skip count, -1 = all)") \ - \ - notproduct(intx, ZapDeadCompiledLocalsFirst, 0, \ - "If +ZapDeadCompiledLocals, " \ - "skip this many before really doing it") \ - \ - notproduct(intx, ZapDeadCompiledLocalsLast, -1, \ - "If +ZapDeadCompiledLocals, " \ - "do this many after skipping (incl. skip count, -1 = all)") \ - \ develop(intx, OptoPrologueNops, 0, \ "Insert this many extra nop instructions " \ "in the prologue of every nmethod") \ + range(0, 128) \ \ product_pd(intx, InteriorEntryAlignment, \ "Code alignment for interior entry points " \ "in generated code (in bytes)") \ + constraint(InteriorEntryAlignmentConstraintFunc, AfterErgo) \ \ product(intx, MaxLoopPad, (OptoLoopAlignment-1), \ "Align a loop if padding size in bytes is less or equal to this " \ "value") \ + range(0, max_jint) \ \ product(intx, MaxVectorSize, 64, \ "Max vector size in bytes, " \ "actual size could be less depending on elements type") \ + range(0, max_jint) \ \ product(bool, AlignVector, true, \ "Perform vector store/load alignment in loop") \ \ product(intx, NumberOfLoopInstrToAlign, 4, \ "Number of first instructions in a loop to align") \ + range(0, max_jint) \ \ notproduct(intx, IndexSetWatch, 0, \ "Trace all operations on this IndexSet (-1 means all, 0 none)") \ @@ -113,9 +102,11 @@ \ develop(intx, OptoNodeListSize, 4, \ "Starting allocation size of Node_List data structures") \ + range(0, max_jint) \ \ develop(intx, OptoBlockListSize, 8, \ "Starting allocation size of Block_List data structures") \ + range(0, max_jint) \ \ develop(intx, OptoPeepholeAt, -1, \ "Apply peephole optimizations to this peephole rule") \ @@ -189,9 +180,11 @@ \ product_pd(intx, LoopUnrollLimit, \ "Unroll loop bodies with node count less than this") \ + range(0, max_jint / 4) \ \ product(intx, LoopMaxUnroll, 16, \ "Maximum number of unrolls for main loop") \ + range(0, max_jint) \ \ product(bool, SuperWordLoopUnrollAnalysis, false, \ "Map number of unrolls for main loop via " \ @@ -203,16 +196,19 @@ product(intx, LoopUnrollMin, 4, \ "Minimum number of unroll loop bodies before checking progress" \ "of rounds of unroll,optimize,..") \ + range(0, max_jint) \ \ develop(intx, UnrollLimitForProfileCheck, 1, \ "Don't use profile_trip_cnt() to restrict unrolling until " \ "unrolling would push the number of unrolled iterations above " \ "UnrollLimitForProfileCheck. A higher value allows more " \ "unrolling. Zero acts as a very large value." ) \ + range(0, max_intx) \ \ product(intx, MultiArrayExpandLimit, 6, \ "Maximum number of individual allocations in an inline-expanded " \ "multianewarray instruction") \ + range(0, max_jint) \ \ notproduct(bool, TraceProfileTripCount, false, \ "Trace profile loop trip count information") \ @@ -259,6 +255,7 @@ \ product(intx, TrackedInitializationLimit, 50, \ "When initializing fields, track up to this many words") \ + range(0, 65535) \ \ product(bool, ReduceFieldZeroing, true, \ "When initializing fields, try to avoid needless zeroing") \ @@ -293,9 +290,11 @@ \ develop_pd(intx, FLOATPRESSURE, \ "Number of float LRG's that constitute high register pressure") \ + range(0, max_jint) \ \ develop_pd(intx, INTPRESSURE, \ "Number of integer LRG's that constitute high register pressure") \ + range(0, max_jint) \ \ notproduct(bool, TraceOptoPipelining, false, \ "Trace pipelining information") \ @@ -306,11 +305,15 @@ product_pd(bool, OptoScheduling, \ "Instruction Scheduling after register allocation") \ \ + product_pd(bool, OptoRegScheduling, \ + "Instruction Scheduling before register allocation for pressure") \ + \ product(bool, PartialPeelLoop, true, \ "Partial peel (rotate) loops") \ \ product(intx, PartialPeelNewPhiDelta, 0, \ "Additional phis that can be created by partial peeling") \ + range(0, max_jint) \ \ notproduct(bool, TracePartialPeeling, false, \ "Trace partial peeling (loop rotation) information") \ @@ -339,6 +342,9 @@ product(bool, SuperWordReductions, true, \ "Enable reductions support in superword.") \ \ + product(bool, DoReserveCopyInSuperWord, true, \ + "Create reserve copy of graph in SuperWord.") \ + \ notproduct(bool, TraceSuperWord, false, \ "Trace superword transforms") \ \ @@ -350,6 +356,7 @@ \ product_pd(intx, ConditionalMoveLimit, \ "Limit of ops to make speculative when using CMOVE") \ + range(0, max_jint) \ \ /* Set BranchOnRegister == false. See 4965987. */ \ product(bool, BranchOnRegister, false, \ @@ -374,6 +381,7 @@ \ develop(intx, PrintIdealGraphPort, 4444, \ "Ideal graph printer to network port") \ + range(0, SHRT_MAX) \ \ notproduct(ccstr, PrintIdealGraphAddress, "127.0.0.1", \ "IP address to connect to visualizer") \ @@ -402,50 +410,64 @@ develop(intx, ImplicitNullCheckThreshold, 3, \ "Don't do implicit null checks if NPE's in a method exceeds " \ "limit") \ + range(0, max_jint) \ \ product(intx, LoopOptsCount, 43, \ "Set level of loop optimization for tier 1 compiles") \ + range(5, 43) \ \ /* controls for heat-based inlining */ \ \ develop(intx, NodeCountInliningCutoff, 18000, \ "If parser node generation exceeds limit stop inlining") \ + range(0, max_jint) \ \ develop(intx, NodeCountInliningStep, 1000, \ "Target size of warm calls inlined between optimization passes") \ + range(0, max_jint) \ \ develop(bool, InlineWarmCalls, false, \ "Use a heat-based priority queue to govern inlining") \ \ develop(intx, HotCallCountThreshold, 999999, \ "large numbers of calls (per method invocation) force hotness") \ + range(0, max_intx) \ \ develop(intx, HotCallProfitThreshold, 999999, \ "highly profitable inlining opportunities force hotness") \ + range(0, max_intx) \ \ develop(intx, HotCallTrivialWork, -1, \ "trivial execution time (no larger than this) forces hotness") \ + range(-1, max_intx) \ \ develop(intx, HotCallTrivialSize, -1, \ "trivial methods (no larger than this) force calls to be hot") \ + range(-1, max_intx) \ \ develop(intx, WarmCallMinCount, -1, \ "number of calls (per method invocation) to enable inlining") \ + range(-1, max_intx) \ \ develop(intx, WarmCallMinProfit, -1, \ "number of calls (per method invocation) to enable inlining") \ + range(-1, max_intx) \ \ develop(intx, WarmCallMaxWork, 999999, \ "execution time of the largest inlinable method") \ + range(0, max_intx) \ \ develop(intx, WarmCallMaxSize, 999999, \ "size of the largest inlinable method") \ + range(0, max_intx) \ \ product(intx, MaxNodeLimit, 80000, \ "Maximum number of nodes") \ + range(1000, max_jint / 3) \ \ product(intx, NodeLimitFudgeFactor, 2000, \ "Fudge Factor for certain optimizations") \ + constraint(NodeLimitFudgeFactorConstraintFunc, AfterErgo) \ \ product(bool, UseJumpTables, true, \ "Use JumpTables instead of a binary search tree for switches") \ @@ -455,12 +477,15 @@ \ product_pd(intx, MinJumpTableSize, \ "Minimum number of targets in a generated jump table") \ + range(0, max_intx) \ \ product(intx, MaxJumpTableSize, 65000, \ "Maximum number of targets in a generated jump table") \ + range(0, max_intx) \ \ product(intx, MaxJumpTableSparseness, 5, \ "Maximum sparseness for jumptables") \ + range(0, max_intx / 4) \ \ product(bool, EliminateLocks, true, \ "Coarsen locks when possible") \ @@ -488,6 +513,7 @@ \ product(intx, AutoBoxCacheMax, 128, \ "Sets max value cached by the java.lang.Integer autobox cache") \ + range(0, max_jint) \ \ experimental(bool, AggressiveUnboxing, false, \ "Control optimizations for aggressive boxing elimination") \ @@ -500,6 +526,7 @@ \ product(double, EscapeAnalysisTimeout, 20. DEBUG_ONLY(+40.), \ "Abort EA when it reaches time limit (in sec)") \ + range(0, DBL_MAX) \ \ develop(bool, ExitEscapeAnalysisOnTimeout, true, \ "Exit or throw assert in EA when it reaches time limit") \ @@ -515,6 +542,7 @@ \ product(intx, EliminateAllocationArraySizeLimit, 64, \ "Array size (number of elements) limit for scalar replacement") \ + range(0, max_jint) \ \ product(bool, OptimizePtrCompare, true, \ "Use escape analysis to optimize pointers compare") \ @@ -536,12 +564,15 @@ \ product(intx, ValueSearchLimit, 1000, \ "Recursion limit in PhaseMacroExpand::value_from_mem_phi") \ + range(0, max_jint) \ \ product(intx, MaxLabelRootDepth, 1100, \ "Maximum times call Label_Root to prevent stack overflow") \ + range(100, max_jint) \ \ diagnostic(intx, DominatorSearchLimit, 1000, \ "Iterations limit in Node::dominates") \ + range(0, max_jint) \ \ product(bool, BlockLayoutByFrequency, true, \ "Use edge frequencies to drive block ordering") \ @@ -651,6 +682,7 @@ \ develop(intx, FreqCountInvocations, 1, \ "Scaling factor for branch frequencies (deprecated)") \ + range(1, max_intx) \ \ product(intx, AliasLevel, 3, \ "0 for no aliasing, 1 for oop/field/static/array split, " \ @@ -669,6 +701,7 @@ \ product(intx, LiveNodeCountInliningCutoff, 40000, \ "max number of live nodes in a method") \ + range(0, max_juint / 8) \ \ diagnostic(bool, OptimizeExpensiveOps, true, \ "Find best control for expensive operations") \ @@ -705,6 +738,7 @@ product(intx, ArrayCopyLoadStoreMaxElem, 8, \ "Maximum number of arraycopy elements inlined as a sequence of" \ "loads/stores") \ + range(0, max_intx) \ \ develop(bool, StressArrayCopyMacroNode, false, \ "Perform ArrayCopy load/store replacement during IGVN only") diff --git a/hotspot/src/share/vm/opto/callGenerator.cpp b/hotspot/src/share/vm/opto/callGenerator.cpp index 716bc339732..7e569551c79 100644 --- a/hotspot/src/share/vm/opto/callGenerator.cpp +++ b/hotspot/src/share/vm/opto/callGenerator.cpp @@ -895,7 +895,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* break; default: - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } return NULL; diff --git a/hotspot/src/share/vm/opto/callnode.hpp b/hotspot/src/share/vm/opto/callnode.hpp index 2c788e52a11..389f09cab07 100644 --- a/hotspot/src/share/vm/opto/callnode.hpp +++ b/hotspot/src/share/vm/opto/callnode.hpp @@ -907,6 +907,18 @@ public: // Convenience for initialization->maybe_set_complete(phase) bool maybe_set_complete(PhaseGVN* phase); + + // Return true if allocation doesn't escape thread, its escape state + // needs be noEscape or ArgEscape. InitializeNode._does_not_escape + // is true when its allocation's escape state is noEscape or + // ArgEscape. In case allocation's InitializeNode is NULL, check + // AlllocateNode._is_non_escaping flag. + // AlllocateNode._is_non_escaping is true when its escape state is + // noEscape. + bool does_not_escape_thread() { + InitializeNode* init = NULL; + return _is_non_escaping || (((init = initialization()) != NULL) && init->does_not_escape()); + } }; //------------------------------AllocateArray--------------------------------- diff --git a/hotspot/src/share/vm/opto/castnode.cpp b/hotspot/src/share/vm/opto/castnode.cpp index e20d13a3262..44ea7c39814 100644 --- a/hotspot/src/share/vm/opto/castnode.cpp +++ b/hotspot/src/share/vm/opto/castnode.cpp @@ -129,7 +129,7 @@ const Type *CastIINode::Value(PhaseTransform *phase) const { } else { stringStream ss; test.dump_on(&ss); - fatal(err_msg_res("unexpected comparison %s", ss.as_string())); + fatal("unexpected comparison %s", ss.as_string()); } int lo_int = (int)lo_long; int hi_int = (int)hi_long; diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index 13fe3781187..fd03d4146c5 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -191,7 +191,7 @@ uint LiveRangeMap::find_const(uint lrg) const { return next; } -PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher) +PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher, bool scheduling_info_generated) : PhaseRegAlloc(unique, cfg, matcher, #ifndef PRODUCT print_chaitin_statistics @@ -205,6 +205,11 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher) , _spilled_twice(Thread::current()->resource_area()) , _lo_degree(0), _lo_stk_degree(0), _hi_degree(0), _simplified(0) , _oldphi(unique) + , _scheduling_info_generated(scheduling_info_generated) + , _sched_int_pressure(0, INTPRESSURE) + , _sched_float_pressure(0, FLOATPRESSURE) + , _scratch_int_pressure(0, INTPRESSURE) + , _scratch_float_pressure(0, FLOATPRESSURE) #ifndef PRODUCT , _trace_spilling(TraceSpilling || C->method_has_option("TraceSpilling")) #endif @@ -350,7 +355,7 @@ void PhaseChaitin::Register_Allocate() { // all copy-related live ranges low and then using the max copy-related // live range as a cut-off for LIVE and the IFG. In other words, I can // build a subset of LIVE and IFG just for copies. - PhaseLive live(_cfg, _lrg_map.names(), &live_arena); + PhaseLive live(_cfg, _lrg_map.names(), &live_arena, false); // Need IFG for coalescing and coloring PhaseIFG ifg(&live_arena); @@ -690,6 +695,29 @@ void PhaseChaitin::de_ssa() { _lrg_map.reset_uf_map(lr_counter); } +void PhaseChaitin::mark_ssa() { + // Use ssa names to populate the live range maps or if no mask + // is available, use the 0 entry. + uint max_idx = 0; + for ( uint i = 0; i < _cfg.number_of_blocks(); i++ ) { + Block* block = _cfg.get_block(i); + uint cnt = block->number_of_nodes(); + + // Handle all the normal Nodes in the block + for ( uint j = 0; j < cnt; j++ ) { + Node *n = block->get_node(j); + // Pre-color to the zero live range, or pick virtual register + const RegMask &rm = n->out_RegMask(); + _lrg_map.map(n->_idx, rm.is_NotEmpty() ? n->_idx : 0); + max_idx = (n->_idx > max_idx) ? n->_idx : max_idx; + } + } + _lrg_map.set_max_lrg_id(max_idx+1); + + // Reset the Union-Find mapping to be identity + _lrg_map.reset_uf_map(max_idx+1); +} + // Gather LiveRanGe information, including register masks. Modification of // cisc spillable in_RegMasks should not be done before AggressiveCoalesce. @@ -707,7 +735,9 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { for (uint j = 1; j < block->number_of_nodes(); j++) { Node* n = block->get_node(j); uint input_edge_start =1; // Skip control most nodes + bool is_machine_node = false; if (n->is_Mach()) { + is_machine_node = true; input_edge_start = n->as_Mach()->oper_input_base(); } uint idx = n->is_Copy(); @@ -929,6 +959,7 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { // Convert operand number to edge index number inp = n->as_Mach()->operand_index(inp); } + // Prepare register mask for each input for( uint k = input_edge_start; k < cnt; k++ ) { uint vreg = _lrg_map.live_range_id(n->in(k)); @@ -948,6 +979,12 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { n->as_Mach()->use_cisc_RegMask(); } + if (is_machine_node && _scheduling_info_generated) { + MachNode* cur_node = n->as_Mach(); + // this is cleaned up by register allocation + if (k >= cur_node->num_opnds()) continue; + } + LRG &lrg = lrgs(vreg); // // Testing for floating point code shape // Node *test = n->in(k); @@ -989,7 +1026,7 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { // double can interfere with TWO aligned pairs, or effectively // FOUR registers! #ifdef ASSERT - if (is_vect) { + if (is_vect && !_scheduling_info_generated) { if (lrg.num_regs() != 0) { assert(lrgmask.is_aligned_sets(lrg.num_regs()), "vector should be aligned"); assert(!lrg._fat_proj, "sanity"); @@ -1733,7 +1770,7 @@ Node *PhaseChaitin::find_base_for_derived( Node **derived_base_map, Node *derive // Check for AddP-related opcodes if (!derived->is_Phi()) { - assert(derived->as_Mach()->ideal_Opcode() == Op_AddP, err_msg_res("but is: %s", derived->Name())); + assert(derived->as_Mach()->ideal_Opcode() == Op_AddP, "but is: %s", derived->Name()); Node *base = derived->in(AddPNode::Base); derived_base_map[derived->_idx] = base; return base; diff --git a/hotspot/src/share/vm/opto/chaitin.hpp b/hotspot/src/share/vm/opto/chaitin.hpp index 96b4eb32db3..27d61820767 100644 --- a/hotspot/src/share/vm/opto/chaitin.hpp +++ b/hotspot/src/share/vm/opto/chaitin.hpp @@ -399,7 +399,6 @@ class PhaseChaitin : public PhaseRegAlloc { int _trip_cnt; int _alternate; - LRG &lrgs(uint idx) const { return _ifg->lrgs(idx); } PhaseLive *_live; // Liveness, used in the interference graph PhaseIFG *_ifg; // Interference graph (for original chunk) Node_List **_lrg_nodes; // Array of node; lists for lrgs which spill @@ -464,16 +463,28 @@ class PhaseChaitin : public PhaseRegAlloc { #endif public: - PhaseChaitin( uint unique, PhaseCFG &cfg, Matcher &matcher ); + PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher, bool track_liveout_pressure); ~PhaseChaitin() {} LiveRangeMap _lrg_map; + LRG &lrgs(uint idx) const { return _ifg->lrgs(idx); } + // Do all the real work of allocate void Register_Allocate(); float high_frequency_lrg() const { return _high_frequency_lrg; } + // Used when scheduling info generated, not in general register allocation + bool _scheduling_info_generated; + + void set_ifg(PhaseIFG &ifg) { _ifg = &ifg; } + void set_live(PhaseLive &live) { _live = &live; } + PhaseLive* get_live() { return _live; } + + // Populate the live range maps with ssa info for scheduling + void mark_ssa(); + #ifndef PRODUCT bool trace_spilling() const { return _trace_spilling; } #endif @@ -516,7 +527,11 @@ private: uint _final_pressure; // number of live ranges that constitute high register pressure - const uint _high_pressure_limit; + uint _high_pressure_limit; + + // initial pressure observed + uint _start_pressure; + public: // lower the register pressure and look for a low to high pressure @@ -537,6 +552,14 @@ private: } } + void init(int limit) { + _current_pressure = 0; + _high_pressure_index = 0; + _final_pressure = 0; + _high_pressure_limit = limit; + _start_pressure = 0; + } + uint high_pressure_index() const { return _high_pressure_index; } @@ -545,6 +568,10 @@ private: return _final_pressure; } + uint start_pressure() const { + return _start_pressure; + } + uint current_pressure() const { return _current_pressure; } @@ -561,6 +588,15 @@ private: _high_pressure_index = 0; } + void set_start_pressure(int value) { + _start_pressure = value; + _final_pressure = value; + } + + void set_current_pressure(int value) { + _current_pressure = value; + } + void check_pressure_at_fatproj(uint fatproj_location, RegMask& fatproj_mask) { // this pressure is only valid at this instruction, i.e. we don't need to lower // the register pressure since the fat proj was never live before (going backwards) @@ -577,14 +613,13 @@ private: } Pressure(uint high_pressure_index, uint high_pressure_limit) - : _current_pressure(0) - , _high_pressure_index(high_pressure_index) - , _high_pressure_limit(high_pressure_limit) - , _final_pressure(0) {} + : _current_pressure(0) + , _high_pressure_index(high_pressure_index) + , _final_pressure(0) + , _high_pressure_limit(high_pressure_limit) + , _start_pressure(0) {} }; - void lower_pressure(Block* b, uint location, LRG& lrg, IndexSet* liveout, Pressure& int_pressure, Pressure& float_pressure); - void raise_pressure(Block* b, LRG& lrg, Pressure& int_pressure, Pressure& float_pressure); void check_for_high_pressure_transition_at_fatproj(uint& block_reg_pressure, uint location, LRG& lrg, Pressure& pressure, const int op_regtype); void add_input_to_liveout(Block* b, Node* n, IndexSet* liveout, double cost, Pressure& int_pressure, Pressure& float_pressure); void compute_initial_block_pressure(Block* b, IndexSet* liveout, Pressure& int_pressure, Pressure& float_pressure, double cost); @@ -600,10 +635,25 @@ private: // acceptable register sets do not overlap, then they do not interfere. uint build_ifg_physical( ResourceArea *a ); +public: // Gather LiveRanGe information, including register masks and base pointer/ // derived pointer relationships. void gather_lrg_masks( bool mod_cisc_masks ); + // user visible pressure variables for scheduling + Pressure _sched_int_pressure; + Pressure _sched_float_pressure; + Pressure _scratch_int_pressure; + Pressure _scratch_float_pressure; + + // Pressure functions for user context + void lower_pressure(Block* b, uint location, LRG& lrg, IndexSet* liveout, Pressure& int_pressure, Pressure& float_pressure); + void raise_pressure(Block* b, LRG& lrg, Pressure& int_pressure, Pressure& float_pressure); + void compute_entry_block_pressure(Block* b); + void compute_exit_block_pressure(Block* b); + void print_pressure_info(Pressure& pressure, const char *str); + +private: // Force the bases of derived pointers to be alive at GC points. bool stretch_base_pointer_live_ranges( ResourceArea *a ); // Helper to stretch above; recursively discover the base Node for diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index 5e361177e86..cf3aea18ee2 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -131,7 +131,6 @@ macro(DivModL) macro(EncodeISOArray) macro(EncodeP) macro(EncodePKlass) -macro(ExpD) macro(FastLock) macro(FastUnlock) macro(Goto) @@ -290,6 +289,10 @@ macro(MulVD) macro(MulReductionVD) macro(DivVF) macro(DivVD) +macro(AbsVF) +macro(AbsVD) +macro(NegVF) +macro(NegVD) macro(SqrtVD) macro(LShiftCntV) macro(RShiftCntV) diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 9f1aedc735c..ae26d11658f 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -317,7 +317,7 @@ static inline bool not_a_node(const Node* n) { // Use breadth-first pass that records state in a Unique_Node_List, // recursive traversal is slower. void Compile::identify_useful_nodes(Unique_Node_List &useful) { - int estimated_worklist_size = unique(); + int estimated_worklist_size = live_nodes(); useful.map( estimated_worklist_size, NULL ); // preallocate space // Initialize worklist @@ -596,7 +596,7 @@ uint Compile::scratch_emit_size(const Node* n) { n->emit(buf, this->regalloc()); // Emitting into the scratch buffer should not fail - assert (!failing(), err_msg_res("Must not have pending failure. Reason is: %s", failure_reason())); + assert (!failing(), "Must not have pending failure. Reason is: %s", failure_reason()); if (is_branch) // Restore label. n->as_MachBranch()->label_set(saveL, save_bnum); @@ -1189,7 +1189,7 @@ void Compile::init_start(StartNode* s) { * the ideal graph. */ StartNode* Compile::start() const { - assert (!failing(), err_msg_res("Must not have pending failure. Reason is: %s", failure_reason())); + assert (!failing(), "Must not have pending failure. Reason is: %s", failure_reason()); for (DUIterator_Fast imax, i = root()->fast_outs(imax); i < imax; i++) { Node* start = root()->fast_out(i); if (start->is_Start()) { @@ -2254,6 +2254,8 @@ void Compile::Optimize() { if (failing()) return; } } + // Ensure that major progress is now clear + C->clear_major_progress(); { // Verify that all previous optimizations produced a valid graph @@ -2336,7 +2338,7 @@ void Compile::Code_Gen() { debug_only( cfg.verify(); ) } - PhaseChaitin regalloc(unique(), cfg, matcher); + PhaseChaitin regalloc(unique(), cfg, matcher, false); _regalloc = ®alloc; { TracePhase tp("regalloc", &timers[_t_registerAllocation]); @@ -3314,7 +3316,7 @@ bool Compile::final_graph_reshaping() { Final_Reshape_Counts frc; // Visit everybody reachable! - // Allocate stack of size C->unique()/2 to avoid frequent realloc + // Allocate stack of size C->live_nodes()/2 to avoid frequent realloc Node_Stack nstack(live_nodes() >> 1); final_graph_reshaping_walk(nstack, root(), frc); @@ -3796,7 +3798,7 @@ void Compile::ConstantTable::emit(CodeBuffer& cb) { } assert(constant_addr, "consts section too small"); assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), - err_msg_res("must be: %d == %d", (int) (constant_addr - _masm.code()->consts()->start()), (int)(con.offset()))); + "must be: %d == %d", (int) (constant_addr - _masm.code()->consts()->start()), (int)(con.offset())); } } @@ -3842,7 +3844,7 @@ Compile::Constant Compile::ConstantTable::add(MachConstantNode* n, MachOper* ope case T_OBJECT: case T_ADDRESS: value.l = (jobject) oper->constant(); break; case T_METADATA: return add((Metadata*)oper->constant()); break; - default: guarantee(false, err_msg_res("unhandled type: %s", type2name(type))); + default: guarantee(false, "unhandled type: %s", type2name(type)); } return add(n, type, value); } @@ -3864,7 +3866,7 @@ void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n if (Compile::current()->in_scratch_emit_size()) return; assert(labels.is_nonempty(), "must be"); - assert((uint) labels.length() == n->outcnt(), err_msg_res("must be equal: %d == %d", labels.length(), n->outcnt())); + assert((uint) labels.length() == n->outcnt(), "must be equal: %d == %d", labels.length(), n->outcnt()); // Since MachConstantNode::constant_offset() also contains // table_base_offset() we need to subtract the table_base_offset() @@ -3876,7 +3878,7 @@ void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n for (uint i = 0; i < n->outcnt(); i++) { address* constant_addr = &jump_table_base[i]; - assert(*constant_addr == (((address) n) + i), err_msg_res("all jump-table entries must contain adjusted node pointer: " INTPTR_FORMAT " == " INTPTR_FORMAT, p2i(*constant_addr), p2i(((address) n) + i))); + assert(*constant_addr == (((address) n) + i), "all jump-table entries must contain adjusted node pointer: " INTPTR_FORMAT " == " INTPTR_FORMAT, p2i(*constant_addr), p2i(((address) n) + i)); *constant_addr = cb.consts()->target(*labels.at(i), (address) constant_addr); cb.consts()->relocate((address) constant_addr, relocInfo::internal_word_type); } @@ -4135,7 +4137,7 @@ int Compile::cmp_expensive_nodes(Node* n1, Node* n2) { if (n1->Opcode() < n2->Opcode()) return -1; else if (n1->Opcode() > n2->Opcode()) return 1; - assert(n1->req() == n2->req(), err_msg_res("can't compare %s nodes: n1->req() = %d, n2->req() = %d", NodeClassNames[n1->Opcode()], n1->req(), n2->req())); + assert(n1->req() == n2->req(), "can't compare %s nodes: n1->req() = %d, n2->req() = %d", NodeClassNames[n1->Opcode()], n1->req(), n2->req()); for (uint i = 1; i < n1->req(); i++) { if (n1->in(i) < n2->in(i)) return -1; else if (n1->in(i) > n2->in(i)) return 1; diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index bb8dc442a89..eb09b285789 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -843,7 +843,7 @@ class Compile : public Phase { } uint live_nodes() const { int val = _unique - _dead_node_count; - assert (val >= 0, err_msg_res("number of tracked dead nodes %d more than created nodes %d", _unique, _dead_node_count)); + assert (val >= 0, "number of tracked dead nodes %d more than created nodes %d", _unique, _dead_node_count); return (uint) val; } #ifdef ASSERT @@ -1208,12 +1208,6 @@ class Compile : public Phase { // Compute the name of old_SP. See .ad for frame layout. OptoReg::Name compute_old_SP(); -#ifdef ENABLE_ZAP_DEAD_LOCALS - static bool is_node_getting_a_safepoint(Node*); - void Insert_zap_nodes(); - Node* call_zap_node(MachSafePointNode* n, int block_no); -#endif - private: // Phase control: void Init(int aliaslevel); // Prepare for a single compilation diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp index c38d0bf074d..08801c70994 100644 --- a/hotspot/src/share/vm/opto/doCall.cpp +++ b/hotspot/src/share/vm/opto/doCall.cpp @@ -599,9 +599,9 @@ void Parse::do_call() { pop_node(rt); // whatever it was, pop it } else if (rt == T_INT || is_subword_type(rt)) { // Nothing. These cases are handled in lambda form bytecode. - assert(ct == T_INT || is_subword_type(ct), err_msg_res("must match: rt=%s, ct=%s", type2name(rt), type2name(ct))); + assert(ct == T_INT || is_subword_type(ct), "must match: rt=%s, ct=%s", type2name(rt), type2name(ct)); } else if (rt == T_OBJECT || rt == T_ARRAY) { - assert(ct == T_OBJECT || ct == T_ARRAY, err_msg_res("rt=%s, ct=%s", type2name(rt), type2name(ct))); + assert(ct == T_OBJECT || ct == T_ARRAY, "rt=%s, ct=%s", type2name(rt), type2name(ct)); if (ctype->is_loaded()) { const TypeOopPtr* arg_type = TypeOopPtr::make_from_klass(rtype->as_klass()); const Type* sig_type = TypeOopPtr::make_from_klass(ctype->as_klass()); @@ -612,7 +612,7 @@ void Parse::do_call() { } } } else { - assert(rt == ct, err_msg_res("unexpected mismatch: rt=%s, ct=%s", type2name(rt), type2name(ct))); + assert(rt == ct, "unexpected mismatch: rt=%s, ct=%s", type2name(rt), type2name(ct)); // push a zero; it's better than getting an oop/int mismatch pop_node(rt); Node* retnode = zerocon(ct); @@ -628,7 +628,7 @@ void Parse::do_call() { // can appear to be "loaded" by different loaders (depending on // the accessing class). assert(!rtype->is_loaded() || !ctype->is_loaded() || rtype == ctype, - err_msg_res("mismatched return types: rtype=%s, ctype=%s", rtype->name(), ctype->name())); + "mismatched return types: rtype=%s, ctype=%s", rtype->name(), ctype->name()); } // If the return type of the method is not loaded, assert that the diff --git a/hotspot/src/share/vm/opto/domgraph.cpp b/hotspot/src/share/vm/opto/domgraph.cpp index 3b21df0ce1d..c285738ac6b 100644 --- a/hotspot/src/share/vm/opto/domgraph.cpp +++ b/hotspot/src/share/vm/opto/domgraph.cpp @@ -506,7 +506,7 @@ void PhaseIdealLoop::Dominators() { // Perform DFS search. Setup 'vertex' as DFS to vertex mapping. Setup // 'semi' as vertex to DFS mapping. Set 'parent' to DFS parent. int NTarjan::DFS( NTarjan *ntarjan, VectorSet &visited, PhaseIdealLoop *pil, uint *dfsorder) { - // Allocate stack of size C->unique()/8 to avoid frequent realloc + // Allocate stack of size C->live_nodes()/8 to avoid frequent realloc GrowableArray dfstack(pil->C->live_nodes() >> 3); Node *b = pil->C->root(); int dfsnum = 1; diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index c4aeab03365..f1db509489d 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -982,7 +982,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "montgomery_square") == 0) ))) { call->dump(); - fatal(err_msg_res("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name)); + fatal("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name); } #endif // Always process arraycopy's destination object since @@ -1201,8 +1201,8 @@ bool ConnectionGraph::complete_connection_graph( C->log()->text("%s", timeout ? "time" : "iterations"); C->log()->end_elem(" limit'"); } - assert(ExitEscapeAnalysisOnTimeout, err_msg_res("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d", - time.seconds(), iterations, nodes_size(), ptnodes_worklist.length())); + assert(ExitEscapeAnalysisOnTimeout, "infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d", + time.seconds(), iterations, nodes_size(), ptnodes_worklist.length()); // Possible infinite build_connection_graph loop, // bailout (no changes to ideal graph were made). return false; diff --git a/hotspot/src/share/vm/opto/gcm.cpp b/hotspot/src/share/vm/opto/gcm.cpp index 744ecc77737..e73494b45e3 100644 --- a/hotspot/src/share/vm/opto/gcm.cpp +++ b/hotspot/src/share/vm/opto/gcm.cpp @@ -34,6 +34,7 @@ #include "opto/phaseX.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" +#include "opto/chaitin.hpp" #include "runtime/deoptimization.hpp" // Portions of code courtesy of Clifford Click @@ -1363,6 +1364,44 @@ void PhaseCFG::global_code_motion() { } } + bool block_size_threshold_ok = false; + intptr_t *recalc_pressure_nodes = NULL; + if (OptoRegScheduling) { + for (uint i = 0; i < number_of_blocks(); i++) { + Block* block = get_block(i); + if (block->number_of_nodes() > 10) { + block_size_threshold_ok = true; + break; + } + } + } + + // Enabling the scheduler for register pressure plus finding blocks of size to schedule for it + // is key to enabling this feature. + PhaseChaitin regalloc(C->unique(), *this, _matcher, true); + ResourceArea live_arena; // Arena for liveness + ResourceMark rm_live(&live_arena); + PhaseLive live(*this, regalloc._lrg_map.names(), &live_arena, true); + PhaseIFG ifg(&live_arena); + if (OptoRegScheduling && block_size_threshold_ok) { + regalloc.mark_ssa(); + Compile::TracePhase tp("computeLive", &timers[_t_computeLive]); + rm_live.reset_to_mark(); // Reclaim working storage + IndexSet::reset_memory(C, &live_arena); + uint node_size = regalloc._lrg_map.max_lrg_id(); + ifg.init(node_size); // Empty IFG + regalloc.set_ifg(ifg); + regalloc.set_live(live); + regalloc.gather_lrg_masks(false); // Collect LRG masks + live.compute(node_size); // Compute liveness + + recalc_pressure_nodes = NEW_RESOURCE_ARRAY(intptr_t, node_size); + for (uint i = 0; i < node_size; i++) { + recalc_pressure_nodes[i] = 0; + } + } + _regalloc = ®alloc; + #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print("\n---- Start Local Scheduling ----\n"); @@ -1375,13 +1414,15 @@ void PhaseCFG::global_code_motion() { visited.Clear(); for (uint i = 0; i < number_of_blocks(); i++) { Block* block = get_block(i); - if (!schedule_local(block, ready_cnt, visited)) { + if (!schedule_local(block, ready_cnt, visited, recalc_pressure_nodes)) { if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) { C->record_method_not_compilable("local schedule failed"); } + _regalloc = NULL; return; } } + _regalloc = NULL; // If we inserted any instructions between a Call and his CatchNode, // clone the instructions on all paths below the Catch. diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index f7842277063..3ccdcf6dbe3 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1251,7 +1251,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, } default: - fatal(err_msg_res("unexpected type: %s", type2name(type))); + fatal("unexpected type: %s", type2name(type)); } assert(chk != NULL, "sanity check"); chk = _gvn.transform(chk); @@ -1950,8 +1950,8 @@ void GraphKit::uncommon_trap(int trap_request, // the current bytecode. int inputs, ignored_depth; if (compute_stack_effects(inputs, ignored_depth)) { - assert(sp() >= inputs, err_msg_res("must have enough JVMS stack to execute %s: sp=%d, inputs=%d", - Bytecodes::name(java_bc()), sp(), inputs)); + assert(sp() >= inputs, "must have enough JVMS stack to execute %s: sp=%d, inputs=%d", + Bytecodes::name(java_bc()), sp(), inputs); } } #endif @@ -1987,7 +1987,7 @@ void GraphKit::uncommon_trap(int trap_request, case Deoptimization::Action_make_not_compilable: break; default: - fatal(err_msg_res("unknown action %d: %s", action, Deoptimization::trap_action_name(action))); + fatal("unknown action %d: %s", action, Deoptimization::trap_action_name(action)); break; #endif } @@ -2509,7 +2509,7 @@ static IfNode* gen_subtype_check_compare(Node* ctrl, Node* in1, Node* in2, BoolT switch(bt) { case T_INT: cmp = new CmpINode(in1, in2); break; case T_ADDRESS: cmp = new CmpPNode(in1, in2); break; - default: fatal(err_msg("unexpected comparison type %s", type2name(bt))); + default: fatal("unexpected comparison type %s", type2name(bt)); } gvn->transform(cmp); Node* bol = gvn->transform(new BoolNode(cmp, test)); diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index fbc34e1093e..24dbba08a11 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -136,7 +136,7 @@ class GraphKit : public Phase { _bci = jvms->bci(); _method = jvms->has_method() ? jvms->method() : NULL; } void set_map(SafePointNode* m) { _map = m; debug_only(verify_map()); } - void set_sp(int sp) { assert(sp >= 0, err_msg_res("sp must be non-negative: %d", sp)); _sp = sp; } + void set_sp(int sp) { assert(sp >= 0, "sp must be non-negative: %d", sp); _sp = sp; } void clean_stack(int from_sp); // clear garbage beyond from_sp to top void inc_sp(int i) { set_sp(sp() + i); } @@ -354,12 +354,12 @@ class GraphKit : public Phase { } Node* zero_check_int(Node* value) { assert(value->bottom_type()->basic_type() == T_INT, - err_msg_res("wrong type: %s", type2name(value->bottom_type()->basic_type()))); + "wrong type: %s", type2name(value->bottom_type()->basic_type())); return null_check_common(value, T_INT); } Node* zero_check_long(Node* value) { assert(value->bottom_type()->basic_type() == T_LONG, - err_msg_res("wrong type: %s", type2name(value->bottom_type()->basic_type()))); + "wrong type: %s", type2name(value->bottom_type()->basic_type())); return null_check_common(value, T_LONG); } // Throw an uncommon trap if a given value is __not__ null. diff --git a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp index 92a8629764f..6c03eaa1e2c 100644 --- a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp +++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp @@ -157,8 +157,8 @@ IdealGraphPrinter::IdealGraphPrinter() { } else { // It would be nice if we could shut down cleanly but it should // be an error if we can't connect to the visualizer. - fatal(err_msg_res("Couldn't connect to visualizer at %s:" INTX_FORMAT, - PrintIdealGraphAddress, PrintIdealGraphPort)); + fatal("Couldn't connect to visualizer at %s:" INTX_FORMAT, + PrintIdealGraphAddress, PrintIdealGraphPort); } } diff --git a/hotspot/src/share/vm/opto/ifg.cpp b/hotspot/src/share/vm/opto/ifg.cpp index f01cd40f7c9..b8b823e9d57 100644 --- a/hotspot/src/share/vm/opto/ifg.cpp +++ b/hotspot/src/share/vm/opto/ifg.cpp @@ -439,8 +439,10 @@ void PhaseChaitin::lower_pressure(Block* b, uint location, LRG& lrg, IndexSet* l } } } - assert(int_pressure.current_pressure() == count_int_pressure(liveout), "the int pressure is incorrect"); - assert(float_pressure.current_pressure() == count_float_pressure(liveout), "the float pressure is incorrect"); + if (_scheduling_info_generated == false) { + assert(int_pressure.current_pressure() == count_int_pressure(liveout), "the int pressure is incorrect"); + assert(float_pressure.current_pressure() == count_float_pressure(liveout), "the float pressure is incorrect"); + } } /* Go to the first non-phi index in a block */ @@ -517,6 +519,58 @@ void PhaseChaitin::compute_initial_block_pressure(Block* b, IndexSet* liveout, P assert(float_pressure.current_pressure() == count_float_pressure(liveout), "the float pressure is incorrect"); } +/* +* Computes the entry register pressure of a block, looking at all live +* ranges in the livein. The register pressure is computed for both float +* and int/pointer registers. +*/ +void PhaseChaitin::compute_entry_block_pressure(Block* b) { + IndexSet* livein = _live->livein(b); + IndexSetIterator elements(livein); + uint lid = elements.next(); + while (lid != 0) { + LRG& lrg = lrgs(lid); + raise_pressure(b, lrg, _sched_int_pressure, _sched_float_pressure); + lid = elements.next(); + } + // Now check phis for locally defined inputs + for (uint j = 0; j < b->number_of_nodes(); j++) { + Node* n = b->get_node(j); + if (n->is_Phi()) { + for (uint k = 1; k < n->req(); k++) { + Node* phi_in = n->in(k); + // Because we are talking about phis, raise register pressure once for each + // instance of a phi to account for a single value + if (_cfg.get_block_for_node(phi_in) == b) { + LRG& lrg = lrgs(phi_in->_idx); + raise_pressure(b, lrg, _sched_int_pressure, _sched_float_pressure); + break; + } + } + } + } + _sched_int_pressure.set_start_pressure(_sched_int_pressure.current_pressure()); + _sched_float_pressure.set_start_pressure(_sched_float_pressure.current_pressure()); +} + +/* +* Computes the exit register pressure of a block, looking at all live +* ranges in the liveout. The register pressure is computed for both float +* and int/pointer registers. +*/ +void PhaseChaitin::compute_exit_block_pressure(Block* b) { + IndexSet* livein = _live->live(b); + IndexSetIterator elements(livein); + _sched_int_pressure.set_current_pressure(0); + _sched_float_pressure.set_current_pressure(0); + uint lid = elements.next(); + while (lid != 0) { + LRG& lrg = lrgs(lid); + raise_pressure(b, lrg, _sched_int_pressure, _sched_float_pressure); + lid = elements.next(); + } +} + /* * Remove dead node if it's not used. * We only remove projection nodes if the node "defining" the projection is @@ -737,6 +791,16 @@ void PhaseChaitin::adjust_high_pressure_index(Block* b, uint& block_hrp_index, P block_hrp_index = i; } +void PhaseChaitin::print_pressure_info(Pressure& pressure, const char *str) { + if (str != NULL) { + tty->print_cr("# *** %s ***", str); + } + tty->print_cr("# start pressure is = %d", pressure.start_pressure()); + tty->print_cr("# max pressure is = %d", pressure.final_pressure()); + tty->print_cr("# end pressure is = %d", pressure.current_pressure()); + tty->print_cr("#"); +} + /* Build an interference graph: * That is, if 2 live ranges are simultaneously alive but in their acceptable * register sets do not overlap, then they do not interfere. The IFG is built diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index fc436985b93..01a21cd48e9 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -31,6 +31,7 @@ #include "opto/cfgnode.hpp" #include "opto/machnode.hpp" #include "opto/runtime.hpp" +#include "opto/chaitin.hpp" #include "runtime/sharedRuntime.hpp" // Optimization - Graph Style @@ -443,7 +444,13 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo // remaining cases (most), choose the instruction with the greatest latency // (that is, the most number of pseudo-cycles required to the end of the // routine). If there is a tie, choose the instruction with the most inputs. -Node* PhaseCFG::select(Block* block, Node_List &worklist, GrowableArray &ready_cnt, VectorSet &next_call, uint sched_slot) { +Node* PhaseCFG::select( + Block* block, + Node_List &worklist, + GrowableArray &ready_cnt, + VectorSet &next_call, + uint sched_slot, + intptr_t* recalc_pressure_nodes) { // If only a single entry on the stack, use it uint cnt = worklist.size(); @@ -458,6 +465,7 @@ Node* PhaseCFG::select(Block* block, Node_List &worklist, GrowableArray &re uint score = 0; // Bigger is better int idx = -1; // Index in worklist int cand_cnt = 0; // Candidate count + bool block_size_threshold_ok = (block->number_of_nodes() > 10) ? true : false; for( uint i=0; i &re } uint n_latency = get_latency_for_node(n); - uint n_score = n->req(); // Many inputs get high score to break ties + uint n_score = n->req(); // Many inputs get high score to break ties + + if (OptoRegScheduling && block_size_threshold_ok) { + if (recalc_pressure_nodes[n->_idx] == 0x7fff7fff) { + _regalloc->_scratch_int_pressure.init(_regalloc->_sched_int_pressure.high_pressure_limit()); + _regalloc->_scratch_float_pressure.init(_regalloc->_sched_float_pressure.high_pressure_limit()); + // simulate the notion that we just picked this node to schedule + n->add_flag(Node::Flag_is_scheduled); + // now caculate its effect upon the graph if we did + adjust_register_pressure(n, block, recalc_pressure_nodes, false); + // return its state for finalize in case somebody else wins + n->remove_flag(Node::Flag_is_scheduled); + // now save the two final pressure components of register pressure, limiting pressure calcs to short size + short int_pressure = (short)_regalloc->_scratch_int_pressure.current_pressure(); + short float_pressure = (short)_regalloc->_scratch_float_pressure.current_pressure(); + recalc_pressure_nodes[n->_idx] = int_pressure; + recalc_pressure_nodes[n->_idx] |= (float_pressure << 16); + } + + if (_scheduling_for_pressure) { + latency = n_latency; + if (n_choice != 3) { + // Now evaluate each register pressure component based on threshold in the score. + // In general the defining register type will dominate the score, ergo we will not see register pressure grow on both banks + // on a single instruction, but we might see it shrink on both banks. + // For each use of register that has a register class that is over the high pressure limit, we build n_score up for + // live ranges that terminate on this instruction. + if (_regalloc->_sched_int_pressure.current_pressure() > _regalloc->_sched_int_pressure.high_pressure_limit()) { + short int_pressure = (short)recalc_pressure_nodes[n->_idx]; + n_score = (int_pressure < 0) ? ((score + n_score) - int_pressure) : (int_pressure > 0) ? 1 : n_score; + } + if (_regalloc->_sched_float_pressure.current_pressure() > _regalloc->_sched_float_pressure.high_pressure_limit()) { + short float_pressure = (short)(recalc_pressure_nodes[n->_idx] >> 16); + n_score = (float_pressure < 0) ? ((score + n_score) - float_pressure) : (float_pressure > 0) ? 1 : n_score; + } + } else { + // make sure we choose these candidates + score = 0; + } + } + } // Keep best latency found cand_cnt++; @@ -562,6 +610,100 @@ Node* PhaseCFG::select(Block* block, Node_List &worklist, GrowableArray &re return n; } +//-------------------------adjust_register_pressure---------------------------- +void PhaseCFG::adjust_register_pressure(Node* n, Block* block, intptr_t* recalc_pressure_nodes, bool finalize_mode) { + PhaseLive* liveinfo = _regalloc->get_live(); + IndexSet* liveout = liveinfo->live(block); + // first adjust the register pressure for the sources + for (uint i = 1; i < n->req(); i++) { + bool lrg_ends = false; + Node *src_n = n->in(i); + if (src_n == NULL) continue; + if (!src_n->is_Mach()) continue; + uint src = _regalloc->_lrg_map.find(src_n); + if (src == 0) continue; + LRG& lrg_src = _regalloc->lrgs(src); + // detect if the live range ends or not + if (liveout->member(src) == false) { + lrg_ends = true; + for (DUIterator_Fast jmax, j = src_n->fast_outs(jmax); j < jmax; j++) { + Node* m = src_n->fast_out(j); // Get user + if (m == n) continue; + if (!m->is_Mach()) continue; + MachNode *mach = m->as_Mach(); + bool src_matches = false; + int iop = mach->ideal_Opcode(); + + switch (iop) { + case Op_StoreB: + case Op_StoreC: + case Op_StoreCM: + case Op_StoreD: + case Op_StoreF: + case Op_StoreI: + case Op_StoreL: + case Op_StoreP: + case Op_StoreN: + case Op_StoreVector: + case Op_StoreNKlass: + for (uint k = 1; k < m->req(); k++) { + Node *in = m->in(k); + if (in == src_n) { + src_matches = true; + break; + } + } + break; + + default: + src_matches = true; + break; + } + + // If we have a store as our use, ignore the non source operands + if (src_matches == false) continue; + + // Mark every unscheduled use which is not n with a recalculation + if ((get_block_for_node(m) == block) && (!m->is_scheduled())) { + if (finalize_mode && !m->is_Phi()) { + recalc_pressure_nodes[m->_idx] = 0x7fff7fff; + } + lrg_ends = false; + } + } + } + // if none, this live range ends and we can adjust register pressure + if (lrg_ends) { + if (finalize_mode) { + _regalloc->lower_pressure(block, 0, lrg_src, NULL, _regalloc->_sched_int_pressure, _regalloc->_sched_float_pressure); + } else { + _regalloc->lower_pressure(block, 0, lrg_src, NULL, _regalloc->_scratch_int_pressure, _regalloc->_scratch_float_pressure); + } + } + } + + // now add the register pressure from the dest and evaluate which heuristic we should use: + // 1.) The default, latency scheduling + // 2.) Register pressure scheduling based on the high pressure limit threshold for int or float register stacks + uint dst = _regalloc->_lrg_map.find(n); + if (dst != 0) { + LRG& lrg_dst = _regalloc->lrgs(dst); + if (finalize_mode) { + _regalloc->raise_pressure(block, lrg_dst, _regalloc->_sched_int_pressure, _regalloc->_sched_float_pressure); + // check to see if we fall over the register pressure cliff here + if (_regalloc->_sched_int_pressure.current_pressure() > _regalloc->_sched_int_pressure.high_pressure_limit()) { + _scheduling_for_pressure = true; + } else if (_regalloc->_sched_float_pressure.current_pressure() > _regalloc->_sched_float_pressure.high_pressure_limit()) { + _scheduling_for_pressure = true; + } else { + // restore latency scheduling mode + _scheduling_for_pressure = false; + } + } else { + _regalloc->raise_pressure(block, lrg_dst, _regalloc->_scratch_int_pressure, _regalloc->_scratch_float_pressure); + } + } +} //------------------------------set_next_call---------------------------------- void PhaseCFG::set_next_call(Block* block, Node* n, VectorSet& next_call) { @@ -644,7 +786,7 @@ uint PhaseCFG::sched_call(Block* block, uint node_cnt, Node_List& worklist, Grow continue; } if( m->is_Phi() ) continue; - int m_cnt = ready_cnt.at(m->_idx)-1; + int m_cnt = ready_cnt.at(m->_idx) - 1; ready_cnt.at_put(m->_idx, m_cnt); if( m_cnt == 0 ) worklist.push(m); @@ -711,7 +853,7 @@ uint PhaseCFG::sched_call(Block* block, uint node_cnt, Node_List& worklist, Grow //------------------------------schedule_local--------------------------------- // Topological sort within a block. Someday become a real scheduler. -bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, VectorSet& next_call) { +bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, VectorSet& next_call, intptr_t *recalc_pressure_nodes) { // Already "sorted" are the block start Node (as the first entry), and // the block-ending Node and any trailing control projections. We leave // these alone. PhiNodes and ParmNodes are made to follow the block start @@ -733,10 +875,24 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto return true; } + bool block_size_threshold_ok = (block->number_of_nodes() > 10) ? true : false; + + // We track the uses of local definitions as input dependences so that + // we know when a given instruction is avialable to be scheduled. + uint i; + if (OptoRegScheduling && block_size_threshold_ok) { + for (i = 1; i < block->number_of_nodes(); i++) { // setup nodes for pressure calc + Node *n = block->get_node(i); + n->remove_flag(Node::Flag_is_scheduled); + if (!n->is_Phi()) { + recalc_pressure_nodes[n->_idx] = 0x7fff7fff; + } + } + } + // Move PhiNodes and ParmNodes from 1 to cnt up to the start uint node_cnt = block->end_idx(); uint phi_cnt = 1; - uint i; for( i = 1; iget_node(i); if( n->is_Phi() || // Found a PhiNode or ParmNode @@ -744,6 +900,10 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto // Move guy at 'phi_cnt' to the end; makes a hole at phi_cnt block->map_node(block->get_node(phi_cnt), i); block->map_node(n, phi_cnt++); // swap Phi/Parm up front + if (OptoRegScheduling && block_size_threshold_ok) { + // mark n as scheduled + n->add_flag(Node::Flag_is_scheduled); + } } else { // All others // Count block-local inputs to 'n' uint cnt = n->len(); // Input count @@ -791,12 +951,18 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto // All the prescheduled guys do not hold back internal nodes uint i3; - for(i3 = 0; i3get_node(i3); // Get pre-scheduled for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) { Node* m = n->fast_out(j); if (get_block_for_node(m) == block) { // Local-block user int m_cnt = ready_cnt.at(m->_idx)-1; + if (OptoRegScheduling && block_size_threshold_ok) { + // mark m as scheduled + if (m_cnt < 0) { + m->add_flag(Node::Flag_is_scheduled); + } + } ready_cnt.at_put(m->_idx, m_cnt); // Fix ready count } } @@ -827,6 +993,18 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto worklist.push(d); } + if (OptoRegScheduling && block_size_threshold_ok) { + // To stage register pressure calculations we need to examine the live set variables + // breaking them up by register class to compartmentalize the calculations. + uint float_pressure = Matcher::float_pressure(FLOATPRESSURE); + _regalloc->_sched_int_pressure.init(INTPRESSURE); + _regalloc->_sched_float_pressure.init(float_pressure); + _regalloc->_scratch_int_pressure.init(INTPRESSURE); + _regalloc->_scratch_float_pressure.init(float_pressure); + + _regalloc->compute_entry_block_pressure(block); + } + // Warm up the 'next_call' heuristic bits needed_for_next_call(block, block->head(), next_call); @@ -858,9 +1036,18 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto #endif // Select and pop a ready guy from worklist - Node* n = select(block, worklist, ready_cnt, next_call, phi_cnt); + Node* n = select(block, worklist, ready_cnt, next_call, phi_cnt, recalc_pressure_nodes); block->map_node(n, phi_cnt++); // Schedule him next + if (OptoRegScheduling && block_size_threshold_ok) { + n->add_flag(Node::Flag_is_scheduled); + + // Now adjust the resister pressure with the node we selected + if (!n->is_Phi()) { + adjust_register_pressure(n, block, recalc_pressure_nodes, true); + } + } + #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print("# select %d: %s", n->_idx, n->Name()); @@ -906,7 +1093,7 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto assert(m->is_MachProj() && n->is_Mach() && n->as_Mach()->has_call(), "unexpected node types"); continue; } - int m_cnt = ready_cnt.at(m->_idx)-1; + int m_cnt = ready_cnt.at(m->_idx) - 1; ready_cnt.at_put(m->_idx, m_cnt); if( m_cnt == 0 ) worklist.push(m); @@ -925,6 +1112,12 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto return false; } + if (OptoRegScheduling && block_size_threshold_ok) { + _regalloc->compute_exit_block_pressure(block); + block->_reg_pressure = _regalloc->_sched_int_pressure.final_pressure(); + block->_freg_pressure = _regalloc->_sched_float_pressure.final_pressure(); + } + #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print_cr("#"); @@ -933,11 +1126,17 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto tty->print("# "); block->get_node(i)->fast_dump(); } + tty->print_cr("# "); + + if (OptoRegScheduling && block_size_threshold_ok) { + tty->print_cr("# pressure info : %d", block->_pre_order); + _regalloc->print_pressure_info(_regalloc->_sched_int_pressure, "int register info"); + _regalloc->print_pressure_info(_regalloc->_sched_float_pressure, "float register info"); + } tty->cr(); } #endif - return true; } diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index ce5d0aeeb1c..2c4b22423b7 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -133,7 +133,7 @@ class LibraryCallKit : public GraphKit { private: void fatal_unexpected_iid(vmIntrinsics::ID iid) { - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); } void set_result(Node* n) { assert(_result == NULL, "only set once"); _result = n; } @@ -222,7 +222,6 @@ class LibraryCallKit : public GraphKit { bool inline_math_negateExactL(); bool inline_math_subtractExactI(bool is_decrement); bool inline_math_subtractExactL(bool is_decrement); - bool inline_exp(); bool inline_pow(); Node* finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName); bool inline_min_max(vmIntrinsics::ID id); @@ -1535,20 +1534,6 @@ Node* LibraryCallKit::finish_pow_exp(Node* result, Node* x, Node* y, const TypeF } } -//------------------------------inline_exp------------------------------------- -// Inline exp instructions, if possible. The Intel hardware only misses -// really odd corner cases (+/- Infinity). Just uncommon-trap them. -bool LibraryCallKit::inline_exp() { - Node* arg = round_double_node(argument(0)); - Node* n = _gvn.transform(new ExpDNode(C, control(), arg)); - - n = finish_pow_exp(n, arg, NULL, OptoRuntime::Math_D_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::dexp), "EXP"); - set_result(n); - - C->set_has_split_ifs(true); // Has chance for split-if optimization - return true; -} - //------------------------------inline_pow------------------------------------- // Inline power instructions, if possible. bool LibraryCallKit::inline_pow() { @@ -1776,8 +1761,10 @@ bool LibraryCallKit::inline_math_native(vmIntrinsics::ID id) { case vmIntrinsics::_dsqrt: return Matcher::match_rule_supported(Op_SqrtD) ? inline_math(id) : false; case vmIntrinsics::_dabs: return Matcher::has_match_rule(Op_AbsD) ? inline_math(id) : false; - case vmIntrinsics::_dexp: return Matcher::has_match_rule(Op_ExpD) ? inline_exp() : - runtime_math(OptoRuntime::Math_D_D_Type(), FN_PTR(SharedRuntime::dexp), "EXP"); + case vmIntrinsics::_dexp: + return StubRoutines::dexp() != NULL ? + runtime_math(OptoRuntime::Math_D_D_Type(), StubRoutines::dexp(), "dexp") : + runtime_math(OptoRuntime::Math_D_D_Type(), FN_PTR(SharedRuntime::dexp), "EXP"); case vmIntrinsics::_dpow: return Matcher::has_match_rule(Op_PowD) ? inline_pow() : runtime_math(OptoRuntime::Math_DD_D_Type(), FN_PTR(SharedRuntime::dpow), "POW"); #undef FN_PTR @@ -2466,7 +2453,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas p = ConvX2UL(p); break; default: - fatal(err_msg_res("unexpected type %d: %s", type, type2name(type))); + fatal("unexpected type %d: %s", type, type2name(type)); break; } } @@ -2755,7 +2742,7 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind } break; default: - fatal(err_msg_res("unexpected type %d: %s", type, type2name(type))); + fatal("unexpected type %d: %s", type, type2name(type)); break; } @@ -3807,7 +3794,7 @@ Node* LibraryCallKit::generate_virtual_guard(Node* obj_klass, ciMethod* method = callee(); int vtable_index = method->vtable_index(); assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index, - err_msg_res("bad index %d", vtable_index)); + "bad index %d", vtable_index); // Get the Method* out of the appropriate vtable entry. int entry_offset = (InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size()) * wordSize + @@ -3859,7 +3846,7 @@ LibraryCallKit::generate_method_call(vmIntrinsics::ID method_id, bool is_virtual // No need to use the linkResolver to get it. vtable_index = method->vtable_index(); assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index, - err_msg_res("bad index %d", vtable_index)); + "bad index %d", vtable_index); } slow_call = new CallDynamicJavaNode(tf, SharedRuntime::get_resolve_virtual_call_stub(), @@ -6131,7 +6118,7 @@ bool LibraryCallKit::inline_digestBase_implCompressMB(int predicate) { } break; default: - fatal(err_msg_res("unknown SHA intrinsic predicate: %d", predicate)); + fatal("unknown SHA intrinsic predicate: %d", predicate); } if (klass_SHA_name != NULL) { // get DigestBase klass to lookup for SHA klass @@ -6236,7 +6223,7 @@ Node* LibraryCallKit::inline_digestBase_implCompressMB_predicate(int predicate) } break; default: - fatal(err_msg_res("unknown SHA intrinsic predicate: %d", predicate)); + fatal("unknown SHA intrinsic predicate: %d", predicate); } ciKlass* klass_SHA = NULL; diff --git a/hotspot/src/share/vm/opto/live.cpp b/hotspot/src/share/vm/opto/live.cpp index 787f5ab88c3..633a00ca82c 100644 --- a/hotspot/src/share/vm/opto/live.cpp +++ b/hotspot/src/share/vm/opto/live.cpp @@ -41,7 +41,14 @@ // block is put on the worklist. // The locally live-in stuff is computed once and added to predecessor // live-out sets. This separate compilation is done in the outer loop below. -PhaseLive::PhaseLive( const PhaseCFG &cfg, const LRG_List &names, Arena *arena ) : Phase(LIVE), _cfg(cfg), _names(names), _arena(arena), _live(0) { +PhaseLive::PhaseLive(const PhaseCFG &cfg, const LRG_List &names, Arena *arena, bool keep_deltas) + : Phase(LIVE), + _cfg(cfg), + _names(names), + _arena(arena), + _live(0), + _livein(0), + _keep_deltas(keep_deltas) { } void PhaseLive::compute(uint maxlrg) { @@ -56,6 +63,13 @@ void PhaseLive::compute(uint maxlrg) { _live[i].initialize(_maxlrg); } + if (_keep_deltas) { + _livein = (IndexSet*)_arena->Amalloc(sizeof(IndexSet) * _cfg.number_of_blocks()); + for (i = 0; i < _cfg.number_of_blocks(); i++) { + _livein[i].initialize(_maxlrg); + } + } + // Init the sparse arrays for delta-sets. ResourceMark rm; // Nuke temp storage on exit @@ -124,7 +138,10 @@ void PhaseLive::compute(uint maxlrg) { // PhiNode uses go in the live-out set of prior blocks. for (uint k = i; k > 0; k--) { - add_liveout(p, _names.at(block->get_node(k-1)->in(l)->_idx), first_pass); + Node *phi = block->get_node(k - 1); + if (l < phi->req()) { + add_liveout(p, _names.at(phi->in(l)->_idx), first_pass); + } } } freeset(block); @@ -200,8 +217,11 @@ IndexSet *PhaseLive::getfreeset( ) { } // Free an IndexSet from a block. -void PhaseLive::freeset( const Block *p ) { +void PhaseLive::freeset( Block *p ) { IndexSet *f = _deltas[p->_pre_order-1]; + if ( _keep_deltas ) { + add_livein(p, f); + } f->set_next(_free_IndexSet); _free_IndexSet = f; // Drop onto free list _deltas[p->_pre_order-1] = NULL; @@ -249,10 +269,23 @@ void PhaseLive::add_liveout( Block *p, IndexSet *lo, VectorSet &first_pass ) { } } +// Add a vector of live-in values to a given blocks live-in set. +void PhaseLive::add_livein(Block *p, IndexSet *lo) { + IndexSet *livein = &_livein[p->_pre_order-1]; + IndexSetIterator elements(lo); + uint r; + while ((r = elements.next()) != 0) { + livein->insert(r); // Then add to live-in set + } +} + #ifndef PRODUCT // Dump the live-out set for a block void PhaseLive::dump( const Block *b ) const { tty->print("Block %d: ",b->_pre_order); + if ( _keep_deltas ) { + tty->print("LiveIn: "); _livein[b->_pre_order-1].dump(); + } tty->print("LiveOut: "); _live[b->_pre_order-1].dump(); uint cnt = b->number_of_nodes(); for( uint i=0; i LRG_List; class PhaseLive : public Phase { // Array of Sets of values live at the start of a block. // Indexed by block pre-order number. - IndexSet *_live; + IndexSet *_live; // live out + IndexSet *_livein; // live in // Array of Sets of values defined locally in the block // Indexed by block pre-order number. @@ -62,15 +63,17 @@ class PhaseLive : public Phase { const LRG_List &_names; // Mapping from Nodes to live ranges uint _maxlrg; // Largest live-range number Arena *_arena; + bool _keep_deltas; // Retain live in information IndexSet *getset( Block *p ); IndexSet *getfreeset( ); - void freeset( const Block *p ); + void freeset( Block *p ); void add_liveout( Block *p, uint r, VectorSet &first_pass ); void add_liveout( Block *p, IndexSet *lo, VectorSet &first_pass ); + void add_livein( Block *p, IndexSet *lo ); public: - PhaseLive(const PhaseCFG &cfg, const LRG_List &names, Arena *arena); + PhaseLive(const PhaseCFG &cfg, const LRG_List &names, Arena *arena, bool keep_deltas); ~PhaseLive() {} // Compute liveness info void compute(uint maxlrg); @@ -79,6 +82,7 @@ public: // Return the live-out set for this block IndexSet *live( const Block * b ) { return &_live[b->_pre_order-1]; } + IndexSet *livein( const Block * b ) { return &_livein[b->_pre_order - 1]; } #ifndef PRODUCT void dump( const Block *b ) const; diff --git a/hotspot/src/share/vm/opto/loopUnswitch.cpp b/hotspot/src/share/vm/opto/loopUnswitch.cpp index a13b9fb5e1f..49e1052a2cd 100644 --- a/hotspot/src/share/vm/opto/loopUnswitch.cpp +++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp @@ -263,3 +263,136 @@ ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop, return iffast; } + +LoopNode* PhaseIdealLoop::create_reserve_version_of_loop(IdealLoopTree *loop, CountedLoopReserveKit* lk) { + Node_List old_new; + LoopNode* head = loop->_head->as_Loop(); + bool counted_loop = head->is_CountedLoop(); + Node* entry = head->in(LoopNode::EntryControl); + _igvn.rehash_node_delayed(entry); + IdealLoopTree* outer_loop = loop->_parent; + + ConINode* const_1 = _igvn.intcon(1); + set_ctrl(const_1, C->root()); + IfNode* iff = new IfNode(entry, const_1, PROB_MAX, COUNT_UNKNOWN); + register_node(iff, outer_loop, entry, dom_depth(entry)); + ProjNode* iffast = new IfTrueNode(iff); + register_node(iffast, outer_loop, iff, dom_depth(iff)); + ProjNode* ifslow = new IfFalseNode(iff); + register_node(ifslow, outer_loop, iff, dom_depth(iff)); + + // Clone the loop body. The clone becomes the fast loop. The + // original pre-header will (illegally) have 3 control users + // (old & new loops & new if). + clone_loop(loop, old_new, dom_depth(head), iff); + assert(old_new[head->_idx]->is_Loop(), "" ); + + LoopNode* slow_head = old_new[head->_idx]->as_Loop(); + +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print_cr("PhaseIdealLoop::create_reserve_version_of_loop:"); + tty->print("\t iff = %d, ", iff->_idx); iff->dump(); + tty->print("\t iffast = %d, ", iffast->_idx); iffast->dump(); + tty->print("\t ifslow = %d, ", ifslow->_idx); ifslow->dump(); + tty->print("\t before replace_input_of: head = %d, ", head->_idx); head->dump(); + tty->print("\t before replace_input_of: slow_head = %d, ", slow_head->_idx); slow_head->dump(); + } +#endif + + // Fast (true) control + _igvn.replace_input_of(head, LoopNode::EntryControl, iffast); + // Slow (false) control + _igvn.replace_input_of(slow_head, LoopNode::EntryControl, ifslow); + + recompute_dom_depth(); + + lk->set_iff(iff); + +#ifndef PRODUCT + if (TraceLoopOpts ) { + tty->print("\t after replace_input_of: head = %d, ", head->_idx); head->dump(); + tty->print("\t after replace_input_of: slow_head = %d, ", slow_head->_idx); slow_head->dump(); + } +#endif + + return slow_head->as_Loop(); +} + +CountedLoopReserveKit::CountedLoopReserveKit(PhaseIdealLoop* phase, IdealLoopTree *loop, bool active = true) : + _phase(phase), + _lpt(loop), + _lp(NULL), + _iff(NULL), + _lp_reserved(NULL), + _has_reserved(false), + _use_new(false), + _active(active) + { + create_reserve(); + }; + +CountedLoopReserveKit::~CountedLoopReserveKit() { + if (!_active) { + return; + } + + if (_has_reserved && !_use_new) { + // intcon(0)->iff-node reverts CF to the reserved copy + ConINode* const_0 = _phase->_igvn.intcon(0); + _phase->set_ctrl(const_0, _phase->C->root()); + _iff->set_req(1, const_0); + + #ifndef PRODUCT + if (TraceLoopOpts) { + tty->print_cr("CountedLoopReserveKit::~CountedLoopReserveKit()"); + tty->print("\t discard loop %d and revert to the reserved loop clone %d: ", _lp->_idx, _lp_reserved->_idx); + _lp_reserved->dump(); + } + #endif + } +} + +bool CountedLoopReserveKit::create_reserve() { + if (!_active) { + return false; + } + + if(!_lpt->_head->is_CountedLoop()) { + NOT_PRODUCT(if(TraceLoopOpts) {tty->print_cr("CountedLoopReserveKit::create_reserve: %d not counted loop", _lpt->_head->_idx);}) + return false; + } + CountedLoopNode *cl = _lpt->_head->as_CountedLoop(); + if (!cl->is_valid_counted_loop()) { + NOT_PRODUCT(if(TraceLoopOpts) {tty->print_cr("CountedLoopReserveKit::create_reserve: %d not valid counted loop", cl->_idx);}) + return false; // skip malformed counted loop + } + if (!cl->is_main_loop()) { + NOT_PRODUCT(if(TraceLoopOpts) {tty->print_cr("CountedLoopReserveKit::create_reserve: %d not main loop", cl->_idx);}) + return false; // skip normal, pre, and post loops + } + + _lp = _lpt->_head->as_Loop(); + _lp_reserved = _phase->create_reserve_version_of_loop(_lpt, this); + + if (!_lp_reserved->is_CountedLoop()) { + return false; + } + + Node* ifslow_pred = _lp_reserved->as_CountedLoop()->in(LoopNode::EntryControl); + + if (!ifslow_pred->is_IfFalse()) { + return false; + } + + Node* iff = ifslow_pred->in(0); + if (!iff->is_If() || iff != _iff) { + return false; + } + + if (iff->in(1)->Opcode() != Op_ConI) { + return false; + } + + return _has_reserved = true; +} diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index f0216d7586c..2f948ebd669 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -38,6 +38,7 @@ class IdealLoopTree; class LoopNode; class Node; class PhaseIdealLoop; +class CountedLoopReserveKit; class VectorSet; class Invariance; struct small_cache; @@ -290,6 +291,7 @@ public: if (phi() == NULL) { return NULL; } + assert(phi()->is_Phi(), "should be PhiNode"); Node *ln = phi()->in(0); if (ln->is_CountedLoop() && ln->as_CountedLoop()->loopexit() == this) { return (CountedLoopNode*)ln; @@ -528,6 +530,8 @@ public: class PhaseIdealLoop : public PhaseTransform { friend class IdealLoopTree; friend class SuperWord; + friend class CountedLoopReserveKit; + // Pre-computed def-use info PhaseIterGVN &_igvn; @@ -964,6 +968,16 @@ public: ProjNode* create_slow_version_of_loop(IdealLoopTree *loop, Node_List &old_new); + // Clone a loop and return the clone head (clone_loop_head). + // Added nodes include int(1), int(0) - disconnected, If, IfTrue, IfFalse, + // This routine was created for usage in CountedLoopReserveKit. + // + // int(1) -> If -> IfTrue -> original_loop_head + // | + // V + // IfFalse -> clone_loop_head (returned by function pointer) + // + LoopNode* create_reserve_version_of_loop(IdealLoopTree *loop, CountedLoopReserveKit* lk); // Clone loop with an invariant test (that does not exit) and // insert a clone of the test that selects which version to // execute. @@ -1116,6 +1130,68 @@ public: #endif }; +// This kit may be used for making of a reserved copy of a loop before this loop +// goes under non-reversible changes. +// +// Function create_reserve() creates a reserved copy (clone) of the loop. +// The reserved copy is created by calling +// PhaseIdealLoop::create_reserve_version_of_loop - see there how +// the original and reserved loops are connected in the outer graph. +// If create_reserve succeeded, it returns 'true' and _has_reserved is set to 'true'. +// +// By default the reserved copy (clone) of the loop is created as dead code - it is +// dominated in the outer loop by this node chain: +// intcon(1)->If->IfFalse->reserved_copy. +// The original loop is dominated by the the same node chain but IfTrue projection: +// intcon(1)->If->IfTrue->original_loop. +// +// In this implementation of CountedLoopReserveKit the ctor includes create_reserve() +// and the dtor, checks _use_new value. +// If _use_new == false, it "switches" control to reserved copy of the loop +// by simple replacing of node intcon(1) with node intcon(0). +// +// Here is a proposed example of usage (see also SuperWord::output in superword.cpp). +// +// void CountedLoopReserveKit_example() +// { +// CountedLoopReserveKit lrk((phase, lpt, DoReserveCopy = true); // create local object +// if (DoReserveCopy && !lrk.has_reserved()) { +// return; //failed to create reserved loop copy +// } +// ... +// //something is wrong, switch to original loop +/// if(something_is_wrong) return; // ~CountedLoopReserveKit makes the switch +// ... +// //everything worked ok, return with the newly modified loop +// lrk.use_new(); +// return; // ~CountedLoopReserveKit does nothing once use_new() was called +// } +// +// Keep in mind, that by default if create_reserve() is not followed by use_new() +// the dtor will "switch to the original" loop. +// NOTE. You you modify outside of the original loop this class is no help. +// +class CountedLoopReserveKit { + private: + PhaseIdealLoop* _phase; + IdealLoopTree* _lpt; + LoopNode* _lp; + IfNode* _iff; + LoopNode* _lp_reserved; + bool _has_reserved; + bool _use_new; + const bool _active; //may be set to false in ctor, then the object is dummy + + public: + CountedLoopReserveKit(PhaseIdealLoop* phase, IdealLoopTree *loop, bool active); + ~CountedLoopReserveKit(); + void use_new() {_use_new = true;} + void set_iff(IfNode* x) {_iff = x;} + bool has_reserved() const { return _active && _has_reserved;} + private: + bool create_reserve(); +};// class CountedLoopReserveKit + inline Node* IdealLoopTree::tail() { // Handle lazy update of _tail field Node *n = _tail; diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp index e2db269467f..252ce70dc62 100644 --- a/hotspot/src/share/vm/opto/loopopts.cpp +++ b/hotspot/src/share/vm/opto/loopopts.cpp @@ -447,21 +447,21 @@ Node *PhaseIdealLoop::remix_address_expressions( Node *n ) { } // Replace (I1 +p (I2 + V)) with ((I1 +p I2) +p V) - if( n2_loop != n_loop && n3_loop == n_loop ) { - if( n->in(3)->Opcode() == Op_AddI ) { + if (n2_loop != n_loop && n3_loop == n_loop) { + if (n->in(3)->Opcode() == Op_AddX) { Node *V = n->in(3)->in(1); Node *I = n->in(3)->in(2); - if( is_member(n_loop,get_ctrl(V)) ) { + if (is_member(n_loop,get_ctrl(V))) { } else { Node *tmp = V; V = I; I = tmp; } - if( !is_member(n_loop,get_ctrl(I)) ) { - Node *add1 = new AddPNode( n->in(1), n->in(2), I ); + if (!is_member(n_loop,get_ctrl(I))) { + Node *add1 = new AddPNode(n->in(1), n->in(2), I); // Stuff new AddP in the loop preheader - register_new_node( add1, n_loop->_head->in(LoopNode::EntryControl) ); - Node *add2 = new AddPNode( n->in(1), add1, V ); - register_new_node( add2, n_ctrl ); - _igvn.replace_node( n, add2 ); + register_new_node(add1, n_loop->_head->in(LoopNode::EntryControl)); + Node *add2 = new AddPNode(n->in(1), add1, V); + register_new_node(add2, n_ctrl); + _igvn.replace_node(n, add2); return add2; } } @@ -653,7 +653,6 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { return iff->in(1); } -#ifdef ASSERT static void enqueue_cfg_uses(Node* m, Unique_Node_List& wq) { for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) { Node* u = m->fast_out(i); @@ -667,7 +666,6 @@ static void enqueue_cfg_uses(Node* m, Unique_Node_List& wq) { } } } -#endif // Try moving a store out of a loop, right before the loop Node* PhaseIdealLoop::try_move_store_before_loop(Node* n, Node *n_ctrl) { @@ -687,11 +685,15 @@ Node* PhaseIdealLoop::try_move_store_before_loop(Node* n, Node *n_ctrl) { // written at iteration i by the second store could be overwritten // at iteration i+n by the first store: it's not safe to move the // first store out of the loop - // - nothing must observe the Phi memory: it guarantees no read - // before the store and no early exit out of the loop - // With those conditions, we are also guaranteed the store post - // dominates the loop head. Otherwise there would be extra Phi - // involved between the loop's Phi and the store. + // - nothing must observe the memory Phi: it guarantees no read + // before the store, we are also guaranteed the store post + // dominates the loop head (ignoring a possible early + // exit). Otherwise there would be extra Phi involved between the + // loop's Phi and the store. + // - there must be no early exit from the loop before the Store + // (such an exit most of the time would be an extra use of the + // memory Phi but sometimes is a bottom memory Phi that takes the + // store as input). if (!n_loop->is_member(address_loop) && !n_loop->is_member(value_loop) && @@ -699,9 +701,10 @@ Node* PhaseIdealLoop::try_move_store_before_loop(Node* n, Node *n_ctrl) { mem->outcnt() == 1 && mem->in(LoopNode::LoopBackControl) == n) { -#ifdef ASSERT - // Verify that store's control does post dominate loop entry and - // that there's no early exit of the loop before the store. + assert(n_loop->_tail != NULL, "need a tail"); + assert(is_dominator(n_ctrl, n_loop->_tail), "store control must not be in a branch in the loop"); + + // Verify that there's no early exit of the loop before the store. bool ctrl_ok = false; { // Follow control from loop head until n, we exit the loop or @@ -709,7 +712,7 @@ Node* PhaseIdealLoop::try_move_store_before_loop(Node* n, Node *n_ctrl) { ResourceMark rm; Unique_Node_List wq; wq.push(n_loop->_head); - assert(n_loop->_tail != NULL, "need a tail"); + for (uint next = 0; next < wq.size(); ++next) { Node *m = wq.at(next); if (m == n->in(0)) { @@ -722,24 +725,27 @@ Node* PhaseIdealLoop::try_move_store_before_loop(Node* n, Node *n_ctrl) { break; } enqueue_cfg_uses(m, wq); + if (wq.size() > 10) { + ctrl_ok = false; + break; + } } } - assert(ctrl_ok, "bad control"); -#endif + if (ctrl_ok) { + // move the Store + _igvn.replace_input_of(mem, LoopNode::LoopBackControl, mem); + _igvn.replace_input_of(n, 0, n_loop->_head->in(LoopNode::EntryControl)); + _igvn.replace_input_of(n, MemNode::Memory, mem->in(LoopNode::EntryControl)); + // Disconnect the phi now. An empty phi can confuse other + // optimizations in this pass of loop opts. + _igvn.replace_node(mem, mem->in(LoopNode::EntryControl)); + n_loop->_body.yank(mem); - // move the Store - _igvn.replace_input_of(mem, LoopNode::LoopBackControl, mem); - _igvn.replace_input_of(n, 0, n_loop->_head->in(LoopNode::EntryControl)); - _igvn.replace_input_of(n, MemNode::Memory, mem->in(LoopNode::EntryControl)); - // Disconnect the phi now. An empty phi can confuse other - // optimizations in this pass of loop opts. - _igvn.replace_node(mem, mem->in(LoopNode::EntryControl)); - n_loop->_body.yank(mem); + IdealLoopTree* new_loop = get_loop(n->in(0)); + set_ctrl_and_loop(n, n->in(0)); - IdealLoopTree* new_loop = get_loop(n->in(0)); - set_ctrl_and_loop(n, n->in(0)); - - return n; + return n; + } } } return NULL; @@ -769,13 +775,15 @@ void PhaseIdealLoop::try_move_store_after_loop(Node* n) { } if (u->is_Phi() && u->in(0) == n_loop->_head) { assert(_igvn.type(u) == Type::MEMORY, "bad phi"); - assert(phi == NULL, "already found"); + // multiple phis on the same slice are possible + if (phi != NULL) { + return; + } phi = u; continue; } } - phi = NULL; - break; + return; } if (phi != NULL) { // Nothing in the loop before the store (next iteration) diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index d72b7e7bf68..783ba1d3eeb 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -1512,7 +1512,8 @@ void PhaseMacroExpand::expand_allocate_common( // MemBarStoreStore so that stores that initialize this object // can't be reordered with a subsequent store that makes this // object accessible by other threads. - if (init == NULL || (!init->is_complete_with_arraycopy() && !init->does_not_escape())) { + if (!alloc->does_not_escape_thread() && + (init == NULL || !init->is_complete_with_arraycopy())) { if (init == NULL || init->req() < InitializeNode::RawStores) { // No InitializeNode or no stores captured by zeroing // elimination. Simply add the MemBarStoreStore after object diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 2c07c458859..30185e2c9d8 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -326,14 +326,14 @@ void Matcher::match( ) { grow_new_node_array(C->unique()); // Reset node counter so MachNodes start with _idx at 0 - int nodes = C->unique(); // save value + int live_nodes = C->live_nodes(); C->set_unique(0); C->reset_dead_node_list(); // Recursively match trees from old space into new space. // Correct leaves of new-space Nodes; they point to old-space. _visited.Clear(); // Clear visit bits for xform call - C->set_cached_top_node(xform( C->top(), nodes )); + C->set_cached_top_node(xform( C->top(), live_nodes )); if (!C->failing()) { Node* xroot = xform( C->root(), 1 ); if (xroot == NULL) { @@ -1001,7 +1001,7 @@ class MStack: public Node_Stack { Node *Matcher::transform( Node *n ) { ShouldNotCallThis(); return n; } Node *Matcher::xform( Node *n, int max_stack ) { // Use one stack to keep both: child's node/state and parent's node/index - MStack mstack(max_stack * 2 * 2); // C->unique() * 2 * 2 + MStack mstack(max_stack * 2 * 2); // usually: C->live_nodes() * 2 * 2 mstack.push(n, Visit, NULL, -1); // set NULL as parent to indicate root while (mstack.is_nonempty()) { @@ -2045,11 +2045,38 @@ bool Matcher::is_bmi_pattern(Node *n, Node *m) { // and then expanded into the inline_cache_reg and a method_oop register // defined in ad_.cpp +// Check for shift by small constant as well +static bool clone_shift(Node* shift, Matcher* matcher, MStack& mstack, VectorSet& address_visited) { + if (shift->Opcode() == Op_LShiftX && shift->in(2)->is_Con() && + shift->in(2)->get_int() <= 3 && + // Are there other uses besides address expressions? + !matcher->is_visited(shift)) { + address_visited.set(shift->_idx); // Flag as address_visited + mstack.push(shift->in(2), Visit); + Node *conv = shift->in(1); +#ifdef _LP64 + // Allow Matcher to match the rule which bypass + // ConvI2L operation for an array index on LP64 + // if the index value is positive. + if (conv->Opcode() == Op_ConvI2L && + conv->as_Type()->type()->is_long()->_lo >= 0 && + // Are there other uses besides address expressions? + !matcher->is_visited(conv)) { + address_visited.set(conv->_idx); // Flag as address_visited + mstack.push(conv->in(1), Pre_Visit); + } else +#endif + mstack.push(conv, Pre_Visit); + return true; + } + return false; +} + //------------------------------find_shared------------------------------------ // Set bits if Node is shared or otherwise a root void Matcher::find_shared( Node *n ) { - // Allocate stack of size C->unique() * 2 to avoid frequent realloc + // Allocate stack of size C->live_nodes() * 2 to avoid frequent realloc MStack mstack(C->live_nodes() * 2); // Mark nodes as address_visited if they are inputs to an address expression VectorSet address_visited(Thread::current()->resource_area()); @@ -2205,7 +2232,10 @@ void Matcher::find_shared( Node *n ) { #endif // Clone addressing expressions as they are "free" in memory access instructions - if( mem_op && i == MemNode::Address && mop == Op_AddP ) { + if (mem_op && i == MemNode::Address && mop == Op_AddP && + // When there are other uses besides address expressions + // put it on stack and mark as shared. + !is_visited(m)) { // Some inputs for address expression are not put on stack // to avoid marking them as shared and forcing them into register // if they are used only in address expressions. @@ -2213,10 +2243,7 @@ void Matcher::find_shared( Node *n ) { // besides address expressions. Node *off = m->in(AddPNode::Offset); - if( off->is_Con() && - // When there are other uses besides address expressions - // put it on stack and mark as shared. - !is_visited(m) ) { + if (off->is_Con()) { address_visited.test_set(m->_idx); // Flag as address_visited Node *adr = m->in(AddPNode::Address); @@ -2229,28 +2256,7 @@ void Matcher::find_shared( Node *n ) { !is_visited(adr) ) { address_visited.set(adr->_idx); // Flag as address_visited Node *shift = adr->in(AddPNode::Offset); - // Check for shift by small constant as well - if( shift->Opcode() == Op_LShiftX && shift->in(2)->is_Con() && - shift->in(2)->get_int() <= 3 && - // Are there other uses besides address expressions? - !is_visited(shift) ) { - address_visited.set(shift->_idx); // Flag as address_visited - mstack.push(shift->in(2), Visit); - Node *conv = shift->in(1); -#ifdef _LP64 - // Allow Matcher to match the rule which bypass - // ConvI2L operation for an array index on LP64 - // if the index value is positive. - if( conv->Opcode() == Op_ConvI2L && - conv->as_Type()->type()->is_long()->_lo >= 0 && - // Are there other uses besides address expressions? - !is_visited(conv) ) { - address_visited.set(conv->_idx); // Flag as address_visited - mstack.push(conv->in(1), Pre_Visit); - } else -#endif - mstack.push(conv, Pre_Visit); - } else { + if (!clone_shift(shift, this, mstack, address_visited)) { mstack.push(shift, Pre_Visit); } mstack.push(adr->in(AddPNode::Address), Pre_Visit); @@ -2263,6 +2269,12 @@ void Matcher::find_shared( Node *n ) { mstack.push(off, Visit); mstack.push(m->in(AddPNode::Base), Pre_Visit); continue; // for(int i = ...) + } else if (clone_shift_expressions && + clone_shift(off, this, mstack, address_visited)) { + address_visited.test_set(m->_idx); // Flag as address_visited + mstack.push(m->in(AddPNode::Address), Pre_Visit); + mstack.push(m->in(AddPNode::Base), Pre_Visit); + continue; } // if( off->is_Con() ) } // if( mem_op && mstack.push(m, Pre_Visit); diff --git a/hotspot/src/share/vm/opto/matcher.hpp b/hotspot/src/share/vm/opto/matcher.hpp index 41c6759b9eb..fc0c66cf345 100644 --- a/hotspot/src/share/vm/opto/matcher.hpp +++ b/hotspot/src/share/vm/opto/matcher.hpp @@ -269,6 +269,9 @@ public: // should generate this one. static const bool match_rule_supported(int opcode); + // Some uarchs have different sized float register resources + static const int float_pressure(int default_pressure_threshold); + // Used to determine if we have fast l2f conversion // USII has it, USIII doesn't static const bool convL2FSupported(void); diff --git a/hotspot/src/share/vm/opto/mathexactnode.cpp b/hotspot/src/share/vm/opto/mathexactnode.cpp index a96656854f5..4c167d255a8 100644 --- a/hotspot/src/share/vm/opto/mathexactnode.cpp +++ b/hotspot/src/share/vm/opto/mathexactnode.cpp @@ -167,7 +167,7 @@ bool OverflowMulLNode::can_overflow(const Type* t1, const Type* t2) const { } const Type* OverflowNode::sub(const Type* t1, const Type* t2) const { - fatal(err_msg_res("sub() should not be called for '%s'", NodeClassNames[this->Opcode()])); + fatal("sub() should not be called for '%s'", NodeClassNames[this->Opcode()]); return TypeInt::CC; } diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 5aa946aee79..d7da53ef871 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1139,7 +1139,7 @@ Node* LoadNode::eliminate_autobox(PhaseGVN* phase) { // Only integer types have boxing cache. assert(bt == T_BOOLEAN || bt == T_CHAR || bt == T_BYTE || bt == T_SHORT || - bt == T_INT || bt == T_LONG, err_msg_res("wrong type = %s", type2name(bt))); + bt == T_INT || bt == T_LONG, "wrong type = %s", type2name(bt)); jlong cache_low = (bt == T_LONG) ? c.as_long() : c.as_int(); if (cache_low != (int)cache_low) { return NULL; // should not happen since cache is array indexed by value @@ -2394,7 +2394,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { Opcode() == Op_StoreVector || phase->C->get_alias_index(adr_type()) == Compile::AliasIdxRaw || (Opcode() == Op_StoreL && st->Opcode() == Op_StoreI), // expanded ClearArrayNode - err_msg_res("no mismatched stores, except on raw memory: %s %s", NodeClassNames[Opcode()], NodeClassNames[st->Opcode()])); + "no mismatched stores, except on raw memory: %s %s", NodeClassNames[Opcode()], NodeClassNames[st->Opcode()]); if (st->in(MemNode::Address)->eqv_uncast(address) && st->as_Store()->memory_size() <= this->memory_size()) { @@ -2945,7 +2945,7 @@ Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Final field stores. Node* alloc = AllocateNode::Ideal_allocation(in(MemBarNode::Precedent), phase); if ((alloc != NULL) && alloc->is_Allocate() && - alloc->as_Allocate()->_is_non_escaping) { + alloc->as_Allocate()->does_not_escape_thread()) { // The allocated object does not escape. eliminate = true; } @@ -3289,7 +3289,7 @@ intptr_t InitializeNode::can_capture_store(StoreNode* st, PhaseTransform* phase, // the store control then we cannot capture the store. assert(!n->is_Store(), "2 stores to same slice on same control?"); Node* base = other_adr; - assert(base->is_AddP(), err_msg_res("should be addp but is %s", base->Name())); + assert(base->is_AddP(), "should be addp but is %s", base->Name()); base = base->in(AddPNode::Base); if (base != NULL) { base = base->uncast(); diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index 0a049163d3a..9ac166bc49f 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -47,6 +47,10 @@ const uint Node::NotAMachineReg = 0xffff0000; #ifndef PRODUCT extern int nodes_created; #endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif #ifdef ASSERT @@ -456,6 +460,10 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, _in[6] = n6; if (n6 != NULL) n6->add_out((Node *)this); } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + //------------------------------clone------------------------------------------ // Clone a Node. diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index 97c844891d0..a779923db00 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -353,7 +353,7 @@ protected: #endif // Reference to the i'th input Node. Error if out of bounds. - Node* in(uint i) const { assert(i < _max, err_msg_res("oob: i=%d, _max=%d", i, _max)); return _in[i]; } + Node* in(uint i) const { assert(i < _max, "oob: i=%d, _max=%d", i, _max); return _in[i]; } // Reference to the i'th input Node. NULL if out of bounds. Node* lookup(uint i) const { return ((i < _max) ? _in[i] : NULL); } // Reference to the i'th output Node. Error if out of bounds. @@ -393,7 +393,7 @@ protected: void ins_req( uint i, Node *n ); // Insert a NEW required input void set_req( uint i, Node *n ) { assert( is_not_dead(n), "can not use dead node"); - assert( i < _cnt, err_msg_res("oob: i=%d, _cnt=%d", i, _cnt)); + assert( i < _cnt, "oob: i=%d, _cnt=%d", i, _cnt); assert( !VerifyHashTableKeys || _hash_lock == 0, "remove node from hash table before modifying it"); Node** p = &_in[i]; // cache this._in, across the del_out call @@ -674,7 +674,8 @@ public: Flag_avoid_back_to_back_after = Flag_avoid_back_to_back_before << 1, Flag_has_call = Flag_avoid_back_to_back_after << 1, Flag_is_reduction = Flag_has_call << 1, - Flag_is_expensive = Flag_is_reduction << 1, + Flag_is_scheduled = Flag_is_reduction, + Flag_is_expensive = Flag_is_scheduled << 1, _max_flags = (Flag_is_expensive << 1) - 1 // allow flags combination }; @@ -861,6 +862,9 @@ public: // It must have the loop's phi as input and provide a def to the phi. bool is_reduction() const { return (_flags & Flag_is_reduction) != 0; } + // Used in lcm to mark nodes that have scheduled + bool is_scheduled() const { return (_flags & Flag_is_scheduled) != 0; } + //----------------- Optimization // Get the worst-case Type output for this Node. diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index 7423155de04..fc8cfdc8ca6 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -116,12 +116,6 @@ void Compile::Output() { } } -# ifdef ENABLE_ZAP_DEAD_LOCALS - if (ZapDeadCompiledLocals) { - Insert_zap_nodes(); - } -# endif - uint* blk_starts = NEW_RESOURCE_ARRAY(uint, _cfg->number_of_blocks() + 1); blk_starts[0] = 0; @@ -184,113 +178,6 @@ bool Compile::need_register_stack_bang() const { return (stub_function() == NULL && has_java_calls()); } -# ifdef ENABLE_ZAP_DEAD_LOCALS - - -// In order to catch compiler oop-map bugs, we have implemented -// a debugging mode called ZapDeadCompilerLocals. -// This mode causes the compiler to insert a call to a runtime routine, -// "zap_dead_locals", right before each place in compiled code -// that could potentially be a gc-point (i.e., a safepoint or oop map point). -// The runtime routine checks that locations mapped as oops are really -// oops, that locations mapped as values do not look like oops, -// and that locations mapped as dead are not used later -// (by zapping them to an invalid address). - -int Compile::_CompiledZap_count = 0; - -void Compile::Insert_zap_nodes() { - bool skip = false; - - - // Dink with static counts because code code without the extra - // runtime calls is MUCH faster for debugging purposes - - if ( CompileZapFirst == 0 ) ; // nothing special - else if ( CompileZapFirst > CompiledZap_count() ) skip = true; - else if ( CompileZapFirst == CompiledZap_count() ) - warning("starting zap compilation after skipping"); - - if ( CompileZapLast == -1 ) ; // nothing special - else if ( CompileZapLast < CompiledZap_count() ) skip = true; - else if ( CompileZapLast == CompiledZap_count() ) - warning("about to compile last zap"); - - ++_CompiledZap_count; // counts skipped zaps, too - - if ( skip ) return; - - - if ( _method == NULL ) - return; // no safepoints/oopmaps emitted for calls in stubs,so we don't care - - // Insert call to zap runtime stub before every node with an oop map - for( uint i=0; i<_cfg->number_of_blocks(); i++ ) { - Block *b = _cfg->get_block(i); - for ( uint j = 0; j < b->number_of_nodes(); ++j ) { - Node *n = b->get_node(j); - - // Determining if we should insert a zap-a-lot node in output. - // We do that for all nodes that has oopmap info, except for calls - // to allocation. Calls to allocation passes in the old top-of-eden pointer - // and expect the C code to reset it. Hence, there can be no safepoints between - // the inlined-allocation and the call to new_Java, etc. - // We also cannot zap monitor calls, as they must hold the microlock - // during the call to Zap, which also wants to grab the microlock. - bool insert = n->is_MachSafePoint() && (n->as_MachSafePoint()->oop_map() != NULL); - if ( insert ) { // it is MachSafePoint - if ( !n->is_MachCall() ) { - insert = false; - } else if ( n->is_MachCall() ) { - MachCallNode* call = n->as_MachCall(); - if (call->entry_point() == OptoRuntime::new_instance_Java() || - call->entry_point() == OptoRuntime::new_array_Java() || - call->entry_point() == OptoRuntime::multianewarray2_Java() || - call->entry_point() == OptoRuntime::multianewarray3_Java() || - call->entry_point() == OptoRuntime::multianewarray4_Java() || - call->entry_point() == OptoRuntime::multianewarray5_Java() || - call->entry_point() == OptoRuntime::slow_arraycopy_Java() || - call->entry_point() == OptoRuntime::complete_monitor_locking_Java() - ) { - insert = false; - } - } - if (insert) { - Node *zap = call_zap_node(n->as_MachSafePoint(), i); - b->insert_node(zap, j); - _cfg->map_node_to_block(zap, b); - ++j; - } - } - } - } -} - - -Node* Compile::call_zap_node(MachSafePointNode* node_to_check, int block_no) { - const TypeFunc *tf = OptoRuntime::zap_dead_locals_Type(); - CallStaticJavaNode* ideal_node = - new CallStaticJavaNode( tf, - OptoRuntime::zap_dead_locals_stub(_method->flags().is_native()), - "call zap dead locals stub", 0, TypePtr::BOTTOM); - // We need to copy the OopMap from the site we're zapping at. - // We have to make a copy, because the zap site might not be - // a call site, and zap_dead is a call site. - OopMap* clone = node_to_check->oop_map()->deep_copy(); - - // Add the cloned OopMap to the zap node - ideal_node->set_oop_map(clone); - return _matcher->match_sfpt(ideal_node); -} - -bool Compile::is_node_getting_a_safepoint( Node* n) { - // This code duplicates the logic prior to the call of add_safepoint - // below in this file. - if( n->is_MachSafePoint() ) return true; - return false; -} - -# endif // ENABLE_ZAP_DEAD_LOCALS // Compute the size of first NumberOfLoopInstrToAlign instructions at the top // of a loop. When aligning a loop we need to provide enough instructions @@ -834,10 +721,6 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) { MachSafePointNode *sfn = mach->as_MachSafePoint(); MachCallNode *mcall; -#ifdef ENABLE_ZAP_DEAD_LOCALS - assert( is_node_getting_a_safepoint(mach), "logic does not match; false negative"); -#endif - int safepoint_pc_offset = current_offset; bool is_method_handle_invoke = false; bool return_oop = false; @@ -973,7 +856,9 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) { assert(jvms->bci() >= InvocationEntryBci && jvms->bci() <= 0x10000, "must be a valid or entry BCI"); assert(!jvms->should_reexecute() || depth == max_depth, "reexecute allowed only for the youngest"); // Now we can describe the scope. - debug_info()->describe_scope(safepoint_pc_offset, scope_method, jvms->bci(), jvms->should_reexecute(), is_method_handle_invoke, return_oop, locvals, expvals, monvals); + methodHandle null_mh; + bool rethrow_exception = false; + debug_info()->describe_scope(safepoint_pc_offset, null_mh, scope_method, jvms->bci(), jvms->should_reexecute(), rethrow_exception, is_method_handle_invoke, return_oop, locvals, expvals, monvals); } // End jvms loop // Mark the end of the scope set. @@ -1056,7 +941,8 @@ void NonSafepointEmitter::emit_non_safepoint() { JVMState* jvms = youngest_jvms->of_depth(depth); ciMethod* method = jvms->has_method() ? jvms->method() : NULL; assert(!jvms->should_reexecute() || depth==max_depth, "reexecute allowed only for the youngest"); - debug_info->describe_scope(pc_offset, method, jvms->bci(), jvms->should_reexecute()); + methodHandle null_mh; + debug_info->describe_scope(pc_offset, null_mh, method, jvms->bci(), jvms->should_reexecute()); } // Mark the end of the scope set. @@ -1294,10 +1180,6 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { if (Pipeline::requires_bundling() && starts_bundle(n)) cb->flush_bundle(false); - // The following logic is duplicated in the code ifdeffed for - // ENABLE_ZAP_DEAD_LOCALS which appears above in this file. It - // should be factored out. Or maybe dispersed to the nodes? - // Special handling for SafePoint/Call Nodes bool is_mcall = false; if (n->is_Mach()) { @@ -1364,9 +1246,6 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { // !!!!! Stubs only need an oopmap right now, so bail out if (sfn->jvms()->method() == NULL) { // Write the oopmap directly to the code blob??!! -# ifdef ENABLE_ZAP_DEAD_LOCALS - assert( !is_node_getting_a_safepoint(sfn), "logic does not match; false positive"); -# endif continue; } } // End synchronization @@ -1554,9 +1433,6 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { // !!!!! Stubs only need an oopmap right now, so bail out if (!mach->is_MachCall() && mach->as_MachSafePoint()->jvms()->method() == NULL) { // Write the oopmap directly to the code blob??!! -# ifdef ENABLE_ZAP_DEAD_LOCALS - assert( !is_node_getting_a_safepoint(mach), "logic does not match; false positive"); -# endif delay_slot = NULL; continue; } @@ -2611,7 +2487,7 @@ void Scheduling::verify_do_def( Node *n, OptoReg::Name def, const char *msg ) { n->dump(); tty->print_cr("..."); prior_use->dump(); - assert(edge_from_to(prior_use,n),msg); + assert(edge_from_to(prior_use,n), "%s", msg); } _reg_node.map(def,NULL); // Kill live USEs } @@ -2649,11 +2525,11 @@ void Scheduling::verify_good_schedule( Block *b, const char *msg ) { OptoReg::Name reg_lo = _regalloc->get_reg_first(def); OptoReg::Name reg_hi = _regalloc->get_reg_second(def); if( OptoReg::is_valid(reg_lo) ) { - assert(!_reg_node[reg_lo] || edge_from_to(_reg_node[reg_lo],def), msg); + assert(!_reg_node[reg_lo] || edge_from_to(_reg_node[reg_lo],def), "%s", msg); _reg_node.map(reg_lo,n); } if( OptoReg::is_valid(reg_hi) ) { - assert(!_reg_node[reg_hi] || edge_from_to(_reg_node[reg_hi],def), msg); + assert(!_reg_node[reg_hi] || edge_from_to(_reg_node[reg_hi],def), "%s", msg); _reg_node.map(reg_hi,n); } } diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index 35728e6dd17..3a07d9f707c 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -1476,13 +1476,13 @@ void Parse::do_one_block() { int pre_bc_sp = sp(); int inputs, depth; bool have_se = !stopped() && compute_stack_effects(inputs, depth); - assert(!have_se || pre_bc_sp >= inputs, err_msg_res("have enough stack to execute this BC: pre_bc_sp=%d, inputs=%d", pre_bc_sp, inputs)); + assert(!have_se || pre_bc_sp >= inputs, "have enough stack to execute this BC: pre_bc_sp=%d, inputs=%d", pre_bc_sp, inputs); #endif //ASSERT do_one_bytecode(); assert(!have_se || stopped() || failing() || (sp() - pre_bc_sp) == depth, - err_msg_res("incorrect depth prediction: sp=%d, pre_bc_sp=%d, depth=%d", sp(), pre_bc_sp, depth)); + "incorrect depth prediction: sp=%d, pre_bc_sp=%d, depth=%d", sp(), pre_bc_sp, depth); do_exceptions(); diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp index 5e80eb863fb..f37e31e9458 100644 --- a/hotspot/src/share/vm/opto/parse3.cpp +++ b/hotspot/src/share/vm/opto/parse3.cpp @@ -404,7 +404,7 @@ void Parse::do_multianewarray() { // The original expression was of this form: new T[length0][length1]... // It is often the case that the lengths are small (except the last). // If that happens, use the fast 1-d creator a constant number of times. - const jint expand_limit = MIN2((juint)MultiArrayExpandLimit, (juint)100); + const jint expand_limit = MIN2((jint)MultiArrayExpandLimit, 100); jint expand_count = 1; // count of allocations in the expansion jint expand_fanout = 1; // running total fanout for (j = 0; j < ndimensions-1; j++) { diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index 3d56ea1b812..d9e253a43e0 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -102,11 +102,6 @@ address OptoRuntime::_rethrow_Java = NULL; address OptoRuntime::_slow_arraycopy_Java = NULL; address OptoRuntime::_register_finalizer_Java = NULL; -# ifdef ENABLE_ZAP_DEAD_LOCALS -address OptoRuntime::_zap_dead_Java_locals_Java = NULL; -address OptoRuntime::_zap_dead_native_locals_Java = NULL; -# endif - ExceptionBlob* OptoRuntime::_exception_blob; // This should be called in an assertion at the start of OptoRuntime routines @@ -152,10 +147,6 @@ bool OptoRuntime::generate(ciEnv* env) { gen(env, _slow_arraycopy_Java , slow_arraycopy_Type , SharedRuntime::slow_arraycopy_C , 0 , false, false, false); gen(env, _register_finalizer_Java , register_finalizer_Type , register_finalizer , 0 , false, false, false); -# ifdef ENABLE_ZAP_DEAD_LOCALS - gen(env, _zap_dead_Java_locals_Java , zap_dead_locals_Type , zap_dead_Java_locals_C , 0 , false, true , false ); - gen(env, _zap_dead_native_locals_Java , zap_dead_locals_Type , zap_dead_native_locals_C , 0 , false, true , false ); -# endif return true; } @@ -604,23 +595,6 @@ const TypeFunc *OptoRuntime::uncommon_trap_Type() { return TypeFunc::make(domain, range); } -# ifdef ENABLE_ZAP_DEAD_LOCALS -// Type used for stub generation for zap_dead_locals. -// No inputs or outputs -const TypeFunc *OptoRuntime::zap_dead_locals_Type() { - // create input type (domain) - const Type **fields = TypeTuple::fields(0); - const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms,fields); - - // create result type (range) - fields = TypeTuple::fields(0); - const TypeTuple *range = TypeTuple::make(TypeFunc::Parms,fields); - - return TypeFunc::make(domain,range); -} -# endif - - //----------------------------------------------------------------------------- // Monitor Handling const TypeFunc *OptoRuntime::complete_monitor_enter_Type() { @@ -1261,7 +1235,7 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* t } // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort(exception)); + Exceptions::debug_check_abort(exception); #ifdef ASSERT if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { @@ -1648,67 +1622,3 @@ static void trace_exception(oop exception_oop, address exception_pc, const char* #endif // PRODUCT - -# ifdef ENABLE_ZAP_DEAD_LOCALS -// Called from call sites in compiled code with oop maps (actually safepoints) -// Zaps dead locals in first java frame. -// Is entry because may need to lock to generate oop maps -// Currently, only used for compiler frames, but someday may be used -// for interpreter frames, too. - -int OptoRuntime::ZapDeadCompiledLocals_count = 0; - -// avoid pointers to member funcs with these helpers -static bool is_java_frame( frame* f) { return f->is_java_frame(); } -static bool is_native_frame(frame* f) { return f->is_native_frame(); } - - -void OptoRuntime::zap_dead_java_or_native_locals(JavaThread* thread, - bool (*is_this_the_right_frame_to_zap)(frame*)) { - assert(JavaThread::current() == thread, "is this needed?"); - - if ( !ZapDeadCompiledLocals ) return; - - bool skip = false; - - if ( ZapDeadCompiledLocalsFirst == 0 ) ; // nothing special - else if ( ZapDeadCompiledLocalsFirst > ZapDeadCompiledLocals_count ) skip = true; - else if ( ZapDeadCompiledLocalsFirst == ZapDeadCompiledLocals_count ) - warning("starting zapping after skipping"); - - if ( ZapDeadCompiledLocalsLast == -1 ) ; // nothing special - else if ( ZapDeadCompiledLocalsLast < ZapDeadCompiledLocals_count ) skip = true; - else if ( ZapDeadCompiledLocalsLast == ZapDeadCompiledLocals_count ) - warning("about to zap last zap"); - - ++ZapDeadCompiledLocals_count; // counts skipped zaps, too - - if ( skip ) return; - - // find java frame and zap it - - for (StackFrameStream sfs(thread); !sfs.is_done(); sfs.next()) { - if (is_this_the_right_frame_to_zap(sfs.current()) ) { - sfs.current()->zap_dead_locals(thread, sfs.register_map()); - return; - } - } - warning("no frame found to zap in zap_dead_Java_locals_C"); -} - -JRT_LEAF(void, OptoRuntime::zap_dead_Java_locals_C(JavaThread* thread)) - zap_dead_java_or_native_locals(thread, is_java_frame); -JRT_END - -// The following does not work because for one thing, the -// thread state is wrong; it expects java, but it is native. -// Also, the invariants in a native stub are different and -// I'm not sure it is safe to have a MachCalRuntimeDirectNode -// in there. -// So for now, we do not zap in native stubs. - -JRT_LEAF(void, OptoRuntime::zap_dead_native_locals_C(JavaThread* thread)) - zap_dead_java_or_native_locals(thread, is_native_frame); -JRT_END - -# endif diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp index 24fd6586db4..8e38f3f3a15 100644 --- a/hotspot/src/share/vm/opto/runtime.hpp +++ b/hotspot/src/share/vm/opto/runtime.hpp @@ -152,12 +152,6 @@ class OptoRuntime : public AllStatic { static address _slow_arraycopy_Java; static address _register_finalizer_Java; -# ifdef ENABLE_ZAP_DEAD_LOCALS - static address _zap_dead_Java_locals_Java; - static address _zap_dead_native_locals_Java; -# endif - - // // Implementation of runtime methods // ================================= @@ -212,19 +206,6 @@ private: static void register_finalizer(oopDesc* obj, JavaThread* thread); - // zaping dead locals, either from Java frames or from native frames -# ifdef ENABLE_ZAP_DEAD_LOCALS - static void zap_dead_Java_locals_C( JavaThread* thread); - static void zap_dead_native_locals_C( JavaThread* thread); - - static void zap_dead_java_or_native_locals( JavaThread*, bool (*)(frame*)); - - public: - static int ZapDeadCompiledLocals_count; - -# endif - - public: static bool is_callee_saved_register(MachRegisterNumbers reg); @@ -256,14 +237,6 @@ private: static address slow_arraycopy_Java() { return _slow_arraycopy_Java; } static address register_finalizer_Java() { return _register_finalizer_Java; } - -# ifdef ENABLE_ZAP_DEAD_LOCALS - static address zap_dead_locals_stub(bool is_native) { return is_native - ? _zap_dead_native_locals_Java - : _zap_dead_Java_locals_Java; } - static MachNode* node_to_call_zap_dead_locals(Node* n, int block_num, bool is_native); -# endif - static ExceptionBlob* exception_blob() { return _exception_blob; } // Leaf routines helping with method data update @@ -353,10 +326,6 @@ private: static const TypeFunc* dtrace_method_entry_exit_Type(); static const TypeFunc* dtrace_object_alloc_Type(); -# ifdef ENABLE_ZAP_DEAD_LOCALS - static const TypeFunc* zap_dead_locals_Type(); -# endif - private: static NamedCounter * volatile _named_counters; diff --git a/hotspot/src/share/vm/opto/stringopts.cpp b/hotspot/src/share/vm/opto/stringopts.cpp index c2129ec765a..4e67f5151fe 100644 --- a/hotspot/src/share/vm/opto/stringopts.cpp +++ b/hotspot/src/share/vm/opto/stringopts.cpp @@ -773,7 +773,7 @@ bool StringConcat::validate_mem_flow() { return false; } } else { - assert(mem->is_Store() || mem->is_LoadStore(), err_msg_res("unexpected node type: %s", mem->Name())); + assert(mem->is_Store() || mem->is_LoadStore(), "unexpected node type: %s", mem->Name()); #ifndef PRODUCT if (PrintOptimizeStringConcat) { tty->print("fusion has incorrect memory flow (unexpected source) for "); @@ -814,7 +814,7 @@ bool StringConcat::validate_mem_flow() { for (SimpleDUIterator i(true_proj); i.has_next(); i.next()) { Node* use = i.get(); assert(use == ctrl || use->is_ConstraintCast(), - err_msg_res("unexpected user: %s", use->Name())); + "unexpected user: %s", use->Name()); } iff = ctrl->in(1)->in(0)->as_If(); @@ -838,7 +838,7 @@ bool StringConcat::validate_mem_flow() { for (SimpleDUIterator i(ctrl); i.has_next(); i.next()) { Node* use = i.get(); assert(use == copy || use == iff || use == curr || use->is_CheckCastPP() || use->is_Load(), - err_msg_res("unexpected user: %s", use->Name())); + "unexpected user: %s", use->Name()); } #endif // ASSERT } diff --git a/hotspot/src/share/vm/opto/subnode.cpp b/hotspot/src/share/vm/opto/subnode.cpp index a41538d75d5..add579e11d8 100644 --- a/hotspot/src/share/vm/opto/subnode.cpp +++ b/hotspot/src/share/vm/opto/subnode.cpp @@ -1530,18 +1530,6 @@ const Type *Log10DNode::Value( PhaseTransform *phase ) const { return TypeD::make( StubRoutines::intrinsic_log10( d ) ); } -//============================================================================= -//------------------------------Value------------------------------------------ -// Compute exp -const Type *ExpDNode::Value( PhaseTransform *phase ) const { - const Type *t1 = phase->type( in(1) ); - if( t1 == Type::TOP ) return Type::TOP; - if( t1->base() != Type::DoubleCon ) return Type::DOUBLE; - double d = t1->getd(); - return TypeD::make( StubRoutines::intrinsic_exp( d ) ); -} - - //============================================================================= //------------------------------Value------------------------------------------ // Compute pow diff --git a/hotspot/src/share/vm/opto/subnode.hpp b/hotspot/src/share/vm/opto/subnode.hpp index a287ffaf026..be563c73926 100644 --- a/hotspot/src/share/vm/opto/subnode.hpp +++ b/hotspot/src/share/vm/opto/subnode.hpp @@ -477,20 +477,6 @@ public: virtual const Type *Value( PhaseTransform *phase ) const; }; -//------------------------------ExpDNode--------------------------------------- -// Exponentiate a double -class ExpDNode : public Node { -public: - ExpDNode(Compile* C, Node *c, Node *in1) : Node(c, in1) { - init_flags(Flag_is_expensive); - C->add_expensive_node(this); - } - virtual int Opcode() const; - const Type *bottom_type() const { return Type::DOUBLE; } - virtual uint ideal_reg() const { return Op_RegD; } - virtual const Type *Value( PhaseTransform *phase ) const; -}; - //------------------------------LogDNode--------------------------------------- // Log_e of a double class LogDNode : public Node { diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 791624e5511..16f7c52801d 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -81,6 +81,10 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) : if (_phase->C->method() != NULL) { _phase->C->method()->has_option_value("VectorizeDebug", _vector_loop_debug); } + _CountedLoopReserveKit_debug = 0; + if (_phase->C->method() != NULL) { + _phase->C->method()->has_option_value("DoReserveCopyInSuperWordDebug", _CountedLoopReserveKit_debug); + } #endif } @@ -769,7 +773,7 @@ int SuperWord::get_iv_adjustment(MemNode* mem_ref) { // if offset is 0. int iv_adjustment_in_bytes = (stride_sign * vw - (offset % vw)); assert(((ABS(iv_adjustment_in_bytes) % elt_size) == 0), - err_msg_res("(%d) should be divisible by (%d)", iv_adjustment_in_bytes, elt_size)); + "(%d) should be divisible by (%d)", iv_adjustment_in_bytes, elt_size); iv_adjustment = iv_adjustment_in_bytes/elt_size; } else { // This memory op is not dependent on iv (scale == 0) @@ -914,7 +918,7 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray &p preds.push(n); NOT_PRODUCT(if (TraceSuperWord && Verbose) tty->print_cr("SuperWord::mem_slice_preds: added pred(%d)", n->_idx);) prev = n; - assert(n->is_Mem(), err_msg_res("unexpected node %s", n->Name())); + assert(n->is_Mem(), "unexpected node %s", n->Name()); n = n->in(MemNode::Memory); } } @@ -1763,6 +1767,22 @@ void SuperWord::co_locate_pack(Node_List* pk) { } } +#ifndef PRODUCT +void SuperWord::print_loop(bool whole) { + Node_Stack stack(_arena, _phase->C->unique() >> 2); + Node_List rpo_list; + VectorSet visited(_arena); + visited.set(lpt()->_head->_idx); + _phase->rpo(lpt()->_head, stack, visited, rpo_list); + _phase->dump(lpt(), rpo_list.size(), rpo_list ); + if(whole) { + tty->print_cr("\n Whole loop tree"); + _phase->dump(); + tty->print_cr(" End of whole loop tree\n"); + } +} +#endif + //------------------------------output--------------------------- // Convert packs into vector node operations void SuperWord::output() { @@ -1770,7 +1790,7 @@ void SuperWord::output() { #ifndef PRODUCT if (TraceLoopOpts) { - tty->print("SuperWord "); + tty->print("SuperWord::output "); lpt()->dump_head(); } #endif @@ -1789,6 +1809,18 @@ void SuperWord::output() { CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); uint max_vlen_in_bytes = 0; uint max_vlen = 0; + + NOT_PRODUCT(if(_CountedLoopReserveKit_debug > 0) {tty->print_cr("SWPointer::output: print loop before create_reserve_version_of_loop"); print_loop(true);}) + + CountedLoopReserveKit make_reversable(_phase, _lpt, DoReserveCopyInSuperWord); + + NOT_PRODUCT(if(_CountedLoopReserveKit_debug > 0) {tty->print_cr("SWPointer::output: print loop after create_reserve_version_of_loop"); print_loop(true);}) + + if (DoReserveCopyInSuperWord && !make_reversable.has_reserved()) { + NOT_PRODUCT({tty->print_cr("SWPointer::output: loop was not reserved correctly, exiting SuperWord");}) + return; + } + for (int i = 0; i < _block.length(); i++) { Node* n = _block.at(i); Node_List* p = my_pack(n); @@ -1858,8 +1890,8 @@ void SuperWord::output() { vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); vlen_in_bytes = vn->as_Vector()->length_in_bytes(); } - } else if (opc == Op_SqrtD) { - // Promote operand to vector (Sqrt is a 2 address instruction) + } else if (opc == Op_SqrtD || opc == Op_AbsF || opc == Op_AbsD || opc == Op_NegF || opc == Op_NegD) { + // Promote operand to vector (Sqrt/Abs/Neg are 2 address instructions) Node* in = vector_opd(p, 1); vn = VectorNode::make(opc, in, NULL, vlen, velt_basic_type(n)); vlen_in_bytes = vn->as_Vector()->length_in_bytes(); @@ -1888,6 +1920,7 @@ void SuperWord::output() { } } C->set_max_vector_size(max_vlen_in_bytes); + if (SuperWordLoopUnrollAnalysis) { if (cl->has_passed_slp()) { uint slp_max_unroll_factor = cl->slp_max_unroll(); @@ -1900,6 +1933,12 @@ void SuperWord::output() { } } } + + if (DoReserveCopyInSuperWord) { + make_reversable.use_new(); + } + NOT_PRODUCT(if(_CountedLoopReserveKit_debug > 0) {tty->print_cr("\n Final loop after SuperWord"); print_loop(true);}) + return; } //------------------------------vector_opd--------------------------- @@ -2110,7 +2149,7 @@ bool SuperWord::construct_bb() { Node* n_tail = n->in(LoopNode::LoopBackControl); if (n_tail != n->in(LoopNode::EntryControl)) { if (!n_tail->is_Mem()) { - assert(n_tail->is_Mem(), err_msg_res("unexpected node for memory slice: %s", n_tail->Name())); + assert(n_tail->is_Mem(), "unexpected node for memory slice: %s", n_tail->Name()); return false; // Bailout } _mem_slice_head.push(n); @@ -2690,15 +2729,25 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) { //----------------------------get_pre_loop_end--------------------------- // Find pre loop end from main loop. Returns null if none. -CountedLoopEndNode* SuperWord::get_pre_loop_end(CountedLoopNode *cl) { - Node *ctrl = cl->in(LoopNode::EntryControl); +CountedLoopEndNode* SuperWord::get_pre_loop_end(CountedLoopNode* cl) { + Node* ctrl = cl->in(LoopNode::EntryControl); if (!ctrl->is_IfTrue() && !ctrl->is_IfFalse()) return NULL; - Node *iffm = ctrl->in(0); + Node* iffm = ctrl->in(0); if (!iffm->is_If()) return NULL; - Node *p_f = iffm->in(0); + Node* bolzm = iffm->in(1); + if (!bolzm->is_Bool()) return NULL; + Node* cmpzm = bolzm->in(1); + if (!cmpzm->is_Cmp()) return NULL; + Node* opqzm = cmpzm->in(2); + // Can not optimize a loop if zero-trip Opaque1 node is optimized + // away and then another round of loop opts attempted. + if (opqzm->Opcode() != Op_Opaque1) { + return NULL; + } + Node* p_f = iffm->in(0); if (!p_f->is_IfFalse()) return NULL; if (!p_f->in(0)->is_CountedLoopEnd()) return NULL; - CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd(); + CountedLoopEndNode* pre_end = p_f->in(0)->as_CountedLoopEnd(); CountedLoopNode* loop_node = pre_end->loopnode(); if (loop_node == NULL || !loop_node->is_pre_loop()) return NULL; return pre_end; @@ -3045,6 +3094,9 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) { } } if (invariant(n)) { + if (opc == Op_ConvI2L) { + n = n->in(1); + } _negate_invar = negate; _invar = n; NOT_PRODUCT(_tracer.offset_plus_k_10(n, _invar, _negate_invar, _offset);) diff --git a/hotspot/src/share/vm/opto/superword.hpp b/hotspot/src/share/vm/opto/superword.hpp index 5e759c411b9..069d03740fc 100644 --- a/hotspot/src/share/vm/opto/superword.hpp +++ b/hotspot/src/share/vm/opto/superword.hpp @@ -200,6 +200,31 @@ class SWNodeInfo VALUE_OBJ_CLASS_SPEC { static const SWNodeInfo initial; }; +// JVMCI: OrderedPair is moved up to deal with compilation issues on Windows +//------------------------------OrderedPair--------------------------- +// Ordered pair of Node*. +class OrderedPair VALUE_OBJ_CLASS_SPEC { + protected: + Node* _p1; + Node* _p2; + public: + OrderedPair() : _p1(NULL), _p2(NULL) {} + OrderedPair(Node* p1, Node* p2) { + if (p1->_idx < p2->_idx) { + _p1 = p1; _p2 = p2; + } else { + _p1 = p2; _p2 = p1; + } + } + + bool operator==(const OrderedPair &rhs) { + return _p1 == rhs._p1 && _p2 == rhs._p2; + } + void print() { tty->print(" (%d, %d)", _p1->_idx, _p2->_idx); } + + static const OrderedPair initial; +}; + // -----------------------------SuperWord--------------------------------- // Transforms scalar operations into packed (superword) operations. class SuperWord : public ResourceObj { @@ -274,6 +299,7 @@ class SuperWord : public ResourceObj { GrowableArray _ii_order; #ifndef PRODUCT uintx _vector_loop_debug; // provide more printing in debug mode + uintx _CountedLoopReserveKit_debug; // for debugging CountedLoopReserveKit #endif // Accessors @@ -350,6 +376,7 @@ class SuperWord : public ResourceObj { // Tracing support #ifndef PRODUCT void find_adjacent_refs_trace_1(Node* best_align_to_mem_ref, int best_iv_adjustment); + void print_loop(bool whole); #endif // Find a memory reference to align the loop induction variable to. MemNode* find_align_to_ref(Node_List &memops); @@ -634,29 +661,4 @@ class SWPointer VALUE_OBJ_CLASS_SPEC { #endif }; - -//------------------------------OrderedPair--------------------------- -// Ordered pair of Node*. -class OrderedPair VALUE_OBJ_CLASS_SPEC { - protected: - Node* _p1; - Node* _p2; - public: - OrderedPair() : _p1(NULL), _p2(NULL) {} - OrderedPair(Node* p1, Node* p2) { - if (p1->_idx < p2->_idx) { - _p1 = p1; _p2 = p2; - } else { - _p1 = p2; _p2 = p1; - } - } - - bool operator==(const OrderedPair &rhs) { - return _p1 == rhs._p1 && _p2 == rhs._p2; - } - void print() { tty->print(" (%d, %d)", _p1->_idx, _p2->_idx); } - - static const OrderedPair initial; -}; - #endif // SHARE_VM_OPTO_SUPERWORD_HPP diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index b0b380490f3..8cf30c4fdfa 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -41,8 +41,6 @@ #include "opto/opcodes.hpp" #include "opto/type.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Portions of code courtesy of Clifford Click // Optimization - Graph Style @@ -2784,7 +2782,7 @@ int TypeRawPtr::hash(void) const { #ifndef PRODUCT void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const { if( _ptr == Constant ) - st->print(INTPTR_FORMAT, _bits); + st->print(INTPTR_FORMAT, p2i(_bits)); else st->print("rawptr:%s", ptr_msg[_ptr]); } @@ -3187,7 +3185,7 @@ int TypeOopPtr::hash(void) const { void TypeOopPtr::dump2( Dict &d, uint depth, outputStream *st ) const { st->print("oopptr:%s", ptr_msg[_ptr]); if( _klass_is_exact ) st->print(":exact"); - if( const_oop() ) st->print(INTPTR_FORMAT, const_oop()); + if( const_oop() ) st->print(INTPTR_FORMAT, p2i(const_oop())); switch( _offset ) { case OffsetTop: st->print("+top"); break; case OffsetBot: st->print("+any"); break; @@ -3358,7 +3356,7 @@ const Type* TypeInstPtr::get_const_boxed_value() const { case T_LONG: return TypeLong::make(constant.as_long()); default: break; } - fatal(err_msg_res("Invalid boxed value type '%s'", type2name(bt))); + fatal("Invalid boxed value type '%s'", type2name(bt)); return NULL; } @@ -4635,7 +4633,7 @@ const Type *TypeMetadataPtr::xdual() const { #ifndef PRODUCT void TypeMetadataPtr::dump2( Dict &d, uint depth, outputStream *st ) const { st->print("metadataptr:%s", ptr_msg[_ptr]); - if( metadata() ) st->print(INTPTR_FORMAT, metadata()); + if( metadata() ) st->print(INTPTR_FORMAT, p2i(metadata())); switch( _offset ) { case OffsetTop: st->print("+top"); break; case OffsetBot: st->print("+any"); break; @@ -5033,7 +5031,7 @@ void TypeKlassPtr::dump2( Dict & d, uint depth, outputStream *st ) const { { const char *name = klass()->name()->as_utf8(); if( name ) { - st->print("klass %s: " INTPTR_FORMAT, name, klass()); + st->print("klass %s: " INTPTR_FORMAT, name, p2i(klass())); } else { ShouldNotReachHere(); } diff --git a/hotspot/src/share/vm/opto/vectornode.cpp b/hotspot/src/share/vm/opto/vectornode.cpp index 274e2b7e759..7fa2f2c1588 100644 --- a/hotspot/src/share/vm/opto/vectornode.cpp +++ b/hotspot/src/share/vm/opto/vectornode.cpp @@ -92,6 +92,18 @@ int VectorNode::opcode(int sopc, BasicType bt) { case Op_DivD: assert(bt == T_DOUBLE, "must be"); return Op_DivVD; + case Op_AbsF: + assert(bt == T_FLOAT, "must be"); + return Op_AbsVF; + case Op_AbsD: + assert(bt == T_DOUBLE, "must be"); + return Op_AbsVD; + case Op_NegF: + assert(bt == T_FLOAT, "must be"); + return Op_NegVF; + case Op_NegD: + assert(bt == T_DOUBLE, "must be"); + return Op_NegVD; case Op_SqrtD: assert(bt == T_DOUBLE, "must be"); return Op_SqrtVD; @@ -255,7 +267,7 @@ VectorNode* VectorNode::make(int opc, Node* n1, Node* n2, uint vlen, BasicType b const TypeVect* vt = TypeVect::make(bt, vlen); int vopc = VectorNode::opcode(opc, bt); // This method should not be called for unimplemented vectors. - guarantee(vopc > 0, err_msg_res("Vector for '%s' is not implemented", NodeClassNames[opc])); + guarantee(vopc > 0, "Vector for '%s' is not implemented", NodeClassNames[opc]); switch (vopc) { case Op_AddVB: return new AddVBNode(n1, n2, vt); case Op_AddVS: return new AddVSNode(n1, n2, vt); @@ -280,6 +292,12 @@ VectorNode* VectorNode::make(int opc, Node* n1, Node* n2, uint vlen, BasicType b case Op_DivVF: return new DivVFNode(n1, n2, vt); case Op_DivVD: return new DivVDNode(n1, n2, vt); + case Op_AbsVF: return new AbsVFNode(n1, vt); + case Op_AbsVD: return new AbsVDNode(n1, vt); + + case Op_NegVF: return new NegVFNode(n1, vt); + case Op_NegVD: return new NegVDNode(n1, vt); + // Currently only supports double precision sqrt case Op_SqrtVD: return new SqrtVDNode(n1, vt); @@ -302,7 +320,7 @@ VectorNode* VectorNode::make(int opc, Node* n1, Node* n2, uint vlen, BasicType b case Op_OrV: return new OrVNode (n1, n2, vt); case Op_XorV: return new XorVNode(n1, n2, vt); } - fatal(err_msg_res("Missed vector creation for '%s'", NodeClassNames[vopc])); + fatal("Missed vector creation for '%s'", NodeClassNames[vopc]); return NULL; } @@ -328,7 +346,7 @@ VectorNode* VectorNode::scalar2vector(Node* s, uint vlen, const Type* opd_t) { case T_DOUBLE: return new ReplicateDNode(s, vt); } - fatal(err_msg_res("Type '%s' is not supported for vectors", type2name(bt))); + fatal("Type '%s' is not supported for vectors", type2name(bt)); return NULL; } @@ -346,7 +364,7 @@ VectorNode* VectorNode::shift_count(Node* shift, Node* cnt, uint vlen, BasicType case Op_URShiftL: return new RShiftCntVNode(cnt, vt); } - fatal(err_msg_res("Missed vector creation for '%s'", NodeClassNames[shift->Opcode()])); + fatal("Missed vector creation for '%s'", NodeClassNames[shift->Opcode()]); return NULL; } @@ -369,7 +387,7 @@ PackNode* PackNode::make(Node* s, uint vlen, BasicType bt) { case T_DOUBLE: return new PackDNode(s, vt); } - fatal(err_msg_res("Type '%s' is not supported for vectors", type2name(bt))); + fatal("Type '%s' is not supported for vectors", type2name(bt)); return NULL; } @@ -405,7 +423,7 @@ PackNode* PackNode::binary_tree_pack(int lo, int hi) { case T_DOUBLE: return new Pack2DNode(n1, n2, TypeVect::make(T_DOUBLE, 2)); } - fatal(err_msg_res("Type '%s' is not supported for vectors", type2name(bt))); + fatal("Type '%s' is not supported for vectors", type2name(bt)); } return NULL; } @@ -448,7 +466,7 @@ Node* ExtractNode::make(Node* v, uint position, BasicType bt) { case T_DOUBLE: return new ExtractDNode(v, pos); } - fatal(err_msg_res("Type '%s' is not supported for vectors", type2name(bt))); + fatal("Type '%s' is not supported for vectors", type2name(bt)); return NULL; } @@ -500,7 +518,7 @@ ReductionNode* ReductionNode::make(int opc, Node *ctrl, Node* n1, Node* n2, Basi int vopc = opcode(opc, bt); // This method should not be called for unimplemented vectors. - guarantee(vopc != opc, err_msg_res("Vector for '%s' is not implemented", NodeClassNames[opc])); + guarantee(vopc != opc, "Vector for '%s' is not implemented", NodeClassNames[opc]); switch (vopc) { case Op_AddReductionVI: return new AddReductionVINode(ctrl, n1, n2); @@ -512,7 +530,7 @@ ReductionNode* ReductionNode::make(int opc, Node *ctrl, Node* n1, Node* n2, Basi case Op_MulReductionVF: return new MulReductionVFNode(ctrl, n1, n2); case Op_MulReductionVD: return new MulReductionVDNode(ctrl, n1, n2); } - fatal(err_msg_res("Missed vector creation for '%s'", NodeClassNames[vopc])); + fatal("Missed vector creation for '%s'", NodeClassNames[vopc]); return NULL; } diff --git a/hotspot/src/share/vm/opto/vectornode.hpp b/hotspot/src/share/vm/opto/vectornode.hpp index 4652730d1dc..4a2ef59e041 100644 --- a/hotspot/src/share/vm/opto/vectornode.hpp +++ b/hotspot/src/share/vm/opto/vectornode.hpp @@ -309,6 +309,38 @@ class DivVDNode : public VectorNode { virtual int Opcode() const; }; +//------------------------------AbsVFNode-------------------------------------- +// Vector Abs float +class AbsVFNode : public VectorNode { + public: + AbsVFNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {} + virtual int Opcode() const; +}; + +//------------------------------AbsVDNode-------------------------------------- +// Vector Abs double +class AbsVDNode : public VectorNode { + public: + AbsVDNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {} + virtual int Opcode() const; +}; + +//------------------------------NegVFNode-------------------------------------- +// Vector Neg float +class NegVFNode : public VectorNode { + public: + NegVFNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {} + virtual int Opcode() const; +}; + +//------------------------------NegVDNode-------------------------------------- +// Vector Neg double +class NegVDNode : public VectorNode { + public: + NegVDNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {} + virtual int Opcode() const; +}; + //------------------------------SqrtVDNode-------------------------------------- // Vector Sqrt double class SqrtVDNode : public VectorNode { diff --git a/hotspot/src/share/vm/precompiled/precompiled.hpp b/hotspot/src/share/vm/precompiled/precompiled.hpp index de7cb876e6c..70e72ab514f 100644 --- a/hotspot/src/share/vm/precompiled/precompiled.hpp +++ b/hotspot/src/share/vm/precompiled/precompiled.hpp @@ -101,7 +101,6 @@ # include "gc/shared/gcStats.hpp" # include "gc/shared/gcUtil.hpp" # include "gc/shared/genCollectedHeap.hpp" -# include "gc/shared/genRemSet.hpp" # include "gc/shared/generation.hpp" # include "gc/shared/generationCounters.hpp" # include "gc/shared/modRefBarrierSet.hpp" @@ -111,7 +110,6 @@ # include "gc/shared/spaceDecorator.hpp" # include "gc/shared/taskqueue.hpp" # include "gc/shared/threadLocalAllocBuffer.hpp" -# include "gc/shared/watermark.hpp" # include "gc/shared/workgroup.hpp" # include "interpreter/abstractInterpreter.hpp" # include "interpreter/bytecode.hpp" @@ -128,6 +126,7 @@ # include "interpreter/templateInterpreter.hpp" # include "interpreter/templateTable.hpp" # include "jvmtifiles/jvmti.h" +# include "logging/log.hpp" # include "memory/allocation.hpp" # include "memory/allocation.inline.hpp" # include "memory/heap.hpp" @@ -290,6 +289,9 @@ # include "c1/c1_ValueType.hpp" # include "c1/c1_globals.hpp" #endif // COMPILER1 +#if INCLUDE_JVMCI +# include "jvmci/jvmci_globals.hpp" +#endif // INCLUDE_JVMCI #if INCLUDE_ALL_GCS # include "gc/cms/compactibleFreeListSpace.hpp" # include "gc/cms/concurrentMarkSweepGeneration.hpp" diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index c18f68e454a..6556b565576 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -81,6 +81,10 @@ #if INCLUDE_ALL_GCS #include "gc/g1/g1SATBCardTableModRefBS.hpp" #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif static jint CurrentVersion = JNI_VERSION_1_8; @@ -3870,6 +3874,7 @@ void TestBufferingOopClosure_test(); void TestCodeCacheRemSet_test(); void FreeRegionList_test(); void test_memset_with_concurrent_readers(); +void TestPredictions_test(); #endif void execute_internal_vm_tests() { @@ -3912,6 +3917,7 @@ void execute_internal_vm_tests() { run_unit_test(FreeRegionList_test()); } run_unit_test(test_memset_with_concurrent_readers()); + run_unit_test(TestPredictions_test()); #endif tty->print_cr("All internal VM tests passed"); } @@ -3986,6 +3992,19 @@ static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { *vm = (JavaVM *)(&main_vm); *(JNIEnv**)penv = thread->jni_environment(); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + if (UseJVMCICompiler) { + // JVMCI is initialized on a CompilerThread + if (BootstrapJVMCI) { + JavaThread* THREAD = thread; + JVMCICompiler* compiler = JVMCICompiler::instance(CATCH); + compiler->bootstrap(); + } + } + } +#endif + // Tracks the time application was running before GC RuntimeService::record_application_start(); diff --git a/hotspot/src/share/vm/prims/jniCheck.cpp b/hotspot/src/share/vm/prims/jniCheck.cpp index b851d0642e0..526eff57099 100644 --- a/hotspot/src/share/vm/prims/jniCheck.cpp +++ b/hotspot/src/share/vm/prims/jniCheck.cpp @@ -102,7 +102,8 @@ extern "C" { \ #define UNCHECKED() (unchecked_jni_NativeInterface) static const char * warn_wrong_jnienv = "Using JNIEnv in the wrong thread"; -static const char * warn_bad_class_descriptor = "JNI FindClass received a bad class descriptor \"%s\". A correct class descriptor " \ +static const char * warn_bad_class_descriptor1 = "JNI FindClass received a bad class descriptor \""; +static const char * warn_bad_class_descriptor2 = "\". A correct class descriptor " \ "has no leading \"L\" or trailing \";\". Incorrect descriptors will not be accepted in future releases."; static const char * fatal_using_jnienv_in_nonjava = "FATAL ERROR in native method: Using JNIEnv in non-Java thread"; static const char * warn_other_function_in_critical = "Warning: Calling other JNI functions in the scope of " \ @@ -484,7 +485,8 @@ void jniCheck::validate_class_descriptor(JavaThread* thr, const char* name) { name[0] == JVM_SIGNATURE_CLASS && // 'L' name[len-1] == JVM_SIGNATURE_ENDCLASS ) { // ';' char msg[JVM_MAXPATHLEN]; - jio_snprintf(msg, JVM_MAXPATHLEN, warn_bad_class_descriptor, name); + jio_snprintf(msg, JVM_MAXPATHLEN, "%s%s%s", + warn_bad_class_descriptor1, name, warn_bad_class_descriptor2); ReportJNIWarning(thr, msg); } } diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index ee57481dc69..c4e5b4e4a41 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -424,6 +424,8 @@ JVM_ENTRY(jobject, JVM_InitProperties(JNIEnv *env, jobject properties)) const char* compiler_name = "HotSpot " CSIZE "Client Compiler"; #elif defined(COMPILER2) const char* compiler_name = "HotSpot " CSIZE "Server Compiler"; +#elif INCLUDE_JVMCI + #error "INCLUDE_JVMCI should imply TIERED" #else const char* compiler_name = ""; #endif // compilers diff --git a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp index 9f661eb2194..3031f1c4e5b 100644 --- a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp +++ b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp @@ -266,7 +266,7 @@ void JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nmethod *nm, address scopes_data = nm->scopes_data_begin(); for( pcd = nm->scopes_pcs_begin(); pcd < nm->scopes_pcs_end(); ++pcd ) { - ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute(), pcd->return_oop()); + ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute(), pcd->rethrow_exception(), pcd->return_oop()); ScopeDesc *sd = &sc0; while( !sd->is_top() ) { sd = sd->sender(); } int bci = sd->bci(); diff --git a/hotspot/src/share/vm/prims/jvmtiEnter.xsl b/hotspot/src/share/vm/prims/jvmtiEnter.xsl index 3d3b38d15a3..09cc129fd7c 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnter.xsl +++ b/hotspot/src/share/vm/prims/jvmtiEnter.xsl @@ -44,9 +44,6 @@ # include "prims/jvmtiRawMonitor.hpp" # include "prims/jvmtiUtil.hpp" -// There are known-bad format/arg pairings in the code generated by this file. -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - @@ -543,8 +540,8 @@ static jvmtiError JNICALL if (trace_flags) { - tty->print_cr("JVMTI [%s] %s %s env=%d", curr_thread_name, func_name, - JvmtiUtil::error_name(JVMTI_ERROR_INVALID_ENVIRONMENT), env); + tty->print_cr("JVMTI [%s] %s %s env=" PTR_FORMAT, curr_thread_name, func_name, + JvmtiUtil::error_name(JVMTI_ERROR_INVALID_ENVIRONMENT), p2i(env)); } @@ -760,8 +757,8 @@ static jvmtiError JNICALL JVMTI_ERROR_INVALID_MONITOR - - not a raw monitor 0x%x - , rmonitor + - not a raw monitor " PTR_FORMAT " + , p2i(rmonitor) } @@ -777,8 +774,8 @@ static jvmtiError JNICALL JVMTI_ERROR_INVALID_THREAD - - jthread resolved to NULL - jthread = 0x%x - , + - jthread resolved to NULL - jthread = " PTR_FORMAT " + , p2i() } @@ -786,8 +783,8 @@ static jvmtiError JNICALL JVMTI_ERROR_INVALID_THREAD - - oop is not a thread - jthread = 0x%x - , + - oop is not a thread - jthread = " PTR_FORMAT " + , p2i() } @@ -798,8 +795,8 @@ static jvmtiError JNICALL JVMTI_ERROR_THREAD_NOT_ALIVE - - not a Java thread - jthread = 0x%x - , + - not a Java thread - jthread = " PTR_FORMAT " + , p2i() } @@ -842,7 +839,7 @@ static jvmtiError JNICALL JVMTI_ERROR_ILLEGAL_ARGUMENT - - negative depth - jthread = 0x%x + - negative depth - jthread = " INT32_FORMAT " , @@ -861,8 +858,8 @@ static jvmtiError JNICALL JVMTI_ERROR_INVALID_CLASS - - resolved to NULL - jclass = 0x%x - , + - resolved to NULL - jclass = " PTR_FORMAT " + , p2i() } @@ -870,8 +867,8 @@ static jvmtiError JNICALL JVMTI_ERROR_INVALID_CLASS - - not a class - jclass = 0x%x - , + - not a class - jclass = " PTR_FORMAT " + , p2i() } @@ -882,8 +879,8 @@ static jvmtiError JNICALL JVMTI_ERROR_INVALID_CLASS - - is a primitive class - jclass = 0x%x - , + - is a primitive class - jclass = " PTR_FORMAT " + , p2i() } @@ -892,8 +889,8 @@ static jvmtiError JNICALL JVMTI_ERROR_INVALID_CLASS - - no Klass* - jclass = 0x%x - , + - no Klass* - jclass = " PTR_FORMAT " + , p2i() } @@ -1034,12 +1031,12 @@ static jvmtiError JNICALL - + g ='%s' - =0x%x + =" PTR_FORMAT " @@ -1047,7 +1044,15 @@ static jvmtiError JNICALL , - + + + + + + + p2i() + + @@ -1057,7 +1062,7 @@ static jvmtiError JNICALL - =0x%x + =" PTR_FORMAT " @@ -1071,7 +1076,7 @@ static jvmtiError JNICALL , - + p2i() @@ -1083,13 +1088,13 @@ static jvmtiError JNICALL - =0x%x + =" PTR_FORMAT " , - + p2i() @@ -1214,18 +1219,25 @@ static jvmtiError JNICALL - + - =%d + =" INT32_FORMAT " + + + + + + + =" INT64_FORMAT " - =%ld + =" INT64_FORMAT " diff --git a/hotspot/src/share/vm/prims/jvmtiEventController.cpp b/hotspot/src/share/vm/prims/jvmtiEventController.cpp index 639c184bd23..893e91d9e94 100644 --- a/hotspot/src/share/vm/prims/jvmtiEventController.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEventController.cpp @@ -38,8 +38,6 @@ #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef JVMTI_TRACE #define EC_TRACE(out) do { \ if (JvmtiTrace::trace_event_controller()) { \ @@ -564,7 +562,7 @@ JvmtiEventControllerPrivate::recompute_enabled() { jlong was_any_env_thread_enabled = JvmtiEventController::_universal_global_event_enabled.get_bits(); jlong any_env_thread_enabled = 0; - EC_TRACE(("JVMTI [-] # recompute enabled - before %llx", was_any_env_thread_enabled)); + EC_TRACE(("JVMTI [-] # recompute enabled - before " UINT64_FORMAT_X, was_any_env_thread_enabled)); // compute non-thread-filters events. // This must be done separately from thread-filtered events, since some @@ -646,7 +644,7 @@ JvmtiEventControllerPrivate::recompute_enabled() { } - EC_TRACE(("JVMTI [-] # recompute enabled - after %llx", any_env_thread_enabled)); + EC_TRACE(("JVMTI [-] # recompute enabled - after " UINT64_FORMAT_X, any_env_thread_enabled)); } diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp index 4e1faf37204..1e061689c05 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp @@ -58,8 +58,6 @@ #include "gc/parallel/psMarkSweep.hpp" #endif // INCLUDE_ALL_GCS -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef JVMTI_TRACE #define EVT_TRACE(evt,out) if ((JvmtiTrace::event_trace_flags(evt) & JvmtiTrace::SHOW_EVENT_SENT) != 0) { SafeResourceMark rm; tty->print_cr out; } #define EVT_TRIG_TRACE(evt,out) if ((JvmtiTrace::event_trace_flags(evt) & JvmtiTrace::SHOW_EVENT_TRIGGER) != 0) { SafeResourceMark rm; tty->print_cr out; } @@ -770,7 +768,7 @@ void JvmtiExport::post_compiled_method_unload( EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD, ("JVMTI [%s] class compile method unload event sent jmethodID " PTR_FORMAT, - JvmtiTrace::safe_get_thread_name(thread), method)); + JvmtiTrace::safe_get_thread_name(thread), p2i(method))); ResourceMark rm(thread); @@ -805,7 +803,7 @@ void JvmtiExport::post_raw_breakpoint(JavaThread *thread, Method* method, addres if (!ets->breakpoint_posted() && ets->is_enabled(JVMTI_EVENT_BREAKPOINT)) { ThreadState old_os_state = thread->osthread()->get_state(); thread->osthread()->set_state(BREAKPOINTED); - EVT_TRACE(JVMTI_EVENT_BREAKPOINT, ("JVMTI [%s] Evt Breakpoint sent %s.%s @ %d", + EVT_TRACE(JVMTI_EVENT_BREAKPOINT, ("JVMTI [%s] Evt Breakpoint sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1258,7 +1256,7 @@ void JvmtiExport::post_single_step(JavaThread *thread, Method* method, address l for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { ets->compare_and_set_current_location(mh(), location, JVMTI_EVENT_SINGLE_STEP); if (!ets->single_stepping_posted() && ets->is_enabled(JVMTI_EVENT_SINGLE_STEP)) { - EVT_TRACE(JVMTI_EVENT_SINGLE_STEP, ("JVMTI [%s] Evt Single Step sent %s.%s @ %d", + EVT_TRACE(JVMTI_EVENT_SINGLE_STEP, ("JVMTI [%s] Evt Single Step sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1298,7 +1296,7 @@ void JvmtiExport::post_exception_throw(JavaThread *thread, Method* method, addre if (ets->is_enabled(JVMTI_EVENT_EXCEPTION) && (exception != NULL)) { EVT_TRACE(JVMTI_EVENT_EXCEPTION, - ("JVMTI [%s] Evt Exception thrown sent %s.%s @ %d", + ("JVMTI [%s] Evt Exception thrown sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1374,7 +1372,7 @@ void JvmtiExport::notice_unwind_due_to_exception(JavaThread *thread, Method* met return; } EVT_TRIG_TRACE(JVMTI_EVENT_EXCEPTION_CATCH, - ("JVMTI [%s] Trg unwind_due_to_exception triggered %s.%s @ %s%d - %s", + ("JVMTI [%s] Trg unwind_due_to_exception triggered %s.%s @ %s" INTX_FORMAT " - %s", JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1409,7 +1407,7 @@ void JvmtiExport::notice_unwind_due_to_exception(JavaThread *thread, Method* met for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (ets->is_enabled(JVMTI_EVENT_EXCEPTION_CATCH) && (exception_handle() != NULL)) { EVT_TRACE(JVMTI_EVENT_EXCEPTION_CATCH, - ("JVMTI [%s] Evt ExceptionCatch sent %s.%s @ %d", + ("JVMTI [%s] Evt ExceptionCatch sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1503,7 +1501,7 @@ void JvmtiExport::post_field_access(JavaThread *thread, Method* method, JvmtiEnvThreadStateIterator it(state); for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (ets->is_enabled(JVMTI_EVENT_FIELD_ACCESS)) { - EVT_TRACE(JVMTI_EVENT_FIELD_ACCESS, ("JVMTI [%s] Evt Field Access event sent %s.%s @ %d", + EVT_TRACE(JVMTI_EVENT_FIELD_ACCESS, ("JVMTI [%s] Evt Field Access event sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1667,7 +1665,7 @@ void JvmtiExport::post_field_modification(JavaThread *thread, Method* method, for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (ets->is_enabled(JVMTI_EVENT_FIELD_MODIFICATION)) { EVT_TRACE(JVMTI_EVENT_FIELD_MODIFICATION, - ("JVMTI [%s] Evt Field Modification event sent %s.%s @ %d", + ("JVMTI [%s] Evt Field Modification event sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1807,7 +1805,7 @@ void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, const jmethodID metho EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, ("JVMTI [%s] class compile method load event sent (by GenerateEvents), jmethodID=" PTR_FORMAT, - JvmtiTrace::safe_get_thread_name(thread), method)); + JvmtiTrace::safe_get_thread_name(thread), p2i(method))); JvmtiEventMark jem(thread); JvmtiJavaThreadEventTransition jet(thread); diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index ca95593ee87..b55e6e6d9a3 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -45,8 +45,6 @@ #include "utilities/bitMap.inline.hpp" #include "utilities/events.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - Array* VM_RedefineClasses::_old_methods = NULL; Array* VM_RedefineClasses::_new_methods = NULL; Method** VM_RedefineClasses::_matching_old_methods = NULL; @@ -1714,12 +1712,12 @@ void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method, // unless we are trying to stress ldc -> ldc_w rewriting RC_TRACE_WITH_THREAD(0x00080000, THREAD, ("%s@" INTPTR_FORMAT " old=%d, new=%d", Bytecodes::name(c), - bcp, cp_index, new_index)); + p2i(bcp), cp_index, new_index)); *(bcp + 1) = new_index; } else { RC_TRACE_WITH_THREAD(0x00080000, THREAD, ("%s->ldc_w@" INTPTR_FORMAT " old=%d, new=%d", - Bytecodes::name(c), bcp, cp_index, new_index)); + Bytecodes::name(c), p2i(bcp), cp_index, new_index)); // the new value needs ldc_w instead of ldc u_char inst_buffer[4]; // max instruction size is 4 bytes bcp = (address)inst_buffer; @@ -1780,7 +1778,7 @@ void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method, // the original index is mapped so update w/ new value RC_TRACE_WITH_THREAD(0x00080000, THREAD, ("%s@" INTPTR_FORMAT " old=%d, new=%d", Bytecodes::name(c), - bcp, cp_index, new_index)); + p2i(bcp), cp_index, new_index)); // Rewriter::rewrite_method() uses put_native_u2() in this // situation because it is reusing the constant pool index // location for a native index into the ConstantPoolCache. diff --git a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp index 3181fc5af38..ecc28a28d32 100644 --- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp @@ -588,7 +588,7 @@ class CallbackWrapper : public StackObj { _obj_tag = (_entry == NULL) ? 0 : _entry->tag(); // get the class and the class's tag value - assert(SystemDictionary::Class_klass()->oop_is_instanceMirror(), "Is not?"); + assert(InstanceKlass::cast(SystemDictionary::Class_klass())->is_mirror_instance_klass(), "Is not?"); _klass_tag = tag_for(tag_map, _o->klass()->java_mirror()); } diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 5aef22c58a2..05b5abb83a8 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -228,8 +228,8 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) { { ResourceMark rm; Method* m2 = m_klass_non_interface->vtable()->method_at(vmindex); assert(m->name() == m2->name() && m->signature() == m2->signature(), - err_msg("at %d, %s != %s", vmindex, - m->name_and_sig_as_C_string(), m2->name_and_sig_as_C_string())); + "at %d, %s != %s", vmindex, + m->name_and_sig_as_C_string(), m2->name_and_sig_as_C_string()); } #endif //ASSERT } @@ -345,7 +345,7 @@ bool MethodHandles::is_method_handle_invoke_name(Klass* klass, Symbol* name) { Symbol* MethodHandles::signature_polymorphic_intrinsic_name(vmIntrinsics::ID iid) { - assert(is_signature_polymorphic_intrinsic(iid), err_msg("iid=%d", iid)); + assert(is_signature_polymorphic_intrinsic(iid), "%d %s", iid, vmIntrinsics::name_at(iid)); switch (iid) { case vmIntrinsics::_invokeBasic: return vmSymbols::invokeBasic_name(); case vmIntrinsics::_linkToVirtual: return vmSymbols::linkToVirtual_name(); @@ -353,7 +353,7 @@ Symbol* MethodHandles::signature_polymorphic_intrinsic_name(vmIntrinsics::ID iid case vmIntrinsics::_linkToSpecial: return vmSymbols::linkToSpecial_name(); case vmIntrinsics::_linkToInterface: return vmSymbols::linkToInterface_name(); } - assert(false, ""); + fatal("unexpected intrinsic id: %d %s", iid, vmIntrinsics::name_at(iid)); return 0; } @@ -365,7 +365,7 @@ int MethodHandles::signature_polymorphic_intrinsic_ref_kind(vmIntrinsics::ID iid case vmIntrinsics::_linkToSpecial: return JVM_REF_invokeSpecial; case vmIntrinsics::_linkToInterface: return JVM_REF_invokeInterface; } - assert(false, err_msg("iid=%d", iid)); + fatal("unexpected intrinsic id: %d %s", iid, vmIntrinsics::name_at(iid)); return 0; } @@ -698,7 +698,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS LinkResolver::resolve_virtual_call(result, Handle(), defc, link_info, false, THREAD); } else { - assert(false, err_msg("ref_kind=%d", ref_kind)); + assert(false, "ref_kind=%d", ref_kind); } if (HAS_PENDING_EXCEPTION) { return empty; diff --git a/hotspot/src/share/vm/prims/nativeLookup.cpp b/hotspot/src/share/vm/prims/nativeLookup.cpp index 89b57e272d0..41eff71f8f6 100644 --- a/hotspot/src/share/vm/prims/nativeLookup.cpp +++ b/hotspot/src/share/vm/prims/nativeLookup.cpp @@ -111,6 +111,10 @@ extern "C" { void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls); void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass); void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass); +#if INCLUDE_JVMCI + jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); + void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); +#endif } #define CC (char*) /* cast a literal from (const char*) */ @@ -121,6 +125,10 @@ static JNINativeMethod lookup_special_native_methods[] = { { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, { CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) }, { CC"Java_sun_hotspot_WhiteBox_registerNatives", NULL, FN_PTR(JVM_RegisterWhiteBoxMethods) }, +#if INCLUDE_JVMCI + { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime", NULL, FN_PTR(JVM_GetJVMCIRuntime) }, + { CC"Java_jdk_vm_ci_hotspot_CompilerToVM_registerNatives", NULL, FN_PTR(JVM_RegisterJVMCINatives) }, +#endif }; static address lookup_special_native(char* jni_name) { diff --git a/hotspot/src/share/vm/prims/privilegedStack.cpp b/hotspot/src/share/vm/prims/privilegedStack.cpp index b214d4bde3e..2796d1446f1 100644 --- a/hotspot/src/share/vm/prims/privilegedStack.cpp +++ b/hotspot/src/share/vm/prims/privilegedStack.cpp @@ -30,8 +30,6 @@ #include "prims/privilegedStack.hpp" #include "runtime/vframe.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void PrivilegedElement::initialize(vframeStream* vfst, oop context, PrivilegedElement* next, TRAPS) { Method* method = vfst->method(); _klass = method->method_holder(); @@ -65,7 +63,7 @@ void PrivilegedElement::classes_do(KlassClosure* f) { #ifndef PRODUCT void PrivilegedElement::print_on(outputStream* st) const { - st->print(" 0x%lx ", _frame_id); + st->print(" " PTR_FORMAT " ", p2i(_frame_id)); _klass->print_value_on(st); if (protection_domain() != NULL) { st->print(" "); diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index 9897f8b6f7f..2d449258660 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -44,8 +44,6 @@ #include "gc/g1/g1SATBCardTableModRefBS.hpp" #endif // INCLUDE_ALL_GCS -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - /* * Implementation of class sun.misc.Unsafe */ @@ -126,7 +124,7 @@ inline void* index_oop_from_field_offset_long(oop p, jlong field_offset) { "raw [ptr+disp] must be consistent with oop::field_base"); } jlong p_size = HeapWordSize * (jlong)(p->size()); - assert(byte_offset < p_size, err_msg("Unsafe access: offset " INT64_FORMAT " > object's size " INT64_FORMAT, byte_offset, p_size)); + assert(byte_offset < p_size, "Unsafe access: offset " INT64_FORMAT " > object's size " INT64_FORMAT, byte_offset, p_size); } #endif if (sizeof(char*) == sizeof(jint)) // (this constant folds!) diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 5a44b5645a0..c930c549728 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -29,6 +29,7 @@ #include "classfile/classLoaderData.hpp" #include "classfile/stringTable.hpp" #include "code/codeCache.hpp" +#include "compiler/methodMatcher.hpp" #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" @@ -64,8 +65,6 @@ #endif // INCLUDE_NMT -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #define SIZE_T_MAX_VALUE ((size_t) -1) bool WhiteBox::_used = false; @@ -200,8 +199,8 @@ WB_ENTRY(void, WB_ReadFromNoaccessArea(JNIEnv* env, jobject o)) "\tUniverse::narrow_oop_base() is " PTR_FORMAT "\n" "\tUniverse::narrow_oop_use_implicit_null_checks() is %d", UseCompressedOops, - rhs.base(), - Universe::narrow_oop_base(), + p2i(rhs.base()), + p2i(Universe::narrow_oop_base()), Universe::narrow_oop_use_implicit_null_checks()); return; } @@ -625,6 +624,32 @@ WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobjec return (mh->queued_for_compilation() || nm != NULL); WB_END + +WB_ENTRY(jint, WB_MatchesMethod(JNIEnv* env, jobject o, jobject method, jstring pattern)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION_(env, JNI_FALSE); + + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + + ResourceMark rm; + char* method_str = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(pattern)); + + const char* error_msg = NULL; + + BasicMatcher* m = BasicMatcher::parse_method_pattern(method_str, error_msg); + if (m == NULL) { + assert(error_msg != NULL, "Must have error_msg"); + tty->print_cr("Got error: %s", error_msg); + return -1; + } + + // Pattern works - now check if it matches + int result = m->matches(mh); + delete m; + assert(result == 0 || result == 1, "Result out of range"); + return result; +WB_END + class AlwaysFalseClosure : public BoolObjectClosure { public: bool do_object_b(oop p) { return false; } @@ -998,7 +1023,7 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo ThreadToNativeFromVM ttn(thread); jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); CHECK_JNI_EXCEPTION_(env, NULL); - result = env->NewObjectArray(4, clazz, NULL); + result = env->NewObjectArray(5, clazz, NULL); if (result == NULL) { return result; } @@ -1020,6 +1045,10 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo CHECK_JNI_EXCEPTION_(env, NULL); env->SetObjectArrayElement(result, 3, id); + jobject address = longBox(thread, env, (jlong) code); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetObjectArrayElement(result, 4, address); + return result; WB_END @@ -1106,6 +1135,13 @@ WB_ENTRY(jobjectArray, WB_GetCodeBlob(JNIEnv* env, jobject o, jlong addr)) return codeBlob2objectArray(thread, env, &stub); WB_END +WB_ENTRY(jlong, WB_GetMethodData(JNIEnv* env, jobject wv, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION_(env, 0); + methodHandle mh(thread, Method::checked_resolve_jmethod_id(jmid)); + return (jlong) mh->method_data(); +WB_END + WB_ENTRY(jlong, WB_GetThreadStackSize(JNIEnv* env, jobject o)) return (jlong) Thread::current()->stack_size(); WB_END @@ -1115,6 +1151,7 @@ WB_ENTRY(jlong, WB_GetThreadRemainingStackSize(JNIEnv* env, jobject o)) return (jlong) t->stack_available(os::current_stack_pointer()) - (jlong) StackShadowPages * os::vm_page_size(); WB_END + int WhiteBox::array_bytes_to_length(size_t bytes) { return Array::bytes_to_length(bytes); } @@ -1191,6 +1228,11 @@ WB_ENTRY(void, WB_ForceSafepoint(JNIEnv* env, jobject wb)) VMThread::execute(&force_safepoint_op); WB_END +WB_ENTRY(long, WB_GetConstantPool(JNIEnv* env, jobject wb, jclass klass)) + instanceKlassHandle ikh(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + return (long) ikh->constants(); +WB_END + template static bool GetMethodOption(JavaThread* thread, JNIEnv* env, jobject method, jstring name, T* value) { assert(value != NULL, "sanity"); @@ -1430,6 +1472,9 @@ static JNINativeMethod methods[] = { CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState}, {CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation}, {CC"unlockCompilation", CC"()V", (void*)&WB_UnlockCompilation}, + {CC"matchesMethod", + CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I", + (void*)&WB_MatchesMethod}, {CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag}, {CC"isLockedVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag}, {CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag}, @@ -1479,12 +1524,15 @@ static JNINativeMethod methods[] = { {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, {CC"getCompilationActivityMode", CC"()I", (void*)&WB_GetCompilationActivityMode}, + {CC"getMethodData0", CC"(Ljava/lang/reflect/Executable;)J", + (void*)&WB_GetMethodData }, {CC"getCodeBlob", CC"(J)[Ljava/lang/Object;",(void*)&WB_GetCodeBlob }, {CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize }, {CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize }, {CC"assertMatchingSafepointCalls", CC"(ZZ)V", (void*)&WB_AssertMatchingSafepointCalls }, {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, + {CC"getConstantPool0", CC"(Ljava/lang/Class;)J", (void*)&WB_GetConstantPool }, {CC"getMethodBooleanOption", CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/Boolean;", (void*)&WB_GetMethodBooleaneOption}, diff --git a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp index 76c2aaa9f22..eb58e37c482 100644 --- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp +++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" +#include "compiler/compileTask.hpp" #include "runtime/advancedThresholdPolicy.hpp" #include "runtime/simpleThresholdPolicy.inline.hpp" @@ -162,6 +163,9 @@ bool AdvancedThresholdPolicy::is_method_profiled(Method* method) { // Called with the queue locked and with at least one element CompileTask* AdvancedThresholdPolicy::select_task(CompileQueue* compile_queue) { +#if INCLUDE_JVMCI + CompileTask *max_non_jvmci_task = NULL; +#endif CompileTask *max_task = NULL; Method* max_method = NULL; jlong t = os::javaTimeMillis(); @@ -179,6 +183,7 @@ CompileTask* AdvancedThresholdPolicy::select_task(CompileQueue* compile_queue) { if (PrintTieredEvents) { print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel)task->comp_level()); } + task->log_task_dequeued("stale"); compile_queue->remove_and_mark_stale(task); method->clear_queued_for_compilation(); task = next_task; @@ -194,6 +199,15 @@ CompileTask* AdvancedThresholdPolicy::select_task(CompileQueue* compile_queue) { task = next_task; } +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + if (max_non_jvmci_task != NULL) { + max_task = max_non_jvmci_task; + max_method = max_task->method(); + } + } +#endif + if (max_task->comp_level() == CompLevel_full_profile && TieredStopAtLevel > CompLevel_full_profile && is_method_profiled(max_method)) { max_task->set_comp_level(CompLevel_limited_profile); @@ -354,6 +368,14 @@ CompLevel AdvancedThresholdPolicy::common(Predicate p, Method* method, CompLevel if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { next_level = CompLevel_full_optimization; } else if ((this->*p)(i, b, cur_level, method)) { +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + // Since JVMCI takes a while to warm up, its queue inevitably backs up during + // early VM execution. + next_level = CompLevel_full_profile; + break; + } +#endif // C1-generated fully profiled code is about 30% slower than the limited profile // code that has only invocation and backedge counters. The observation is that // if C2 queue is large enough we can spend too much time in the fully profiled code @@ -362,7 +384,7 @@ CompLevel AdvancedThresholdPolicy::common(Predicate p, Method* method, CompLevel // we choose to compile a limited profiled version and then recompile with full profiling // when the load on C2 goes down. if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) > - Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { + Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { next_level = CompLevel_limited_profile; } else { next_level = CompLevel_full_profile; diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index c2307e85d6e..a35a00bb2dd 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -32,6 +32,7 @@ #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/taskqueue.hpp" +#include "logging/logConfiguration.hpp" #include "memory/allocation.inline.hpp" #include "memory/universe.inline.hpp" #include "oops/oop.inline.hpp" @@ -50,6 +51,9 @@ #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" #include "utilities/stringUtils.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#endif #if INCLUDE_ALL_GCS #include "gc/cms/compactibleFreeListSpace.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" @@ -213,6 +217,8 @@ void Arguments::init_system_properties() { // Set OS specific system properties values os::init_system_properties_values(); + + JVMCI_ONLY(JVMCIRuntime::init_system_properties(&_system_properties);) } // Update/Initialize System properties after JDK version number is known @@ -793,8 +799,10 @@ static bool set_bool_flag(const char* name, bool value, Flag::Flags origin) { } static bool set_fp_numeric_flag(const char* name, char* value, Flag::Flags origin) { - double v; - if (sscanf(value, "%lf", &v) != 1) { + char* end; + errno = 0; + double v = strtod(value, &end); + if ((errno != 0) || (*end != 0)) { return false; } @@ -978,9 +986,9 @@ bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { return set_string_flag(real_name, value, origin); } -#define SIGNED_FP_NUMBER_RANGE "[-0123456789.]" +#define SIGNED_FP_NUMBER_RANGE "[-0123456789.eE+]" #define SIGNED_NUMBER_RANGE "[-0123456789]" -#define NUMBER_RANGE "[0123456789]" +#define NUMBER_RANGE "[0123456789eE+-]" char value[BUFLEN + 1]; char value2[BUFLEN + 1]; if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE "=" "%" XSTR(BUFLEN) SIGNED_NUMBER_RANGE "." "%" XSTR(BUFLEN) NUMBER_RANGE "%c", name, value, value2, &dummy) == 3) { @@ -1374,7 +1382,7 @@ void Arguments::set_mode_flags(Mode mode) { } } -#if defined(COMPILER2) || defined(_LP64) || !INCLUDE_CDS +#if defined(COMPILER2) || INCLUDE_JVMCI || defined(_LP64) || !INCLUDE_CDS // Conflict: required to use shared spaces (-Xshare:on), but // incompatible command line options were chosen. @@ -1834,7 +1842,7 @@ void Arguments::select_gc() { void Arguments::set_ergonomics_flags() { select_gc(); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // Shared spaces work fine with other GCs but causes bytecode rewriting // to be disabled, which hurts interpreter performance and decreases // server performance. When -server is specified, keep the default off @@ -1918,7 +1926,7 @@ void Arguments::set_parallel_gc_flags() { void Arguments::set_g1_gc_flags() { assert(UseG1GC, "Error"); -#ifdef COMPILER1 +#if defined(COMPILER1) || INCLUDE_JVMCI FastTLABRefill = false; #endif FLAG_SET_DEFAULT(ParallelGCThreads, Abstract_VM_Version::parallel_worker_threads()); @@ -2428,20 +2436,6 @@ bool Arguments::check_vm_args_consistency() { MarkSweepAlwaysCompactCount = 1; // Move objects every gc. } - if (UseParallelOldGC && ParallelOldGCSplitALot) { - // Settings to encourage splitting. - if (!FLAG_IS_CMDLINE(NewRatio)) { - if (FLAG_SET_CMDLINE(uintx, NewRatio, 2) != Flag::SUCCESS) { - status = false; - } - } - if (!FLAG_IS_CMDLINE(ScavengeBeforeFullGC)) { - if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != Flag::SUCCESS) { - status = false; - } - } - } - if (!(UseParallelGC || UseParallelOldGC) && FLAG_IS_DEFAULT(ScavengeBeforeFullGC)) { FLAG_SET_DEFAULT(ScavengeBeforeFullGC, false); } @@ -2495,6 +2489,22 @@ bool Arguments::check_vm_args_consistency() { } #endif } +#if INCLUDE_JVMCI + if (EnableJVMCI) { + if (!ScavengeRootsInCode) { + warning("forcing ScavengeRootsInCode non-zero because JVMCI is enabled"); + ScavengeRootsInCode = 1; + } + if (FLAG_IS_DEFAULT(TypeProfileLevel)) { + TypeProfileLevel = 0; + } + if (UseJVMCICompiler) { + if (FLAG_IS_DEFAULT(TypeProfileWidth)) { + TypeProfileWidth = 8; + } + } + } +#endif // Check lower bounds of the code cache // Template Interpreter code is approximately 3X larger in debug builds. @@ -3190,6 +3200,26 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, if (FLAG_SET_CMDLINE(bool, PrintGCTimeStamps, true) != Flag::SUCCESS) { return JNI_EINVAL; } + } else if (match_option(option, "-Xlog", &tail)) { + bool ret = false; + if (strcmp(tail, ":help") == 0) { + LogConfiguration::print_command_line_help(defaultStream::output_stream()); + vm_exit(0); + } else if (strcmp(tail, ":disable") == 0) { + LogConfiguration::disable_logging(); + ret = true; + } else if (*tail == '\0') { + ret = LogConfiguration::parse_command_line_arguments(); + assert(ret, "-Xlog without arguments should never fail to parse"); + } else if (*tail == ':') { + ret = LogConfiguration::parse_command_line_arguments(tail + 1); + } + if (ret == false) { + jio_fprintf(defaultStream::error_stream(), + "Invalid -Xlog option '-Xlog%s'\n", + tail); + return JNI_EINVAL; + } // JNI hooks } else if (match_option(option, "-Xcheck", &tail)) { if (!strcmp(tail, ":jni")) { @@ -3306,19 +3336,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, return JNI_EINVAL; } #endif - } else if (match_option(option, "-XX:MaxDirectMemorySize=", &tail)) { - julong max_direct_memory_size = 0; - ArgsRange errcode = parse_memory_size(tail, &max_direct_memory_size, 0); - if (errcode != arg_in_range) { - jio_fprintf(defaultStream::error_stream(), - "Invalid maximum direct memory size: %s\n", - option->optionString); - describe_range_error(errcode); - return JNI_EINVAL; - } - if (FLAG_SET_CMDLINE(size_t, MaxDirectMemorySize, max_direct_memory_size) != Flag::SUCCESS) { - return JNI_EINVAL; - } #if !INCLUDE_MANAGEMENT } else if (match_option(option, "-XX:+ManagementServer")) { jio_fprintf(defaultStream::error_stream(), @@ -3463,6 +3480,37 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req const char* fileSep = os::file_separator(); sprintf(path, "%s%slib%sendorsed", Arguments::get_java_home(), fileSep, fileSep); +#if INCLUDE_JVMCI + jint res = JVMCIRuntime::save_options(_system_properties); + if (res != JNI_OK) { + return res; + } + + if (EnableJVMCI) { + // Append lib/jvmci/*.jar to boot class path + char jvmciDir[JVM_MAXPATHLEN]; + const char* fileSep = os::file_separator(); + jio_snprintf(jvmciDir, sizeof(jvmciDir), "%s%slib%sjvmci", Arguments::get_java_home(), fileSep, fileSep); + DIR* dir = os::opendir(jvmciDir); + if (dir != NULL) { + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(jvmciDir), mtInternal); + while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { + const char* name = entry->d_name; + const char* ext = name + strlen(name) - 4; + if (ext > name && strcmp(ext, ".jar") == 0) { + char fileName[JVM_MAXPATHLEN]; + jio_snprintf(fileName, sizeof(fileName), "%s%s%s", jvmciDir, fileSep, name); + scp_p->add_suffix(fileName); + scp_assembly_required = true; + } + } + FREE_C_HEAP_ARRAY(char, dbuf); + os::closedir(dir); + } + } +#endif // INCLUDE_JVMCI + if (CheckEndorsedAndExtDirs) { int nonEmptyDirs = 0; // check endorsed directory @@ -3521,7 +3569,7 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req FLAG_SET_ERGO(uintx, InitialTenuringThreshold, MaxTenuringThreshold); } -#ifndef COMPILER2 +#if !defined(COMPILER2) && !INCLUDE_JVMCI // Don't degrade server performance for footprint if (FLAG_IS_DEFAULT(UseLargePages) && MaxHeapSize < LargePageHeapSizeThreshold) { @@ -3531,7 +3579,7 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req FLAG_SET_DEFAULT(UseLargePages, false); } -#else +#elif defined(COMPILER2) if (!FLAG_IS_DEFAULT(OptoLoopAlignment) && FLAG_IS_DEFAULT(MaxLoopPad)) { FLAG_SET_DEFAULT(MaxLoopPad, OptoLoopAlignment-1); } @@ -3690,8 +3738,6 @@ jint Arguments::parse_options_environment_variable(const char* name, return retcode; } -const int OPTION_BUFFER_SIZE = 1024; - jint Arguments::parse_vm_options_file(const char* file_name, ScopedVMInitArgs* vm_args) { // read file into buffer int fd = ::open(file_name, O_RDONLY); @@ -3702,8 +3748,24 @@ jint Arguments::parse_vm_options_file(const char* file_name, ScopedVMInitArgs* v return JNI_ERR; } + struct stat stbuf; + int retcode = os::stat(file_name, &stbuf); + if (retcode != 0) { + jio_fprintf(defaultStream::error_stream(), + "Could not stat options file '%s'\n", + file_name); + os::close(fd); + return JNI_ERR; + } + + if (stbuf.st_size == 0) { + // tell caller there is no option data and that is ok + os::close(fd); + return JNI_OK; + } + // '+ 1' for NULL termination even with max bytes - int bytes_alloc = OPTION_BUFFER_SIZE + 1; + size_t bytes_alloc = stbuf.st_size + 1; char *buf = NEW_C_HEAP_ARRAY_RETURN_NULL(char, bytes_alloc, mtInternal); if (NULL == buf) { @@ -3713,14 +3775,14 @@ jint Arguments::parse_vm_options_file(const char* file_name, ScopedVMInitArgs* v return JNI_ENOMEM; } - memset(buf, 0, (unsigned)bytes_alloc); + memset(buf, 0, bytes_alloc); // Fill buffer // Use ::read() instead of os::read because os::read() // might do a thread state transition // and it is too early for that here - int bytes_read = ::read(fd, (void *)buf, (unsigned)bytes_alloc); + ssize_t bytes_read = ::read(fd, (void *)buf, (unsigned)bytes_alloc); os::close(fd); if (bytes_read < 0) { FREE_C_HEAP_ARRAY(char, buf); @@ -3735,16 +3797,7 @@ jint Arguments::parse_vm_options_file(const char* file_name, ScopedVMInitArgs* v return JNI_OK; } - // file is larger than OPTION_BUFFER_SIZE - if (bytes_read > bytes_alloc - 1) { - FREE_C_HEAP_ARRAY(char, buf); - jio_fprintf(defaultStream::error_stream(), - "Options file '%s' is larger than %d bytes.\n", - file_name, bytes_alloc - 1); - return JNI_EINVAL; - } - - int retcode = parse_options_buffer(file_name, buf, bytes_read, vm_args); + retcode = parse_options_buffer(file_name, buf, bytes_read, vm_args); FREE_C_HEAP_ARRAY(char, buf); return retcode; @@ -3910,16 +3963,8 @@ jint Arguments::insert_vm_options_file(const JavaVMInitArgs* args, return code; } - // Now set global settings from the vm_option file, giving an error if - // it has VMOptionsFile in it - code = match_special_option_and_act(vm_options_file_args->get(), flags_file, - NULL, NULL, NULL); - if (code != JNI_OK) { - return code; - } - if (vm_options_file_args->get()->nOptions < 1) { - return 0; + return JNI_OK; } return args_out->insert(args, vm_options_file_args->get(), @@ -3954,17 +3999,29 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, // The caller accepts -XX:VMOptionsFile if (*vm_options_file != NULL) { jio_fprintf(defaultStream::error_stream(), - "Only one VM Options file is supported " - "on the command line\n"); + "The VM Options file can only be specified once and " + "only on the command line.\n"); return JNI_EINVAL; } *vm_options_file = (char *) tail; vm_options_file_pos = index; // save position of -XX:VMOptionsFile - if (*vm_options_file == NULL) { - jio_fprintf(defaultStream::error_stream(), - "Cannot copy vm_options_file name.\n"); - return JNI_ENOMEM; + // If there's a VMOptionsFile, parse that (also can set flags_file) + jint code = insert_vm_options_file(args, flags_file, vm_options_file, + vm_options_file_pos, + vm_options_file_args, args_out); + if (code != JNI_OK) { + return code; + } + if (args_out->is_set()) { + // The VMOptions file inserted some options so switch 'args' + // to the new set of options, and continue processing which + // preserves "last option wins" semantics. + args = args_out->get(); + // The first option from the VMOptionsFile replaces the + // current option. So we back track to process the + // replacement option. + index--; } } else { jio_fprintf(defaultStream::error_stream(), @@ -4024,12 +4081,6 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, } #endif } - - // If there's a VMOptionsFile, parse that (also can set flags_file) - if ((vm_options_file != NULL) && (*vm_options_file != NULL)) { - return insert_vm_options_file(args, flags_file, vm_options_file, - vm_options_file_pos, vm_options_file_args, args_out); - } return JNI_OK; } @@ -4279,6 +4330,9 @@ jint Arguments::apply_ergo() { #ifdef COMPILER1 || !UseFastLocking #endif // COMPILER1 +#if INCLUDE_JVMCI + || !JVMCIUseFastLocking +#endif ) { if (!FLAG_IS_DEFAULT(UseBiasedLocking) && UseBiasedLocking) { // flag set to true on command line; warn the user that they diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp index 5db0382640b..5371aa30da2 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp @@ -33,6 +33,9 @@ #include "runtime/commandLineFlagConstraintsRuntime.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" +#if INCLUDE_JVMCI +#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" +#endif class CommandLineFlagConstraint_bool : public CommandLineFlagConstraint { CommandLineFlagConstraintFunc_bool _constraint; @@ -220,7 +223,7 @@ void emit_constraint_double(const char* name, CommandLineFlagConstraintFunc_doub #define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type // the "name" argument must be a string literal -#define INITIAL_CONSTRAINTS_SIZE 16 +#define INITIAL_CONSTRAINTS_SIZE 45 GrowableArray* CommandLineFlagConstraintList::_constraints = NULL; CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse; @@ -251,6 +254,18 @@ void CommandLineFlagConstraintList::init(void) { IGNORE_RANGE, EMIT_CONSTRAINT_CHECK)); +#if INCLUDE_JVMCI + emit_constraint_no(NULL JVMCI_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, + EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, + EMIT_CONSTRAINT_PRODUCT_FLAG, + EMIT_CONSTRAINT_PD_PRODUCT_FLAG, + EMIT_CONSTRAINT_DIAGNOSTIC_FLAG, + EMIT_CONSTRAINT_EXPERIMENTAL_FLAG, + EMIT_CONSTRAINT_NOTPRODUCT_FLAG, + IGNORE_RANGE, + EMIT_CONSTRAINT_CHECK)); +#endif // INCLUDE_JVMCI + #ifdef COMPILER1 emit_constraint_no(NULL C1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, @@ -274,7 +289,7 @@ void CommandLineFlagConstraintList::init(void) { EMIT_CONSTRAINT_CHECK)); #endif // COMPILER2 -#ifndef INCLUDE_ALL_GCS +#if INCLUDE_ALL_GCS emit_constraint_no(NULL G1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, EMIT_CONSTRAINT_PRODUCT_FLAG, @@ -305,10 +320,7 @@ CommandLineFlagConstraint* CommandLineFlagConstraintList::find_if_needs_check(co // Check constraints for specific constraint type. bool CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::ConstraintType type) { - // Skip if we already checked. - if (type < _validating_type) { - return true; - } + guarantee(type > _validating_type, "Constraint check is out of order."); _validating_type = type; bool status = true; diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp index ee330018eae..120dfff1d64 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp @@ -54,9 +54,9 @@ public: enum ConstraintType { // Will be validated during argument processing (Arguments::parse_argument). AtParse = 0, - // Will be validated by CommandLineFlags::check_constraints_of_after_ergo(). - AfterErgo = 1, - // Will be validated by CommandLineFlags::check_constraints_of_after_memory_init(). + // Will be validated inside Threads::create_vm(), right after Arguments::apply_ergo(). + AfterErgo = 1, + // Will be validated inside universe_init(), right after Metaspace::global_initialize(). AfterMemoryInit = 2 }; diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp index 0b864a09700..7b5485339ae 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp @@ -23,6 +23,10 @@ */ #include "precompiled.hpp" +#include "oops/metadata.hpp" +#include "runtime/os.hpp" +#include "code/relocInfo.hpp" +#include "interpreter/invocationCounter.hpp" #include "runtime/arguments.hpp" #include "runtime/commandLineFlagConstraintsCompiler.hpp" #include "runtime/commandLineFlagRangeList.hpp" @@ -58,7 +62,7 @@ Flag::Error AliasLevelConstraintFunc(intx value, bool verbose) { */ Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { int min_number_of_compiler_threads = 0; -#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) +#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) && !INCLUDE_JVMCI // case 1 #else if (!TieredCompilation || (TieredStopAtLevel < CompLevel_full_optimization)) { @@ -84,3 +88,308 @@ Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { return Flag::SUCCESS; } } + +Flag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose) { + if (value < 0) { + CommandLineError::print(verbose, + "Unable to determine system-specific value for AllocatePrefetchDistance. " + "Please provide appropriate value, if unsure, use 0 to disable prefetching\n"); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { + intx max_value = max_intx; +#if defined(SPARC) + max_value = 1; +#elif defined(X86) + max_value = 3; +#endif + if (value < 0 || value > max_value) { + CommandLineError::print(verbose, + "AllocatePrefetchInstr (" INTX_FORMAT ") must be " + "between 0 and " INTX_FORMAT "\n", value, max_value); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose) { + if (value < 0 || value > max_jint) { + CommandLineError::print(verbose, + "AllocatePrefetchStepSize (" INTX_FORMAT ") " + "must be between 0 and %d\n", + AllocatePrefetchStepSize, + max_jint); + return Flag::VIOLATES_CONSTRAINT; + } + + if (AllocatePrefetchDistance % AllocatePrefetchStepSize != 0) { + CommandLineError::print(verbose, + "AllocatePrefetchDistance (" INTX_FORMAT ") " + "%% AllocatePrefetchStepSize (" INTX_FORMAT ") " + "= " INTX_FORMAT " " + "must be 0\n", + AllocatePrefetchDistance, AllocatePrefetchStepSize, + AllocatePrefetchDistance % AllocatePrefetchStepSize); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error CompileThresholdConstraintFunc(intx value, bool verbose) { + if (value < 0 || value > INT_MAX >> InvocationCounter::count_shift) { + CommandLineError::print(verbose, + "CompileThreshold (" INTX_FORMAT ") " + "must be between 0 and %d\n", + value, + INT_MAX >> InvocationCounter::count_shift); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { + int backward_branch_limit; + if (ProfileInterpreter) { + if (OnStackReplacePercentage < InterpreterProfilePercentage) { + CommandLineError::print(verbose, + "OnStackReplacePercentage (" INTX_FORMAT ") must be " + "larger than InterpreterProfilePercentage (" INTX_FORMAT ")\n", + OnStackReplacePercentage, InterpreterProfilePercentage); + return Flag::VIOLATES_CONSTRAINT; + } + + backward_branch_limit = ((CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100) + << InvocationCounter::count_shift; + + if (backward_branch_limit < 0) { + CommandLineError::print(verbose, + "CompileThreshold * (InterpreterProfilePercentage - OnStackReplacePercentage) / 100 = " + INTX_FORMAT " " + "must be between 0 and " INTX_FORMAT ", try changing " + "CompileThreshold, InterpreterProfilePercentage, and/or OnStackReplacePercentage\n", + (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100, + INT_MAX >> InvocationCounter::count_shift); + return Flag::VIOLATES_CONSTRAINT; + } + } else { + if (OnStackReplacePercentage < 0 ) { + CommandLineError::print(verbose, + "OnStackReplacePercentage (" INTX_FORMAT ") must be " + "non-negative\n", OnStackReplacePercentage); + return Flag::VIOLATES_CONSTRAINT; + } + + backward_branch_limit = ((CompileThreshold * OnStackReplacePercentage) / 100) + << InvocationCounter::count_shift; + + if (backward_branch_limit < 0) { + CommandLineError::print(verbose, + "CompileThreshold * OnStackReplacePercentage / 100 = " INTX_FORMAT " " + "must be between 0 and " INTX_FORMAT ", try changing " + "CompileThreshold and/or OnStackReplacePercentage\n", + (CompileThreshold * OnStackReplacePercentage) / 100, + INT_MAX >> InvocationCounter::count_shift); + return Flag::VIOLATES_CONSTRAINT; + } + } + return Flag::SUCCESS; +} + +Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { + if (CodeCacheSegmentSize < (uintx)CodeEntryAlignment) { + CommandLineError::print(verbose, + "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " + "larger than or equal to CodeEntryAlignment (" INTX_FORMAT ")" + "to align entry points\n", + CodeCacheSegmentSize, CodeEntryAlignment); + return Flag::VIOLATES_CONSTRAINT; + } + + if (CodeCacheSegmentSize < sizeof(jdouble)) { + CommandLineError::print(verbose, + "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " + "at least " SIZE_FORMAT " to align constants\n", + CodeCacheSegmentSize, sizeof(jdouble)); + return Flag::VIOLATES_CONSTRAINT; + } + +#ifdef COMPILER2 + if (CodeCacheSegmentSize < (uintx)OptoLoopAlignment) { + CommandLineError::print(verbose, + "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " + "larger than or equal to OptoLoopAlignment (" INTX_FORMAT ")" + "to align inner loops\n", + CodeCacheSegmentSize, OptoLoopAlignment); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + return Flag::SUCCESS; +} + +Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { + if (value < min_jint || value > max_jint) { + CommandLineError::print(verbose, + "CompileThreadPriority (" INTX_FORMAT ") " + "must be between %d and %d. " + "Please also make sure to specify values that are " + "meaningful to your operating system\n", + value, min_jint, max_jint); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { +#ifdef SPARC + if (CodeEntryAlignment % relocInfo::addr_unit() != 0) { + CommandLineError::print(verbose, + "CodeEntryAlignment (" INTX_FORMAT ") must be " + "multiple of NOP size\n", CodeEntryAlignment); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + if (!is_power_of_2(value)) { + CommandLineError::print(verbose, + "CodeEntryAlignment (" INTX_FORMAT ") must be " + "a power of two\n", CodeEntryAlignment); + return Flag::VIOLATES_CONSTRAINT; + } + + if (CodeEntryAlignment < 16) { + CommandLineError::print(verbose, + "CodeEntryAlignment (" INTX_FORMAT ") must be " + "greater than or equal to %d\n", + CodeEntryAlignment, 16); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { + if (value < 0 || value > 16) { + CommandLineError::print(verbose, + "OptoLoopAlignment (" INTX_FORMAT ") " + "must be between 0 and 16\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } + + if (!is_power_of_2(value)) { + CommandLineError::print(verbose, + "OptoLoopAlignment (" INTX_FORMAT ") " + "must be a power of two\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } + +#ifdef SPARC + if (OptoLoopAlignment % relocInfo::addr_unit() != 0) { + CommandLineError::print(verbose, + "OptoLoopAlignment (" INTX_FORMAT ") must be " + "multiple of NOP size\n"); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + return Flag::SUCCESS; +} + +Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose) { + if (value != 0) { + CommandLineError::print(verbose, + "ArraycopyDstPrefetchDistance (" INTX_FORMAT ") must be 0\n"); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose) { + if (value != 0) { + CommandLineError::print(verbose, + "ArraycopySrcPrefetchDistance (" INTX_FORMAT ") must be 0\n"); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose) { + for (int i = 0; i < 3; i++) { + if (value % 10 > 2) { + CommandLineError::print(verbose, + "Invalid value (" UINTX_FORMAT ") " + "in TypeProfileLevel at position %d\n", value, i); + return Flag::VIOLATES_CONSTRAINT; + } + value = value / 10; + } + + return Flag::SUCCESS; +} + +#ifdef COMPILER2 +Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { + if (InteriorEntryAlignment > CodeEntryAlignment) { + CommandLineError::print(verbose, + "InteriorEntryAlignment (" INTX_FORMAT ") must be " + "less than or equal to CodeEntryAlignment (" INTX_FORMAT ")\n", + InteriorEntryAlignment, CodeEntryAlignment); + return Flag::VIOLATES_CONSTRAINT; + } + +#ifdef SPARC + if (InteriorEntryAlignment % relocInfo::addr_unit() != 0) { + CommandLineError::print(verbose, + "InteriorEntryAlignment (" INTX_FORMAT ") must be " + "multiple of NOP size\n"); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + if (!is_power_of_2(value)) { + CommandLineError::print(verbose, + "InteriorEntryAlignment (" INTX_FORMAT ") must be " + "a power of two\n", InteriorEntryAlignment); + return Flag::VIOLATES_CONSTRAINT; + } + + int minimum_alignment = 16; +#if defined(SPARC) || (defined(X86) && !defined(AMD64)) + minimum_alignment = 4; +#endif + + if (InteriorEntryAlignment < minimum_alignment) { + CommandLineError::print(verbose, + "InteriorEntryAlignment (" INTX_FORMAT ") must be " + "greater than or equal to %d\n", + InteriorEntryAlignment, minimum_alignment); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose) { + if (value < MaxNodeLimit * 2 / 100 || value > MaxNodeLimit * 40 / 100) { + CommandLineError::print(verbose, + "NodeLimitFudgeFactor must be between 2%% and 40%% " + "of MaxNodeLimit (" INTX_FORMAT ")\n", + MaxNodeLimit); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} +#endif // COMPILER2 diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp index 1770a107d5f..f9d07848960 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp @@ -38,4 +38,34 @@ Flag::Error AliasLevelConstraintFunc(intx value, bool verbose); Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose); +Flag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose); + +Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose); + +Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose); + +Flag::Error CompileThresholdConstraintFunc(intx value, bool verbose); + +Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose); + +Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose); + +Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose); + +Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose); + +Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose); + +Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose); + +Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose); + +Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose); + +#ifdef COMPILER2 +Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose); + +Flag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose); +#endif + #endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP */ diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp index ba277cefc56..3b9419f075a 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp @@ -23,16 +23,19 @@ */ #include "precompiled.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/collectorPolicy.hpp" +#include "gc/shared/threadLocalAllocBuffer.hpp" #include "runtime/arguments.hpp" #include "runtime/commandLineFlagConstraintsGC.hpp" #include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" #include "utilities/defaultStream.hpp" #if INCLUDE_ALL_GCS #include "gc/g1/g1_globals.hpp" #include "gc/g1/heapRegionBounds.inline.hpp" -#include "gc/parallel/parallelScavengeHeap.hpp" #include "gc/shared/plab.hpp" #endif // INCLUDE_ALL_GCS #ifdef COMPILER1 @@ -42,6 +45,71 @@ #include "opto/c2_globals.hpp" #endif // COMPILER2 +// Some flags that have default values that indicate that the +// JVM should automatically determine an appropriate value +// for that flag. In those cases it is only appropriate for the +// constraint checking to be done if the user has specified the +// value(s) of the flag(s) on the command line. In the constraint +// checking functions, FLAG_IS_CMDLINE() is used to check if +// the flag has been set by the user and so should be checked. + +#if INCLUDE_ALL_GCS +static Flag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) { + // CMSWorkQueueDrainThreshold is verified to be less than max_juint + if (UseConcMarkSweepGC && (threads > (uint)(max_jint / (uint)threshold))) { + CommandLineError::print(verbose, + "ParallelGCThreads (" UINT32_FORMAT ") or CMSWorkQueueDrainThreshold (" + UINTX_FORMAT ") is too large\n", + threads, threshold); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} +#endif + +// As ParallelGCThreads differs among GC modes, we need constraint function. +Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + // Parallel GC passes ParallelGCThreads when creating GrowableArray as 'int' type parameter. + // So can't exceed with "max_jint" + if (UseParallelGC && (value > (uint)max_jint)) { + CommandLineError::print(verbose, + "ParallelGCThreads (" UINT32_FORMAT ") must be " + "less than or equal to " UINT32_FORMAT " for Parallel GC\n", + value, max_jint); + return Flag::VIOLATES_CONSTRAINT; + } + // To avoid overflow at ParScanClosure::do_oop_work. + if (UseConcMarkSweepGC && (value > (max_jint / 10))) { + CommandLineError::print(verbose, + "ParallelGCThreads (" UINT32_FORMAT ") must be " + "less than or equal to " UINT32_FORMAT " for CMS GC\n", + value, (max_jint / 10)); + return Flag::VIOLATES_CONSTRAINT; + } + status = ParallelGCThreadsAndCMSWorkQueueDrainThreshold(value, CMSWorkQueueDrainThreshold, verbose); +#endif + return status; +} + +// As ConcGCThreads should be smaller than ParallelGCThreads, +// we need constraint function. +Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { +#if INCLUDE_ALL_GCS + // CMS and G1 GCs use ConcGCThreads. + if ((UseConcMarkSweepGC || UseG1GC) && (value > ParallelGCThreads)) { + CommandLineError::print(verbose, + "ConcGCThreads (" UINT32_FORMAT ") must be " + "less than or equal to ParallelGCThreads (" UINT32_FORMAT ")\n", + value, ParallelGCThreads); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; +} + static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS if ((UseConcMarkSweepGC || UseG1GC) && (value < PLAB::min_size())) { @@ -69,16 +137,40 @@ static Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbos } static Flag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) { - if (MinPLABSizeBounds(name, value, verbose) == Flag::SUCCESS) { + Flag::Error status = MinPLABSizeBounds(name, value, verbose); + + if (status == Flag::SUCCESS) { return MaxPLABSizeBounds(name, value, verbose); } - return Flag::VIOLATES_CONSTRAINT; + return status; } Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) { return MinMaxPLABSizeBounds("YoungPLABSize", value, verbose); } +Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + if (value == 0) { + CommandLineError::print(verbose, + "OldPLABSize (" SIZE_FORMAT ") must be greater than 0", + value); + return Flag::VIOLATES_CONSTRAINT; + } + // For CMS, OldPLABSize is the number of free blocks of a given size that are used when + // replenishing the local per-worker free list caches. + // For more details, please refer to Arguments::set_cms_and_parnew_gc_flags(). + status = MaxPLABSizeBounds("OldPLABSize", value, verbose); + } else { + status = MinMaxPLABSizeBounds("OldPLABSize", value, verbose); + } +#endif + return status; +} + Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxHeapFreeRatio) { CommandLineError::print(verbose, @@ -103,6 +195,23 @@ Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) { } } +static Flag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) { + if ((softRef > 0) && ((maxHeap / M) > (max_uintx / softRef))) { + CommandLineError::print(verbose, + "Desired lifetime of SoftReferences cannot be expressed correctly. " + "MaxHeapSize (" SIZE_FORMAT ") or SoftRefLRUPolicyMSPerMB " + "(" INTX_FORMAT ") is too large\n", + maxHeap, softRef); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) { + return CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(MaxHeapSize, value, verbose); +} + Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxMetaspaceFreeRatio) { CommandLineError::print(verbose, @@ -127,45 +236,111 @@ Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { } } -// GC workaround for "-XX:+UseConcMarkSweepGC" -// which sets InitialTenuringThreshold to 7 but leaves MaxTenuringThreshold remaining at 6 -// and therefore would invalidate the constraint -#define UseConcMarkSweepGCWorkaroundIfNeeded(initial, max) { \ - if ((initial == 7) && (max == 6)) { \ - return Flag::SUCCESS; \ - } \ -} - Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { - UseConcMarkSweepGCWorkaroundIfNeeded(value, MaxTenuringThreshold); - - if (value > MaxTenuringThreshold) { - CommandLineError::print(verbose, - "InitialTenuringThreshold (" UINTX_FORMAT ") must be " - "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n", - value, MaxTenuringThreshold); - return Flag::VIOLATES_CONSTRAINT; - } else { - return Flag::SUCCESS; +#if INCLUDE_ALL_GCS + // InitialTenuringThreshold is only used for ParallelGC. + if (UseParallelGC && (value > MaxTenuringThreshold)) { + CommandLineError::print(verbose, + "InitialTenuringThreshold (" UINTX_FORMAT ") must be " + "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n", + value, MaxTenuringThreshold); + return Flag::VIOLATES_CONSTRAINT; } +#endif + return Flag::SUCCESS; } Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { - UseConcMarkSweepGCWorkaroundIfNeeded(InitialTenuringThreshold, value); - - if (value < InitialTenuringThreshold) { +#if INCLUDE_ALL_GCS + // As only ParallelGC uses InitialTenuringThreshold, + // we don't need to compare InitialTenuringThreshold with MaxTenuringThreshold. + if (UseParallelGC && (value < InitialTenuringThreshold)) { CommandLineError::print(verbose, "MaxTenuringThreshold (" UINTX_FORMAT ") must be " "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n", value, InitialTenuringThreshold); return Flag::VIOLATES_CONSTRAINT; + } +#endif + + // MaxTenuringThreshold=0 means NeverTenure=false && AlwaysTenure=true + if ((value == 0) && (NeverTenure || !AlwaysTenure)) { + CommandLineError::print(verbose, + "MaxTenuringThreshold (0) should match to NeverTenure=false " + "&& AlwaysTenure=true. But we have NeverTenure=%s " + "AlwaysTenure=%s\n", + NeverTenure ? "true" : "false", + AlwaysTenure ? "true" : "false"); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} + +#if INCLUDE_ALL_GCS +Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + + // Default value of G1RSetRegionEntries=0 means will be set ergonomically. + // Minimum value is 1. + if (FLAG_IS_CMDLINE(G1RSetRegionEntries) && (value < 1)) { + CommandLineError::print(verbose, + "G1RSetRegionEntries (" INTX_FORMAT ") must be " + "greater than or equal to 1\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + + // Default value of G1RSetSparseRegionEntries=0 means will be set ergonomically. + // Minimum value is 1. + if (FLAG_IS_CMDLINE(G1RSetSparseRegionEntries) && (value < 1)) { + CommandLineError::print(verbose, + "G1RSetSparseRegionEntries (" INTX_FORMAT ") must be " + "greater than or equal to 1\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error G1YoungSurvRateNumRegionsSummaryConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + + if (value > (intx)HeapRegionBounds::target_number()) { + CommandLineError::print(verbose, + "G1YoungSurvRateNumRegionsSummary (" INTX_FORMAT ") must be " + "less than or equal to region count (" SIZE_FORMAT ")\n", + value, HeapRegionBounds::target_number()); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + + // Default value of G1HeapRegionSize=0 means will be set ergonomically. + if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < HeapRegionBounds::min_size())) { + CommandLineError::print(verbose, + "G1HeapRegionSize (" SIZE_FORMAT ") must be " + "greater than or equal to ergonomic heap region minimum size\n", + value); + return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; } } -#if INCLUDE_ALL_GCS Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + if (value > G1MaxNewSizePercent) { CommandLineError::print(verbose, "G1NewSizePercent (" UINTX_FORMAT ") must be " @@ -178,6 +353,8 @@ Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { } Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + if (value < G1NewSizePercent) { CommandLineError::print(verbose, "G1MaxNewSizePercent (" UINTX_FORMAT ") must be " @@ -188,15 +365,56 @@ Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { return Flag::SUCCESS; } } - #endif // INCLUDE_ALL_GCS -Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { - if (value > CMSOldPLABMax) { +Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC && (value > ((uintx)max_jint / (uintx)ParallelGCThreads))) { CommandLineError::print(verbose, - "CMSOldPLABMin (" SIZE_FORMAT ") must be " - "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n", - value, CMSOldPLABMax); + "ParGCStridesPerThread (" UINTX_FORMAT ") must be " + "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n", + value, ((uintx)max_jint / (uintx)ParallelGCThreads)); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; +} + +Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + if (value > CMSOldPLABMax) { + CommandLineError::print(verbose, + "CMSOldPLABMin (" SIZE_FORMAT ") must be " + "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n", + value, CMSOldPLABMax); + return Flag::VIOLATES_CONSTRAINT; + } + status = MaxPLABSizeBounds("CMSOldPLABMin", value, verbose); + } +#endif + return status; +} + +Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + status = MaxPLABSizeBounds("CMSOldPLABMax", value, verbose); + } +#endif + return status; +} + +Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { + if (value > MarkStackSizeMax) { + CommandLineError::print(verbose, + "MarkStackSize (" SIZE_FORMAT ") must be " + "less than or equal to MarkStackSizeMax (" SIZE_FORMAT ")\n", + value, MarkStackSizeMax); return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; @@ -204,23 +422,212 @@ Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { } Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) { - if (value <= CMSPrecleanNumerator) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) { CommandLineError::print(verbose, "CMSPrecleanDenominator (" UINTX_FORMAT ") must be " "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n", value, CMSPrecleanNumerator); return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; +} + +Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC && (value >= CMSPrecleanDenominator)) { + CommandLineError::print(verbose, + "CMSPrecleanNumerator (" UINTX_FORMAT ") must be " + "less than CMSPrecleanDenominator (" UINTX_FORMAT ")\n", + value, CMSPrecleanDenominator); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; +} + +Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(ParallelGCThreads, value, verbose); + } +#endif + return Flag::SUCCESS; +} + +Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseG1GC && FLAG_IS_CMDLINE(MaxGCPauseMillis) && (value >= GCPauseIntervalMillis)) { + CommandLineError::print(verbose, + "MaxGCPauseMillis (" UINTX_FORMAT ") must be " + "less than GCPauseIntervalMillis (" UINTX_FORMAT ")\n", + value, GCPauseIntervalMillis); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + return Flag::SUCCESS; +} + +Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseG1GC) { + if (FLAG_IS_CMDLINE(GCPauseIntervalMillis)) { + if (value < 1) { + CommandLineError::print(verbose, + "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " + "greater than or equal to 1\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } + if (value <= MaxGCPauseMillis) { + CommandLineError::print(verbose, + "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " + "greater than MaxGCPauseMillis (" UINTX_FORMAT ")\n", + value, MaxGCPauseMillis); + return Flag::VIOLATES_CONSTRAINT; + } + } + } +#endif + return Flag::SUCCESS; +} + +Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) { + size_t aligned_max = (size_t)align_size_down(max_uintx/2, Metaspace::reserve_alignment_words()); + if (value > aligned_max) { + CommandLineError::print(verbose, + "InitialBootClassLoaderMetaspaceSize (" SIZE_FORMAT ") must be " + "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", + value, aligned_max); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} + +static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) { + // For G1 GC, we don't know until G1CollectorPolicy is created. + size_t heap_alignment; + +#if INCLUDE_ALL_GCS + if (UseG1GC) { + heap_alignment = HeapRegionBounds::max_size(); + } else +#endif + { + heap_alignment = CollectorPolicy::compute_heap_alignment(); + } + + // Not to overflow 'align_size_up(value, _heap_alignment) used from CollectorPolicy::initialize_flags()'. + size_t aligned_max = ((max_uintx - heap_alignment) & ~(heap_alignment-1)); + if (value > aligned_max) { + CommandLineError::print(verbose, + "%s (" SIZE_FORMAT ") must be " + "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", + name, value, aligned_max); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} + +Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) { + return MaxSizeForHeapAlignment("InitialHeapSize", value, verbose); +} + +Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { + Flag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose); + + if (status == Flag::SUCCESS) { + status = CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(value, SoftRefLRUPolicyMSPerMB, verbose); + } + return status; +} + +Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) { +#ifdef _LP64 +#if INCLUDE_ALL_GCS + // Overflow would happen for uint type variable of YoungGenSizer::_min_desired_young_length + // when the value to be assigned exceeds uint range. + // i.e. result of '(uint)(NewSize / region size(1~32MB))' + // So maximum of NewSize should be 'max_juint * 1M' + if (UseG1GC && (value > (max_juint * 1 * M))) { + CommandLineError::print(verbose, + "NewSize (" SIZE_FORMAT ") must be less than ergonomic maximum value\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } +#endif // INCLUDE_ALL_GCS +#endif // _LP64 + return Flag::SUCCESS; +} + +Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { + // At least, alignment reserve area is needed. + if (value < ThreadLocalAllocBuffer::alignment_reserve_in_bytes()) { + CommandLineError::print(verbose, + "MinTLABSize (" SIZE_FORMAT ") must be " + "greater than or equal to reserved area in TLAB (" SIZE_FORMAT ")\n", + value, ThreadLocalAllocBuffer::alignment_reserve_in_bytes()); + return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; } } -Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { - if (value > (CMSPrecleanDenominator - 1)) { +Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { + // Skip for default value of zero which means set ergonomically. + if (FLAG_IS_CMDLINE(TLABSize)) { + if (value < MinTLABSize) { + CommandLineError::print(verbose, + "TLABSize (" SIZE_FORMAT ") must be " + "greater than or equal to MinTLABSize (" SIZE_FORMAT ")\n", + value, MinTLABSize); + return Flag::VIOLATES_CONSTRAINT; + } + if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { + CommandLineError::print(verbose, + "TLABSize (" SIZE_FORMAT ") must be " + "less than or equal to ergonomic TLAB maximum size (" SIZE_FORMAT ")\n", + value, (ThreadLocalAllocBuffer::max_size() * HeapWordSize)); + return Flag::VIOLATES_CONSTRAINT; + } + } + return Flag::SUCCESS; +} + +Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { + if (FLAG_IS_CMDLINE(SurvivorRatio) && + (value > (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()))) { CommandLineError::print(verbose, - "CMSPrecleanNumerator (" UINTX_FORMAT ") must be " - "less than or equal to CMSPrecleanDenominator - 1 (" UINTX_FORMAT ")\n", - value, CMSPrecleanDenominator - 1); + "SurvivorRatio (" UINTX_FORMAT ") must be " + "less than or equal to ergonomic SurvivorRatio maximum (" SIZE_FORMAT ")\n", + value, + (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment())); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { + if (value > MaxMetaspaceSize) { + CommandLineError::print(verbose, + "MetaspaceSize (" SIZE_FORMAT ") must be " + "less than or equal to MaxMetaspaceSize (" SIZE_FORMAT ")\n", + value, MaxMetaspaceSize); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { + if (value < MetaspaceSize) { + CommandLineError::print(verbose, + "MaxMetaspaceSize (" SIZE_FORMAT ") must be " + "greater than or equal to MetaspaceSize (" SIZE_FORMAT ")\n", + value, MaxMetaspaceSize); return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp index 7635c660f23..e5ad691fcf2 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp @@ -34,27 +34,45 @@ * an appropriate error value. */ +Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose); +Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose); Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose); - +Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose); Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose); Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose); - +Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose); Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); - Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose); Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose); #if INCLUDE_ALL_GCS +Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose); +Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose); +Flag::Error G1YoungSurvRateNumRegionsSummaryConstraintFunc(intx value, bool verbose); +Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose); Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose); Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose); #endif // INCLUDE_ALL_GCS +Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose); Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); - +Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); +Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose); Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); - +Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose); +Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose); +Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose); +Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose); +Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose); +Flag::Error NewSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose); +Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose); +Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose); +Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose); Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose); #endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSGC_HPP */ diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp index ae676276c45..a34896c49aa 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp @@ -27,6 +27,7 @@ #include "runtime/commandLineFlagConstraintsRuntime.hpp" #include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals.hpp" +#include "runtime/task.hpp" #include "utilities/defaultStream.hpp" Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { @@ -41,7 +42,7 @@ Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { if (value >= (intx)os::vm_page_size()) { CommandLineError::print(verbose, "ObjectAlignmentInBytes (" INTX_FORMAT ") must be " - "less than page size " INTX_FORMAT "\n", + "less than page size (" INTX_FORMAT ")\n", value, (intx)os::vm_page_size()); return Flag::VIOLATES_CONSTRAINT; } @@ -51,7 +52,7 @@ Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { // Need to enforce the padding not to break the existing field alignments. // It is sufficient to check against the largest type size. Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) { - if ((value != 0) && ((value % BytesPerLong) != 0)) { + if ((value % BytesPerLong) != 0) { CommandLineError::print(verbose, "ContendedPaddingWidth (" INTX_FORMAT ") must be " "a multiple of %d\n", @@ -61,3 +62,71 @@ Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) { return Flag::SUCCESS; } } + +Flag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose) { + if (value > BiasedLockingBulkRevokeThreshold) { + CommandLineError::print(verbose, + "BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ") must be " + "less than or equal to BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ")\n", + value, BiasedLockingBulkRevokeThreshold); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose) { + if ((value % PeriodicTask::interval_gran) != 0) { + CommandLineError::print(verbose, + "BiasedLockingStartupDelay (" INTX_FORMAT ") must be " + "evenly divisible by PeriodicTask::interval_gran (" INTX_FORMAT ")\n", + value, PeriodicTask::interval_gran); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose) { + if (value < BiasedLockingBulkRebiasThreshold) { + CommandLineError::print(verbose, + "BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ") must be " + "greater than or equal to BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ")\n", + value, BiasedLockingBulkRebiasThreshold); + return Flag::VIOLATES_CONSTRAINT; + } else if ((double)value/(double)BiasedLockingDecayTime > 0.1) { + CommandLineError::print(verbose, + "The ratio of BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ")" + " to BiasedLockingDecayTime (" INTX_FORMAT ") must be " + "less than or equal to 0.1\n", + value, BiasedLockingBulkRebiasThreshold); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose) { + if (BiasedLockingBulkRebiasThreshold/(double)value > 0.1) { + CommandLineError::print(verbose, + "The ratio of BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ")" + " to BiasedLockingDecayTime (" INTX_FORMAT ") must be " + "less than or equal to 0.1\n", + BiasedLockingBulkRebiasThreshold, value); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose) { + if ((value % PeriodicTask::interval_gran != 0)) { + CommandLineError::print(verbose, + "PerfDataSamplingInterval (" INTX_FORMAT ") must be " + "evenly divisible by PeriodicTask::interval_gran (" INTX_FORMAT ")\n", + value, PeriodicTask::interval_gran); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp index b81a640eee7..788b3b0dc75 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp @@ -38,4 +38,11 @@ Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose); Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose); +Flag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose); +Flag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose); +Flag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose); +Flag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose); + +Flag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose); + #endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP */ diff --git a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp index cb764e2e989..b25f7ccdd28 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp @@ -29,6 +29,7 @@ #include "runtime/arguments.hpp" #include "runtime/commandLineFlagRangeList.hpp" #include "runtime/os.hpp" +#include "runtime/task.hpp" #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" @@ -278,7 +279,7 @@ void emit_range_double(const char* name, double min, double max) { // Generate func argument to pass into emit_range_xxx functions #define EMIT_RANGE_CHECK(a, b) , a, b -#define INITIAL_RANGES_SIZE 128 +#define INITIAL_RANGES_SIZE 204 GrowableArray* CommandLineFlagRangeList::_ranges = NULL; // Check the ranges of all flags that have them @@ -309,6 +310,18 @@ void CommandLineFlagRangeList::init(void) { EMIT_RANGE_CHECK, IGNORE_CONSTRAINT)); +#if INCLUDE_JVMCI + emit_range_no(NULL JVMCI_FLAGS(EMIT_RANGE_DEVELOPER_FLAG, + EMIT_RANGE_PD_DEVELOPER_FLAG, + EMIT_RANGE_PRODUCT_FLAG, + EMIT_RANGE_PD_PRODUCT_FLAG, + EMIT_RANGE_DIAGNOSTIC_FLAG, + EMIT_RANGE_EXPERIMENTAL_FLAG, + EMIT_RANGE_NOTPRODUCT_FLAG, + EMIT_RANGE_CHECK, + IGNORE_CONSTRAINT)); +#endif // INCLUDE_JVMCI + #ifdef COMPILER1 emit_range_no(NULL C1_FLAGS(EMIT_RANGE_DEVELOPER_FLAG, EMIT_RANGE_PD_DEVELOPER_FLAG, diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index a6acc8aa00a..a79acbcede7 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -37,6 +37,7 @@ #include "memory/resourceArea.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" +#include "oops/fieldStreams.hpp" #include "oops/verifyOopClosure.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/biasedLocking.hpp" @@ -53,7 +54,11 @@ #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#endif + bool DeoptimizationMarker::_is_active = false; @@ -112,7 +117,7 @@ void Deoptimization::UnrollBlock::print() { tty->print_cr(" size_of_deoptimized_frame = %d", _size_of_deoptimized_frame); tty->print( " frame_sizes: "); for (int index = 0; index < number_of_frames(); index++) { - tty->print("%d ", frame_sizes()[index]); + tty->print(INTX_FORMAT " ", frame_sizes()[index]); } tty->cr(); } @@ -132,6 +137,9 @@ JRT_BLOCK_ENTRY(Deoptimization::UnrollBlock*, Deoptimization::fetch_unroll_info( // handler. Note this fact before we start generating temporary frames // that can confuse an asynchronous stack walker. This counter is // decremented at the end of unpack_frames(). + if (TraceDeoptimization) { + tty->print_cr("Deoptimizing thread " INTPTR_FORMAT, p2i(thread)); + } thread->inc_in_deopt_handler(); return fetch_unroll_info_helper(thread); @@ -159,6 +167,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread // Set the deoptee nmethod assert(thread->deopt_nmethod() == NULL, "Pending deopt!"); thread->set_deopt_nmethod(deoptee.cb()->as_nmethod_or_null()); + bool skip_internal = thread->deopt_nmethod() != NULL && !thread->deopt_nmethod()->compiler()->is_jvmci(); if (VerifyStack) { thread->validate_frame_layout(); @@ -179,11 +188,13 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread bool realloc_failures = false; -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // Reallocate the non-escaping objects and restore their fields. Then // relock objects if synchronization on them was eliminated. +#ifndef INCLUDE_JVMCI if (DoEscapeAnalysis || EliminateNestedLocks) { if (EliminateAllocations) { +#endif // INCLUDE_JVMCI assert (chunk->at(0)->scope() != NULL,"expect only compiled java frames"); GrowableArray* objects = chunk->at(0)->scope()->objects(); @@ -206,18 +217,18 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread assert(Universe::heap()->is_in_or_null(result), "must be heap pointer"); if (TraceDeoptimization) { ttyLocker ttyl; - tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, (void *)result, thread); + tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, p2i(result), p2i(thread)); } } if (objects != NULL) { JRT_BLOCK realloc_failures = realloc_objects(thread, &deoptee, objects, THREAD); JRT_END - reassign_fields(&deoptee, &map, objects, realloc_failures); + reassign_fields(&deoptee, &map, objects, realloc_failures, skip_internal); #ifndef PRODUCT if (TraceDeoptimization) { ttyLocker ttyl; - tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread); + tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, p2i(thread)); print_objects(objects, realloc_failures); } #endif @@ -226,8 +237,10 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread // Restore result. deoptee.set_saved_oop_result(&map, return_value()); } +#ifndef INCLUDE_JVMCI } if (EliminateLocks) { +#endif // INCLUDE_JVMCI #ifndef PRODUCT bool first = true; #endif @@ -238,37 +251,40 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread if (monitors->is_nonempty()) { relock_objects(monitors, thread, realloc_failures); #ifndef PRODUCT - if (TraceDeoptimization) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; for (int j = 0; j < monitors->length(); j++) { MonitorInfo* mi = monitors->at(j); if (mi->eliminated()) { if (first) { first = false; - tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread); + tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, p2i(thread)); } if (mi->owner_is_scalar_replaced()) { Klass* k = java_lang_Class::as_Klass(mi->owner_klass()); tty->print_cr(" failed reallocation for klass %s", k->external_name()); } else { - tty->print_cr(" object <" INTPTR_FORMAT "> locked", (void *)mi->owner()); + tty->print_cr(" object <" INTPTR_FORMAT "> locked", p2i(mi->owner())); } } } } -#endif +#endif // !PRODUCT } } +#ifndef INCLUDE_JVMCI } } -#endif // COMPILER2 +#endif // INCLUDE_JVMCI +#endif // COMPILER2 || INCLUDE_JVMCI + // Ensure that no safepoint is taken after pointers have been stored // in fields of rematerialized objects. If a safepoint occurs from here on // out the java state residing in the vframeArray will be missed. No_Safepoint_Verifier no_safepoint; vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk, realloc_failures); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (realloc_failures) { pop_frames_failed_reallocs(thread, array); } @@ -318,7 +334,11 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread unpack_sp = deoptee.unextended_sp(); #ifdef ASSERT - assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub(), "just checking"); + assert(cb->is_deoptimization_stub() || + cb->is_uncommon_trap_stub() || + strcmp("Stub", cb->name()) == 0 || + strcmp("Stub", cb->name()) == 0, + "unexpected code blob: %s", cb->name()); #endif #else intptr_t* unpack_sp = stub_frame.sender(&dummy_map).unextended_sp(); @@ -550,11 +570,12 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m #ifndef PRODUCT if (TraceDeoptimization) { ttyLocker ttyl; - tty->print_cr("DEOPT UNPACKING thread " INTPTR_FORMAT " vframeArray " INTPTR_FORMAT " mode %d", thread, array, exec_mode); + tty->print_cr("DEOPT UNPACKING thread " INTPTR_FORMAT " vframeArray " INTPTR_FORMAT " mode %d", + p2i(thread), p2i(array), exec_mode); } #endif Events::log(thread, "DEOPT UNPACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT " mode %d", - stub_frame.pc(), stub_frame.sp(), exec_mode); + p2i(stub_frame.pc()), p2i(stub_frame.sp()), exec_mode); UnrollBlock* info = array->unroll_block(); @@ -690,7 +711,7 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m tty->print_cr(" top_frame_expression_stack_adjustment = %d", top_frame_expression_stack_adjustment); tty->print_cr(" exec_mode = %d", exec_mode); tty->print_cr(" cur_invoke_parameter_size = %d", cur_invoke_parameter_size); - tty->print_cr(" Thread = " INTPTR_FORMAT ", thread ID = " UINTX_FORMAT, thread, thread->osthread()->thread_id()); + tty->print_cr(" Thread = " INTPTR_FORMAT ", thread ID = %d", p2i(thread), thread->osthread()->thread_id()); tty->print_cr(" Interpreted frames:"); for (int k = 0; k < cur_array->frames(); k++) { vframeArrayElement* el = cur_array->element(k); @@ -721,7 +742,7 @@ int Deoptimization::deoptimize_dependents() { Deoptimization::DeoptAction Deoptimization::_unloaded_action = Deoptimization::Action_reinterpret; -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArray* objects, TRAPS) { Handle pending_exception(thread->pending_exception()); const char* exception_file = thread->exception_file(); @@ -769,77 +790,6 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArra return failures; } -// This assumes that the fields are stored in ObjectValue in the same order -// they are yielded by do_nonstatic_fields. -class FieldReassigner: public FieldClosure { - frame* _fr; - RegisterMap* _reg_map; - ObjectValue* _sv; - InstanceKlass* _ik; - oop _obj; - - int _i; -public: - FieldReassigner(frame* fr, RegisterMap* reg_map, ObjectValue* sv, oop obj) : - _fr(fr), _reg_map(reg_map), _sv(sv), _obj(obj), _i(0) {} - - int i() const { return _i; } - - - void do_field(fieldDescriptor* fd) { - intptr_t val; - StackValue* value = - StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(i())); - int offset = fd->offset(); - switch (fd->field_type()) { - case T_OBJECT: case T_ARRAY: - assert(value->type() == T_OBJECT, "Agreement."); - _obj->obj_field_put(offset, value->get_obj()()); - break; - - case T_LONG: case T_DOUBLE: { - assert(value->type() == T_INT, "Agreement."); - StackValue* low = - StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(++_i)); -#ifdef _LP64 - jlong res = (jlong)low->get_int(); -#else -#ifdef SPARC - // For SPARC we have to swap high and low words. - jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); -#else - jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); -#endif //SPARC -#endif - _obj->long_field_put(offset, res); - break; - } - // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. - case T_INT: case T_FLOAT: // 4 bytes. - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->int_field_put(offset, (jint)*((jint*)&val)); - break; - - case T_SHORT: case T_CHAR: // 2 bytes - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->short_field_put(offset, (jshort)*((jint*)&val)); - break; - - case T_BOOLEAN: case T_BYTE: // 1 byte - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->bool_field_put(offset, (jboolean)*((jint*)&val)); - break; - - default: - ShouldNotReachHere(); - } - _i++; - } -}; - // restore elements of an eliminated type array void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) { int index = 0; @@ -867,11 +817,43 @@ void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_ma } // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. - case T_INT: case T_FLOAT: // 4 bytes. + case T_INT: case T_FLOAT: { // 4 bytes. assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - obj->int_at_put(index, (jint)*((jint*)&val)); + bool big_value = false; + if (i + 1 < sv->field_size() && type == T_INT) { + if (sv->field_at(i)->is_location()) { + Location::Type type = ((LocationValue*) sv->field_at(i))->location().type(); + if (type == Location::dbl || type == Location::lng) { + big_value = true; + } + } else if (sv->field_at(i)->is_constant_int()) { + ScopeValue* next_scope_field = sv->field_at(i + 1); + if (next_scope_field->is_constant_long() || next_scope_field->is_constant_double()) { + big_value = true; + } + } + } + + if (big_value) { + StackValue* low = StackValue::create_stack_value(fr, reg_map, sv->field_at(++i)); + #ifdef _LP64 + jlong res = (jlong)low->get_int(); + #else + #ifdef SPARC + // For SPARC we have to swap high and low words. + jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); + #else + jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); + #endif //SPARC + #endif + obj->int_at_put(index, (jint)*((jint*)&res)); + obj->int_at_put(++index, (jint)*(((jint*)&res) + 1)); + } else { + val = value->get_int(); + obj->int_at_put(index, (jint)*((jint*)&val)); + } break; + } case T_SHORT: case T_CHAR: // 2 bytes assert(value->type() == T_INT, "Agreement."); @@ -902,22 +884,135 @@ void Deoptimization::reassign_object_array_elements(frame* fr, RegisterMap* reg_ } } +class ReassignedField { +public: + int _offset; + BasicType _type; +public: + ReassignedField() { + _offset = 0; + _type = T_ILLEGAL; + } +}; + +int compare(ReassignedField* left, ReassignedField* right) { + return left->_offset - right->_offset; +} + +// Restore fields of an eliminated instance object using the same field order +// returned by HotSpotResolvedObjectTypeImpl.getInstanceFields(true) +static int reassign_fields_by_klass(InstanceKlass* klass, frame* fr, RegisterMap* reg_map, ObjectValue* sv, int svIndex, oop obj, bool skip_internal) { + if (klass->superklass() != NULL) { + svIndex = reassign_fields_by_klass(klass->superklass(), fr, reg_map, sv, svIndex, obj, skip_internal); + } + + GrowableArray* fields = new GrowableArray(); + for (AllFieldStream fs(klass); !fs.done(); fs.next()) { + if (!fs.access_flags().is_static() && (!skip_internal || !fs.access_flags().is_internal())) { + ReassignedField field; + field._offset = fs.offset(); + field._type = FieldType::basic_type(fs.signature()); + fields->append(field); + } + } + fields->sort(compare); + for (int i = 0; i < fields->length(); i++) { + intptr_t val; + ScopeValue* scope_field = sv->field_at(svIndex); + StackValue* value = StackValue::create_stack_value(fr, reg_map, scope_field); + int offset = fields->at(i)._offset; + BasicType type = fields->at(i)._type; + switch (type) { + case T_OBJECT: case T_ARRAY: + assert(value->type() == T_OBJECT, "Agreement."); + obj->obj_field_put(offset, value->get_obj()()); + break; + + // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. + case T_INT: case T_FLOAT: { // 4 bytes. + assert(value->type() == T_INT, "Agreement."); + bool big_value = false; + if (i+1 < fields->length() && fields->at(i+1)._type == T_INT) { + if (scope_field->is_location()) { + Location::Type type = ((LocationValue*) scope_field)->location().type(); + if (type == Location::dbl || type == Location::lng) { + big_value = true; + } + } + if (scope_field->is_constant_int()) { + ScopeValue* next_scope_field = sv->field_at(svIndex + 1); + if (next_scope_field->is_constant_long() || next_scope_field->is_constant_double()) { + big_value = true; + } + } + } + + if (big_value) { + i++; + assert(i < fields->length(), "second T_INT field needed"); + assert(fields->at(i)._type == T_INT, "T_INT field needed"); + } else { + val = value->get_int(); + obj->int_field_put(offset, (jint)*((jint*)&val)); + break; + } + } + /* no break */ + + case T_LONG: case T_DOUBLE: { + assert(value->type() == T_INT, "Agreement."); + StackValue* low = StackValue::create_stack_value(fr, reg_map, sv->field_at(++svIndex)); +#ifdef _LP64 + jlong res = (jlong)low->get_int(); +#else +#ifdef SPARC + // For SPARC we have to swap high and low words. + jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); +#else + jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); +#endif //SPARC +#endif + obj->long_field_put(offset, res); + break; + } + + case T_SHORT: case T_CHAR: // 2 bytes + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->short_field_put(offset, (jshort)*((jint*)&val)); + break; + + case T_BOOLEAN: case T_BYTE: // 1 byte + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->bool_field_put(offset, (jboolean)*((jint*)&val)); + break; + + default: + ShouldNotReachHere(); + } + svIndex++; + } + return svIndex; +} // restore fields of all eliminated objects and arrays -void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects, bool realloc_failures) { +void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects, bool realloc_failures, bool skip_internal) { for (int i = 0; i < objects->length(); i++) { ObjectValue* sv = (ObjectValue*) objects->at(i); KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())); Handle obj = sv->value(); assert(obj.not_null() || realloc_failures, "reallocation was missed"); + if (PrintDeoptimizationDetails) { + tty->print_cr("reassign fields for object of type %s!", k->name()->as_C_string()); + } if (obj.is_null()) { continue; } if (k->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(k()); - FieldReassigner reassign(fr, reg_map, sv, obj()); - ik->do_nonstatic_fields(&reassign); + reassign_fields_by_klass(ik, fr, reg_map, sv, 0, obj(), skip_internal); } else if (k->oop_is_typeArray()) { TypeArrayKlass* ak = TypeArrayKlass::cast(k()); reassign_type_array_elements(fr, reg_map, sv, (typeArrayOop) obj(), ak->element_type()); @@ -966,7 +1061,7 @@ void Deoptimization::print_objects(GrowableArray* objects, bool rea KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())); Handle obj = sv->value(); - tty->print(" object <" INTPTR_FORMAT "> of type ", (void *)sv->value()()); + tty->print(" object <" INTPTR_FORMAT "> of type ", p2i(sv->value()())); k->print_value(); assert(obj.not_null() || realloc_failures, "reallocation was missed"); if (obj.is_null()) { @@ -982,15 +1077,15 @@ void Deoptimization::print_objects(GrowableArray* objects, bool rea } } #endif -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray* chunk, bool realloc_failures) { - Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, fr.pc(), fr.sp()); + Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, p2i(fr.pc()), p2i(fr.sp())); #ifndef PRODUCT - if (TraceDeoptimization) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; - tty->print("DEOPT PACKING thread " INTPTR_FORMAT " ", thread); + tty->print("DEOPT PACKING thread " INTPTR_FORMAT " ", p2i(thread)); fr.print_on(tty); tty->print_cr(" Virtual frames (innermost first):"); for (int index = 0; index < chunk->length(); index++) { @@ -1033,16 +1128,16 @@ vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, Re assert(array->structural_compare(thread, chunk), "just checking"); #ifndef PRODUCT - if (TraceDeoptimization) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; - tty->print_cr(" Created vframeArray " INTPTR_FORMAT, array); + tty->print_cr(" Created vframeArray " INTPTR_FORMAT, p2i(array)); } #endif // PRODUCT return array; } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array) { // Reallocation of some scalar replaced objects failed. Record // that we need to pop all the interpreter frames for the @@ -1150,17 +1245,38 @@ void Deoptimization::revoke_biases_of_monitors(CodeBlob* cb) { } -void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr) { +void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) { assert(fr.can_be_deoptimized(), "checking frame type"); - gather_statistics(Reason_constraint, Action_none, Bytecodes::_illegal); + gather_statistics(reason, Action_none, Bytecodes::_illegal); - // Patch the nmethod so that when execution returns to it we will + if (LogCompilation && xtty != NULL) { + nmethod* nm = fr.cb()->as_nmethod_or_null(); + assert(nm != NULL, "only compiled methods can deopt"); + + ttyLocker ttyl; + xtty->begin_head("deoptimized thread='" UINTX_FORMAT "'", (uintx)thread->osthread()->thread_id()); + nm->log_identity(xtty); + xtty->end_head(); + for (ScopeDesc* sd = nm->scope_desc_at(fr.pc()); ; sd = sd->sender()) { + xtty->begin_elem("jvms bci='%d'", sd->bci()); + xtty->method(sd->method()); + xtty->end_elem(); + if (sd->is_top()) break; + } + xtty->tail("deoptimized"); + } + + // Patch the compiled method so that when execution returns to it we will // deopt the execution state and return to the interpreter. fr.deoptimize(thread); } void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map) { + deoptimize(thread, fr, map, Reason_constraint); +} + +void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map, DeoptReason reason) { // Deoptimize only if the frame comes from compile code. // Do not deoptimize the frame which is already patched // during the execution of the loops below. @@ -1172,12 +1288,12 @@ void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map) if (UseBiasedLocking) { revoke_biases_of_monitors(thread, fr, map); } - deoptimize_single_frame(thread, fr); + deoptimize_single_frame(thread, fr, reason); } -void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id) { +void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason) { assert(thread == Thread::current() || SafepointSynchronize::is_at_safepoint(), "can only deoptimize other thread at a safepoint"); // Compute frame and register map based on thread and sp. @@ -1186,19 +1302,22 @@ void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id) while (fr.id() != id) { fr = fr.sender(®_map); } - deoptimize(thread, fr, ®_map); + deoptimize(thread, fr, ®_map, reason); } -void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) { +void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason) { if (thread == Thread::current()) { - Deoptimization::deoptimize_frame_internal(thread, id); + Deoptimization::deoptimize_frame_internal(thread, id, reason); } else { - VM_DeoptimizeFrame deopt(thread, id); + VM_DeoptimizeFrame deopt(thread, id, reason); VMThread::execute(&deopt); } } +void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) { + deoptimize_frame(thread, id, Reason_constraint); +} // JVMTI PopFrame support JRT_LEAF(void, Deoptimization::popframe_preserve_args(JavaThread* thread, int bytes_to_save, void* start_address)) @@ -1225,7 +1344,7 @@ Deoptimization::get_method_data(JavaThread* thread, methodHandle m, return mdo; } -#if defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI void Deoptimization::load_class_by_index(constantPoolHandle constant_pool, int index, TRAPS) { // in case of an unresolved klass entry, load the class. if (constant_pool->tag_at(index).is_unresolved_klass()) { @@ -1288,7 +1407,12 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra thread->inc_in_deopt_handler(); // We need to update the map if we have biased locking. +#if INCLUDE_JVMCI + // JVMCI might need to get an exception from the stack, which in turn requires the register map to be valid + RegisterMap reg_map(thread, true); +#else RegisterMap reg_map(thread, UseBiasedLocking); +#endif frame stub_frame = thread->last_frame(); frame fr = stub_frame.sender(®_map); // Make sure the calling nmethod is not getting deoptimized and removed @@ -1296,8 +1420,8 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra nmethodLocker nl(fr.pc()); // Log a message - Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT, - trap_request, fr.pc()); + Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT " relative=" INTPTR_FORMAT, + trap_request, p2i(fr.pc()), fr.pc() - fr.cb()->code_begin()); { ResourceMark rm; @@ -1307,6 +1431,9 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra DeoptReason reason = trap_request_reason(trap_request); DeoptAction action = trap_request_action(trap_request); +#if INCLUDE_JVMCI + int debug_id = trap_request_debug_id(trap_request); +#endif jint unloaded_class_index = trap_request_index(trap_request); // CP idx or -1 vframe* vf = vframe::new_vframe(&fr, ®_map, thread); @@ -1315,10 +1442,71 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra nmethod* nm = cvf->code(); ScopeDesc* trap_scope = cvf->scope(); + + if (TraceDeoptimization) { + ttyLocker ttyl; + tty->print_cr(" bci=%d pc=" INTPTR_FORMAT ", relative_pc=" INTPTR_FORMAT ", method=%s" JVMCI_ONLY(", debug_id=%d"), trap_scope->bci(), p2i(fr.pc()), fr.pc() - nm->code_begin(), trap_scope->method()->name_and_sig_as_C_string() +#if INCLUDE_JVMCI + , debug_id +#endif + ); + } + methodHandle trap_method = trap_scope->method(); int trap_bci = trap_scope->bci(); +#if INCLUDE_JVMCI + oop speculation = thread->pending_failed_speculation(); + if (nm->is_compiled_by_jvmci()) { + if (speculation != NULL) { + oop speculation_log = nm->speculation_log(); + if (speculation_log != NULL) { + if (TraceDeoptimization || TraceUncollectedSpeculations) { + if (SpeculationLog::lastFailed(speculation_log) != NULL) { + tty->print_cr("A speculation that was not collected by the compiler is being overwritten"); + } + } + if (TraceDeoptimization) { + tty->print_cr("Saving speculation to speculation log"); + } + SpeculationLog::set_lastFailed(speculation_log, speculation); + } else { + if (TraceDeoptimization) { + tty->print_cr("Speculation present but no speculation log"); + } + } + thread->set_pending_failed_speculation(NULL); + } else { + if (TraceDeoptimization) { + tty->print_cr("No speculation"); + } + } + } else { + assert(speculation == NULL, "There should not be a speculation for method compiled by non-JVMCI compilers"); + } + + if (trap_bci == SynchronizationEntryBCI) { + trap_bci = 0; + thread->set_pending_monitorenter(true); + } + + if (reason == Deoptimization::Reason_transfer_to_interpreter) { + thread->set_pending_transfer_to_interpreter(true); + } +#endif + Bytecodes::Code trap_bc = trap_method->java_code_at(trap_bci); + if (trap_scope->rethrow_exception()) { + if (PrintDeoptimizationDetails) { + tty->print_cr("Exception to be rethrown in the interpreter for method %s::%s at bci %d", trap_method->method_holder()->name()->as_C_string(), trap_method->name()->as_C_string(), trap_bci); + } + GrowableArray* expressions = trap_scope->expressions(); + guarantee(expressions != NULL, "must have exception to throw"); + ScopeValue* topOfStack = expressions->top(); + Handle topOfStackObj = StackValue::create_stack_value(&fr, ®_map, topOfStack)->get_obj(); + THREAD->set_pending_exception(topOfStackObj(), NULL, 0); + } + // Record this event in the histogram. gather_statistics(reason, action, trap_bc); @@ -1326,12 +1514,23 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra // Need MDO to record RTM code generation state. bool create_if_missing = ProfileTraps || UseCodeAging RTM_OPT_ONLY( || UseRTMLocking ); + methodHandle profiled_method; +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci()) { + profiled_method = nm->method(); + } else { + profiled_method = trap_method; + } +#else + profiled_method = trap_method; +#endif + MethodData* trap_mdo = - get_method_data(thread, trap_method, create_if_missing); + get_method_data(thread, profiled_method, create_if_missing); // Log a message Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d", - trap_reason_name(reason), trap_action_name(action), fr.pc(), + trap_reason_name(reason), trap_action_name(action), p2i(fr.pc()), trap_method->name_and_sig_as_C_string(), trap_bci); // Print a bunch of diagnostics, if requested. @@ -1385,12 +1584,33 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra if (TraceDeoptimization) { // make noise on the tty tty->print("Uncommon trap occurred in"); nm->method()->print_short_name(tty); - tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d", - fr.pc(), + tty->print(" compiler=%s compile_id=%d", nm->compiler() == NULL ? "" : nm->compiler()->name(), nm->compile_id()); +#if INCLUDE_JVMCI + oop installedCode = nm->jvmci_installed_code(); + if (installedCode != NULL) { + oop installedCodeName = NULL; + if (installedCode->is_a(InstalledCode::klass())) { + installedCodeName = InstalledCode::name(installedCode); + } + if (installedCodeName != NULL) { + tty->print(" (JVMCI: installedCodeName=%s) ", java_lang_String::as_utf8_string(installedCodeName)); + } else { + tty->print(" (JVMCI: installed code has no name) "); + } + } else if (nm->is_compiled_by_jvmci()) { + tty->print(" (JVMCI: no installed code) "); + } +#endif + tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d" JVMCI_ONLY(" debug_id=%d"), + p2i(fr.pc()), os::current_thread_id(), trap_reason_name(reason), trap_action_name(action), - unloaded_class_index); + unloaded_class_index +#if INCLUDE_JVMCI + , debug_id +#endif + ); if (class_name != NULL) { tty->print(unresolved ? " unresolved class: " : " symbol: "); class_name->print_symbol_on(tty); @@ -1524,11 +1744,14 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra bool inc_recompile_count = false; ProfileData* pdata = NULL; if (ProfileTraps && update_trap_state && trap_mdo != NULL) { - assert(trap_mdo == get_method_data(thread, trap_method, false), "sanity"); + assert(trap_mdo == get_method_data(thread, profiled_method, false), "sanity"); uint this_trap_count = 0; bool maybe_prior_trap = false; bool maybe_prior_recompile = false; - pdata = query_update_method_data(trap_mdo, trap_bci, reason, + pdata = query_update_method_data(trap_mdo, trap_bci, reason, true, +#if INCLUDE_JVMCI + nm->is_compiled_by_jvmci() && nm->is_osr_method(), +#endif nm->method(), //outputs: this_trap_count, @@ -1660,26 +1883,42 @@ ProfileData* Deoptimization::query_update_method_data(MethodData* trap_mdo, int trap_bci, Deoptimization::DeoptReason reason, + bool update_total_trap_count, +#if INCLUDE_JVMCI + bool is_osr, +#endif Method* compiled_method, //outputs: uint& ret_this_trap_count, bool& ret_maybe_prior_trap, bool& ret_maybe_prior_recompile) { - uint prior_trap_count = trap_mdo->trap_count(reason); - uint this_trap_count = trap_mdo->inc_trap_count(reason); + bool maybe_prior_trap = false; + bool maybe_prior_recompile = false; + uint this_trap_count = 0; + if (update_total_trap_count) { + uint idx = reason; +#if INCLUDE_JVMCI + if (is_osr) { + idx += Reason_LIMIT; + } +#endif + uint prior_trap_count = trap_mdo->trap_count(idx); + this_trap_count = trap_mdo->inc_trap_count(idx); - // If the runtime cannot find a place to store trap history, - // it is estimated based on the general condition of the method. - // If the method has ever been recompiled, or has ever incurred - // a trap with the present reason , then this BCI is assumed - // (pessimistically) to be the culprit. - bool maybe_prior_trap = (prior_trap_count != 0); - bool maybe_prior_recompile = (trap_mdo->decompile_count() != 0); + // If the runtime cannot find a place to store trap history, + // it is estimated based on the general condition of the method. + // If the method has ever been recompiled, or has ever incurred + // a trap with the present reason , then this BCI is assumed + // (pessimistically) to be the culprit. + maybe_prior_trap = (prior_trap_count != 0); + maybe_prior_recompile = (trap_mdo->decompile_count() != 0); + } ProfileData* pdata = NULL; // For reasons which are recorded per bytecode, we check per-BCI data. DeoptReason per_bc_reason = reason_recorded_per_bytecode_if_any(reason); + assert(per_bc_reason != Reason_none || update_total_trap_count, "must be"); if (per_bc_reason != Reason_none) { // Find the profile data for this BCI. If there isn't one, // try to allocate one from the MDO's set of spares. @@ -1732,8 +1971,14 @@ Deoptimization::update_method_data_from_interpreter(MethodData* trap_mdo, int tr bool ignore_maybe_prior_trap; bool ignore_maybe_prior_recompile; assert(!reason_is_speculate(reason), "reason speculate only used by compiler"); + // JVMCI uses the total counts to determine if deoptimizations are happening too frequently -> do not adjust total counts + bool update_total_counts = JVMCI_ONLY(false) NOT_JVMCI(true); query_update_method_data(trap_mdo, trap_bci, (DeoptReason)reason, + update_total_counts, +#if INCLUDE_JVMCI + false, +#endif NULL, ignore_this_trap_count, ignore_maybe_prior_trap, @@ -1741,7 +1986,9 @@ Deoptimization::update_method_data_from_interpreter(MethodData* trap_mdo, int tr } Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, jint trap_request) { - + if (TraceDeoptimization) { + tty->print("Uncommon trap "); + } // Still in Java no safepoints { // This enters VM and may safepoint @@ -1846,12 +2093,12 @@ const char* Deoptimization::_trap_reason_name[] = { // Note: Keep this in sync. with enum DeoptReason. "none", "null_check", - "null_assert", + "null_assert" JVMCI_ONLY("_or_unreached0"), "range_check", "class_check", "array_check", - "intrinsic", - "bimorphic", + "intrinsic" JVMCI_ONLY("_or_type_checked_inlining"), + "bimorphic" JVMCI_ONLY("_or_optimized_type_check"), "unloaded", "uninitialized", "unreached", @@ -1866,6 +2113,13 @@ const char* Deoptimization::_trap_reason_name[] = { "rtm_state_change", "unstable_if", "unstable_fused_if", +#if INCLUDE_JVMCI + "aliasing", + "transfer_to_interpreter", + "not_compiled_exception_handler", + "unresolved", + "jsr_mismatch", +#endif "tenured" }; const char* Deoptimization::_trap_action_name[] = { @@ -1905,13 +2159,24 @@ const char* Deoptimization::format_trap_request(char* buf, size_t buflen, jint unloaded_class_index = trap_request_index(trap_request); const char* reason = trap_reason_name(trap_request_reason(trap_request)); const char* action = trap_action_name(trap_request_action(trap_request)); +#if INCLUDE_JVMCI + int debug_id = trap_request_debug_id(trap_request); +#endif size_t len; if (unloaded_class_index < 0) { - len = jio_snprintf(buf, buflen, "reason='%s' action='%s'", - reason, action); + len = jio_snprintf(buf, buflen, "reason='%s' action='%s'" JVMCI_ONLY(" debug_id='%d'"), + reason, action +#if INCLUDE_JVMCI + ,debug_id +#endif + ); } else { - len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'", - reason, action, unloaded_class_index); + len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'" JVMCI_ONLY(" debug_id='%d'"), + reason, action, unloaded_class_index +#if INCLUDE_JVMCI + ,debug_id +#endif + ); } if (len >= buflen) buf[buflen-1] = '\0'; @@ -2008,7 +2273,7 @@ void Deoptimization::print_statistics() { if (xtty != NULL) xtty->tail("statistics"); } } -#else // COMPILER2 || SHARK +#else // COMPILER2 || SHARK || INCLUDE_JVMCI // Stubs for C1 only system. @@ -2044,4 +2309,4 @@ const char* Deoptimization::format_trap_state(char* buf, size_t buflen, return buf; } -#endif // COMPILER2 || SHARK +#endif // COMPILER2 || SHARK || INCLUDE_JVMCI diff --git a/hotspot/src/share/vm/runtime/deoptimization.hpp b/hotspot/src/share/vm/runtime/deoptimization.hpp index 81900682e67..e02836849b6 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.hpp +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp @@ -41,7 +41,13 @@ class Deoptimization : AllStatic { enum DeoptReason { Reason_many = -1, // indicates presence of several reasons Reason_none = 0, // indicates absence of a relevant deopt. - // Next 7 reasons are recorded per bytecode in DataLayout::trap_bits + // Next 7 reasons are recorded per bytecode in DataLayout::trap_bits. + // This is more complicated for JVMCI as JVMCI may deoptimize to *some* bytecode before the + // bytecode that actually caused the deopt (with inlining, JVMCI may even deoptimize to a + // bytecode in another method): + // - bytecode y in method b() causes deopt + // - JVMCI deoptimizes to bytecode x in method a() + // -> the deopt reason will be recorded for method a() at bytecode x Reason_null_check, // saw unexpected null or zero divisor (@bci) Reason_null_assert, // saw unexpected non-null or non-zero (@bci) Reason_range_check, // saw unexpected array index (@bci) @@ -50,6 +56,13 @@ class Deoptimization : AllStatic { Reason_intrinsic, // saw unexpected operand to intrinsic (@bci) Reason_bimorphic, // saw unexpected object class in bimorphic inlining (@bci) +#if INCLUDE_JVMCI + Reason_unreached0 = Reason_null_assert, + Reason_type_checked_inlining = Reason_intrinsic, + Reason_optimized_type_check = Reason_bimorphic, +#endif + + // recorded per method Reason_unloaded, // unloaded class or constant pool entry Reason_uninitialized, // bad class state (uninitialized) Reason_unreached, // code is not reached, compiler @@ -64,11 +77,19 @@ class Deoptimization : AllStatic { Reason_rtm_state_change, // rtm state change detected Reason_unstable_if, // a branch predicted always false was taken Reason_unstable_fused_if, // fused two ifs that had each one untaken branch. One is now taken. +#if INCLUDE_JVMCI + Reason_aliasing, // optimistic assumption about aliasing failed + Reason_transfer_to_interpreter, // explicit transferToInterpreter() + Reason_not_compiled_exception_handler, + Reason_unresolved, + Reason_jsr_mismatch, +#endif // Reason_tenured is counted separately, add normal counted Reasons above. // Related to MethodData::_trap_hist_limit where Reason_tenured isn't included Reason_tenured, // age of the code has reached the limit Reason_LIMIT, + // Note: Keep this enum in sync. with _trap_reason_name. Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc // Note: Reason_RECORDED_LIMIT should be < 8 to fit into 3 bits of @@ -91,8 +112,10 @@ class Deoptimization : AllStatic { enum { _action_bits = 3, _reason_bits = 5, + _debug_id_bits = 23, _action_shift = 0, _reason_shift = _action_shift+_action_bits, + _debug_id_shift = _reason_shift+_reason_bits, BC_CASE_LIMIT = PRODUCT_ONLY(1) NOT_PRODUCT(4) // for _deoptimization_hist }; @@ -109,10 +132,11 @@ class Deoptimization : AllStatic { // Deoptimizes a frame lazily. nmethod gets patched deopt happens on return to the frame static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map); + static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map, DeoptReason reason); private: // Does the actual work for deoptimizing a single frame - static void deoptimize_single_frame(JavaThread* thread, frame fr); + static void deoptimize_single_frame(JavaThread* thread, frame fr, DeoptReason reason); // Helper function to revoke biases of all monitors in frame if UseBiasedLocking // is enabled @@ -121,16 +145,18 @@ class Deoptimization : AllStatic { // executing in a particular CodeBlob if UseBiasedLocking is enabled static void revoke_biases_of_monitors(CodeBlob* cb); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI +JVMCI_ONLY(public:) + // Support for restoring non-escaping objects static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray* objects, TRAPS); static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type); static void reassign_object_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, objArrayOop obj); - static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects, bool realloc_failures); + static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects, bool realloc_failures, bool skip_internal); static void relock_objects(GrowableArray* monitors, JavaThread* thread, bool realloc_failures); static void pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array); NOT_PRODUCT(static void print_objects(GrowableArray* objects, bool realloc_failures);) -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI public: static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray* chunk, bool realloc_failures); @@ -140,6 +166,7 @@ class Deoptimization : AllStatic { // UnrollBlock is returned by fetch_unroll_info() to the deoptimization handler (blob). // This is only a CheapObj to ease debugging after a deopt failure class UnrollBlock : public CHeapObj { + friend class VMStructs; private: int _size_of_deoptimized_frame; // Size, in bytes, of current deoptimized frame int _caller_adjustment; // Adjustment, in bytes, to caller's SP by initial interpreted frame @@ -243,10 +270,11 @@ class Deoptimization : AllStatic { // Only called from VMDeoptimizeFrame // @argument thread. Thread where stub_frame resides. // @argument id. id of frame that should be deoptimized. - static void deoptimize_frame_internal(JavaThread* thread, intptr_t* id); + static void deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason); - // If thread is not the current thread then execute + // if thread is not the current thread then execute // VM_DeoptimizeFrame otherwise deoptimize directly. + static void deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason); static void deoptimize_frame(JavaThread* thread, intptr_t* id); // Statistics @@ -276,6 +304,14 @@ class Deoptimization : AllStatic { // standard action for unloaded CP entry return _unloaded_action; } + static int trap_request_debug_id(int trap_request) { + if (trap_request < 0) { + return ((~(trap_request) >> _debug_id_shift) & right_n_bits(_debug_id_bits)); + } else { + // standard action for unloaded CP entry + return 0; + } + } static int trap_request_index(int trap_request) { if (trap_request < 0) return -1; @@ -374,6 +410,10 @@ class Deoptimization : AllStatic { static ProfileData* query_update_method_data(MethodData* trap_mdo, int trap_bci, DeoptReason reason, + bool update_total_trap_count, +#if INCLUDE_JVMCI + bool is_osr, +#endif Method* compiled_method, //outputs: uint& ret_this_trap_count, diff --git a/hotspot/src/share/vm/runtime/fprofiler.cpp b/hotspot/src/share/vm/runtime/fprofiler.cpp index 83b308c1495..fbc51b4047d 100644 --- a/hotspot/src/share/vm/runtime/fprofiler.cpp +++ b/hotspot/src/share/vm/runtime/fprofiler.cpp @@ -42,8 +42,6 @@ #include "runtime/vframe.hpp" #include "utilities/macros.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Static fields of FlatProfiler int FlatProfiler::received_gc_ticks = 0; int FlatProfiler::vm_operation_ticks = 0; @@ -186,7 +184,7 @@ void PCRecorder::print() { if (counters == NULL) return; tty->cr(); - tty->print_cr("Printing compiled methods with PC buckets having more than %d ticks", ProfilerPCTickThreshold); + tty->print_cr("Printing compiled methods with PC buckets having more than " INTX_FORMAT " ticks", ProfilerPCTickThreshold); tty->print_cr("==================================================================="); tty->cr(); @@ -1494,7 +1492,7 @@ void ThreadProfiler::print(const char* thread_name) { } if (WizardMode) { - tty->print_cr("Node area used: %dKb", (area_top - area_bottom) / 1024); + tty->print_cr("Node area used: " INTX_FORMAT " Kb", (area_top - area_bottom) / 1024); } reset(); } diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index c48cc28a3ad..3abf884cfbb 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -50,9 +50,6 @@ #include "runtime/thread.inline.hpp" #include "utilities/decoder.hpp" - -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - RegisterMap::RegisterMap(JavaThread *thread, bool update_map) { _thread = thread; _update_map = update_map; @@ -112,7 +109,7 @@ void RegisterMap::print_on(outputStream* st) const { if (src != NULL) { r->print_on(st); - st->print(" [" INTPTR_FORMAT "] = ", src); + st->print(" [" INTPTR_FORMAT "] = ", p2i(src)); if (((uintptr_t)src & (sizeof(*src)-1)) != 0) { st->print_cr(""); } else { @@ -494,9 +491,10 @@ void frame::print_value_on(outputStream* st, JavaThread *thread) const { NOT_PRODUCT(address begin = pc()-40;) NOT_PRODUCT(address end = NULL;) - st->print("%s frame (sp=" INTPTR_FORMAT " unextended sp=" INTPTR_FORMAT, print_name(), sp(), unextended_sp()); + st->print("%s frame (sp=" INTPTR_FORMAT " unextended sp=" INTPTR_FORMAT, print_name(), p2i(sp()), p2i(unextended_sp())); if (sp() != NULL) - st->print(", fp=" INTPTR_FORMAT ", real_fp=" INTPTR_FORMAT ", pc=" INTPTR_FORMAT, fp(), real_fp(), pc()); + st->print(", fp=" INTPTR_FORMAT ", real_fp=" INTPTR_FORMAT ", pc=" INTPTR_FORMAT, + p2i(fp()), p2i(real_fp()), p2i(pc())); if (StubRoutines::contains(pc())) { st->print_cr(")"); @@ -569,15 +567,15 @@ void frame::interpreter_frame_print_on(outputStream* st) const { st->print_cr("]"); } // monitor - st->print_cr(" - monitor[" INTPTR_FORMAT "]", interpreter_frame_monitor_begin()); + st->print_cr(" - monitor[" INTPTR_FORMAT "]", p2i(interpreter_frame_monitor_begin())); // bcp - st->print(" - bcp [" INTPTR_FORMAT "]", interpreter_frame_bcp()); + st->print(" - bcp [" INTPTR_FORMAT "]", p2i(interpreter_frame_bcp())); st->fill_to(23); st->print_cr("; @%d", interpreter_frame_bci()); // locals - st->print_cr(" - locals [" INTPTR_FORMAT "]", interpreter_frame_local_at(0)); + st->print_cr(" - locals [" INTPTR_FORMAT "]", p2i(interpreter_frame_local_at(0))); // method - st->print(" - method [" INTPTR_FORMAT "]", (address)interpreter_frame_method()); + st->print(" - method [" INTPTR_FORMAT "]", p2i(interpreter_frame_method())); st->fill_to(23); st->print("; "); interpreter_frame_method()->print_name(st); @@ -606,7 +604,7 @@ void frame::print_C_frame(outputStream* st, char* buf, int buflen, address pc) { while ((p2 = strstr(p1, os::file_separator())) != NULL) p1 = p2 + len; st->print(" [%s+0x%x]", p1, offset); } else { - st->print(" " PTR_FORMAT, pc); + st->print(" " PTR_FORMAT, p2i(pc)); } // function name - os::dll_address_to_function_name() may return confusing @@ -645,14 +643,14 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose st->print("j %s", buf); st->print("+%d", this->interpreter_frame_bci()); } else { - st->print("j " PTR_FORMAT, pc()); + st->print("j " PTR_FORMAT, p2i(pc())); } } else if (StubRoutines::contains(pc())) { StubCodeDesc* desc = StubCodeDesc::desc_for(pc()); if (desc != NULL) { st->print("v ~StubRoutines::%s", desc->name()); } else { - st->print("v ~StubRoutines::" PTR_FORMAT, pc()); + st->print("v ~StubRoutines::" PTR_FORMAT, p2i(pc())); } } else if (_cb->is_buffer_blob()) { st->print("v ~BufferBlob::%s", ((BufferBlob *)_cb)->name()); @@ -661,12 +659,19 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose Method* m = nm->method(); if (m != NULL) { m->name_and_sig_as_C_string(buf, buflen); - st->print("J %d%s %s %s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+0x%x]", + st->print("J %d%s %s ", nm->compile_id(), (nm->is_osr_method() ? "%" : ""), - ((nm->compiler() != NULL) ? nm->compiler()->name() : ""), - buf, m->code_size(), _pc, _cb->code_begin(), _pc - _cb->code_begin()); + ((nm->compiler() != NULL) ? nm->compiler()->name() : "")); +#if INCLUDE_JVMCI + char* jvmciName = nm->jvmci_installed_code_name(buf, buflen); + if (jvmciName != NULL) { + st->print(" (%s)", jvmciName); + } +#endif + st->print("%s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", + buf, m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); } else { - st->print("J " PTR_FORMAT, pc()); + st->print("J " PTR_FORMAT, p2i(pc())); } } else if (_cb->is_runtime_stub()) { st->print("v ~RuntimeStub::%s", ((RuntimeStub *)_cb)->name()); @@ -677,7 +682,7 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose } else if (_cb->is_safepoint_stub()) { st->print("v ~SafepointBlob"); } else { - st->print("v blob " PTR_FORMAT, pc()); + st->print("v blob " PTR_FORMAT, p2i(pc())); } } else { print_C_frame(st, buf, buflen, pc()); @@ -998,7 +1003,8 @@ class CompiledArgumentOopFinder: public SignatureInfo { } }; -void frame::oops_compiled_arguments_do(Symbol* signature, bool has_receiver, bool has_appendix, const RegisterMap* reg_map, OopClosure* f) { +void frame::oops_compiled_arguments_do(Symbol* signature, bool has_receiver, bool has_appendix, + const RegisterMap* reg_map, OopClosure* f) { ResourceMark rm; CompiledArgumentOopFinder finder(signature, has_receiver, has_appendix, f, *this, reg_map); finder.oops_do(); @@ -1022,7 +1028,7 @@ oop frame::retrieve_receiver(RegisterMap* reg_map) { return NULL; } oop r = *oop_adr; - assert(Universe::heap()->is_in_or_null(r), err_msg("bad receiver: " INTPTR_FORMAT " (" INTX_FORMAT ")", (void *) r, (void *) r)); + assert(Universe::heap()->is_in_or_null(r), "bad receiver: " INTPTR_FORMAT " (" INTX_FORMAT ")", p2i(r), p2i(r)); return r; } @@ -1111,104 +1117,6 @@ void frame::metadata_do(void f(Metadata*)) { } } -# ifdef ENABLE_ZAP_DEAD_LOCALS - -void frame::CheckValueClosure::do_oop(oop* p) { - if (CheckOopishValues && Universe::heap()->is_in_reserved(*p)) { - warning("value @ " INTPTR_FORMAT " looks oopish (" INTPTR_FORMAT ") (thread = " INTPTR_FORMAT ")", p, (address)*p, Thread::current()); - } -} -frame::CheckValueClosure frame::_check_value; - - -void frame::CheckOopClosure::do_oop(oop* p) { - if (*p != NULL && !(*p)->is_oop()) { - warning("value @ " INTPTR_FORMAT " should be an oop (" INTPTR_FORMAT ") (thread = " INTPTR_FORMAT ")", p, (address)*p, Thread::current()); - } -} -frame::CheckOopClosure frame::_check_oop; - -void frame::check_derived_oop(oop* base, oop* derived) { - _check_oop.do_oop(base); -} - - -void frame::ZapDeadClosure::do_oop(oop* p) { - if (TraceZapDeadLocals) tty->print_cr("zapping @ " INTPTR_FORMAT " containing " INTPTR_FORMAT, p, (address)*p); - *p = cast_to_oop(0xbabebabe); -} -frame::ZapDeadClosure frame::_zap_dead; - -void frame::zap_dead_locals(JavaThread* thread, const RegisterMap* map) { - assert(thread == Thread::current(), "need to synchronize to do this to another thread"); - // Tracing - part 1 - if (TraceZapDeadLocals) { - ResourceMark rm(thread); - tty->print_cr("--------------------------------------------------------------------------------"); - tty->print("Zapping dead locals in "); - print_on(tty); - tty->cr(); - } - // Zapping - if (is_entry_frame ()) zap_dead_entry_locals (thread, map); - else if (is_interpreted_frame()) zap_dead_interpreted_locals(thread, map); - else if (is_compiled_frame()) zap_dead_compiled_locals (thread, map); - - else - // could be is_runtime_frame - // so remove error: ShouldNotReachHere(); - ; - // Tracing - part 2 - if (TraceZapDeadLocals) { - tty->cr(); - } -} - - -void frame::zap_dead_interpreted_locals(JavaThread *thread, const RegisterMap* map) { - // get current interpreter 'pc' - assert(is_interpreted_frame(), "Not an interpreted frame"); - Method* m = interpreter_frame_method(); - int bci = interpreter_frame_bci(); - - int max_locals = m->is_native() ? m->size_of_parameters() : m->max_locals(); - - // process dynamic part - InterpreterFrameClosure value_blk(this, max_locals, m->max_stack(), - &_check_value); - InterpreterFrameClosure oop_blk(this, max_locals, m->max_stack(), - &_check_oop ); - InterpreterFrameClosure dead_blk(this, max_locals, m->max_stack(), - &_zap_dead ); - - // get frame map - InterpreterOopMap mask; - m->mask_for(bci, &mask); - mask.iterate_all( &oop_blk, &value_blk, &dead_blk); -} - - -void frame::zap_dead_compiled_locals(JavaThread* thread, const RegisterMap* reg_map) { - - ResourceMark rm(thread); - assert(_cb != NULL, "sanity check"); - if (_cb->oop_maps() != NULL) { - OopMapSet::all_do(this, reg_map, &_check_oop, check_derived_oop, &_check_value); - } -} - - -void frame::zap_dead_entry_locals(JavaThread*, const RegisterMap*) { - if (TraceZapDeadLocals) warning("frame::zap_dead_entry_locals unimplemented"); -} - - -void frame::zap_dead_deoptimized_locals(JavaThread*, const RegisterMap*) { - if (TraceZapDeadLocals) warning("frame::zap_dead_deoptimized_locals unimplemented"); -} - -# endif // ENABLE_ZAP_DEAD_LOCALS - void frame::verify(const RegisterMap* map) { // for now make sure receiver type is correct if (is_interpreted_frame()) { @@ -1220,7 +1128,9 @@ void frame::verify(const RegisterMap* map) { // make sure we have the right receiver type } } - COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(), "must be empty before verify");) +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_empty(), "must be empty before verify"); +#endif oops_do_internal(&VerifyOopClosure::verify_oop, NULL, NULL, (RegisterMap*)map, false); } @@ -1321,7 +1231,7 @@ void frame::describe(FrameValues& values, int frame_no) { nmethod* nm = cb()->as_nmethod_or_null(); values.describe(-1, info_address, FormatBuffer<1024>("#%d nmethod " INTPTR_FORMAT " for method %s%s", frame_no, - nm, nm->method()->name_and_sig_as_C_string(), + p2i(nm), nm->method()->name_and_sig_as_C_string(), (_deopt_state == is_deoptimized) ? " (deoptimized)" : ((_deopt_state == unknown) ? " (state unknown)" : "")), @@ -1331,7 +1241,7 @@ void frame::describe(FrameValues& values, int frame_no) { nmethod* nm = cb()->as_nmethod_or_null(); values.describe(-1, info_address, FormatBuffer<1024>("#%d nmethod " INTPTR_FORMAT " for native method %s", frame_no, - nm, nm->method()->name_and_sig_as_C_string()), 2); + p2i(nm), nm->method()->name_and_sig_as_C_string()), 2); } else { // provide default info if not handled before char *info = (char *) "special frame"; @@ -1388,8 +1298,8 @@ void FrameValues::validate() { if (prev.location == fv.location) { if (fv.owner != prev.owner) { tty->print_cr("overlapping storage"); - tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", prev.location, *prev.location, prev.description); - tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", fv.location, *fv.location, fv.description); + tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", p2i(prev.location), *prev.location, prev.description); + tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", p2i(fv.location), *fv.location, fv.description); error = true; } } else { @@ -1433,14 +1343,14 @@ void FrameValues::print(JavaThread* thread) { for (int i = max_index; i >= min_index; i--) { FrameValue fv = _values.at(i); while (cur > fv.location) { - tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT, cur, *cur); + tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT, p2i(cur), *cur); cur--; } if (last == fv.location) { const char* spacer = " " LP64_ONLY(" "); tty->print_cr(" %s %s %s", spacer, spacer, fv.description); } else { - tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", fv.location, *fv.location, fv.description); + tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", p2i(fv.location), *fv.location, fv.description); last = fv.location; cur--; } diff --git a/hotspot/src/share/vm/runtime/frame.hpp b/hotspot/src/share/vm/runtime/frame.hpp index df5d3b2bd90..0b208d249d9 100644 --- a/hotspot/src/share/vm/runtime/frame.hpp +++ b/hotspot/src/share/vm/runtime/frame.hpp @@ -405,39 +405,6 @@ class frame VALUE_OBJ_CLASS_SPEC { // RedefineClasses support for finding live interpreted methods on the stack void metadata_do(void f(Metadata*)); -# ifdef ENABLE_ZAP_DEAD_LOCALS - private: - class CheckValueClosure: public OopClosure { - public: - void do_oop(oop* p); - void do_oop(narrowOop* p) { ShouldNotReachHere(); } - }; - static CheckValueClosure _check_value; - - class CheckOopClosure: public OopClosure { - public: - void do_oop(oop* p); - void do_oop(narrowOop* p) { ShouldNotReachHere(); } - }; - static CheckOopClosure _check_oop; - - static void check_derived_oop(oop* base, oop* derived); - - class ZapDeadClosure: public OopClosure { - public: - void do_oop(oop* p); - void do_oop(narrowOop* p) { ShouldNotReachHere(); } - }; - static ZapDeadClosure _zap_dead; - - public: - // Zapping - void zap_dead_locals (JavaThread* thread, const RegisterMap* map); - void zap_dead_interpreted_locals(JavaThread* thread, const RegisterMap* map); - void zap_dead_compiled_locals (JavaThread* thread, const RegisterMap* map); - void zap_dead_entry_locals (JavaThread* thread, const RegisterMap* map); - void zap_dead_deoptimized_locals(JavaThread* thread, const RegisterMap* map); -# endif // Verification void verify(const RegisterMap* map); static bool verify_return_pc(address x); diff --git a/hotspot/src/share/vm/runtime/globals.cpp b/hotspot/src/share/vm/runtime/globals.cpp index 6b79347e6e8..3357fcfc323 100644 --- a/hotspot/src/share/vm/runtime/globals.cpp +++ b/hotspot/src/share/vm/runtime/globals.cpp @@ -42,6 +42,9 @@ #ifdef COMPILER1 #include "c1/c1_globals.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmci_globals.hpp" +#endif #ifdef COMPILER2 #include "opto/c2_globals.hpp" #endif @@ -49,8 +52,6 @@ #include "shark/shark_globals.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - RUNTIME_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_PD_DEVELOPER_FLAG, \ MATERIALIZE_PRODUCT_FLAG, \ @@ -93,7 +94,7 @@ static bool is_product_build() { void Flag::check_writable() { if (is_constant_in_binary()) { - fatal(err_msg("flag is constant: %s", _name)); + fatal("flag is constant: %s", _name); } } @@ -369,11 +370,11 @@ void Flag::print_on(outputStream* st, bool withComments, bool printRanges) { } else if (is_uint()) { st->print("%-16u", get_uint()); } else if (is_intx()) { - st->print("%-16ld", get_intx()); + st->print(INTX_FORMAT_W(-16), get_intx()); } else if (is_uintx()) { - st->print("%-16lu", get_uintx()); + st->print(UINTX_FORMAT_W(-16), get_uintx()); } else if (is_uint64_t()) { - st->print("%-16lu", get_uint64_t()); + st->print(UINT64_FORMAT_W(-16), get_uint64_t()); } else if (is_size_t()) { st->print(SIZE_FORMAT_W(-16), get_size_t()); } else if (is_double()) { @@ -441,6 +442,7 @@ void Flag::print_kind(outputStream* st) { }; Data data[] = { + { KIND_JVMCI, "JVMCI" }, { KIND_C1, "C1" }, { KIND_C2, "C2" }, { KIND_ARCH, "ARCH" }, @@ -548,6 +550,14 @@ const char* Flag::flag_error_str(Flag::Error error) { #define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, #define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_NOT_PRODUCT) }, +#define JVMCI_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT) }, +#define JVMCI_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP) }, +#define JVMCI_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DIAGNOSTIC) }, +#define JVMCI_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_EXPERIMENTAL) }, +#define JVMCI_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_NOT_PRODUCT) }, + #ifdef _LP64 #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_LP64_PRODUCT) }, #else @@ -616,6 +626,17 @@ static Flag flagTable[] = { IGNORE_RANGE, \ IGNORE_CONSTRAINT) #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_STRUCT, \ + JVMCI_PD_DEVELOP_FLAG_STRUCT, \ + JVMCI_PRODUCT_FLAG_STRUCT, \ + JVMCI_PD_PRODUCT_FLAG_STRUCT, \ + JVMCI_DIAGNOSTIC_FLAG_STRUCT, \ + JVMCI_EXPERIMENTAL_FLAG_STRUCT, \ + JVMCI_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) +#endif // INCLUDE_JVMCI #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, \ C1_PD_DEVELOP_FLAG_STRUCT, \ diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index d690459c988..73592162625 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -25,7 +25,9 @@ #ifndef SHARE_VM_RUNTIME_GLOBALS_HPP #define SHARE_VM_RUNTIME_GLOBALS_HPP +#include #include "utilities/debug.hpp" +#include // for DBL_MAX // use this for flags that are true per default in the tiered build // but false in non-tiered builds, and vice versa @@ -176,7 +178,7 @@ #endif #endif -#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) +#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) && !INCLUDE_JVMCI define_pd_global(bool, BackgroundCompilation, false); define_pd_global(bool, UseTLAB, false); define_pd_global(bool, CICompileOSR, false); @@ -211,11 +213,11 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); #define CI_COMPILER_COUNT 0 #else -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI #define CI_COMPILER_COUNT 2 #else #define CI_COMPILER_COUNT 1 -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI #endif // no compilers @@ -254,6 +256,7 @@ struct Flag { KIND_SHARK = 1 << 15, KIND_LP64_PRODUCT = 1 << 16, KIND_COMMERCIAL = 1 << 17, + KIND_JVMCI = 1 << 18, KIND_MASK = ~VALUE_ORIGIN_MASK }; @@ -527,7 +530,7 @@ public: // notproduct flags are settable / visible only during development and are not declared in the PRODUCT version // A flag must be declared with one of the following types: -// bool, intx, uintx, size_t, ccstr, double, or uint64_t. +// bool, int, uint, intx, uintx, size_t, ccstr, double, or uint64_t. // The type "ccstr" is an alias for "const char*" and is used // only in this file, because the macrology requires single-token type names. @@ -700,6 +703,7 @@ public: \ product(intx, UseSSE, 99, \ "Highest supported SSE instructions set on x86/x64") \ + range(0, 99) \ \ product(bool, UseAES, false, \ "Control whether AES instructions can be used on x86/x64") \ @@ -890,9 +894,11 @@ public: /* typically, at most a few retries are needed */ \ product(intx, SuspendRetryCount, 50, \ "Maximum retry count for an external suspend request") \ + range(0, max_intx) \ \ product(intx, SuspendRetryDelay, 5, \ "Milliseconds to delay per retry (* current_retry_count)") \ + range(0, max_intx) \ \ product(bool, AssertOnSuspendWaitFailure, false, \ "Assert/Guarantee on external suspend wait failure") \ @@ -937,16 +943,6 @@ public: notproduct(bool, VerifyCodeCache, false, \ "Verify code cache on memory allocation/deallocation") \ \ - develop(bool, ZapDeadCompiledLocals, false, \ - "Zap dead locals in compiler frames") \ - \ - notproduct(bool, ZapDeadLocalsOld, false, \ - "Zap dead locals (old version, zaps all frames when " \ - "entering the VM") \ - \ - notproduct(bool, CheckOopishValues, false, \ - "Warn if value contains oop (requires ZapDeadLocals)") \ - \ develop(bool, UseMallocOnly, false, \ "Use only malloc/free for allocation (no resource area/arena)") \ \ @@ -1108,9 +1104,15 @@ public: diagnostic(ccstr, PrintAssemblyOptions, NULL, \ "Print options string passed to disassembler.so") \ \ + notproduct(bool, PrintNMethodStatistics, false, \ + "Print a summary statistic for the generated nmethods") \ + \ diagnostic(bool, PrintNMethods, false, \ "Print assembly code for nmethods when generated") \ \ + diagnostic(intx, PrintNMethodsAtLevel, -1, \ + "Only print code for nmethods at the given compilation level") \ + \ diagnostic(bool, PrintNativeNMethods, false, \ "Print assembly code for native nmethods when generated") \ \ @@ -1258,6 +1260,7 @@ public: "Control emission of inline sync fast-path code") \ \ product(intx, MonitorBound, 0, "Bound Monitor population") \ + range(0, max_jint) \ \ product(bool, MonitorInUseLists, false, "Track Monitors for Deflation") \ \ @@ -1341,6 +1344,7 @@ public: "Maximum allowable local JNI handle capacity to " \ "EnsureLocalCapacity() and PushLocalFrame(), " \ "where <= 0 is unlimited, default: 65536") \ + range(min_intx, max_intx) \ \ product(bool, EagerXrunInit, false, \ "Eagerly initialize -Xrun libraries; allows startup profiling, " \ @@ -1376,7 +1380,7 @@ public: product(intx, ContendedPaddingWidth, 128, \ "How many bytes to pad the fields/classes marked @Contended with")\ range(0, 8192) \ - constraint(ContendedPaddingWidthConstraintFunc,AtParse) \ + constraint(ContendedPaddingWidthConstraintFunc,AfterErgo) \ \ product(bool, EnableContended, true, \ "Enable @Contended annotation support") \ @@ -1389,6 +1393,8 @@ public: \ product(intx, BiasedLockingStartupDelay, 4000, \ "Number of milliseconds to wait before enabling biased locking") \ + range(0, (intx)(max_jint-(max_jint%PeriodicTask::interval_gran))) \ + constraint(BiasedLockingStartupDelayFunc,AfterErgo) \ \ diagnostic(bool, PrintBiasedLockingStatistics, false, \ "Print statistics of biased locking in JVM") \ @@ -1396,14 +1402,20 @@ public: product(intx, BiasedLockingBulkRebiasThreshold, 20, \ "Threshold of number of revocations per type to try to " \ "rebias all objects in the heap of that type") \ + range(0, max_intx) \ + constraint(BiasedLockingBulkRebiasThresholdFunc,AfterErgo) \ \ product(intx, BiasedLockingBulkRevokeThreshold, 40, \ "Threshold of number of revocations per type to permanently " \ "revoke biases of all objects in the heap of that type") \ + range(0, max_intx) \ + constraint(BiasedLockingBulkRevokeThresholdFunc,AfterErgo) \ \ product(intx, BiasedLockingDecayTime, 25000, \ "Decay time (in milliseconds) to re-enable bulk rebiasing of a " \ "type after previous bulk rebias") \ + range(500, max_intx) \ + constraint(BiasedLockingDecayTimeFunc,AfterErgo) \ \ /* tracing */ \ \ @@ -1428,8 +1440,9 @@ public: product(bool, StressLdcRewrite, false, \ "Force ldc -> ldc_w rewrite during RedefineClasses") \ \ - product(intx, TraceRedefineClasses, 0, \ + product(uintx, TraceRedefineClasses, 0, \ "Trace level for JVMTI RedefineClasses") \ + range(0, 0xFFFFFFFF) \ \ /* change to false by default sometime after Mustang */ \ product(bool, VerifyMergedCPBytecodes, true, \ @@ -1489,9 +1502,6 @@ public: develop(bool, TraceCompiledIC, false, \ "Trace changes of compiled IC") \ \ - notproduct(bool, TraceZapDeadLocals, false, \ - "Trace zapping dead locals") \ - \ develop(bool, TraceStartupTime, false, \ "Trace setup time") \ \ @@ -1547,6 +1557,7 @@ public: \ product(uint, ParallelGCThreads, 0, \ "Number of parallel threads parallel gc will use") \ + constraint(ParallelGCThreadsConstraintFunc,AfterErgo) \ \ diagnostic(bool, UseSemaphoreGCThreadsSynchronization, true, \ "Use semaphore synchronization for the GC Threads, " \ @@ -1568,24 +1579,9 @@ public: product(bool, TraceDynamicGCThreads, false, \ "Trace the dynamic GC thread usage") \ \ - develop(bool, ParallelOldGCSplitALot, false, \ - "Provoke splitting (copying data from a young gen space to " \ - "multiple destination spaces)") \ - \ - develop(uintx, ParallelOldGCSplitInterval, 3, \ - "How often to provoke splitting a young gen space") \ - range(0, max_uintx) \ - \ product(uint, ConcGCThreads, 0, \ "Number of threads concurrent gc will use") \ - \ - product(size_t, YoungPLABSize, 4096, \ - "Size of young gen promotion LAB's (in HeapWords)") \ - constraint(YoungPLABSizeConstraintFunc,AfterMemoryInit) \ - \ - product(size_t, OldPLABSize, 1024, \ - "Size of old gen promotion LAB's (in HeapWords), or Number \ - of blocks to attempt to claim when refilling CMS LAB's") \ + constraint(ConcGCThreadsConstraintFunc,AfterErgo) \ \ product(uintx, GCTaskTimeStampEntries, 200, \ "Number of time stamp entries per gc worker thread") \ @@ -1601,9 +1597,6 @@ public: product(bool, ScavengeBeforeFullGC, true, \ "Scavenge youngest generation before each full GC.") \ \ - develop(bool, ScavengeWithObjectsInToSpace, false, \ - "Allow scavenges to occur when to-space contains objects") \ - \ product(bool, UseConcMarkSweepGC, false, \ "Use Concurrent Mark-Sweep GC in the old generation") \ \ @@ -1693,6 +1686,7 @@ public: "The number of strides per worker thread that we divide up the " \ "card table scanning work into") \ range(1, max_uintx) \ + constraint(ParGCStridesPerThreadConstraintFunc,AfterErgo) \ \ diagnostic(intx, ParGCCardsPerStrideChunk, 256, \ "The number of cards in each chunk of the parallel chunks used " \ @@ -1715,12 +1709,13 @@ public: "Maximum size of CMS gen promotion LAB caches per worker " \ "per block size") \ range(1, max_uintx) \ + constraint(CMSOldPLABMaxConstraintFunc,AfterMemoryInit) \ \ product(size_t, CMSOldPLABMin, 16, \ "Minimum size of CMS gen promotion LAB caches per worker " \ "per block size") \ range(1, max_uintx) \ - constraint(CMSOldPLABMinConstraintFunc,AfterErgo) \ + constraint(CMSOldPLABMinConstraintFunc,AfterMemoryInit) \ \ product(uintx, CMSOldPLABNumRefills, 4, \ "Nominal number of refills of CMS gen promotion LAB cache " \ @@ -1779,24 +1774,29 @@ public: product(double, FLSLargestBlockCoalesceProximity, 0.99, \ "CMS: the smaller the percentage the greater the coalescing " \ "force") \ + range(0.0, 1.0) \ \ product(double, CMSSmallCoalSurplusPercent, 1.05, \ "CMS: the factor by which to inflate estimated demand of small " \ "block sizes to prevent coalescing with an adjoining block") \ + range(0.0, DBL_MAX) \ \ product(double, CMSLargeCoalSurplusPercent, 0.95, \ "CMS: the factor by which to inflate estimated demand of large " \ "block sizes to prevent coalescing with an adjoining block") \ + range(0.0, DBL_MAX) \ \ product(double, CMSSmallSplitSurplusPercent, 1.10, \ "CMS: the factor by which to inflate estimated demand of small " \ "block sizes to prevent splitting to supply demand for smaller " \ "blocks") \ + range(0.0, DBL_MAX) \ \ product(double, CMSLargeSplitSurplusPercent, 1.00, \ "CMS: the factor by which to inflate estimated demand of large " \ "block sizes to prevent splitting to supply demand for smaller " \ "blocks") \ + range(0.0, DBL_MAX) \ \ product(bool, CMSExtrapolateSweep, false, \ "CMS: cushion for block demand during sweep") \ @@ -1824,9 +1824,11 @@ public: \ develop(intx, CMSDictionaryChoice, 0, \ "Use BinaryTreeDictionary as default in the CMS generation") \ + range(0, 2) \ \ product(uintx, CMSIndexedFreeListReplenish, 4, \ "Replenish an indexed free list with this number of chunks") \ + range(1, max_uintx) \ \ product(bool, CMSReplenishIntermediate, true, \ "Replenish all intermediate free-list caches") \ @@ -1841,14 +1843,15 @@ public: develop(bool, CMSOverflowEarlyRestoration, false, \ "Restore preserved marks early") \ \ - product(size_t, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \ - "Size of marking stack") \ - \ /* where does the range max value of (max_jint - 1) come from? */ \ product(size_t, MarkStackSizeMax, NOT_LP64(4*M) LP64_ONLY(512*M), \ "Maximum size of marking stack") \ range(1, (max_jint - 1)) \ \ + product(size_t, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \ + "Size of marking stack") \ + constraint(MarkStackSizeConstraintFunc,AfterErgo) \ + \ notproduct(bool, CMSMarkStackOverflowALot, false, \ "Simulate frequent marking stack / work queue overflow") \ \ @@ -1861,6 +1864,7 @@ public: \ product(intx, CMSMaxAbortablePrecleanTime, 5000, \ "Maximum time in abortable preclean (in milliseconds)") \ + range(0, max_intx) \ \ product(uintx, CMSAbortablePrecleanMinWorkPerIteration, 100, \ "Nominal minimum work per abortable preclean iteration") \ @@ -1868,6 +1872,7 @@ public: manageable(intx, CMSAbortablePrecleanWaitMillis, 100, \ "Time that we sleep between iterations when not given " \ "enough work per iteration") \ + range(0, max_intx) \ \ product(size_t, CMSRescanMultiple, 32, \ "Size (in cards) of CMS parallel rescan task") \ @@ -1974,6 +1979,8 @@ public: \ product(uintx, CMSWorkQueueDrainThreshold, 10, \ "Don't drain below this size per parallel worker/thief") \ + range(1, max_juint) \ + constraint(CMSWorkQueueDrainThresholdConstraintFunc,AfterErgo) \ \ manageable(intx, CMSWaitDuration, 2000, \ "Time in milliseconds that CMS thread waits for young GC") \ @@ -2173,6 +2180,7 @@ public: \ product_pd(uint64_t, MaxRAM, \ "Real memory size (in bytes) used to set maximum heap size") \ + range(0, 0XFFFFFFFFFFFFFFFF) \ \ product(size_t, ErgoHeapSizeLimit, 0, \ "Maximum ergonomically set heap size (in bytes); zero means use " \ @@ -2225,15 +2233,11 @@ public: \ develop(intx, PSAdaptiveSizePolicyResizeVirtualSpaceAlot, -1, \ "Resize the virtual spaces of the young or old generations") \ + range(-1, 1) \ \ product(uintx, AdaptiveSizeThroughPutPolicy, 0, \ "Policy for changing generation size for throughput goals") \ - \ - develop(bool, PSAdjustTenuredGenForMinorPause, false, \ - "Adjust tenured generation to achieve a minor pause goal") \ - \ - develop(bool, PSAdjustYoungGenForMajorPause, false, \ - "Adjust young generation to achieve a major pause goal") \ + range(0, 1) \ \ product(uintx, AdaptiveSizePolicyInitializingSteps, 20, \ "Number of steps where heuristics is used before data is used") \ @@ -2299,9 +2303,12 @@ public: product(uintx, MaxGCPauseMillis, max_uintx, \ "Adaptive size policy maximum GC pause time goal in millisecond, "\ "or (G1 Only) the maximum GC time per MMU time slice") \ + range(1, max_uintx) \ + constraint(MaxGCPauseMillisConstraintFunc,AfterMemoryInit) \ \ product(uintx, GCPauseIntervalMillis, 0, \ "Time slice for MMU specification") \ + constraint(GCPauseIntervalMillisConstraintFunc,AfterMemoryInit) \ \ product(uintx, MaxGCMinorPauseMillis, max_uintx, \ "Adaptive size policy maximum GC minor pause time goal " \ @@ -2322,6 +2329,7 @@ public: \ product(uintx, MinSurvivorRatio, 3, \ "Minimum ratio of young generation/survivor space size") \ + range(3, max_uintx) \ \ product(uintx, InitialSurvivorRatio, 8, \ "Initial ratio of young generation/survivor space size") \ @@ -2345,6 +2353,7 @@ public: \ develop(uintx, AdaptiveSizePolicyGCTimeLimitThreshold, 5, \ "Number of consecutive collections before gc time limit fires") \ + range(1, max_uintx) \ \ product(bool, PrintAdaptiveSizePolicy, false, \ "Print information about AdaptiveSizePolicy") \ @@ -2444,6 +2453,7 @@ public: develop(intx, ConcGCYieldTimeout, 0, \ "If non-zero, assert that GC threads yield within this " \ "number of milliseconds") \ + range(0, max_intx) \ \ product(bool, PrintReferenceGC, false, \ "Print times spent handling reference objects during GC " \ @@ -2482,6 +2492,8 @@ public: product(size_t, InitialBootClassLoaderMetaspaceSize, \ NOT_LP64(2200*K) LP64_ONLY(4*M), \ "Initial size of the boot class loader data metaspace") \ + range(30*K, max_uintx/BytesPerWord) \ + constraint(InitialBootClassLoaderMetaspaceSizeConstraintFunc, AfterErgo)\ \ product(bool, TraceYoungGenTime, false, \ "Trace accumulated time for young collection") \ @@ -2558,6 +2570,7 @@ public: experimental(double, ObjectCountCutOffPercent, 0.5, \ "The percentage of the used heap that the instances of a class " \ "must occupy for the class to generate a trace event") \ + range(0.0, 100.0) \ \ /* GC log rotation setting */ \ \ @@ -2670,10 +2683,13 @@ public: product(intx, PrintSafepointStatisticsCount, 300, \ "Total number of safepoint statistics collected " \ "before printing them out") \ + range(1, max_intx) \ \ product(intx, PrintSafepointStatisticsTimeout, -1, \ "Print safepoint statistics only when safepoint takes " \ "more than PrintSafepointSatisticsTimeout in millis") \ + LP64_ONLY(range(-1, max_intx/MICROUNITS)) \ + NOT_LP64(range(-1, max_intx)) \ \ product(bool, TraceSafepointCleanupTime, false, \ "Print the break down of clean up tasks performed during " \ @@ -2718,10 +2734,12 @@ public: diagnostic(intx, HotMethodDetectionLimit, 100000, \ "Number of compiled code invocations after which " \ "the method is considered as hot by the flusher") \ + range(1, max_jint) \ \ diagnostic(intx, MinPassesBeforeFlush, 10, \ "Minimum number of sweeper passes before an nmethod " \ "can be flushed") \ + range(0, max_intx) \ \ product(bool, UseCodeAging, true, \ "Insert counter to detect warm methods") \ @@ -2800,11 +2818,11 @@ public: "standard exit from VM if bytecode verify error " \ "(only in debug mode)") \ \ - notproduct(ccstr, AbortVMOnException, NULL, \ + diagnostic(ccstr, AbortVMOnException, NULL, \ "Call fatal if this exception is thrown. Example: " \ "java -XX:AbortVMOnException=java.lang.NullPointerException Foo") \ \ - notproduct(ccstr, AbortVMOnExceptionMessage, NULL, \ + diagnostic(ccstr, AbortVMOnExceptionMessage, NULL, \ "Call fatal if the exception pointed by AbortVMOnException " \ "has this message") \ \ @@ -2838,7 +2856,7 @@ public: \ develop(bool, CompileTheWorld, false, \ "Compile all methods in all classes in bootstrap class path " \ - "(stress test)") \ + "(stress test)") \ \ develop(bool, CompileTheWorldPreloadClasses, true, \ "Preload all classes used by a class before start loading") \ @@ -2876,13 +2894,16 @@ public: "Y: Type profiling of return value at call; " \ "X: Type profiling of parameters to methods; " \ "X, Y and Z in 0=off ; 1=jsr292 only; 2=all methods") \ + constraint(TypeProfileLevelConstraintFunc, AfterErgo) \ \ product(intx, TypeProfileArgsLimit, 2, \ "max number of call arguments to consider for type profiling") \ + range(0, 16) \ \ product(intx, TypeProfileParmsLimit, 2, \ "max number of incoming parameters to consider for type profiling"\ ", -1 for all") \ + range(-1, 64) \ \ /* statistics */ \ develop(bool, CountCompiledCalls, false, \ @@ -3041,13 +3062,17 @@ public: "Analyze bytecodes to estimate escape state of arguments") \ \ product(intx, BCEATraceLevel, 0, \ - "How much tracing to do of bytecode escape analysis estimates") \ + "How much tracing to do of bytecode escape analysis estimates " \ + "(0-3)") \ + range(0, 3) \ \ product(intx, MaxBCEAEstimateLevel, 5, \ "Maximum number of nested calls that are analyzed by BC EA") \ + range(0, max_jint) \ \ product(intx, MaxBCEAEstimateSize, 150, \ "Maximum bytecode size of a method to be analyzed by BC EA") \ + range(0, max_jint) \ \ product(intx, AllocatePrefetchStyle, 1, \ "0 = no prefetch, " \ @@ -3057,46 +3082,63 @@ public: range(0, 3) \ \ product(intx, AllocatePrefetchDistance, -1, \ - "Distance to prefetch ahead of allocation pointer") \ + "Distance to prefetch ahead of allocation pointer. " \ + "-1: use system-specific value (automatically determined") \ + constraint(AllocatePrefetchDistanceConstraintFunc, AfterMemoryInit)\ \ product(intx, AllocatePrefetchLines, 3, \ "Number of lines to prefetch ahead of array allocation pointer") \ + range(1, max_jint / 2) \ \ product(intx, AllocateInstancePrefetchLines, 1, \ "Number of lines to prefetch ahead of instance allocation " \ "pointer") \ + range(1, max_jint / 2) \ \ product(intx, AllocatePrefetchStepSize, 16, \ "Step size in bytes of sequential prefetch instructions") \ + constraint(AllocatePrefetchStepSizeConstraintFunc,AfterMemoryInit)\ \ product(intx, AllocatePrefetchInstr, 0, \ "Prefetch instruction to prefetch ahead of allocation pointer") \ + constraint(AllocatePrefetchInstrConstraintFunc, AfterErgo) \ \ /* deoptimization */ \ develop(bool, TraceDeoptimization, false, \ "Trace deoptimization") \ \ + develop(bool, PrintDeoptimizationDetails, false, \ + "Print more information about deoptimization") \ + \ develop(bool, DebugDeoptimization, false, \ "Tracing various information while debugging deoptimization") \ \ product(intx, SelfDestructTimer, 0, \ "Will cause VM to terminate after a given time (in minutes) " \ "(0 means off)") \ + range(0, max_intx) \ \ product(intx, MaxJavaStackTraceDepth, 1024, \ "The maximum number of lines in the stack trace for Java " \ "exceptions (0 means all)") \ + range(0, max_jint/2) \ \ + /* notice: the max range value here is max_jint, not max_intx */ \ + /* because of overflow issue */ \ NOT_EMBEDDED(diagnostic(intx, GuaranteedSafepointInterval, 1000, \ "Guarantee a safepoint (at least) every so many milliseconds " \ "(0 means none)")) \ + NOT_EMBEDDED(range(0, max_jint)) \ \ EMBEDDED_ONLY(product(intx, GuaranteedSafepointInterval, 0, \ "Guarantee a safepoint (at least) every so many milliseconds " \ "(0 means none)")) \ + EMBEDDED_ONLY(range(0, max_jint)) \ \ product(intx, SafepointTimeoutDelay, 10000, \ "Delay in milliseconds for option SafepointTimeout") \ + LP64_ONLY(range(0, max_intx/MICROUNITS)) \ + NOT_LP64(range(0, max_intx)) \ \ product(intx, NmethodSweepActivity, 10, \ "Removes cold nmethods from code cache if > 0. Higher values " \ @@ -3137,30 +3179,38 @@ public: \ product(intx, MaxInlineLevel, 9, \ "maximum number of nested calls that are inlined") \ + range(0, max_jint) \ \ product(intx, MaxRecursiveInlineLevel, 1, \ "maximum number of nested recursive calls that are inlined") \ + range(0, max_jint) \ \ develop(intx, MaxForceInlineLevel, 100, \ "maximum number of nested calls that are forced for inlining " \ - "(using CompilerOracle or marked w/ @ForceInline)") \ + "(using CompileCommand or marked w/ @ForceInline)") \ + range(0, max_jint) \ \ product_pd(intx, InlineSmallCode, \ "Only inline already compiled methods if their code size is " \ "less than this") \ + range(0, max_jint) \ \ product(intx, MaxInlineSize, 35, \ "The maximum bytecode size of a method to be inlined") \ + range(0, max_jint) \ \ product_pd(intx, FreqInlineSize, \ "The maximum bytecode size of a frequent method to be inlined") \ + range(0, max_jint) \ \ product(intx, MaxTrivialSize, 6, \ "The maximum bytecode size of a trivial method to be inlined") \ + range(0, max_jint) \ \ product(intx, MinInliningThreshold, 250, \ "The minimum invocation count a method needs to have to be " \ "inlined") \ + range(0, max_jint) \ \ develop(intx, MethodHistogramCutoff, 100, \ "The cutoff value for method invocation histogram (+CountCalls)") \ @@ -3180,6 +3230,7 @@ public: product(intx, ProfileIntervalsTicks, 100, \ "Number of ticks between printing of interval profile " \ "(+ProfileIntervals)") \ + range(0, max_intx) \ \ notproduct(intx, ScavengeALotInterval, 1, \ "Interval between which scavenge will occur with +ScavengeALot") \ @@ -3213,17 +3264,24 @@ public: diagnostic(intx, MallocVerifyInterval, 0, \ "If non-zero, verify C heap after every N calls to " \ "malloc/realloc/free") \ + range(0, max_intx) \ \ diagnostic(intx, MallocVerifyStart, 0, \ "If non-zero, start verifying C heap after Nth call to " \ "malloc/realloc/free") \ + range(0, max_intx) \ \ diagnostic(uintx, MallocMaxTestWords, 0, \ "If non-zero, maximum number of words that malloc/realloc can " \ "allocate (for testing only)") \ + range(0, max_uintx) \ \ - product(intx, TypeProfileWidth, 2, \ + product(intx, TypeProfileWidth, 2, \ "Number of receiver types to record in call/cast profile") \ + range(0, 8) \ + \ + experimental(intx, MethodProfileWidth, 0, \ + "Number of methods to record in call profile") \ \ develop(intx, BciProfileWidth, 2, \ "Number of return bci's to record in ret profile") \ @@ -3238,45 +3296,56 @@ public: \ product(intx, PerMethodTrapLimit, 100, \ "Limit on traps (of one kind) in a method (includes inlines)") \ + range(0, max_jint) \ \ experimental(intx, PerMethodSpecTrapLimit, 5000, \ "Limit on speculative traps (of one kind) in a method " \ "(includes inlines)") \ + range(0, max_jint) \ \ product(intx, PerBytecodeTrapLimit, 4, \ "Limit on traps (of one kind) at a particular BCI") \ + range(0, max_jint) \ \ experimental(intx, SpecTrapLimitExtraEntries, 3, \ "Extra method data trap entries for speculation") \ \ develop(intx, InlineFrequencyRatio, 20, \ "Ratio of call site execution to caller method invocation") \ + range(0, max_jint) \ \ develop_pd(intx, InlineFrequencyCount, \ "Count of call site execution necessary to trigger frequent " \ "inlining") \ + range(0, max_jint) \ \ develop(intx, InlineThrowCount, 50, \ "Force inlining of interpreted methods that throw this often") \ + range(0, max_jint) \ \ develop(intx, InlineThrowMaxSize, 200, \ "Force inlining of throwing methods smaller than this") \ + range(0, max_jint) \ \ develop(intx, ProfilerNodeSize, 1024, \ "Size in K to allocate for the Profile Nodes of each thread") \ + range(0, 1024) \ \ /* gc parameters */ \ product(size_t, InitialHeapSize, 0, \ "Initial heap size (in bytes); zero means use ergonomics") \ + constraint(InitialHeapSizeConstraintFunc,AfterErgo) \ \ product(size_t, MaxHeapSize, ScaleForWordSize(96*M), \ "Maximum heap size (in bytes)") \ + constraint(MaxHeapSizeConstraintFunc,AfterErgo) \ \ product(size_t, OldSize, ScaleForWordSize(4*M), \ "Initial tenured generation size (in bytes)") \ \ product(size_t, NewSize, ScaleForWordSize(1*M), \ "Initial new generation size (in bytes)") \ + constraint(NewSizeConstraintFunc,AfterErgo) \ \ product(size_t, MaxNewSize, max_uintx, \ "Maximum new generation size (in bytes), max_uintx means set " \ @@ -3286,12 +3355,23 @@ public: "Maximum size in bytes of objects allocated in DefNew " \ "generation; zero means no maximum") \ \ - product(size_t, TLABSize, 0, \ - "Starting TLAB size (in bytes); zero means set ergonomically") \ - \ product(size_t, MinTLABSize, 2*K, \ "Minimum allowed TLAB size (in bytes)") \ range(1, max_uintx) \ + constraint(MinTLABSizeConstraintFunc,AfterMemoryInit) \ + \ + product(size_t, TLABSize, 0, \ + "Starting TLAB size (in bytes); zero means set ergonomically") \ + constraint(TLABSizeConstraintFunc,AfterMemoryInit) \ + \ + product(size_t, YoungPLABSize, 4096, \ + "Size of young gen promotion LAB's (in HeapWords)") \ + constraint(YoungPLABSizeConstraintFunc,AfterMemoryInit) \ + \ + product(size_t, OldPLABSize, 1024, \ + "Size of old gen promotion LAB's (in HeapWords), or Number " \ + "of blocks to attempt to claim when refilling CMS LAB's") \ + constraint(OldPLABSizeConstraintFunc,AfterMemoryInit) \ \ product(uintx, TLABAllocationWeight, 35, \ "Allocation averaging weight") \ @@ -3312,9 +3392,12 @@ public: \ product(uintx, SurvivorRatio, 8, \ "Ratio of eden/survivor space size") \ + range(1, max_uintx-2) \ + constraint(SurvivorRatioConstraintFunc,AfterMemoryInit) \ \ product(uintx, NewRatio, 2, \ "Ratio of old/new generation sizes") \ + range(0, max_uintx-1) \ \ product_pd(size_t, NewSizeThreadIncrease, \ "Additional size added to desired new generation size per " \ @@ -3322,9 +3405,11 @@ public: \ product_pd(size_t, MetaspaceSize, \ "Initial size of Metaspaces (in bytes)") \ + constraint(MetaspaceSizeConstraintFunc,AfterErgo) \ \ product(size_t, MaxMetaspaceSize, max_uintx, \ "Maximum size of Metaspaces (in bytes)") \ + constraint(MaxMetaspaceSizeConstraintFunc,AfterErgo) \ \ product(size_t, CompressedClassSpaceSize, 1*G, \ "Maximum size of class area in Metaspace when compressed " \ @@ -3347,6 +3432,8 @@ public: \ product(intx, SoftRefLRUPolicyMSPerMB, 1000, \ "Number of milliseconds per MB of free space in the heap") \ + range(0, max_intx) \ + constraint(SoftRefLRUPolicyMSPerMBConstraintFunc,AfterMemoryInit) \ \ product(size_t, MinHeapDeltaBytes, ScaleForWordSize(128*K), \ "The minimum change in heap space due to GC (in bytes)") \ @@ -3378,6 +3465,7 @@ public: \ diagnostic(intx, VerifyGCLevel, 0, \ "Generation level at which to start +VerifyBefore/AfterGC") \ + range(0, 1) \ \ product(uintx, MaxTenuringThreshold, 15, \ "Maximum value for tenuring threshold") \ @@ -3430,12 +3518,15 @@ public: product(intx, DeferThrSuspendLoopCount, 4000, \ "(Unstable) Number of times to iterate in safepoint loop " \ "before blocking VM threads ") \ + range(-1, max_jint-1) \ \ product(intx, DeferPollingPageLoopCount, -1, \ "(Unsafe,Unstable) Number of iterations in safepoint loop " \ "before changing safepoint polling page to RO ") \ + range(-1, max_jint-1) \ \ product(intx, SafepointSpinBeforeYield, 2000, "(Unstable)") \ + range(0, max_intx) \ \ product(bool, PSChunkLargeArrays, true, \ "Process large arrays in chunks") \ @@ -3447,66 +3538,80 @@ public: /* stack parameters */ \ product_pd(intx, StackYellowPages, \ "Number of yellow zone (recoverable overflows) pages") \ - range(1, max_intx) \ + range(MIN_STACK_YELLOW_PAGES, (DEFAULT_STACK_YELLOW_PAGES+5)) \ \ product_pd(intx, StackRedPages, \ "Number of red zone (unrecoverable overflows) pages") \ - range(1, max_intx) \ + range(MIN_STACK_RED_PAGES, (DEFAULT_STACK_RED_PAGES+2)) \ \ /* greater stack shadow pages can't generate instruction to bang stack */ \ product_pd(intx, StackShadowPages, \ "Number of shadow zone (for overflow checking) pages " \ "this should exceed the depth of the VM and native call stack") \ - range(1, 50) \ + range(MIN_STACK_SHADOW_PAGES, (DEFAULT_STACK_SHADOW_PAGES+30)) \ \ product_pd(intx, ThreadStackSize, \ "Thread Stack Size (in Kbytes)") \ + range(0, max_intx-os::vm_page_size()) \ \ product_pd(intx, VMThreadStackSize, \ "Non-Java Thread Stack Size (in Kbytes)") \ + range(0, max_intx/(1 * K)) \ \ product_pd(intx, CompilerThreadStackSize, \ "Compiler Thread Stack Size (in Kbytes)") \ + range(0, max_intx) \ \ develop_pd(size_t, JVMInvokeMethodSlack, \ "Stack space (bytes) required for JVM_InvokeMethod to complete") \ \ /* code cache parameters */ \ /* ppc64/tiered compilation has large code-entry alignment. */ \ - develop(uintx, CodeCacheSegmentSize, 64 PPC64_ONLY(+64) NOT_PPC64(TIERED_ONLY(+64)),\ + develop(uintx, CodeCacheSegmentSize, \ + 64 PPC64_ONLY(+64) NOT_PPC64(TIERED_ONLY(+64)), \ "Code cache segment size (in bytes) - smallest unit of " \ "allocation") \ range(1, 1024) \ + constraint(CodeCacheSegmentSizeConstraintFunc, AfterErgo) \ \ develop_pd(intx, CodeEntryAlignment, \ "Code entry alignment for generated code (in bytes)") \ + constraint(CodeEntryAlignmentConstraintFunc, AfterErgo) \ \ product_pd(intx, OptoLoopAlignment, \ "Align inner loops to zero relative to this modulus") \ + constraint(OptoLoopAlignmentConstraintFunc, AfterErgo) \ \ product_pd(uintx, InitialCodeCacheSize, \ "Initial code cache size (in bytes)") \ + range(0, max_uintx) \ \ develop_pd(uintx, CodeCacheMinimumUseSpace, \ "Minimum code cache size (in bytes) required to start VM.") \ + range(0, max_uintx) \ \ product(bool, SegmentedCodeCache, false, \ "Use a segmented code cache") \ \ product_pd(uintx, ReservedCodeCacheSize, \ "Reserved code cache size (in bytes) - maximum code cache size") \ + range(0, max_uintx) \ \ product_pd(uintx, NonProfiledCodeHeapSize, \ "Size of code heap with non-profiled methods (in bytes)") \ + range(0, max_uintx) \ \ product_pd(uintx, ProfiledCodeHeapSize, \ "Size of code heap with profiled methods (in bytes)") \ + range(0, max_uintx) \ \ product_pd(uintx, NonNMethodCodeHeapSize, \ "Size of code heap with non-nmethods (in bytes)") \ + range(0, max_uintx) \ \ product_pd(uintx, CodeCacheExpansionSize, \ "Code cache expansion size (in bytes)") \ + range(0, max_uintx) \ \ develop_pd(uintx, CodeCacheMinBlockLength, \ "Minimum number of segments in a code cache block") \ @@ -3636,10 +3741,12 @@ public: product(intx, CompilerThreadPriority, -1, \ "The native priority at which compiler threads should run " \ "(-1 means no change)") \ + constraint(CompilerThreadPriorityConstraintFunc, AfterErgo) \ \ product(intx, VMThreadPriority, -1, \ "The native priority at which the VM thread should run " \ "(-1 means no change)") \ + range(-1, 127) \ \ product(bool, CompilerThreadHintNoPreempt, true, \ "(Solaris only) Give compiler threads an extra quanta") \ @@ -3649,33 +3756,43 @@ public: \ product(intx, JavaPriority1_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ + range(-1, 127) \ \ product(intx, JavaPriority2_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ + range(-1, 127) \ \ product(intx, JavaPriority3_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ + range(-1, 127) \ \ product(intx, JavaPriority4_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ + range(-1, 127) \ \ product(intx, JavaPriority5_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ + range(-1, 127) \ \ product(intx, JavaPriority6_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ + range(-1, 127) \ \ product(intx, JavaPriority7_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ + range(-1, 127) \ \ product(intx, JavaPriority8_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ + range(-1, 127) \ \ product(intx, JavaPriority9_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ + range(-1, 127) \ \ product(intx, JavaPriority10_To_OSPriority,-1, \ "Map Java priorities to OS priorities") \ + range(-1, 127) \ \ experimental(bool, UseCriticalJavaThreadPriority, false, \ "Java thread priority 10 maps to critical scheduling priority") \ @@ -3708,6 +3825,7 @@ public: /* recompilation */ \ product_pd(intx, CompileThreshold, \ "number of interpreted method invocations before (re-)compiling") \ + constraint(CompileThresholdConstraintFunc, AfterErgo) \ \ product(double, CompileThresholdScaling, 1.0, \ "Factor to control when first compilation happens " \ @@ -3721,90 +3839,115 @@ public: "If a value is specified for a method, compilation thresholds " \ "for that method are scaled by both the value of the global flag "\ "and the value of the per-method flag.") \ + range(0.0, DBL_MAX) \ \ product(intx, Tier0InvokeNotifyFreqLog, 7, \ "Interpreter (tier 0) invocation notification frequency") \ + range(0, 30) \ \ product(intx, Tier2InvokeNotifyFreqLog, 11, \ "C1 without MDO (tier 2) invocation notification frequency") \ + range(0, 30) \ \ product(intx, Tier3InvokeNotifyFreqLog, 10, \ "C1 with MDO profiling (tier 3) invocation notification " \ "frequency") \ + range(0, 30) \ \ product(intx, Tier23InlineeNotifyFreqLog, 20, \ "Inlinee invocation (tiers 2 and 3) notification frequency") \ + range(0, 30) \ \ product(intx, Tier0BackedgeNotifyFreqLog, 10, \ "Interpreter (tier 0) invocation notification frequency") \ + range(0, 30) \ \ product(intx, Tier2BackedgeNotifyFreqLog, 14, \ "C1 without MDO (tier 2) invocation notification frequency") \ + range(0, 30) \ \ product(intx, Tier3BackedgeNotifyFreqLog, 13, \ "C1 with MDO profiling (tier 3) invocation notification " \ "frequency") \ + range(0, 30) \ \ product(intx, Tier2CompileThreshold, 0, \ "threshold at which tier 2 compilation is invoked") \ + range(0, max_jint) \ \ product(intx, Tier2BackEdgeThreshold, 0, \ "Back edge threshold at which tier 2 compilation is invoked") \ + range(0, max_jint) \ \ product(intx, Tier3InvocationThreshold, 200, \ "Compile if number of method invocations crosses this " \ "threshold") \ + range(0, max_jint) \ \ product(intx, Tier3MinInvocationThreshold, 100, \ "Minimum invocation to compile at tier 3") \ + range(0, max_jint) \ \ product(intx, Tier3CompileThreshold, 2000, \ "Threshold at which tier 3 compilation is invoked (invocation " \ - "minimum must be satisfied") \ + "minimum must be satisfied)") \ + range(0, max_jint) \ \ product(intx, Tier3BackEdgeThreshold, 60000, \ "Back edge threshold at which tier 3 OSR compilation is invoked") \ + range(0, max_jint) \ \ product(intx, Tier4InvocationThreshold, 5000, \ "Compile if number of method invocations crosses this " \ "threshold") \ + range(0, max_jint) \ \ product(intx, Tier4MinInvocationThreshold, 600, \ "Minimum invocation to compile at tier 4") \ + range(0, max_jint) \ \ product(intx, Tier4CompileThreshold, 15000, \ "Threshold at which tier 4 compilation is invoked (invocation " \ "minimum must be satisfied") \ + range(0, max_jint) \ \ product(intx, Tier4BackEdgeThreshold, 40000, \ "Back edge threshold at which tier 4 OSR compilation is invoked") \ + range(0, max_jint) \ \ product(intx, Tier3DelayOn, 5, \ "If C2 queue size grows over this amount per compiler thread " \ "stop compiling at tier 3 and start compiling at tier 2") \ + range(0, max_jint) \ \ product(intx, Tier3DelayOff, 2, \ "If C2 queue size is less than this amount per compiler thread " \ "allow methods compiled at tier 2 transition to tier 3") \ + range(0, max_jint) \ \ product(intx, Tier3LoadFeedback, 5, \ "Tier 3 thresholds will increase twofold when C1 queue size " \ "reaches this amount per compiler thread") \ + range(0, max_jint) \ \ product(intx, Tier4LoadFeedback, 3, \ "Tier 4 thresholds will increase twofold when C2 queue size " \ "reaches this amount per compiler thread") \ + range(0, max_jint) \ \ product(intx, TieredCompileTaskTimeout, 50, \ "Kill compile task if method was not used within " \ "given timeout in milliseconds") \ + range(0, max_intx) \ \ product(intx, TieredStopAtLevel, 4, \ "Stop at given compilation level") \ + range(0, 4) \ \ product(intx, Tier0ProfilingStartPercentage, 200, \ "Start profiling in interpreter if the counters exceed tier 3 " \ "thresholds by the specified percentage") \ + range(0, max_jint) \ \ product(uintx, IncreaseFirstTierCompileThresholdAt, 50, \ "Increase the compile threshold for C1 compilation if the code " \ @@ -3813,9 +3956,11 @@ public: \ product(intx, TieredRateUpdateMinTime, 1, \ "Minimum rate sampling interval (in milliseconds)") \ + range(0, max_intx) \ \ product(intx, TieredRateUpdateMaxTime, 25, \ "Maximum rate sampling interval (in milliseconds)") \ + range(0, max_intx) \ \ product_pd(bool, TieredCompilation, \ "Enable tiered compilation") \ @@ -3826,6 +3971,7 @@ public: product_pd(intx, OnStackReplacePercentage, \ "NON_TIERED number of method invocations/branches (expressed as " \ "% of CompileThreshold) before (re-)compiling OSR code") \ + constraint(OnStackReplacePercentageConstraintFunc, AfterErgo) \ \ product(intx, InterpreterProfilePercentage, 33, \ "NON_TIERED number of method invocations/branches (expressed as " \ @@ -3856,6 +4002,7 @@ public: \ product(size_t, MaxDirectMemorySize, 0, \ "Maximum total size of NIO direct-buffer allocations") \ + range(0, (size_t)SIZE_MAX) \ \ /* Flags used for temporary code during development */ \ \ @@ -3884,6 +4031,8 @@ public: \ product(intx, PerfDataSamplingInterval, 50, \ "Data sampling interval (in milliseconds)") \ + range(PeriodicTask::min_interval, max_jint) \ + constraint(PerfDataSamplingIntervalFunc, AfterErgo) \ \ develop(bool, PerfTraceDataCreation, false, \ "Trace creation of Performance Data Entries") \ @@ -3897,9 +4046,11 @@ public: product(intx, PerfDataMemorySize, 64*K, \ "Size of performance data memory region. Will be rounded " \ "up to a multiple of the native os page size.") \ + range(128, 32*64*K) \ \ product(intx, PerfMaxStringConstLength, 1024, \ "Maximum PerfStringConstant string length before truncation") \ + range(32, 32*K) \ \ product(bool, PerfAllowAtExitRegistration, false, \ "Allow registration of atexit() methods") \ @@ -3959,10 +4110,10 @@ public: "If PrintSharedArchiveAndExit is true, also print the shared " \ "dictionary") \ \ - product(size_t, SharedReadWriteSize, NOT_LP64(12*M) LP64_ONLY(16*M), \ + product(size_t, SharedReadWriteSize, NOT_LP64(12*M) LP64_ONLY(16*M), \ "Size of read-write space for metadata (in bytes)") \ \ - product(size_t, SharedReadOnlySize, NOT_LP64(12*M) LP64_ONLY(16*M), \ + product(size_t, SharedReadOnlySize, NOT_LP64(12*M) LP64_ONLY(16*M), \ "Size of read-only space for metadata (in bytes)") \ \ product(uintx, SharedMiscDataSize, NOT_LP64(2*M) LP64_ONLY(4*M), \ @@ -3977,6 +4128,7 @@ public: \ product(uintx, SharedSymbolTableBucketSize, 4, \ "Average number of symbols per bucket in shared table") \ + range(2, 246) \ \ diagnostic(bool, IgnoreUnverifiableClassesDuringDump, false, \ "Do not quit -Xshare:dump even if we encounter unverifiable " \ diff --git a/hotspot/src/share/vm/runtime/globals_extension.hpp b/hotspot/src/share/vm/runtime/globals_extension.hpp index 98773e81099..55247dcad22 100644 --- a/hotspot/src/share/vm/runtime/globals_extension.hpp +++ b/hotspot/src/share/vm/runtime/globals_extension.hpp @@ -44,6 +44,14 @@ #define RUNTIME_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), #define RUNTIME_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define JVMCI_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define JVMCI_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), + #ifdef _LP64 #define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #else @@ -105,6 +113,17 @@ typedef enum { IGNORE_RANGE, \ IGNORE_CONSTRAINT) #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_MEMBER, \ + JVMCI_PD_DEVELOP_FLAG_MEMBER, \ + JVMCI_PRODUCT_FLAG_MEMBER, \ + JVMCI_PD_PRODUCT_FLAG_MEMBER, \ + JVMCI_DIAGNOSTIC_FLAG_MEMBER, \ + JVMCI_EXPERIMENTAL_FLAG_MEMBER, \ + JVMCI_NOTPRODUCT_FLAG_MEMBER, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) +#endif // INCLUDE_JVMCI #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, \ C1_PD_DEVELOP_FLAG_MEMBER, \ @@ -151,6 +170,14 @@ typedef enum { #define RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), + #define C1_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), @@ -212,6 +239,17 @@ typedef enum { IGNORE_RANGE, IGNORE_CONSTRAINT) #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_MEMBER_WITH_TYPE, + JVMCI_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE, + JVMCI_PRODUCT_FLAG_MEMBER_WITH_TYPE, + JVMCI_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE, + JVMCI_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE, + JVMCI_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE, + JVMCI_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE, + IGNORE_RANGE, + IGNORE_CONSTRAINT) +#endif // INCLUDE_JVMCI #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER_WITH_TYPE, C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE, diff --git a/hotspot/src/share/vm/runtime/handles.cpp b/hotspot/src/share/vm/runtime/handles.cpp index a9b1dcad326..08e04e41470 100644 --- a/hotspot/src/share/vm/runtime/handles.cpp +++ b/hotspot/src/share/vm/runtime/handles.cpp @@ -30,13 +30,11 @@ #include "runtime/handles.inline.hpp" #include "runtime/thread.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef ASSERT 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(obj->is_oop(), err_msg("not an oop: " INTPTR_FORMAT, (intptr_t*) obj)); + assert(obj->is_oop(), "not an oop: " INTPTR_FORMAT, p2i(obj)); return real_allocate_handle(obj); } @@ -85,10 +83,9 @@ void HandleArea::oops_do(OopClosure* f) { // The thread local handle areas should not get very large if (TraceHandleAllocation && (size_t)handles_visited > TotalHandleAllocationLimit) { #ifdef ASSERT - warning("%d: Visited in HandleMark : %d", - _nof_handlemarks, handles_visited); + warning("%d: Visited in HandleMark : " SIZE_FORMAT, _nof_handlemarks, handles_visited); #else - warning("Visited in HandleMark : %d", handles_visited); + warning("Visited in HandleMark : " SIZE_FORMAT, handles_visited); #endif } if (_prev != NULL) _prev->oops_do(f); @@ -137,10 +134,10 @@ HandleMark::~HandleMark() { handles /= sizeof(void *); // Adjust for size of a handle if (handles > HandleAllocationLimit) { // Note: _nof_handlemarks is only set in debug mode - warning("%d: Allocated in HandleMark : %d", _nof_handlemarks, handles); + warning("%d: Allocated in HandleMark : " SIZE_FORMAT, _nof_handlemarks, handles); } - tty->print_cr("Handles %d", handles); + tty->print_cr("Handles " SIZE_FORMAT, handles); } #endif diff --git a/hotspot/src/share/vm/runtime/interfaceSupport.cpp b/hotspot/src/share/vm/runtime/interfaceSupport.cpp index 337fb594cb2..9f19a5f18ca 100644 --- a/hotspot/src/share/vm/runtime/interfaceSupport.cpp +++ b/hotspot/src/share/vm/runtime/interfaceSupport.cpp @@ -36,8 +36,6 @@ #include "runtime/vframe.hpp" #include "utilities/preserveException.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Implementation of InterfaceSupport #ifdef ASSERT @@ -73,7 +71,7 @@ RuntimeHistogramElement::RuntimeHistogramElement(const char* elementName) { } void InterfaceSupport::trace(const char* result_type, const char* header) { - tty->print_cr("%6d %s", _number_of_calls, header); + tty->print_cr("%6ld %s", _number_of_calls, header); } void InterfaceSupport::gc_alot() { @@ -109,8 +107,7 @@ void InterfaceSupport::gc_alot() { if (FullGCALotInterval > 1) { _fullgc_alot_counter = 1+(long)((double)FullGCALotInterval*os::random()/(max_jint+1.0)); if (PrintGCDetails && Verbose) { - tty->print_cr("Full gc no: %u\tInterval: %d", invocations, - _fullgc_alot_counter); + tty->print_cr("Full gc no: %u\tInterval: %ld", invocations, _fullgc_alot_counter); } } else { _fullgc_alot_counter = 1; @@ -130,8 +127,7 @@ void InterfaceSupport::gc_alot() { if (ScavengeALotInterval > 1) { _scavenge_alot_counter = 1+(long)((double)ScavengeALotInterval*os::random()/(max_jint+1.0)); if (PrintGCDetails && Verbose) { - tty->print_cr("Scavenge no: %u\tInterval: %d", invocations, - _scavenge_alot_counter); + tty->print_cr("Scavenge no: %u\tInterval: %ld", invocations, _scavenge_alot_counter); } } else { _scavenge_alot_counter = 1; @@ -167,25 +163,6 @@ void InterfaceSupport::walk_stack() { walk_stack_from(thread->last_java_vframe(®_map)); } - -# ifdef ENABLE_ZAP_DEAD_LOCALS - -static int zap_traversals = 0; - -void InterfaceSupport::zap_dead_locals_old() { - JavaThread* thread = JavaThread::current(); - if (zap_traversals == -1) // edit constant for debugging - warning("I am here"); - int zap_frame_count = 0; // count frames to help debugging - for (StackFrameStream sfs(thread); !sfs.is_done(); sfs.next()) { - sfs.current()->zap_dead_locals(thread, sfs.register_map()); - ++zap_frame_count; - } - ++zap_traversals; -} - -# endif - // invocation counter for InterfaceSupport::deoptimizeAll/zombieAll functions int deoptimizeAllCounter = 0; int zombieAllCounter = 0; diff --git a/hotspot/src/share/vm/runtime/interfaceSupport.hpp b/hotspot/src/share/vm/runtime/interfaceSupport.hpp index 590b772af36..206d101e945 100644 --- a/hotspot/src/share/vm/runtime/interfaceSupport.hpp +++ b/hotspot/src/share/vm/runtime/interfaceSupport.hpp @@ -84,10 +84,6 @@ class InterfaceSupport: AllStatic { static void walk_stack_from(vframe* start_vf); static void walk_stack(); -# ifdef ENABLE_ZAP_DEAD_LOCALS - static void zap_dead_locals_old(); -# endif - static void zombieAll(); static void unlinkSymbols(); static void deoptimizeAll(); @@ -357,11 +353,6 @@ class VMEntryWrapper { if (WalkStackALot) { InterfaceSupport::walk_stack(); } -#ifdef ENABLE_ZAP_DEAD_LOCALS - if (ZapDeadLocalsOld) { - InterfaceSupport::zap_dead_locals_old(); - } -#endif #ifdef COMPILER2 // This option is not used by Compiler 1 if (StressDerivedPointers) { diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 43f61f7dde6..d1d3d34adf7 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -31,6 +31,10 @@ #include "compiler/compilerOracle.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "interpreter/bytecodeHistogram.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif #include "memory/oopFactory.hpp" #include "memory/universe.hpp" #include "oops/constantPool.hpp" @@ -80,8 +84,6 @@ #include "opto/runtime.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - GrowableArray* collected_profiled_methods; int compare_methods(Method** a, Method** b) { @@ -159,7 +161,7 @@ void print_method_invocation_histogram() { collected_invoked_methods->sort(&compare_methods); // tty->cr(); - tty->print_cr("Histogram Over MethodOop Invocation Counters (cutoff = %d):", MethodHistogramCutoff); + tty->print_cr("Histogram Over MethodOop Invocation Counters (cutoff = " INTX_FORMAT "):", MethodHistogramCutoff); tty->cr(); tty->print_cr("____Count_(I+C)____Method________________________Module_________________"); unsigned total = 0, int_total = 0, comp_total = 0, static_total = 0, final_total = 0, @@ -236,7 +238,6 @@ void print_statistics() { Runtime1::print_statistics(); Deoptimization::print_statistics(); SharedRuntime::print_statistics(); - nmethod::print_statistics(); } #endif /* COMPILER1 */ @@ -246,7 +247,6 @@ void print_statistics() { Compile::print_statistics(); #ifndef COMPILER1 Deoptimization::print_statistics(); - nmethod::print_statistics(); SharedRuntime::print_statistics(); #endif //COMPILER1 os::print_statistics(); @@ -264,7 +264,21 @@ void print_statistics() { IndexSet::print_statistics(); } #endif // ASSERT -#endif // COMPILER2 +#else +#ifdef INCLUDE_JVMCI +#ifndef COMPILER1 + if ((TraceDeoptimization || LogVMOutput || LogCompilation) && UseCompiler) { + FlagSetting fs(DisplayVMOutput, DisplayVMOutput && TraceDeoptimization); + Deoptimization::print_statistics(); + SharedRuntime::print_statistics(); + } +#endif +#endif +#endif + + if (PrintNMethodStatistics) { + nmethod::print_statistics(); + } if (CountCompiledCalls) { print_method_invocation_histogram(); } @@ -331,14 +345,6 @@ void print_statistics() { BiasedLocking::print_counters(); } -#ifdef ENABLE_ZAP_DEAD_LOCALS -#ifdef COMPILER2 - if (ZapDeadCompiledLocals) { - tty->print_cr("Compile::CompiledZap_count = %d", Compile::CompiledZap_count); - tty->print_cr("OptoRuntime::ZapDeadCompiledLocals_count = %d", OptoRuntime::ZapDeadCompiledLocals_count); - } -#endif // COMPILER2 -#endif // ENABLE_ZAP_DEAD_LOCALS // Native memory tracking data if (PrintNMTStatistics) { MemTracker::final_report(tty); @@ -417,6 +423,10 @@ void before_exit(JavaThread * thread) { } } +#if INCLUDE_JVMCI + JVMCIRuntime::shutdown(); +#endif + // Hang forever on exit if we're reporting an error. if (ShowMessageBoxOnError && is_error_reported()) { os::infinite_sleep(); diff --git a/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 9d4eccd8d69..c94e9d24f6a 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -41,6 +41,10 @@ #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif // ----------------------------------------------------- // Implementation of JavaCallWrapper @@ -51,7 +55,7 @@ JavaCallWrapper::JavaCallWrapper(methodHandle callee_method, Handle receiver, Ja guarantee(thread->is_Java_thread(), "crucial check - the VM thread cannot and must not escape to Java code"); assert(!thread->owns_locks(), "must release all locks when leaving VM"); - guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler"); + guarantee(thread->can_call_java(), "cannot make java calls from the native compiler"); _result = result; // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub, @@ -309,19 +313,27 @@ void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArgument CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();) - // Verify the arguments +#if INCLUDE_JVMCI + // Gets the nmethod (if any) that should be called instead of normal target + nmethod* alternative_target = args->alternative_target(); + if (alternative_target == NULL) { +#endif +// Verify the arguments if (CheckJNICalls) { args->verify(method, result->get_type(), thread); } else debug_only(args->verify(method, result->get_type(), thread)); +#if INCLUDE_JVMCI + } +#else // Ignore call if method is empty if (method->is_empty_method()) { assert(result->get_type() == T_VOID, "an empty method must return a void value"); return; } - +#endif #ifdef ASSERT { InstanceKlass* holder = method->method_holder(); @@ -333,7 +345,7 @@ void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArgument #endif - assert(!thread->is_Compiler_thread(), "cannot compile from the compiler"); + assert(thread->can_call_java(), "cannot compile from the native compiler"); if (CompilationPolicy::must_be_compiled(method)) { CompileBroker::compile_method(method, InvocationEntryBci, CompilationPolicy::policy()->initial_compile_level(), @@ -377,6 +389,17 @@ void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArgument os::bang_stack_shadow_pages(); } +#if INCLUDE_JVMCI + if (alternative_target != NULL) { + if (alternative_target->is_alive()) { + thread->set_jvmci_alternate_call_target(alternative_target->verified_entry_point()); + entry_point = method->adapter()->get_i2c_entry(); + } else { + THROW(vmSymbols::jdk_vm_ci_code_InvalidInstalledCodeException()); + } + } +#endif + // do call { JavaCallWrapper link(method, receiver, result, CHECK); { HandleMark hm(thread); // HandleMark used by HandleMarkCleaner diff --git a/hotspot/src/share/vm/runtime/javaCalls.hpp b/hotspot/src/share/vm/runtime/javaCalls.hpp index 9ab755aca2e..9ac2c9a5ea4 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.hpp +++ b/hotspot/src/share/vm/runtime/javaCalls.hpp @@ -103,6 +103,7 @@ class JavaCallArguments : public StackObj { int _size; int _max_size; bool _start_at_zero; // Support late setting of receiver + JVMCI_ONLY(nmethod* _alternative_target;) // Nmethod that should be called instead of normal target void initialize() { // Starts at first element to support set_receiver. @@ -112,6 +113,7 @@ class JavaCallArguments : public StackObj { _max_size = _default_size; _size = 0; _start_at_zero = false; + JVMCI_ONLY(_alternative_target = NULL;) } public: @@ -133,11 +135,22 @@ class JavaCallArguments : public StackObj { _max_size = max_size; _size = 0; _start_at_zero = false; + JVMCI_ONLY(_alternative_target = NULL;) } else { initialize(); } } +#if INCLUDE_JVMCI + void set_alternative_target(nmethod* target) { + _alternative_target = target; + } + + nmethod* alternative_target() { + return _alternative_target; + } +#endif + inline void push_oop(Handle h) { _is_oop[_size] = true; JNITypes::put_obj((oop)h.raw_value(), _value, _size); } diff --git a/hotspot/src/share/vm/runtime/jniHandles.cpp b/hotspot/src/share/vm/runtime/jniHandles.cpp index 9ce7ce8ae44..a19283eb432 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.cpp +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp @@ -30,8 +30,6 @@ #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - JNIHandleBlock* JNIHandles::_global_handles = NULL; JNIHandleBlock* JNIHandles::_weak_global_handles = NULL; oop JNIHandles::_deleted_handle = NULL; @@ -281,7 +279,7 @@ JNIHandleBlock* JNIHandleBlock::allocate_block(Thread* thread) { _blocks_allocated++; if (TraceJNIHandleAllocation) { tty->print_cr("JNIHandleBlock " INTPTR_FORMAT " allocated (%d total blocks)", - block, _blocks_allocated); + p2i(block), _blocks_allocated); } if (ZapJNIHandleArea) block->zap(); #ifndef PRODUCT @@ -396,7 +394,7 @@ void JNIHandleBlock::weak_oops_do(BoolObjectClosure* is_alive, } else { // The weakly referenced object is not alive, clear the reference by storing NULL if (TraceReferenceGC) { - tty->print_cr("Clearing JNI weak reference (" INTPTR_FORMAT ")", root); + tty->print_cr("Clearing JNI weak reference (" INTPTR_FORMAT ")", p2i(root)); } *root = NULL; } @@ -504,7 +502,7 @@ void JNIHandleBlock::rebuild_free_list() { } if (TraceJNIHandleAllocation) { tty->print_cr("Rebuild free list JNIHandleBlock " INTPTR_FORMAT " blocks=%d used=%d free=%d add=%d", - this, blocks, total-free, free, _allocate_before_rebuild); + p2i(this), blocks, total-free, free, _allocate_before_rebuild); } } diff --git a/hotspot/src/share/vm/runtime/memprofiler.cpp b/hotspot/src/share/vm/runtime/memprofiler.cpp index aeffd06845b..6e33d378457 100644 --- a/hotspot/src/share/vm/runtime/memprofiler.cpp +++ b/hotspot/src/share/vm/runtime/memprofiler.cpp @@ -75,7 +75,7 @@ void MemProfiler::engage() { // Create log file _log_fp = fopen(log_name , "w+"); if (_log_fp == NULL) { - fatal(err_msg("MemProfiler: Cannot create log file: %s", log_name)); + fatal("MemProfiler: Cannot create log file: %s", log_name); } fprintf(_log_fp, "MemProfiler: sizes are in Kb, time is in seconds since startup\n\n"); fprintf(_log_fp, " time, #thr, #cls, heap, heap, perm, perm, code, hndls, rescs, oopmp\n"); diff --git a/hotspot/src/share/vm/runtime/mutex.cpp b/hotspot/src/share/vm/runtime/mutex.cpp index 3879e82a4ae..954ad8e330e 100644 --- a/hotspot/src/share/vm/runtime/mutex.cpp +++ b/hotspot/src/share/vm/runtime/mutex.cpp @@ -42,8 +42,6 @@ # include "mutex_bsd.inline.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o // // Native Monitor-Mutex locking - theory of operations @@ -897,8 +895,7 @@ int Monitor::IWait(Thread * Self, jlong timo) { void Monitor::lock(Thread * Self) { // Ensure that the Monitor requires/allows safepoint checks. assert(_safepoint_check_required != Monitor::_safepoint_check_never, - err_msg("This lock should never have a safepoint check: %s", - name())); + "This lock should never have a safepoint check: %s", name()); #ifdef CHECK_UNHANDLED_OOPS // Clear unhandled oops so we get a crash right away. Only clear for non-vm @@ -960,8 +957,7 @@ void Monitor::lock() { void Monitor::lock_without_safepoint_check(Thread * Self) { // Ensure that the Monitor does not require or allow safepoint checks. assert(_safepoint_check_required != Monitor::_safepoint_check_always, - err_msg("This lock should always have a safepoint check: %s", - name())); + "This lock should always have a safepoint check: %s", name()); assert(_owner != Self, "invariant"); ILock(Self); assert(_owner == NULL, "invariant"); @@ -1093,9 +1089,9 @@ bool Monitor::wait(bool no_safepoint_check, long timeout, bool as_suspend_equivalent) { // Make sure safepoint checking is used properly. assert(!(_safepoint_check_required == Monitor::_safepoint_check_never && no_safepoint_check == false), - err_msg("This lock should never have a safepoint check: %s", name())); + "This lock should never have a safepoint check: %s", name()); assert(!(_safepoint_check_required == Monitor::_safepoint_check_always && no_safepoint_check == true), - err_msg("This lock should always have a safepoint check: %s", name())); + "This lock should always have a safepoint check: %s", name()); Thread * const Self = Thread::current(); assert(_owner == Self, "invariant"); @@ -1214,9 +1210,9 @@ bool Monitor::owned_by_self() const { } void Monitor::print_on_error(outputStream* st) const { - st->print("[" PTR_FORMAT, this); + st->print("[" PTR_FORMAT, p2i(this)); st->print("] %s", _name); - st->print(" - owner thread: " PTR_FORMAT, _owner); + st->print(" - owner thread: " PTR_FORMAT, p2i(_owner)); } @@ -1227,7 +1223,8 @@ void Monitor::print_on_error(outputStream* st) const { #ifndef PRODUCT void Monitor::print_on(outputStream* st) const { - st->print_cr("Mutex: [0x%lx/0x%lx] %s - owner: 0x%lx", this, _LockWord.FullWord, _name, _owner); + st->print_cr("Mutex: [" PTR_FORMAT "/" PTR_FORMAT "] %s - owner: " PTR_FORMAT, + p2i(this), _LockWord.FullWord, _name, p2i(_owner)); } #endif @@ -1335,9 +1332,9 @@ void Monitor::set_owner_implementation(Thread *new_owner) { !(this == Safepoint_lock && contains(locks, Terminator_lock) && SafepointSynchronize::is_synchronizing())) { new_owner->print_owned_locks(); - fatal(err_msg("acquiring lock %s/%d out of order with lock %s/%d -- " - "possible deadlock", this->name(), this->rank(), - locks->name(), locks->rank())); + fatal("acquiring lock %s/%d out of order with lock %s/%d -- " + "possible deadlock", this->name(), this->rank(), + locks->name(), locks->rank()); } this->_next = new_owner->_owned_locks; @@ -1386,8 +1383,7 @@ void Monitor::check_prelock_state(Thread *thread) { || rank() == Mutex::special, "wrong thread state for using locks"); if (StrictSafepointChecks) { if (thread->is_VM_thread() && !allow_vm_block()) { - fatal(err_msg("VM thread using lock %s (not allowed to block on)", - name())); + fatal("VM thread using lock %s (not allowed to block on)", name()); } debug_only(if (rank() != Mutex::special) \ thread->check_for_valid_safepoint_state(false);) diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index f540eba4c49..cea2360025d 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -127,6 +127,7 @@ Monitor* GCTaskManager_lock = NULL; Mutex* Management_lock = NULL; Monitor* Service_lock = NULL; Monitor* PeriodicTask_lock = NULL; +Mutex* LogConfiguration_lock = NULL; #ifdef INCLUDE_TRACE Mutex* JfrStacktrace_lock = NULL; @@ -155,7 +156,7 @@ void assert_locked_or_safepoint(const Monitor * lock) { // see if invoker of VM operation owns it VM_Operation* op = VMThread::vm_operation(); if (op != NULL && op->calling_thread() == lock->owner()) return; - fatal(err_msg("must own lock %s", lock->name())); + fatal("must own lock %s", lock->name()); } // a stronger assertion than the above @@ -163,7 +164,7 @@ void assert_lock_strong(const Monitor * lock) { if (IgnoreLockingAssertions) return; assert(lock != NULL, "Need non-NULL lock"); if (lock->owned_by_self()) return; - fatal(err_msg("must own lock %s", lock->name())); + fatal("must own lock %s", lock->name()); } #endif @@ -282,6 +283,7 @@ void mutex_init() { if (WhiteBoxAPI) { def(Compilation_lock , Monitor, leaf, false, Monitor::_safepoint_check_never); } + def(LogConfiguration_lock , Mutex, nonleaf, false, Monitor::_safepoint_check_always); #ifdef INCLUDE_TRACE def(JfrMsg_lock , Monitor, leaf, true, Monitor::_safepoint_check_always); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index e2c1118aa25..715025b6c23 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -126,6 +126,7 @@ extern Mutex* MMUTracker_lock; // protects the MMU extern Mutex* Management_lock; // a lock used to serialize JVM management extern Monitor* Service_lock; // a lock used for service thread operation extern Monitor* PeriodicTask_lock; // protects the periodic task structure +extern Mutex* LogConfiguration_lock; // protects configuration of logging #ifdef INCLUDE_TRACE extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 068bcacdc12..32e4b0942fb 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -61,8 +61,6 @@ # include -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - OSThread* os::_starting_thread = NULL; address os::_polling_page = NULL; volatile int32_t* os::_mem_serialize_page = NULL; @@ -621,12 +619,12 @@ void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) { ptr = guarded.get_user_ptr(); #endif if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) { - tty->print_cr("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr); + tty->print_cr("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); breakpoint(); } debug_only(if (paranoid) verify_memory(ptr)); if (PrintMalloc && tty != NULL) { - tty->print_cr("os::malloc " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr); + tty->print_cr("os::malloc " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); } // we do not track guard memory @@ -658,7 +656,7 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCa return os::malloc(size, memflags, stack); } if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) { - tty->print_cr("os::realloc caught " PTR_FORMAT, memblock); + tty->print_cr("os::realloc caught " PTR_FORMAT, p2i(memblock)); breakpoint(); } // NMT support @@ -671,7 +669,7 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCa // always move the block void* ptr = os::malloc(size, memflags, stack); if (PrintMalloc && tty != NULL) { - tty->print_cr("os::realloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, memblock, ptr); + tty->print_cr("os::realloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, p2i(memblock), p2i(ptr)); } // Copy to new memory if malloc didn't fail if ( ptr != NULL ) { @@ -681,7 +679,7 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCa memcpy(ptr, memblock, MIN2(size, memblock_size)); if (paranoid) verify_memory(MemTracker::malloc_base(ptr)); if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) { - tty->print_cr("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr); + tty->print_cr("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); breakpoint(); } os::free(memblock); @@ -696,7 +694,7 @@ void os::free(void *memblock) { #ifdef ASSERT if (memblock == NULL) return; if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) { - if (tty != NULL) tty->print_cr("os::free caught " PTR_FORMAT, memblock); + if (tty != NULL) tty->print_cr("os::free caught " PTR_FORMAT, p2i(memblock)); breakpoint(); } void* membase = MemTracker::record_free(memblock); @@ -796,7 +794,7 @@ void os::print_hex_dump(outputStream* st, address start, address end, int unitsi } address p = start; - st->print(PTR_FORMAT ": ", start); + st->print(PTR_FORMAT ": ", p2i(start)); while (p < end) { switch (unitsize) { case 1: st->print("%02x", *(u1*)p); break; @@ -809,7 +807,7 @@ void os::print_hex_dump(outputStream* st, address start, address end, int unitsi if (cols >= cols_per_line && p < end) { cols = 0; st->cr(); - st->print(PTR_FORMAT ": ", p); + st->print(PTR_FORMAT ": ", p2i(p)); } else { st->print(" "); } @@ -856,9 +854,9 @@ void os::print_summary_info(outputStream* st, char* buf, size_t buflen) { size_t mem = physical_memory()/G; if (mem == 0) { // for low memory systems mem = physical_memory()/M; - st->print("%d cores, %dM, ", processor_count(), mem); + st->print("%d cores, " SIZE_FORMAT "M, ", processor_count(), mem); } else { - st->print("%d cores, %dG, ", processor_count(), mem); + st->print("%d cores, " SIZE_FORMAT "G, ", processor_count(), mem); } get_summary_os_info(buf, buflen); st->print_raw(buf); @@ -914,41 +912,40 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { // the interpreter is generated into a buffer blob InterpreterCodelet* i = Interpreter::codelet_containing(addr); if (i != NULL) { - st->print_cr(INTPTR_FORMAT " is at code_begin+%d in an Interpreter codelet", addr, (int)(addr - i->code_begin())); + st->print_cr(INTPTR_FORMAT " is at code_begin+%d in an Interpreter codelet", p2i(addr), (int)(addr - i->code_begin())); i->print_on(st); return; } if (Interpreter::contains(addr)) { st->print_cr(INTPTR_FORMAT " is pointing into interpreter code" - " (not bytecode specific)", addr); + " (not bytecode specific)", p2i(addr)); return; } // if (AdapterHandlerLibrary::contains(b)) { - st->print_cr(INTPTR_FORMAT " is at code_begin+%d in an AdapterHandler", addr, (int)(addr - b->code_begin())); + st->print_cr(INTPTR_FORMAT " is at code_begin+%d in an AdapterHandler", p2i(addr), (int)(addr - b->code_begin())); AdapterHandlerLibrary::print_handler_on(st, b); } // the stubroutines are generated into a buffer blob StubCodeDesc* d = StubCodeDesc::desc_for(addr); if (d != NULL) { - st->print_cr(INTPTR_FORMAT " is at begin+%d in a stub", addr, (int)(addr - d->begin())); + st->print_cr(INTPTR_FORMAT " is at begin+%d in a stub", p2i(addr), (int)(addr - d->begin())); d->print_on(st); st->cr(); return; } if (StubRoutines::contains(addr)) { - st->print_cr(INTPTR_FORMAT " is pointing to an (unnamed) " - "stub routine", addr); + st->print_cr(INTPTR_FORMAT " is pointing to an (unnamed) stub routine", p2i(addr)); return; } // the InlineCacheBuffer is using stubs generated into a buffer blob if (InlineCacheBuffer::contains(addr)) { - st->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", addr); + st->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", p2i(addr)); return; } VtableStub* v = VtableStubs::stub_containing(addr); if (v != NULL) { - st->print_cr(INTPTR_FORMAT " is at entry_point+%d in a vtable stub", addr, (int)(addr - v->entry_point())); + st->print_cr(INTPTR_FORMAT " is at entry_point+%d in a vtable stub", p2i(addr), (int)(addr - v->entry_point())); v->print_on(st); st->cr(); return; @@ -958,7 +955,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { if (nm != NULL) { ResourceMark rm; st->print(INTPTR_FORMAT " is at entry_point+%d in (nmethod*)" INTPTR_FORMAT, - addr, (int)(addr - nm->entry_point()), nm); + p2i(addr), (int)(addr - nm->entry_point()), p2i(nm)); if (verbose) { st->print(" for "); nm->method()->print_value_on(st); @@ -967,7 +964,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { nm->print_nmethod(verbose); return; } - st->print_cr(INTPTR_FORMAT " is at code_begin+%d in ", addr, (int)(addr - b->code_begin())); + st->print_cr(INTPTR_FORMAT " is at code_begin+%d in ", p2i(addr), (int)(addr - b->code_begin())); b->print_on(st); return; } @@ -985,9 +982,9 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { } if (print) { if (p == (HeapWord*) addr) { - st->print_cr(INTPTR_FORMAT " is an oop", addr); + st->print_cr(INTPTR_FORMAT " is an oop", p2i(addr)); } else { - st->print_cr(INTPTR_FORMAT " is pointing into object: " INTPTR_FORMAT, addr, p); + st->print_cr(INTPTR_FORMAT " is pointing into object: " INTPTR_FORMAT, p2i(addr), p2i(p)); } oop(p)->print_on(st); return; @@ -995,22 +992,22 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { } else { if (Universe::heap()->is_in_reserved(addr)) { st->print_cr(INTPTR_FORMAT " is an unallocated location " - "in the heap", addr); + "in the heap", p2i(addr)); return; } } if (JNIHandles::is_global_handle((jobject) addr)) { - st->print_cr(INTPTR_FORMAT " is a global jni handle", addr); + st->print_cr(INTPTR_FORMAT " is a global jni handle", p2i(addr)); return; } if (JNIHandles::is_weak_global_handle((jobject) addr)) { - st->print_cr(INTPTR_FORMAT " is a weak global jni handle", addr); + st->print_cr(INTPTR_FORMAT " is a weak global jni handle", p2i(addr)); return; } #ifndef PRODUCT // we don't keep the block list in product mode if (JNIHandleBlock::any_contains((jobject) addr)) { - st->print_cr(INTPTR_FORMAT " is a local jni handle", addr); + st->print_cr(INTPTR_FORMAT " is a local jni handle", p2i(addr)); return; } #endif @@ -1020,7 +1017,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { if (thread->privileged_stack_top() != NULL && thread->privileged_stack_top()->contains(addr)) { st->print_cr(INTPTR_FORMAT " is pointing into the privilege stack " - "for thread: " INTPTR_FORMAT, addr, thread); + "for thread: " INTPTR_FORMAT, p2i(addr), p2i(thread)); if (verbose) thread->print_on(st); return; } @@ -1029,7 +1026,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { if (verbose) { thread->print_on(st); } else { - st->print_cr(INTPTR_FORMAT " is a thread", addr); + st->print_cr(INTPTR_FORMAT " is a thread", p2i(addr)); } return; } @@ -1038,7 +1035,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { if (thread->stack_base() >= addr && addr > (thread->stack_base() - thread->stack_size())) { st->print_cr(INTPTR_FORMAT " is pointing into the stack for thread: " - INTPTR_FORMAT, addr, thread); + INTPTR_FORMAT, p2i(addr), p2i(thread)); if (verbose) thread->print_on(st); return; } @@ -1052,7 +1049,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { st->cr(); } else { // Use addr->print() from the debugger instead (not here) - st->print_cr(INTPTR_FORMAT " is pointing into metadata", addr); + st->print_cr(INTPTR_FORMAT " is pointing into metadata", p2i(addr)); } return; } @@ -1062,7 +1059,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { return; } - st->print_cr(INTPTR_FORMAT " is an unknown value", addr); + st->print_cr(INTPTR_FORMAT " is an unknown value", p2i(addr)); } // Looks like all platforms except IA64 can use the same function to check @@ -1461,7 +1458,7 @@ void os::trace_page_sizes(const char* str, const size_t region_min_size, " pg_sz=" SIZE_FORMAT " base=" PTR_FORMAT " size=" SIZE_FORMAT, str, region_min_size, region_max_size, - page_size, base, size); + page_size, p2i(base), size); } } #endif // #ifndef PRODUCT @@ -1679,7 +1676,7 @@ os::SuspendResume::State os::SuspendResume::switch_state(os::SuspendResume::Stat #ifndef PRODUCT -#define assert_eq(a,b) assert(a == b, err_msg(SIZE_FORMAT " != " SIZE_FORMAT, a, b)) +#define assert_eq(a,b) assert(a == b, SIZE_FORMAT " != " SIZE_FORMAT, a, b) class TestOS : AllStatic { static size_t small_page_size() { diff --git a/hotspot/src/share/vm/runtime/osThread.cpp b/hotspot/src/share/vm/runtime/osThread.cpp index 57bf1f524fd..37cf6362a4c 100644 --- a/hotspot/src/share/vm/runtime/osThread.cpp +++ b/hotspot/src/share/vm/runtime/osThread.cpp @@ -26,8 +26,6 @@ #include "oops/oop.inline.hpp" #include "runtime/osThread.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - OSThread::OSThread(OSThreadStartFunc start_proc, void* start_parm) { pd_initialize(); set_start_proc(start_proc); @@ -41,7 +39,7 @@ OSThread::~OSThread() { // Printing void OSThread::print_on(outputStream *st) const { - st->print("nid=0x%lx ", thread_id()); + st->print("nid=0x%x ", thread_id()); switch (_state) { case ALLOCATED: st->print("allocated "); break; case INITIALIZED: st->print("initialized "); break; diff --git a/hotspot/src/share/vm/runtime/perfData.cpp b/hotspot/src/share/vm/runtime/perfData.cpp index 847e52fb9ea..959bc7dd99b 100644 --- a/hotspot/src/share/vm/runtime/perfData.cpp +++ b/hotspot/src/share/vm/runtime/perfData.cpp @@ -34,8 +34,6 @@ #include "utilities/exceptions.hpp" #include "utilities/globalDefinitions.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - PerfDataList* PerfDataManager::_all = NULL; PerfDataList* PerfDataManager::_sampled = NULL; PerfDataList* PerfDataManager::_constants = NULL; @@ -170,14 +168,14 @@ void PerfData::create_entry(BasicType dtype, size_t dsize, size_t vlen) { if (PerfTraceDataCreation) { tty->print("name = %s, dtype = %d, variability = %d," - " units = %d, dsize = %d, vlen = %d," - " pad_length = %d, size = %d, on_c_heap = %s," + " units = %d, dsize = " SIZE_FORMAT ", vlen = " SIZE_FORMAT "," + " pad_length = " SIZE_FORMAT ", size = " SIZE_FORMAT ", on_c_heap = %s," " address = " INTPTR_FORMAT "," " data address = " INTPTR_FORMAT "\n", cname, dtype, variability(), units(), dsize, vlen, pad_length, size, is_on_c_heap() ? "TRUE":"FALSE", - psmp, valuep); + p2i(psmp), p2i(valuep)); } // record the start of the entry and the location of the data field. diff --git a/hotspot/src/share/vm/runtime/perfMemory.cpp b/hotspot/src/share/vm/runtime/perfMemory.cpp index d857ec57bf8..794f7beb947 100644 --- a/hotspot/src/share/vm/runtime/perfMemory.cpp +++ b/hotspot/src/share/vm/runtime/perfMemory.cpp @@ -36,8 +36,6 @@ #include "runtime/statSampler.hpp" #include "utilities/globalDefinitions.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Prefix of performance data file. const char PERFDATA_NAME[] = "hsperfdata"; @@ -96,7 +94,7 @@ void PerfMemory::initialize() { if (PerfTraceMemOps) { tty->print("PerfDataMemorySize = " SIZE_FORMAT "," - " os::vm_allocation_granularity = " SIZE_FORMAT "," + " os::vm_allocation_granularity = %d," " adjusted size = " SIZE_FORMAT "\n", PerfDataMemorySize, os::vm_allocation_granularity(), @@ -129,7 +127,7 @@ void PerfMemory::initialize() { if (PerfTraceMemOps) { tty->print("PerfMemory created: address = " INTPTR_FORMAT "," " size = " SIZE_FORMAT "\n", - (void*)_start, + p2i(_start), _capacity); } diff --git a/hotspot/src/share/vm/runtime/rframe.cpp b/hotspot/src/share/vm/runtime/rframe.cpp index 57893cd26c4..dea7ef78696 100644 --- a/hotspot/src/share/vm/runtime/rframe.cpp +++ b/hotspot/src/share/vm/runtime/rframe.cpp @@ -155,7 +155,7 @@ void InterpretedRFrame::init() { void RFrame::print(const char* kind) { #ifndef PRODUCT -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI int cnt = top_method()->interpreter_invocation_count(); #else int cnt = top_method()->invocation_count(); diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp index 0bf041bf6d4..37d23b4c97c 100644 --- a/hotspot/src/share/vm/runtime/safepoint.cpp +++ b/hotspot/src/share/vm/runtime/safepoint.cpp @@ -63,8 +63,6 @@ #include "c1/c1_globals.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // -------------------------------------------------------------------------------------------------- // Implementation of Safepoint begin/end @@ -340,7 +338,7 @@ void SafepointSynchronize::begin() { tty->print_cr("# SafepointSynchronize: Finished after " INT64_FORMAT_W(6) " ms", ((current_time - safepoint_limit_time) / MICROUNITS + - SafepointTimeoutDelay)); + (jlong)SafepointTimeoutDelay)); } } #endif @@ -689,7 +687,7 @@ void SafepointSynchronize::block(JavaThread *thread) { break; default: - fatal(err_msg("Illegal threadstate encountered: %d", state)); + fatal("Illegal threadstate encountered: %d", state); } // Check for pending. async. exceptions or suspends - except if the @@ -773,12 +771,10 @@ void SafepointSynchronize::print_safepoint_timeout(SafepointTimeoutReason reason // To debug the long safepoint, specify both DieOnSafepointTimeout & // ShowMessageBoxOnError. if (DieOnSafepointTimeout) { - char msg[1024]; VM_Operation *op = VMThread::vm_operation(); - sprintf(msg, "Safepoint sync time longer than " INTX_FORMAT "ms detected when executing %s.", - SafepointTimeoutDelay, - op != NULL ? op->name() : "no vm operation"); - fatal(msg); + fatal("Safepoint sync time longer than " INTX_FORMAT "ms detected when executing %s.", + SafepointTimeoutDelay, + op != NULL ? op->name() : "no vm operation"); } } @@ -895,7 +891,7 @@ void ThreadSafepointState::restart() { case _running: default: tty->print_cr("restart thread " INTPTR_FORMAT " with state %d", - _thread, _type); + p2i(_thread), _type); _thread->print(); ShouldNotReachHere(); } @@ -917,7 +913,7 @@ void ThreadSafepointState::print_on(outputStream *st) const { st->print_cr("Thread: " INTPTR_FORMAT " [0x%2x] State: %s _has_called_back %d _at_poll_safepoint %d", - _thread, _thread->osthread()->thread_id(), s, _has_called_back, + p2i(_thread), _thread->osthread()->thread_id(), s, _has_called_back, _at_poll_safepoint); _thread->print_thread_state_on(st); @@ -936,7 +932,7 @@ void ThreadSafepointState::handle_polling_page_exception() { // Step 1: Find the nmethod from the return address if (ShowSafepointMsgs && Verbose) { - tty->print_cr("Polling page exception at " INTPTR_FORMAT, thread()->saved_exception_pc()); + tty->print_cr("Polling page exception at " INTPTR_FORMAT, p2i(thread()->saved_exception_pc())); } address real_return_addr = thread()->saved_exception_pc(); @@ -1054,10 +1050,6 @@ static void print_header() { void SafepointSynchronize::deferred_initialize_stat() { if (init_done) return; - if (PrintSafepointStatisticsCount <= 0) { - fatal("Wrong PrintSafepointStatisticsCount"); - } - // If PrintSafepointStatisticsTimeout is specified, the statistics data will // be printed right away, in which case, _safepoint_stats will regress to // a single element array. Otherwise, it is a circular ring buffer with default @@ -1168,7 +1160,7 @@ void SafepointSynchronize::end_statistics(jlong vmop_end_time) { // PrintSafepointStatisticsTimeout will be printed out right away. // By default, it is -1 meaning all samples will be put into the list. if ( PrintSafepointStatisticsTimeout > 0) { - if (spstat->_time_to_sync > PrintSafepointStatisticsTimeout * MICROUNITS) { + if (spstat->_time_to_sync > (jlong)PrintSafepointStatisticsTimeout * MICROUNITS) { print_statistics(); } } else { @@ -1234,7 +1226,7 @@ void SafepointSynchronize::print_stat_on_exit() { os::javaTimeNanos() - cleanup_end_time; if ( PrintSafepointStatisticsTimeout < 0 || - spstat->_time_to_sync > PrintSafepointStatisticsTimeout * MICROUNITS) { + spstat->_time_to_sync > (jlong)PrintSafepointStatisticsTimeout * MICROUNITS) { print_statistics(); } tty->cr(); @@ -1243,8 +1235,8 @@ void SafepointSynchronize::print_stat_on_exit() { if (!need_to_track_page_armed_status) { tty->print_cr("Polling page always armed"); } else { - tty->print_cr("Defer polling page loop count = %d\n", - DeferPollingPageLoopCount); + tty->print_cr("Defer polling page loop count = " INTX_FORMAT "\n", + DeferPollingPageLoopCount); } for (int index = 0; index < VM_Operation::VMOp_Terminating; index++) { diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 29589656c8c..da2fe478f1d 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" @@ -46,6 +47,7 @@ #include "runtime/arguments.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/compilationPolicy.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" @@ -64,8 +66,6 @@ #include "c1/c1_Runtime1.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Shared stub locations RuntimeStub* SharedRuntime::_wrong_method_blob; RuntimeStub* SharedRuntime::_wrong_method_abstract_blob; @@ -93,12 +93,13 @@ void SharedRuntime::generate_stubs() { _resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C), "resolve_virtual_call"); _resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C), "resolve_static_call"); -#ifdef COMPILER2 - // Vectors are generated only by C2. - if (is_wide_vector(MaxVectorSize)) { +#if defined(COMPILER2) || INCLUDE_JVMCI + // Vectors are generated only by C2 and JVMCI. + bool support_wide = is_wide_vector(MaxVectorSize); + if (support_wide) { _polling_page_vectors_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_VECTOR_LOOP); } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI _polling_page_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_LOOP); _polling_page_return_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_RETURN); @@ -183,7 +184,7 @@ void SharedRuntime::print_ic_miss_histogram() { tty->print_cr("IC Miss Histogram:"); int tot_misses = 0; for (int i = 0; i < _ICmiss_index; i++) { - tty->print_cr(" at: " INTPTR_FORMAT " nof: %d", _ICmiss_at[i], _ICmiss_count[i]); + tty->print_cr(" at: " INTPTR_FORMAT " nof: %d", p2i(_ICmiss_at[i]), _ICmiss_count[i]); tot_misses += _ICmiss_count[i]; } tty->print_cr("Total IC misses: %7d", tot_misses); @@ -455,12 +456,18 @@ JRT_END // previous frame depending on the return address. address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thread, address return_address) { - assert(frame::verify_return_pc(return_address), err_msg("must be a return address: " INTPTR_FORMAT, return_address)); + assert(frame::verify_return_pc(return_address), "must be a return address: " INTPTR_FORMAT, p2i(return_address)); assert(thread->frames_to_pop_failed_realloc() == 0 || Interpreter::contains(return_address), "missed frames to pop?"); // Reset method handle flag. thread->set_is_method_handle_return(false); +#if INCLUDE_JVMCI + // JVMCI's ExceptionHandlerStub expects the thread local exception PC to be clear + // and other exception handler continuations do not read it + thread->set_exception_pc(NULL); +#endif + // The fastest case first CodeBlob* blob = CodeCache::find_blob(return_address); nmethod* nm = (blob != NULL) ? blob->as_nmethod_or_null() : NULL; @@ -498,7 +505,7 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thre #ifndef PRODUCT { ResourceMark rm; - tty->print_cr("No exception handler found for exception at " INTPTR_FORMAT " - potential problems:", return_address); + tty->print_cr("No exception handler found for exception at " INTPTR_FORMAT " - potential problems:", p2i(return_address)); tty->print_cr("a) exception happened in (new?) code stubs/buffers that is not handled here"); tty->print_cr("b) other problem"); } @@ -526,8 +533,13 @@ address SharedRuntime::get_poll_stub(address pc) { assert(((nmethod*)cb)->is_at_poll_or_poll_return(pc), "safepoint polling: type must be poll"); - assert(((NativeInstruction*)pc)->is_safepoint_poll(), - "Only polling locations are used for safepoint"); +#ifdef ASSERT + if (!((NativeInstruction*)pc)->is_safepoint_poll()) { + tty->print_cr("bad pc: " PTR_FORMAT, p2i(pc)); + Disassembler::decode(cb); + fatal("Only polling locations are used for safepoint"); + } +#endif bool at_poll_return = ((nmethod*)cb)->is_at_poll_return(pc); bool has_wide_vectors = ((nmethod*)cb)->has_wide_vectors(); @@ -617,6 +629,33 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, assert(nm != NULL, "must exist"); ResourceMark rm; +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci()) { + // lookup exception handler for this pc + int catch_pco = ret_pc - nm->code_begin(); + ExceptionHandlerTable table(nm); + HandlerTableEntry *t = table.entry_for(catch_pco, -1, 0); + if (t != NULL) { + return nm->code_begin() + t->pco(); + } else { + // there is no exception handler for this pc => deoptimize + nm->make_not_entrant(); + + // Use Deoptimization::deoptimize for all of its side-effects: + // revoking biases of monitors, gathering traps statistics, logging... + // it also patches the return pc but we do not care about that + // since we return a continuation to the deopt_blob below. + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, UseBiasedLocking); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + Deoptimization::deoptimize(thread, caller_frame, ®_map, Deoptimization::Reason_not_compiled_exception_handler); + + return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + } +#endif // INCLUDE_JVMCI + ScopeDesc* sd = nm->scope_desc_at(ret_pc); // determine handler bci, if any EXCEPTION_MARK; @@ -685,7 +724,7 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, #endif if (t == NULL) { - tty->print_cr("MISSING EXCEPTION HANDLER for pc " INTPTR_FORMAT " and handler bci %d", ret_pc, handler_bci); + tty->print_cr("MISSING EXCEPTION HANDLER for pc " INTPTR_FORMAT " and handler bci %d", p2i(ret_pc), handler_bci); tty->print_cr(" Exception:"); exception->print(); tty->cr(); @@ -737,6 +776,15 @@ JRT_ENTRY(void, SharedRuntime::throw_StackOverflowError(JavaThread* thread)) throw_and_post_jvmti_exception(thread, exception); JRT_END +#if INCLUDE_JVMCI +address SharedRuntime::deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason) { + assert(deopt_reason > Deoptimization::Reason_none && deopt_reason < Deoptimization::Reason_LIMIT, "invalid deopt reason"); + thread->set_jvmci_implicit_exception_pc(pc); + thread->set_pending_deoptimization(Deoptimization::make_trap_request((Deoptimization::DeoptReason)deopt_reason, Deoptimization::Action_reinterpret)); + return (SharedRuntime::deopt_blob()->implicit_exception_uncommon_trap()); +} +#endif // INCLUDE_JVMCI + address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, address pc, SharedRuntime::ImplicitExceptionKind exception_kind) @@ -769,7 +817,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, // in a debug VM to verify the correctness of the compiled // method stack banging. assert(thread->deopt_mark() == NULL, "no stack overflow from deopt blob/uncommon trap"); - Events::log_exception(thread, "StackOverflowError at " INTPTR_FORMAT, pc); + Events::log_exception(thread, "StackOverflowError at " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_StackOverflowError_entry(); } @@ -786,10 +834,10 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, if (vt_stub->is_abstract_method_error(pc)) { assert(!vt_stub->is_vtable_stub(), "should never see AbstractMethodErrors from vtable-type VtableStubs"); - Events::log_exception(thread, "AbstractMethodError at " INTPTR_FORMAT, pc); + Events::log_exception(thread, "AbstractMethodError at " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_AbstractMethodError_entry(); } else { - Events::log_exception(thread, "NullPointerException at vtable entry " INTPTR_FORMAT, pc); + Events::log_exception(thread, "NullPointerException at vtable entry " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_NullPointerException_at_call_entry(); } } else { @@ -806,10 +854,10 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, if (!cb->is_nmethod()) { bool is_in_blob = cb->is_adapter_blob() || cb->is_method_handles_adapter_blob(); if (!is_in_blob) { - cb->print(); - fatal(err_msg("exception happened outside interpreter, nmethods and vtable stubs at pc " INTPTR_FORMAT, pc)); + // Allow normal crash reporting to handle this + return NULL; } - Events::log_exception(thread, "NullPointerException in code blob at " INTPTR_FORMAT, pc); + Events::log_exception(thread, "NullPointerException in code blob at " INTPTR_FORMAT, p2i(pc)); // There is no handler here, so we will simply unwind. return StubRoutines::throw_NullPointerException_at_call_entry(); } @@ -821,20 +869,32 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, // => the nmethod is not yet active (i.e., the frame // is not set up yet) => use return address pushed by // caller => don't push another return address - Events::log_exception(thread, "NullPointerException in IC check " INTPTR_FORMAT, pc); + Events::log_exception(thread, "NullPointerException in IC check " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_NullPointerException_at_call_entry(); } if (nm->method()->is_method_handle_intrinsic()) { // exception happened inside MH dispatch code, similar to a vtable stub - Events::log_exception(thread, "NullPointerException in MH adapter " INTPTR_FORMAT, pc); + Events::log_exception(thread, "NullPointerException in MH adapter " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_NullPointerException_at_call_entry(); } #ifndef PRODUCT _implicit_null_throws++; #endif +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci() && nm->pc_desc_at(pc) != NULL) { + // If there's no PcDesc then we'll die way down inside of + // deopt instead of just getting normal error reporting, + // so only go there if it will succeed. + return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check); + } else { +#endif // INCLUDE_JVMCI + assert (nm->is_nmethod(), "Expect nmethod"); target_pc = nm->continuation_for_implicit_exception(pc); +#if INCLUDE_JVMCI + } +#endif // INCLUDE_JVMCI // If there's an unexpected fault, target_pc might be NULL, // in which case we want to fall through into the normal // error handling code. @@ -846,11 +906,19 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, case IMPLICIT_DIVIDE_BY_ZERO: { nmethod* nm = CodeCache::find_nmethod(pc); - guarantee(nm != NULL, "must have containing nmethod for implicit division-by-zero exceptions"); + guarantee(nm != NULL, "must have containing compiled method for implicit division-by-zero exceptions"); #ifndef PRODUCT _implicit_div0_throws++; #endif +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci() && nm->pc_desc_at(pc) != NULL) { + return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_div0_check); + } else { +#endif // INCLUDE_JVMCI target_pc = nm->continuation_for_implicit_exception(pc); +#if INCLUDE_JVMCI + } +#endif // INCLUDE_JVMCI // If there's an unexpected fault, target_pc might be NULL, // in which case we want to fall through into the normal // error handling code. @@ -862,12 +930,18 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, assert(exception_kind == IMPLICIT_NULL || exception_kind == IMPLICIT_DIVIDE_BY_ZERO, "wrong implicit exception kind"); - // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort("java.lang.NullPointerException")); if (exception_kind == IMPLICIT_NULL) { - Events::log_exception(thread, "Implicit null exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc); +#ifndef PRODUCT + // for AbortVMOnException flag + Exceptions::debug_check_abort("java.lang.NullPointerException"); +#endif //PRODUCT + Events::log_exception(thread, "Implicit null exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, p2i(pc), p2i(target_pc)); } else { - Events::log_exception(thread, "Implicit division by zero exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc); +#ifndef PRODUCT + // for AbortVMOnException flag + Exceptions::debug_check_abort("java.lang.ArithmeticException"); +#endif //PRODUCT + Events::log_exception(thread, "Implicit division by zero exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, p2i(pc), p2i(target_pc)); } return target_pc; } @@ -916,6 +990,16 @@ JRT_END JRT_ENTRY_NO_ASYNC(void, SharedRuntime::register_finalizer(JavaThread* thread, oopDesc* obj)) assert(obj->is_oop(), "must be a valid oop"); +#if INCLUDE_JVMCI + // This removes the requirement for JVMCI compilers to emit code + // performing a dynamic check that obj has a finalizer before + // calling this routine. There should be no performance impact + // for C1 since it emits a dynamic check. C2 and the interpreter + // uses other runtime routines for registering finalizers. + if (!obj->klass()->has_finalizer()) { + return; + } +#endif // INCLUDE_JVMCI assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise"); InstanceKlass::register_finalizer(instanceOop(obj), CHECK); JRT_END @@ -1157,6 +1241,7 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread, methodHandle callee_method = call_info.selected_method(); assert((!is_virtual && invoke_code == Bytecodes::_invokestatic ) || + (!is_virtual && invoke_code == Bytecodes::_invokespecial) || (!is_virtual && invoke_code == Bytecodes::_invokehandle ) || (!is_virtual && invoke_code == Bytecodes::_invokedynamic) || ( is_virtual && invoke_code != Bytecodes::_invokestatic ), "inconsistent bytecode"); @@ -1176,7 +1261,8 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread, (is_optimized) ? "optimized " : "", (is_virtual) ? "virtual" : "static", Bytecodes::name(invoke_code)); callee_method->print_short_name(tty); - tty->print_cr(" at pc: " INTPTR_FORMAT " to code: " INTPTR_FORMAT, caller_frame.pc(), callee_method->code()); + tty->print_cr(" at pc: " INTPTR_FORMAT " to code: " INTPTR_FORMAT, + p2i(caller_frame.pc()), p2i(callee_method->code())); } #endif @@ -1367,9 +1453,6 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_opt_virtual_call_C(JavaThread *t JRT_END - - - methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) { ResourceMark rm(thread); CallInfo call_info; @@ -1397,8 +1480,8 @@ methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) { ResourceMark rm(thread); tty->print("converting IC miss to reresolve (%s) call to", Bytecodes::name(bc)); callee_method->print_short_name(tty); - tty->print_cr(" from pc: " INTPTR_FORMAT, caller_frame.pc()); - tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code()); + tty->print_cr(" from pc: " INTPTR_FORMAT, p2i(caller_frame.pc())); + tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code())); } return callee_method; } @@ -1415,7 +1498,7 @@ methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) { ResourceMark rm(thread); tty->print("IC miss (%s) call to", Bytecodes::name(bc)); callee_method->print_short_name(tty); - tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code()); + tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code())); } if (ICMissHistogram) { @@ -1447,7 +1530,7 @@ methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) { ResourceMark rm(thread); tty->print("OPTIMIZED IC miss (%s) call to", Bytecodes::name(bc)); callee_method->print_short_name(tty); - tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code()); + tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code())); } should_be_mono = true; } else if (inline_cache->is_icholder_call()) { @@ -1464,7 +1547,7 @@ methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) { ResourceMark rm(thread); tty->print("FALSE IC miss (%s) converting to compiled call to", Bytecodes::name(bc)); callee_method->print_short_name(tty); - tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code()); + tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code())); } should_be_mono = true; } @@ -1493,6 +1576,8 @@ methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) { } else { // Either clean or megamorphic } + } else { + fatal("Unimplemented"); } } // Release CompiledIC_lock @@ -1520,6 +1605,10 @@ methodHandle SharedRuntime::reresolve_call_site(JavaThread *thread, TRAPS) { address pc = caller.pc(); + // Check for static or virtual call + bool is_static_call = false; + nmethod* caller_nm = CodeCache::find_nmethod(pc); + // Default call_addr is the location of the "basic" call. // Determine the address of the call we a reresolving. With // Inline Caches we will always find a recognizable call. @@ -1549,10 +1638,6 @@ methodHandle SharedRuntime::reresolve_call_site(JavaThread *thread, TRAPS) { call_addr = ncall->instruction_address(); } } - - // Check for static or virtual call - bool is_static_call = false; - nmethod* caller_nm = CodeCache::find_nmethod(pc); // Make sure nmethod doesn't get deoptimized and removed until // this is done with it. // CLEANUP - with lazy deopt shouldn't need this lock @@ -1604,7 +1689,7 @@ methodHandle SharedRuntime::reresolve_call_site(JavaThread *thread, TRAPS) { ResourceMark rm(thread); tty->print("handle_wrong_method reresolving call to"); callee_method->print_short_name(tty); - tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code()); + tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code())); } #endif @@ -1630,7 +1715,7 @@ void SharedRuntime::check_member_name_argument_is_last_argument(methodHandle met for (int i = 0; i < member_arg_pos; i++) { VMReg a = regs_with_member_name[i].first(); VMReg b = regs_without_member_name[i].first(); - assert(a->value() == b->value(), err_msg_res("register allocation mismatch: a=%d, b=%d", a->value(), b->value())); + assert(a->value() == b->value(), "register allocation mismatch: a=" INTX_FORMAT ", b=" INTX_FORMAT, a->value(), b->value()); } assert(regs_with_member_name[member_arg_pos].first()->is_valid(), "bad member arg"); } @@ -1712,25 +1797,25 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal if (callee == cb || callee->is_adapter_blob()) { // static call or optimized virtual if (TraceCallFixup) { - tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc); + tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc)); moop->print_short_name(tty); - tty->print_cr(" to " INTPTR_FORMAT, entry_point); + tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point)); } call->set_destination_mt_safe(entry_point); } else { if (TraceCallFixup) { - tty->print("failed to fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc); + tty->print("failed to fixup callsite at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc)); moop->print_short_name(tty); - tty->print_cr(" to " INTPTR_FORMAT, entry_point); + tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point)); } // assert is too strong could also be resolve destinations. // assert(InlineCacheBuffer::contains(destination) || VtableStubs::contains(destination), "must be"); } } else { if (TraceCallFixup) { - tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", caller_pc); + tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc)); moop->print_short_name(tty); - tty->print_cr(" to " INTPTR_FORMAT, entry_point); + tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point)); } } } @@ -2567,8 +2652,7 @@ void AdapterHandlerLibrary::create_native_wrapper(methodHandle method) { // Perform the work while holding the lock, but perform any printing outside the lock MutexLocker mu(AdapterHandlerLibrary_lock); // See if somebody beat us to it - nm = method->code(); - if (nm != NULL) { + if (method->code() != NULL) { return; } @@ -2810,7 +2894,7 @@ JRT_LEAF(void, SharedRuntime::OSR_migration_end( intptr_t* buf) ) FREE_C_HEAP_ARRAY(intptr_t, buf); JRT_END -bool AdapterHandlerLibrary::contains(CodeBlob* b) { +bool AdapterHandlerLibrary::contains(const CodeBlob* b) { AdapterHandlerTableIterator iter(_adapters); while (iter.has_next()) { AdapterHandlerEntry* a = iter.next(); @@ -2819,7 +2903,7 @@ bool AdapterHandlerLibrary::contains(CodeBlob* b) { return false; } -void AdapterHandlerLibrary::print_handler_on(outputStream* st, CodeBlob* b) { +void AdapterHandlerLibrary::print_handler_on(outputStream* st, const CodeBlob* b) { AdapterHandlerTableIterator iter(_adapters); while (iter.has_next()) { AdapterHandlerEntry* a = iter.next(); @@ -2834,8 +2918,8 @@ void AdapterHandlerLibrary::print_handler_on(outputStream* st, CodeBlob* b) { void AdapterHandlerEntry::print_adapter_on(outputStream* st) const { st->print_cr("AHE@" INTPTR_FORMAT ": %s i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT, - (intptr_t) this, fingerprint()->as_string(), - get_i2c_entry(), get_c2i_entry(), get_c2i_unverified_entry()); + p2i(this), fingerprint()->as_string(), + p2i(get_i2c_entry()), p2i(get_c2i_entry()), p2i(get_c2i_unverified_entry())); } diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index f94a8693572..65db7ad38e7 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -199,6 +199,9 @@ class SharedRuntime: AllStatic { static address continuation_for_implicit_exception(JavaThread* thread, address faulting_pc, ImplicitExceptionKind exception_kind); +#if INCLUDE_JVMCI + static address deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason); +#endif // Shared stub locations static address get_poll_stub(address pc); @@ -417,6 +420,12 @@ class SharedRuntime: AllStatic { const VMRegPair *regs, AdapterFingerPrint* fingerprint); + static void gen_i2c_adapter(MacroAssembler *_masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs); + // OSR support // OSR_migration_begin will extract the jvm state from an interpreter @@ -475,6 +484,7 @@ class SharedRuntime: AllStatic { // A compiled caller has just called the interpreter, but compiled code // exists. Patch the caller so he no longer calls into the interpreter. static void fixup_callers_callsite(Method* moop, address ret_pc); + static bool should_fixup_call_destination(address destination, address entry_point, address caller_pc, Method* moop, CodeBlob* cb); // Slow-path Locking and Unlocking static void complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread); @@ -673,9 +683,9 @@ class AdapterHandlerLibrary: public AllStatic { static void create_native_wrapper(methodHandle method); static AdapterHandlerEntry* get_adapter(methodHandle method); - static void print_handler(CodeBlob* b) { print_handler_on(tty, b); } - static void print_handler_on(outputStream* st, CodeBlob* b); - static bool contains(CodeBlob* b); + static void print_handler(const CodeBlob* b) { print_handler_on(tty, b); } + static void print_handler_on(outputStream* st, const CodeBlob* b); + static bool contains(const CodeBlob* b); #ifndef PRODUCT static void print_statistics(); #endif // PRODUCT diff --git a/hotspot/src/share/vm/runtime/signature.cpp b/hotspot/src/share/vm/runtime/signature.cpp index 425a3705b7e..9e616a44add 100644 --- a/hotspot/src/share/vm/runtime/signature.cpp +++ b/hotspot/src/share/vm/runtime/signature.cpp @@ -32,8 +32,6 @@ #include "oops/typeArrayKlass.hpp" #include "runtime/signature.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Implementation of SignatureIterator // Signature syntax: @@ -51,7 +49,7 @@ SignatureIterator::SignatureIterator(Symbol* signature) { } void SignatureIterator::expect(char c) { - if (_signature->byte_at(_index) != c) fatal(err_msg("expecting %c", c)); + if (_signature->byte_at(_index) != c) fatal("expecting %c", c); _index++; } @@ -209,7 +207,7 @@ void SignatureIterator::iterate_parameters( uint64_t fingerprint ) { return; break; default: - tty->print_cr("*** parameter is %d", fingerprint & parameter_feature_mask); + tty->print_cr("*** parameter is " UINT64_FORMAT, fingerprint & parameter_feature_mask); tty->print_cr("*** fingerprint is " PTR64_FORMAT, saved_fingerprint); ShouldNotReachHere(); break; diff --git a/hotspot/src/share/vm/runtime/stackValueCollection.cpp b/hotspot/src/share/vm/runtime/stackValueCollection.cpp index fdf448b3718..15c88f0243a 100644 --- a/hotspot/src/share/vm/runtime/stackValueCollection.cpp +++ b/hotspot/src/share/vm/runtime/stackValueCollection.cpp @@ -25,8 +25,6 @@ #include "precompiled.hpp" #include "runtime/stackValueCollection.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - jint StackValueCollection::int_at(int slot) const { intptr_t val = at(slot)->get_int(); jint ival = *((jint*) (&val)); diff --git a/hotspot/src/share/vm/runtime/stubRoutines.cpp b/hotspot/src/share/vm/runtime/stubRoutines.cpp index 4ee48738da8..e0f3136fa60 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp @@ -136,8 +136,9 @@ address StubRoutines::_sha512_implCompress = NULL; address StubRoutines::_sha512_implCompressMB = NULL; address StubRoutines::_updateBytesCRC32 = NULL; -address StubRoutines::_crc_table_adr = NULL; +address StubRoutines::_crc_table_adr = NULL; +address StubRoutines::_crc32c_table_addr = NULL; address StubRoutines::_updateBytesCRC32C = NULL; address StubRoutines::_updateBytesAdler32 = NULL; @@ -147,9 +148,10 @@ address StubRoutines::_mulAdd = NULL; address StubRoutines::_montgomeryMultiply = NULL; address StubRoutines::_montgomerySquare = NULL; +address StubRoutines::_dexp = NULL; + double (* StubRoutines::_intrinsic_log )(double) = NULL; double (* StubRoutines::_intrinsic_log10 )(double) = NULL; -double (* StubRoutines::_intrinsic_exp )(double) = NULL; double (* StubRoutines::_intrinsic_pow )(double, double) = NULL; double (* StubRoutines::_intrinsic_sin )(double) = NULL; double (* StubRoutines::_intrinsic_cos )(double) = NULL; diff --git a/hotspot/src/share/vm/runtime/stubRoutines.hpp b/hotspot/src/share/vm/runtime/stubRoutines.hpp index 3e5e9338ce6..e42485a96fc 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.hpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp @@ -197,6 +197,7 @@ class StubRoutines: AllStatic { static address _updateBytesCRC32; static address _crc_table_adr; + static address _crc32c_table_addr; static address _updateBytesCRC32C; static address _updateBytesAdler32; @@ -206,6 +207,8 @@ class StubRoutines: AllStatic { static address _montgomeryMultiply; static address _montgomerySquare; + static address _dexp; + // These are versions of the java.lang.Math methods which perform // the same operations as the intrinsic version. They are used for // constant folding in the compiler to ensure equivalence. If the @@ -214,7 +217,6 @@ class StubRoutines: AllStatic { // SharedRuntime. static double (*_intrinsic_log)(double); static double (*_intrinsic_log10)(double); - static double (*_intrinsic_exp)(double); static double (*_intrinsic_pow)(double, double); static double (*_intrinsic_sin)(double); static double (*_intrinsic_cos)(double); @@ -364,6 +366,7 @@ class StubRoutines: AllStatic { static address updateBytesCRC32() { return _updateBytesCRC32; } static address crc_table_addr() { return _crc_table_adr; } + static address crc32c_table_addr() { return _crc32c_table_addr; } static address updateBytesCRC32C() { return _updateBytesCRC32C; } static address updateBytesAdler32() { return _updateBytesAdler32; } @@ -373,6 +376,8 @@ class StubRoutines: AllStatic { static address montgomeryMultiply() { return _montgomeryMultiply; } static address montgomerySquare() { return _montgomerySquare; } + static address dexp() {return _dexp; } + static address select_fill_function(BasicType t, bool aligned, const char* &name); static address zero_aligned_words() { return _zero_aligned_words; } @@ -385,10 +390,6 @@ class StubRoutines: AllStatic { assert(_intrinsic_log != NULL, "must be defined"); return _intrinsic_log10(d); } - static double intrinsic_exp(double d) { - assert(_intrinsic_exp != NULL, "must be defined"); - return _intrinsic_exp(d); - } static double intrinsic_pow(double d, double d2) { assert(_intrinsic_pow != NULL, "must be defined"); return _intrinsic_pow(d, d2); diff --git a/hotspot/src/share/vm/runtime/sweeper.cpp b/hotspot/src/share/vm/runtime/sweeper.cpp index 0d4e04c75de..fad5edf0f9a 100644 --- a/hotspot/src/share/vm/runtime/sweeper.cpp +++ b/hotspot/src/share/vm/runtime/sweeper.cpp @@ -43,8 +43,6 @@ #include "utilities/ticks.inline.hpp" #include "utilities/xmlstream.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef ASSERT #define SWEEP(nm) record_sweep(nm, __LINE__) @@ -62,12 +60,12 @@ class SweeperRecord { void print() { tty->print_cr("traversal = %d compile_id = %d %s uep = " PTR_FORMAT " vep = " - PTR_FORMAT " state = %d traversal_mark %d line = %d", + PTR_FORMAT " state = %d traversal_mark %ld line = %d", traversal, compile_id, kind == NULL ? "" : kind, - uep, - vep, + p2i(uep), + p2i(vep), state, traversal_mark, line); @@ -223,7 +221,7 @@ void NMethodSweeper::mark_active_nmethods() { _total_time_this_sweep = Tickspan(); if (PrintMethodFlushing) { - tty->print_cr("### Sweep: stack traversal %d", _traversals); + tty->print_cr("### Sweep: stack traversal %ld", _traversals); } Threads::nmethods_do(&mark_activation_closure); @@ -482,7 +480,7 @@ void NMethodSweeper::sweep_code_cache() { #ifdef ASSERT if(PrintMethodFlushing) { - tty->print_cr("### sweeper: sweep time(%d): ", (jlong)sweep_time.value()); + tty->print_cr("### sweeper: sweep time(" JLONG_FORMAT "): ", sweep_time.value()); } #endif @@ -592,14 +590,14 @@ NMethodSweeper::MethodStateChange NMethodSweeper::process_nmethod(nmethod* nm) { if (nm->is_marked_for_reclamation()) { assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); + tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), p2i(nm)); } release_nmethod(nm); assert(result == None, "sanity"); result = Flushed; } else { if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); + tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), p2i(nm)); } nm->mark_for_reclamation(); // Keep track of code cache state change @@ -619,7 +617,7 @@ NMethodSweeper::MethodStateChange NMethodSweeper::process_nmethod(nmethod* nm) { nm->clear_ic_stubs(); } if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); + tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), p2i(nm)); } // Code cache state change is tracked in make_zombie() nm->make_zombie(); @@ -636,7 +634,7 @@ NMethodSweeper::MethodStateChange NMethodSweeper::process_nmethod(nmethod* nm) { } else if (nm->is_unloaded()) { // Unloaded code, just make it a zombie if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm); + tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), p2i(nm)); } if (nm->is_osr_method()) { SWEEP(nm); @@ -743,7 +741,7 @@ void NMethodSweeper::possibly_flush(nmethod* nm) { // Code cache state change is tracked in make_not_entrant() if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %d/" PTR_FORMAT "made not-entrant: hotness counter %d/%d threshold %f", - nm->compile_id(), nm, nm->hotness_counter(), reset_val, threshold); + nm->compile_id(), p2i(nm), nm->hotness_counter(), reset_val, threshold); } } } diff --git a/hotspot/src/share/vm/runtime/sweeper.hpp b/hotspot/src/share/vm/runtime/sweeper.hpp index aa4860b5f71..ccf5125c808 100644 --- a/hotspot/src/share/vm/runtime/sweeper.hpp +++ b/hotspot/src/share/vm/runtime/sweeper.hpp @@ -27,7 +27,9 @@ class WhiteBox; +#include "code/codeCache.hpp" #include "utilities/ticks.hpp" + // An NmethodSweeper is an incremental cleaner for: // - cleanup inline caches // - reclamation of nmethods diff --git a/hotspot/src/share/vm/runtime/synchronizer.cpp b/hotspot/src/share/vm/runtime/synchronizer.cpp index d8d0ebde790..fec10fd757b 100644 --- a/hotspot/src/share/vm/runtime/synchronizer.cpp +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp @@ -52,8 +52,6 @@ #define NOINLINE #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // The "core" versions of monitor enter and exit reside in this file. // The interpreter and compilers contain specialized transliterated // variants of the enter-exit fast-path operations. See i486.ad fast_lock(), @@ -1417,7 +1415,7 @@ ObjectMonitor * NOINLINE ObjectSynchronizer::inflate(Thread * Self, if (object->is_instance()) { ResourceMark rm; tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - (void *) object, (intptr_t) object->mark(), + p2i(object), p2i(object->mark()), object->klass()->external_name()); } } @@ -1465,7 +1463,7 @@ ObjectMonitor * NOINLINE ObjectSynchronizer::inflate(Thread * Self, if (object->is_instance()) { ResourceMark rm; tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - (void *) object, (intptr_t) object->mark(), + p2i(object), p2i(object->mark()), object->klass()->external_name()); } } @@ -1529,7 +1527,7 @@ bool ObjectSynchronizer::deflate_monitor(ObjectMonitor* mid, oop obj, if (obj->is_instance()) { ResourceMark rm; tty->print_cr("Deflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - (void *) obj, (intptr_t) obj->mark(), obj->klass()->external_name()); + p2i(obj), p2i(obj->mark()), obj->klass()->external_name()); } } @@ -1702,9 +1700,9 @@ class ReleaseJavaMonitorsClosure: public MonitorClosure { Handle obj((oop) mid->object()); tty->print("INFO: unexpected locked object:"); javaVFrame::print_locked_object_class_name(tty, obj, "locked"); - fatal(err_msg("exiting JavaThread=" INTPTR_FORMAT - " unexpectedly owns ObjectMonitor=" INTPTR_FORMAT, - THREAD, mid)); + fatal("exiting JavaThread=" INTPTR_FORMAT + " unexpectedly owns ObjectMonitor=" INTPTR_FORMAT, + p2i(THREAD), p2i(mid)); } (void)mid->complete_exit(CHECK); } diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 2c260428a4c..1fa6e2a7325 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -31,12 +31,14 @@ #include "code/codeCacheExtensions.hpp" #include "code/scopeDesc.hpp" #include "compiler/compileBroker.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/workgroup.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/linkResolver.hpp" #include "interpreter/oopMapCache.hpp" #include "jvmtifiles/jvmtiEnv.hpp" +#include "logging/logConfiguration.hpp" #include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" #include "memory/universe.inline.hpp" @@ -99,6 +101,10 @@ #include "gc/g1/concurrentMarkThread.inline.hpp" #include "gc/parallel/pcTasks.hpp" #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif @@ -110,8 +116,6 @@ #include "runtime/rtmLocking.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef DTRACE_ENABLED // Only bother with this argument setup if dtrace is available @@ -163,7 +167,7 @@ void* Thread::allocate(size_t size, bool throw_excpt, MEMFLAGS flags) { if (TraceBiasedLocking) { if (aligned_addr != real_malloc_addr) { tty->print_cr("Aligned thread " INTPTR_FORMAT " to " INTPTR_FORMAT, - real_malloc_addr, aligned_addr); + p2i(real_malloc_addr), p2i(aligned_addr)); } } ((Thread*) aligned_addr)->_real_malloc_address = real_malloc_addr; @@ -797,7 +801,7 @@ void Thread::print_on(outputStream* st) const { if (os::get_native_priority(this, &os_prio) == OS_OK) { st->print("os_prio=%d ", os_prio); } - st->print("tid=" INTPTR_FORMAT " ", this); + st->print("tid=" INTPTR_FORMAT " ", p2i(this)); ext().print_on(st); osthread()->print_on(st); } @@ -816,7 +820,7 @@ void Thread::print_on_error(outputStream* st, char* buf, int buflen) const { else st->print("Thread"); st->print(" [stack: " PTR_FORMAT "," PTR_FORMAT "]", - _stack_base - _stack_size, _stack_base); + p2i(_stack_base - _stack_size), p2i(_stack_base)); if (osthread()) { st->print(" [id=%d]", osthread()->thread_id()); @@ -879,7 +883,7 @@ void Thread::check_for_valid_safepoint_state(bool potential_vm_operation) { cur != VMOperationRequest_lock && cur != VMOperationQueue_lock) || cur->rank() == Mutex::special) { - fatal(err_msg("Thread holding lock at safepoint that vm can block on: %s", cur->name())); + fatal("Thread holding lock at safepoint that vm can block on: %s", cur->name()); } } } @@ -1148,6 +1152,7 @@ void JavaThread::allocate_threadObj(Handle thread_group, const char* thread_name NamedThread::NamedThread() : Thread() { _name = NULL; _processed_thread = NULL; + _gc_id = GCId::undefined(); } NamedThread::~NamedThread() { @@ -1386,6 +1391,33 @@ void WatcherThread::print_on(outputStream* st) const { // ======= JavaThread ======== +#if INCLUDE_JVMCI + +jlong* JavaThread::_jvmci_old_thread_counters; + +bool jvmci_counters_include(JavaThread* thread) { + oop threadObj = thread->threadObj(); + return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread(); +} + +void JavaThread::collect_counters(typeArrayOop array) { + if (JVMCICounterSize > 0) { + MutexLocker tl(Threads_lock); + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, _jvmci_old_thread_counters[i]); + } + for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { + if (jvmci_counters_include(tp)) { + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, array->long_at(i) + tp->_jvmci_counters[i]); + } + } + } + } +} + +#endif // INCLUDE_JVMCI + // A JavaThread is a normal Java thread void JavaThread::initialize() { @@ -1418,6 +1450,20 @@ void JavaThread::initialize() { _in_deopt_handler = 0; _doing_unsafe_access = false; _stack_guard_state = stack_guard_unused; +#if INCLUDE_JVMCI + _pending_monitorenter = false; + _pending_deoptimization = -1; + _pending_failed_speculation = NULL; + _pending_transfer_to_interpreter = false; + _jvmci._alternate_call_target = NULL; + assert(_jvmci._implicit_exception_pc == NULL, "must be"); + if (JVMCICounterSize > 0) { + _jvmci_counters = NEW_C_HEAP_ARRAY(jlong, JVMCICounterSize, mtInternal); + memset(_jvmci_counters, 0, sizeof(jlong) * JVMCICounterSize); + } else { + _jvmci_counters = NULL; + } +#endif // INCLUDE_JVMCI (void)const_cast(_exception_oop = oop(NULL)); _exception_pc = 0; _exception_handler_pc = 0; @@ -1592,6 +1638,17 @@ JavaThread::~JavaThread() { ThreadSafepointState::destroy(this); if (_thread_profiler != NULL) delete _thread_profiler; if (_thread_stat != NULL) delete _thread_stat; + +#if INCLUDE_JVMCI + if (JVMCICounterSize > 0) { + if (jvmci_counters_include(this)) { + for (int i = 0; i < JVMCICounterSize; i++) { + _jvmci_old_thread_counters[i] += _jvmci_counters[i]; + } + } + FREE_C_HEAP_ARRAY(jlong, _jvmci_counters); + } +#endif // INCLUDE_JVMCI } @@ -2039,10 +2096,10 @@ void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) { if (TraceExceptions) { ResourceMark rm; - tty->print("Async. exception installed at runtime exit (" INTPTR_FORMAT ")", this); + tty->print("Async. exception installed at runtime exit (" INTPTR_FORMAT ")", p2i(this)); if (has_last_Java_frame()) { frame f = last_frame(); - tty->print(" (pc: " INTPTR_FORMAT " sp: " INTPTR_FORMAT " )", f.pc(), f.sp()); + tty->print(" (pc: " INTPTR_FORMAT " sp: " INTPTR_FORMAT " )", p2i(f.pc()), p2i(f.sp())); } tty->print_cr(" of type: %s", InstanceKlass::cast(_pending_async_exception->klass())->external_name()); } @@ -2135,7 +2192,7 @@ void JavaThread::send_thread_stop(oop java_throwable) { // Do not throw asynchronous exceptions against the compiler thread // (the compiler thread should not be a Java thread -- fix in 1.4.2) - if (is_Compiler_thread()) return; + if (!can_call_java()) return; { // Actually throw the Throwable against the target Thread - however @@ -2165,7 +2222,7 @@ void JavaThread::send_thread_stop(oop java_throwable) { tty->print_cr("Pending Async. exception installed of type: %s", InstanceKlass::cast(_pending_async_exception->klass())->external_name()); } // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort(InstanceKlass::cast(_pending_async_exception->klass())->external_name())); + Exceptions::debug_check_abort(InstanceKlass::cast(_pending_async_exception->klass())->external_name()); } } @@ -2614,12 +2671,6 @@ void JavaThread::deoptimized_wrt_marked_nmethods() { StackFrameStream fst(this, UseBiasedLocking); for (; !fst.is_done(); fst.next()) { if (fst.current()->should_be_deoptimized()) { - if (LogCompilation && xtty != NULL) { - nmethod* nm = fst.current()->cb()->as_nmethod_or_null(); - xtty->elem("deoptimized thread='" UINTX_FORMAT "' compile_id='%d'", - this->name(), nm != NULL ? nm->compile_id() : -1); - } - Deoptimization::deoptimize(this, *fst.current(), fst.register_map()); } } @@ -2658,6 +2709,8 @@ void JavaThread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) // Traverse the GCHandles Thread::oops_do(f, cld_f, cf); + JVMCI_ONLY(f->do_oop((oop*)&_pending_failed_speculation);) + assert((!has_last_Java_frame() && java_call_counter() == 0) || (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!"); @@ -2809,7 +2862,7 @@ void JavaThread::print_on_error(outputStream* st, char *buf, int buflen) const { st->print(", id=%d", osthread()->thread_id()); } st->print(", stack(" PTR_FORMAT "," PTR_FORMAT ")", - _stack_base - _stack_size, _stack_base); + p2i(_stack_base - _stack_size), p2i(_stack_base)); st->print("]"); return; } @@ -3047,15 +3100,15 @@ class PrintAndVerifyOopClosure: public OopClosure { template inline void do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); if (obj == NULL) return; - tty->print(INTPTR_FORMAT ": ", p); + tty->print(INTPTR_FORMAT ": ", p2i(p)); if (obj->is_oop_or_null()) { if (obj->is_objArray()) { - tty->print_cr("valid objArray: " INTPTR_FORMAT, (oopDesc*) obj); + tty->print_cr("valid objArray: " INTPTR_FORMAT, p2i(obj)); } else { obj->print(); } } else { - tty->print_cr("invalid oop: " INTPTR_FORMAT, (oopDesc*) obj); + tty->print_cr("invalid oop: " INTPTR_FORMAT, p2i(obj)); } tty->cr(); } @@ -3175,6 +3228,10 @@ CompilerThread::CompilerThread(CompileQueue* queue, #endif } +bool CompilerThread::can_call_java() const { + return _compiler != NULL && _compiler->is_jvmci(); +} + // Create sweeper thread CodeCacheSweeperThread::CodeCacheSweeperThread() : JavaThread(&sweeper_thread_entry) { @@ -3306,6 +3363,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // Initialize the os module before using TLS os::init(); + // Record VM creation timing statistics + TraceVmCreationTime create_vm_timer; + create_vm_timer.start(); + // Initialize system properties. Arguments::init_system_properties(); @@ -3315,6 +3376,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // Update/Initialize System properties after JDK version number is known Arguments::init_version_specific_system_properties(); + // Make sure to initialize log configuration *before* parsing arguments + LogConfiguration::initialize(create_vm_timer.begin_time()); + // Parse arguments jint parse_result = Arguments::parse(args); if (parse_result != JNI_OK) return parse_result; @@ -3341,10 +3405,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { HOTSPOT_VM_INIT_BEGIN(); - // Record VM creation timing statistics - TraceVmCreationTime create_vm_timer; - create_vm_timer.start(); - // Timing (must come after argument parsing) TraceTime timer("Create VM", TraceStartupTime); @@ -3380,6 +3440,15 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // Initialize global data structures and create system classes in heap vm_init_globals(); +#if INCLUDE_JVMCI + if (JVMCICounterSize > 0) { + JavaThread::_jvmci_old_thread_counters = NEW_C_HEAP_ARRAY(jlong, JVMCICounterSize, mtInternal); + memset(JavaThread::_jvmci_old_thread_counters, 0, sizeof(jlong) * JVMCICounterSize); + } else { + JavaThread::_jvmci_old_thread_counters = NULL; + } +#endif // INCLUDE_JVMCI + // Attach the main thread to this os thread JavaThread* main_thread = new JavaThread(); main_thread->set_thread_state(_thread_in_vm); @@ -3492,6 +3561,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // debug stuff, that does not work until all basic classes have been initialized. set_init_completed(); + LogConfiguration::post_initialize(); Metaspace::post_initialize(); HOTSPOT_VM_INIT_END(); @@ -3506,7 +3576,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // Note that we do not use CHECK_0 here since we are inside an EXCEPTION_MARK and // set_init_completed has just been called, causing exceptions not to be shortcut // anymore. We call vm_exit_during_initialization directly instead. - SystemDictionary::compute_java_system_loader(CHECK_JNI_ERR); + SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR)); #if INCLUDE_ALL_GCS // Support for ConcurrentMarkSweep. This should be cleaned up @@ -3554,8 +3624,17 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { Chunk::start_chunk_pool_cleaner_task(); } +#if INCLUDE_JVMCI + if (EnableJVMCI) { + const char* jvmciCompiler = Arguments::PropertyList_get_value(Arguments::system_properties(), "jvmci.compiler"); + if (jvmciCompiler != NULL) { + JVMCIRuntime::save_compiler(jvmciCompiler); + } + } +#endif // INCLUDE_JVMCI + // initialize compiler(s) -#if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI CompileBroker::compilation_init(); #endif @@ -3963,9 +4042,17 @@ bool Threads::destroy_vm() { delete thread; +#if INCLUDE_JVMCI + if (JVMCICounterSize > 0) { + FREE_C_HEAP_ARRAY(jlong, JavaThread::_jvmci_old_thread_counters); + } +#endif + // exit_globals() will delete tty exit_globals(); + LogConfiguration::finalize(); + return true; } @@ -4007,7 +4094,7 @@ void Threads::add(JavaThread* p, bool force_daemon) { ThreadService::add_thread(p, daemon); // Possible GC point. - Events::log(p, "Thread added: " INTPTR_FORMAT, p); + Events::log(p, "Thread added: " INTPTR_FORMAT, p2i(p)); } void Threads::remove(JavaThread* p) { @@ -4053,7 +4140,7 @@ void Threads::remove(JavaThread* p) { } // unlock Threads_lock // Since Events::log uses a lock, we grab it outside the Threads_lock - Events::log(p, "Thread exited: " INTPTR_FORMAT, p); + Events::log(p, "Thread exited: " INTPTR_FORMAT, p2i(p)); } // Threads_lock must be held when this is called (or must be called during a safepoint) @@ -4096,7 +4183,7 @@ void Threads::assert_all_threads_claimed() { ALL_JAVA_THREADS(p) { const int thread_parity = p->oops_do_parity(); assert((thread_parity == _thread_claim_parity), - err_msg("Thread " PTR_FORMAT " has incorrect parity %d != %d", p2i(p), thread_parity, _thread_claim_parity)); + "Thread " PTR_FORMAT " has incorrect parity %d != %d", p2i(p), thread_parity, _thread_claim_parity); } } #endif // ASSERT @@ -4179,7 +4266,7 @@ GrowableArray* Threads::get_pending_threads(int count, { MutexLockerEx ml(doLock ? Threads_lock : NULL); ALL_JAVA_THREADS(p) { - if (p->is_Compiler_thread()) continue; + if (!p->can_call_java()) continue; address pending = (address)p->current_pending_monitor(); if (pending == monitor) { // found a match @@ -4236,7 +4323,7 @@ JavaThread *Threads::owning_thread_from_monitor_owner(address owner, void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format, bool print_concurrent_locks) { char buf[32]; - st->print_cr("%s", os::local_time_string(buf, sizeof(buf))); + st->print_raw_cr(os::local_time_string(buf, sizeof(buf))); st->print_cr("Full thread dump %s (%s %s):", Abstract_VM_Version::vm_name(), @@ -4296,7 +4383,7 @@ void Threads::print_on_error(outputStream* st, Thread* current, char* buf, st->print("%s", is_current ? "=>" : " "); - st->print(PTR_FORMAT, thread); + st->print(PTR_FORMAT, p2i(thread)); st->print(" "); thread->print_on_error(st, buf, buflen); st->cr(); @@ -4309,7 +4396,7 @@ void Threads::print_on_error(outputStream* st, Thread* current, char* buf, found_current = found_current || is_current; st->print("%s", current == VMThread::vm_thread() ? "=>" : " "); - st->print(PTR_FORMAT, VMThread::vm_thread()); + st->print(PTR_FORMAT, p2i(VMThread::vm_thread())); st->print(" "); VMThread::vm_thread()->print_on_error(st, buf, buflen); st->cr(); @@ -4320,14 +4407,14 @@ void Threads::print_on_error(outputStream* st, Thread* current, char* buf, found_current = found_current || is_current; st->print("%s", is_current ? "=>" : " "); - st->print(PTR_FORMAT, wt); + st->print(PTR_FORMAT, p2i(wt)); st->print(" "); wt->print_on_error(st, buf, buflen); st->cr(); } if (!found_current) { st->cr(); - st->print("=>" PTR_FORMAT " (exited) ", current); + st->print("=>" PTR_FORMAT " (exited) ", p2i(current)); current->print_on_error(st, buf, buflen); st->cr(); } diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index 087952002ad..2c0411d8f26 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -329,6 +329,9 @@ class Thread: public ThreadShadow { virtual bool is_Named_thread() const { return false; } virtual bool is_Worker_thread() const { return false; } + // Can this thread make Java upcalls + virtual bool can_call_java() const { return false; } + // Casts virtual WorkerThread* as_Worker_thread() const { return NULL; } @@ -678,6 +681,7 @@ class NamedThread: public Thread { char* _name; // log JavaThread being processed by oops_do JavaThread* _processed_thread; + uint _gc_id; // The current GC id when a thread takes part in GC public: NamedThread(); @@ -690,6 +694,9 @@ class NamedThread: public Thread { JavaThread *processed_thread() { return _processed_thread; } void set_processed_thread(JavaThread *thread) { _processed_thread = thread; } virtual void print_on(outputStream* st) const; + + void set_gc_id(uint gc_id) { _gc_id = gc_id; } + uint gc_id() { return _gc_id; } }; // Worker threads are named and have an id of an assigned work. @@ -900,6 +907,43 @@ class JavaThread: public Thread { private: +#if INCLUDE_JVMCI + // The _pending_* fields below are used to communicate extra information + // from an uncommon trap in JVMCI compiled code to the uncommon trap handler. + + // Communicates the DeoptReason and DeoptAction of the uncommon trap + int _pending_deoptimization; + + // Specifies whether the uncommon trap is to bci 0 of a synchronized method + // before the monitor has been acquired. + bool _pending_monitorenter; + + // Specifies if the DeoptReason for the last uncommon trap was Reason_transfer_to_interpreter + bool _pending_transfer_to_interpreter; + + // An object that JVMCI compiled code can use to further describe and + // uniquely identify the speculative optimization guarded by the uncommon trap + oop _pending_failed_speculation; + + // These fields are mutually exclusive in terms of live ranges. + union { + // Communicates the pc at which the most recent implicit exception occurred + // from the signal handler to a deoptimization stub. + address _implicit_exception_pc; + + // Communicates an alternative call target to an i2c stub from a JavaCall . + address _alternate_call_target; + } _jvmci; + + // Support for high precision, thread sensitive counters in JVMCI compiled code. + jlong* _jvmci_counters; + + public: + static jlong* _jvmci_old_thread_counters; + static void collect_counters(typeArrayOop array); + private: +#endif // INCLUDE_JVMCI + StackGuardState _stack_guard_state; // Precompute the limit of the stack as used in stack overflow checks. @@ -914,6 +958,7 @@ class JavaThread: public Thread { volatile address _exception_handler_pc; // PC for handler of exception volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site. + private: // support for JNI critical regions jint _jni_active_critical; // count of entries into JNI critical region @@ -1001,6 +1046,7 @@ class JavaThread: public Thread { // Testers virtual bool is_Java_thread() const { return true; } + virtual bool can_call_java() const { return true; } // Thread chain operations JavaThread* next() const { return _next; } @@ -1259,6 +1305,18 @@ class JavaThread: public Thread { MemRegion deferred_card_mark() const { return _deferred_card_mark; } void set_deferred_card_mark(MemRegion mr) { _deferred_card_mark = mr; } +#if INCLUDE_JVMCI + int pending_deoptimization() const { return _pending_deoptimization; } + oop pending_failed_speculation() const { return _pending_failed_speculation; } + bool has_pending_monitorenter() const { return _pending_monitorenter; } + void set_pending_monitorenter(bool b) { _pending_monitorenter = b; } + void set_pending_deoptimization(int reason) { _pending_deoptimization = reason; } + void set_pending_failed_speculation(oop failed_speculation) { _pending_failed_speculation = failed_speculation; } + void set_pending_transfer_to_interpreter(bool b) { _pending_transfer_to_interpreter = b; } + void set_jvmci_alternate_call_target(address a) { assert(_jvmci._alternate_call_target == NULL, "must be"); _jvmci._alternate_call_target = a; } + void set_jvmci_implicit_exception_pc(address a) { assert(_jvmci._implicit_exception_pc == NULL, "must be"); _jvmci._implicit_exception_pc = a; } +#endif // INCLUDE_JVMCI + // Exception handling for compiled methods oop exception_oop() const { return _exception_oop; } address exception_pc() const { return _exception_pc; } @@ -1359,6 +1417,14 @@ class JavaThread: public Thread { static ByteSize thread_state_offset() { return byte_offset_of(JavaThread, _thread_state); } static ByteSize saved_exception_pc_offset() { return byte_offset_of(JavaThread, _saved_exception_pc); } static ByteSize osthread_offset() { return byte_offset_of(JavaThread, _osthread); } +#if INCLUDE_JVMCI + static ByteSize pending_deoptimization_offset() { return byte_offset_of(JavaThread, _pending_deoptimization); } + static ByteSize pending_monitorenter_offset() { return byte_offset_of(JavaThread, _pending_monitorenter); } + static ByteSize pending_failed_speculation_offset() { return byte_offset_of(JavaThread, _pending_failed_speculation); } + static ByteSize jvmci_alternate_call_target_offset() { return byte_offset_of(JavaThread, _jvmci._alternate_call_target); } + static ByteSize jvmci_implicit_exception_pc_offset() { return byte_offset_of(JavaThread, _jvmci._implicit_exception_pc); } + static ByteSize jvmci_counters_offset() { return byte_offset_of(JavaThread, _jvmci_counters); } +#endif // INCLUDE_JVMCI static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } @@ -1828,8 +1894,11 @@ class CompilerThread : public JavaThread { CompilerThread(CompileQueue* queue, CompilerCounters* counters); bool is_Compiler_thread() const { return true; } - // Hide this compiler thread from external view. - bool is_hidden_from_external_view() const { return true; } + + virtual bool can_call_java() const; + + // Hide native compiler threads from external view. + bool is_hidden_from_external_view() const { return !can_call_java(); } void set_compiler(AbstractCompiler* c) { _compiler = c; } AbstractCompiler* compiler() const { return _compiler; } diff --git a/hotspot/src/share/vm/runtime/timer.cpp b/hotspot/src/share/vm/runtime/timer.cpp index 33131220bc7..0a869a43b8a 100644 --- a/hotspot/src/share/vm/runtime/timer.cpp +++ b/hotspot/src/share/vm/runtime/timer.cpp @@ -36,6 +36,22 @@ double TimeHelper::counter_to_millis(jlong counter) { return counter_to_seconds(counter) * 1000.0; } +elapsedTimer::elapsedTimer(jlong time, jlong timeUnitsPerSecond) { + _active = false; + jlong osTimeUnitsPerSecond = os::elapsed_frequency(); + assert(osTimeUnitsPerSecond % 1000 == 0, "must be"); + assert(timeUnitsPerSecond % 1000 == 0, "must be"); + while (osTimeUnitsPerSecond < timeUnitsPerSecond) { + timeUnitsPerSecond /= 1000; + time *= 1000; + } + while (osTimeUnitsPerSecond > timeUnitsPerSecond) { + timeUnitsPerSecond *= 1000; + time /= 1000; + } + _counter = time; +} + void elapsedTimer::add(elapsedTimer t) { _counter += t._counter; } diff --git a/hotspot/src/share/vm/runtime/timer.hpp b/hotspot/src/share/vm/runtime/timer.hpp index feba01eb9e3..bd003eb40e6 100644 --- a/hotspot/src/share/vm/runtime/timer.hpp +++ b/hotspot/src/share/vm/runtime/timer.hpp @@ -37,6 +37,7 @@ class elapsedTimer VALUE_OBJ_CLASS_SPEC { bool _active; public: elapsedTimer() { _active = false; reset(); } + elapsedTimer(jlong time, jlong timeUnitsPerSecond); void add(elapsedTimer t); void start(); void stop(); diff --git a/hotspot/src/share/vm/runtime/unhandledOops.cpp b/hotspot/src/share/vm/runtime/unhandledOops.cpp index 51452d661aa..2f9ced36dd5 100644 --- a/hotspot/src/share/vm/runtime/unhandledOops.cpp +++ b/hotspot/src/share/vm/runtime/unhandledOops.cpp @@ -31,8 +31,6 @@ #include "runtime/unhandledOops.hpp" #include "utilities/globalDefinitions.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef CHECK_UNHANDLED_OOPS const int free_list_size = 256; @@ -52,7 +50,7 @@ UnhandledOops::~UnhandledOops() { void UnhandledOops::dump_oops(UnhandledOops *list) { for (int k = 0; k < list->_oop_list->length(); k++) { UnhandledOopEntry entry = list->_oop_list->at(k); - tty->print(" " INTPTR_FORMAT, entry._oop_ptr); + tty->print(" " INTPTR_FORMAT, p2i(entry._oop_ptr)); } tty->cr(); } @@ -68,7 +66,7 @@ void UnhandledOops::register_unhandled_oop(oop* op, address pc) { _level ++; if (unhandled_oop_print) { for (int i=0; i<_level; i++) tty->print(" "); - tty->print_cr("r " INTPTR_FORMAT, op); + tty->print_cr("r " INTPTR_FORMAT, p2i(op)); } UnhandledOopEntry entry(op, pc); _oop_list->push(entry); @@ -105,7 +103,7 @@ void UnhandledOops::unregister_unhandled_oop(oop* op) { _level --; if (unhandled_oop_print) { for (int i=0; i<_level; i++) tty->print(" "); - tty->print_cr("u " INTPTR_FORMAT, op); + tty->print_cr("u " INTPTR_FORMAT, p2i(op)); } int i = _oop_list->find_from_end(op, match_oop_entry); @@ -122,9 +120,9 @@ void UnhandledOops::clear_unhandled_oops() { // anymore, it must not have gotten unregistered properly and it's a bug // in the unhandled oop generator. if(!_thread->is_in_stack((address)entry._oop_ptr)) { - tty->print_cr("oop_ptr is " INTPTR_FORMAT, (address)entry._oop_ptr); + tty->print_cr("oop_ptr is " INTPTR_FORMAT, p2i(entry._oop_ptr)); tty->print_cr("thread is " INTPTR_FORMAT " from pc " INTPTR_FORMAT, - (address)_thread, (address)entry._pc); + p2i(_thread), p2i(entry._pc)); assert(false, "heap is corrupted by the unhandled oop detector"); } // Set unhandled oops to a pattern that will crash distinctively diff --git a/hotspot/src/share/vm/runtime/vframe.cpp b/hotspot/src/share/vm/runtime/vframe.cpp index d0210ef58bf..a7e91173bea 100644 --- a/hotspot/src/share/vm/runtime/vframe.cpp +++ b/hotspot/src/share/vm/runtime/vframe.cpp @@ -46,8 +46,6 @@ #include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - vframe::vframe(const frame* fr, const RegisterMap* reg_map, JavaThread* thread) : _reg_map(reg_map), _thread(thread) { assert(fr != NULL, "must have frame"); @@ -146,7 +144,7 @@ GrowableArray* javaVFrame::locked_monitors() { void javaVFrame::print_locked_object_class_name(outputStream* st, Handle obj, const char* lock_state) { if (obj.not_null()) { - st->print("\t- %s <" INTPTR_FORMAT "> ", lock_state, (address)obj()); + st->print("\t- %s <" INTPTR_FORMAT "> ", lock_state, p2i(obj())); if (obj->klass() == SystemDictionary::Class_klass()) { st->print_cr("(a java.lang.Class for %s)", java_lang_Class::as_external_name(obj())); } else { @@ -186,7 +184,7 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) { } else if (thread()->current_park_blocker() != NULL) { oop obj = thread()->current_park_blocker(); Klass* k = obj->klass(); - st->print_cr("\t- %s <" INTPTR_FORMAT "> (a %s)", "parking to wait for ", (address)obj, k->external_name()); + st->print_cr("\t- %s <" INTPTR_FORMAT "> (a %s)", "parking to wait for ", p2i(obj), k->external_name()); } } @@ -400,7 +398,7 @@ StackValueCollection* interpretedVFrame::stack_data(bool expressions) const { InterpreterOopMap oop_mask; // oopmap for current bci - if (TraceDeoptimization && Verbose) { + if ((TraceDeoptimization && Verbose) JVMCI_ONLY( || PrintDeoptimizationDetails)) { methodHandle m_h(Thread::current(), method()); OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask); } else { @@ -493,7 +491,7 @@ vframeStream::vframeStream(JavaThread* thread, frame top_frame, // This function is used in Class.forName, Class.newInstance, Method.Invoke, // AccessController.doPrivileged. void vframeStreamCommon::security_get_caller_frame(int depth) { - assert(depth >= 0, err_msg("invalid depth: %d", depth)); + assert(depth >= 0, "invalid depth: %d", depth); for (int n = 0; !at_end(); security_next()) { if (!method()->is_ignored_by_security_stack_walk()) { if (n == depth) { @@ -583,7 +581,7 @@ void entryVFrame::print_value() const { void entryVFrame::print() { vframe::print(); tty->print_cr("C Chunk inbetween Java"); - tty->print_cr("C link " INTPTR_FORMAT, _fr.link()); + tty->print_cr("C link " INTPTR_FORMAT, p2i(_fr.link())); } @@ -620,7 +618,7 @@ void javaVFrame::print() { tty->print("( null )"); } else { monitor->owner()->print_value(); - tty->print("(owner=" INTPTR_FORMAT ")", (address)monitor->owner()); + tty->print("(owner=" INTPTR_FORMAT ")", p2i(monitor->owner())); } if (monitor->eliminated()) { if(is_compiled_frame()) { @@ -641,7 +639,7 @@ void javaVFrame::print_value() const { Method* m = method(); InstanceKlass* k = m->method_holder(); tty->print_cr("frame( sp=" INTPTR_FORMAT ", unextended_sp=" INTPTR_FORMAT ", fp=" INTPTR_FORMAT ", pc=" INTPTR_FORMAT ")", - _fr.sp(), _fr.unextended_sp(), _fr.fp(), _fr.pc()); + p2i(_fr.sp()), p2i(_fr.unextended_sp()), p2i(_fr.fp()), p2i(_fr.pc())); tty->print("%s.%s", k->internal_name(), m->name()->as_C_string()); if (!m->is_native()) { diff --git a/hotspot/src/share/vm/runtime/vframeArray.cpp b/hotspot/src/share/vm/runtime/vframeArray.cpp index d3e989e59e2..29be4e4e4bd 100644 --- a/hotspot/src/share/vm/runtime/vframeArray.cpp +++ b/hotspot/src/share/vm/runtime/vframeArray.cpp @@ -44,8 +44,6 @@ #include "opto/runtime.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - int vframeArrayElement:: bci(void) const { return (_bci == SynchronizationEntryBCI ? 0 : _bci); } void vframeArrayElement::free_monitors(JavaThread* jt) { @@ -294,7 +292,7 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, _frame.patch_pc(thread, pc); - assert (!method()->is_synchronized() || locks > 0 || _removed_monitors, "synchronized methods must have monitors"); + assert (!method()->is_synchronized() || locks > 0 || _removed_monitors || raw_bci() == SynchronizationEntryBCI, "synchronized methods must have monitors"); BasicObjectLock* top = iframe()->interpreter_frame_monitor_begin(); for (int index = 0; index < locks; index++) { @@ -317,6 +315,10 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, } } + if (PrintDeoptimizationDetails) { + tty->print_cr("Expressions size: %d", expressions()->size()); + } + // Unpack expression stack // If this is an intermediate frame (i.e. not top frame) then this // only unpacks the part of the expression stack not used by callee @@ -329,9 +331,26 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, switch(value->type()) { case T_INT: *addr = value->get_int(); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print_cr("Reconstructed expression %d (INT): %d", i, (int)(*addr)); + } +#endif break; case T_OBJECT: *addr = value->get_int(T_OBJECT); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print("Reconstructed expression %d (OBJECT): ", i); + oop o = (oop)(address)(*addr); + if (o == NULL) { + tty->print_cr("NULL"); + } else { + ResourceMark rm; + tty->print_raw_cr(o->klass()->name()->as_C_string()); + } + } +#endif break; case T_CONFLICT: // A dead stack slot. Initialize to null in case it is an oop. @@ -350,9 +369,26 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, switch(value->type()) { case T_INT: *addr = value->get_int(); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print_cr("Reconstructed local %d (INT): %d", i, (int)(*addr)); + } +#endif break; case T_OBJECT: *addr = value->get_int(T_OBJECT); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print("Reconstructed local %d (OBJECT): ", i); + oop o = (oop)(address)(*addr); + if (o == NULL) { + tty->print_cr("NULL"); + } else { + ResourceMark rm; + tty->print_raw_cr(o->klass()->name()->as_C_string()); + } + } +#endif break; case T_CONFLICT: // A dead location. If it is an oop then we need a NULL to prevent GC from following it @@ -394,7 +430,7 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, } #ifndef PRODUCT - if (TraceDeoptimization && Verbose) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; tty->print_cr("[%d Interpreted Frame]", ++unpack_counter); iframe()->print_on(tty); @@ -415,7 +451,7 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, int bci = method()->bci_from(bcp); tty->print(" - %s", Bytecodes::name(code)); tty->print(" @ bci %d ", bci); - tty->print_cr("sp = " PTR_FORMAT, iframe()->sp()); + tty->print_cr("sp = " PTR_FORMAT, p2i(iframe()->sp())); } #endif // PRODUCT @@ -605,7 +641,7 @@ address vframeArray::register_location(int i) const { // Note: we cannot have print_on as const, as we allocate inside the method void vframeArray::print_on_2(outputStream* st) { - st->print_cr(" - sp: " INTPTR_FORMAT, sp()); + st->print_cr(" - sp: " INTPTR_FORMAT, p2i(sp())); st->print(" - thread: "); Thread::current()->print(); st->print_cr(" - frame size: %d", frame_size()); @@ -615,7 +651,7 @@ void vframeArray::print_on_2(outputStream* st) { } void vframeArrayElement::print(outputStream* st) { - st->print_cr(" - interpreter_frame -> sp: " INTPTR_FORMAT, iframe()->sp()); + st->print_cr(" - interpreter_frame -> sp: " INTPTR_FORMAT, p2i(iframe()->sp())); } void vframeArray::print_value_on(outputStream* st) const { diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 23df8077b6a..2befdb2885d 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -55,7 +55,6 @@ #include "gc/shared/generation.hpp" #include "gc/shared/generationSpec.hpp" #include "gc/shared/space.hpp" -#include "gc/shared/watermark.hpp" #include "interpreter/bytecodeInterpreter.hpp" #include "interpreter/bytecodes.hpp" #include "interpreter/interpreter.hpp" @@ -107,6 +106,22 @@ #include "utilities/hashtable.hpp" #include "utilities/macros.hpp" +#ifdef TARGET_OS_FAMILY_linux +# include "vmStructs_linux.hpp" +#endif +#ifdef TARGET_OS_FAMILY_solaris +# include "vmStructs_solaris.hpp" +#endif +#ifdef TARGET_OS_FAMILY_windows +# include "vmStructs_windows.hpp" +#endif +#ifdef TARGET_OS_FAMILY_aix +# include "vmStructs_aix.hpp" +#endif +#ifdef TARGET_OS_FAMILY_bsd +# include "vmStructs_bsd.hpp" +#endif + #ifdef TARGET_ARCH_x86 # include "vmStructs_x86.hpp" #endif @@ -125,6 +140,7 @@ #ifdef TARGET_ARCH_aarch64 # include "vmStructs_aarch64.hpp" #endif + #ifdef TARGET_OS_ARCH_linux_x86 # include "vmStructs_linux_x86.hpp" #endif @@ -161,6 +177,7 @@ #ifdef TARGET_OS_ARCH_bsd_zero # include "vmStructs_bsd_zero.hpp" #endif + #if INCLUDE_ALL_GCS #include "gc/cms/compactibleFreeListSpace.hpp" #include "gc/cms/concurrentMarkSweepGeneration.hpp" @@ -178,6 +195,10 @@ #include "gc/parallel/vmStructs_parallelgc.hpp" #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI +# include "jvmci/vmStructs_jvmci.hpp" +#endif + #if INCLUDE_TRACE #include "runtime/vmStructs_trace.hpp" #endif @@ -311,6 +332,7 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(InstanceKlass, _static_oop_field_count, u2) \ nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \ nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \ + nonstatic_field(InstanceKlass, _misc_flags, u2) \ nonstatic_field(InstanceKlass, _minor_version, u2) \ nonstatic_field(InstanceKlass, _major_version, u2) \ nonstatic_field(InstanceKlass, _init_state, u1) \ @@ -382,8 +404,8 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(Method, _method_counters, MethodCounters*) \ nonstatic_field(Method, _access_flags, AccessFlags) \ nonstatic_field(Method, _vtable_index, int) \ - nonstatic_field(Method, _method_size, u2) \ nonstatic_field(Method, _intrinsic_id, u2) \ + nonstatic_field(Method, _flags, u1) \ nonproduct_nonstatic_field(Method, _compiled_invocation_count, int) \ volatile_nonstatic_field(Method, _code, nmethod*) \ nonstatic_field(Method, _i2i_entry, address) \ @@ -408,6 +430,7 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(Symbol, _identity_hash, short) \ nonstatic_field(Symbol, _length, unsigned short) \ unchecked_nonstatic_field(Symbol, _body, sizeof(jbyte)) /* NOTE: no type */ \ + nonstatic_field(Symbol, _body[0], jbyte) \ nonstatic_field(TypeArrayKlass, _max_length, int) \ \ /***********************/ \ @@ -470,6 +493,8 @@ typedef CompactHashtable SymbolCompactHashTable; static_field(Universe, _bootstrapping, bool) \ static_field(Universe, _fully_initialized, bool) \ static_field(Universe, _verify_count, int) \ + static_field(Universe, _verify_oop_mask, uintptr_t) \ + static_field(Universe, _verify_oop_bits, uintptr_t) \ static_field(Universe, _non_oop_bits, intptr_t) \ static_field(Universe, _narrow_oop._base, address) \ static_field(Universe, _narrow_oop._shift, int) \ @@ -489,6 +514,10 @@ typedef CompactHashtable SymbolCompactHashTable; \ unchecked_nonstatic_field(ageTable, sizes, sizeof(ageTable::sizes)) \ \ + nonstatic_field(BarrierSet, _fake_rtti, BarrierSet::FakeRtti) \ + \ + nonstatic_field(BarrierSet::FakeRtti, _concrete_tag, BarrierSet::Name) \ + \ nonstatic_field(BlockOffsetTable, _bottom, HeapWord*) \ nonstatic_field(BlockOffsetTable, _end, HeapWord*) \ \ @@ -504,7 +533,7 @@ typedef CompactHashtable SymbolCompactHashTable; \ nonstatic_field(BlockOffsetArrayNonContigSpace, _unallocated_block, HeapWord*) \ \ - nonstatic_field(CardGeneration, _rs, GenRemSet*) \ + nonstatic_field(CardGeneration, _rs, CardTableRS*) \ nonstatic_field(CardGeneration, _bts, BlockOffsetSharedArray*) \ nonstatic_field(CardGeneration, _shrink_factor, size_t) \ nonstatic_field(CardGeneration, _capacity_at_prologue, size_t) \ @@ -578,6 +607,7 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _pf_top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \ static_field(ThreadLocalAllocBuffer, _target_refills, unsigned) \ @@ -593,8 +623,6 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(VirtualSpace, _lower_high, char*) \ nonstatic_field(VirtualSpace, _middle_high, char*) \ nonstatic_field(VirtualSpace, _upper_high, char*) \ - nonstatic_field(WaterMark, _point, HeapWord*) \ - nonstatic_field(WaterMark, _space, Space*) \ \ /************************/ \ /* PerfMemory - jvmstat */ \ @@ -787,6 +815,8 @@ typedef CompactHashtable SymbolCompactHashTable; /********************************/ \ \ static_field(CodeCache, _heaps, GrowableArray*) \ + static_field(CodeCache, _low_bound, address) \ + static_field(CodeCache, _high_bound, address) \ static_field(CodeCache, _scavenge_root_nmethods, nmethod*) \ \ /*******************************/ \ @@ -832,16 +862,48 @@ typedef CompactHashtable SymbolCompactHashTable; static_field(StubRoutines, _ghash_processBlocks, address) \ static_field(StubRoutines, _updateBytesCRC32, address) \ static_field(StubRoutines, _crc_table_adr, address) \ + static_field(StubRoutines, _crc32c_table_addr, address) \ static_field(StubRoutines, _updateBytesCRC32C, address) \ static_field(StubRoutines, _multiplyToLen, address) \ static_field(StubRoutines, _squareToLen, address) \ static_field(StubRoutines, _mulAdd, address) \ + static_field(StubRoutines, _dexp, address) \ + static_field(StubRoutines, _jbyte_arraycopy, address) \ + static_field(StubRoutines, _jshort_arraycopy, address) \ + static_field(StubRoutines, _jint_arraycopy, address) \ + static_field(StubRoutines, _jlong_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _checkcast_arraycopy, address) \ + static_field(StubRoutines, _checkcast_arraycopy_uninit, address) \ + static_field(StubRoutines, _unsafe_arraycopy, address) \ + static_field(StubRoutines, _generic_arraycopy, address) \ \ /*****************/ \ /* SharedRuntime */ \ /*****************/ \ \ + static_field(SharedRuntime, _wrong_method_blob, RuntimeStub*) \ static_field(SharedRuntime, _ic_miss_blob, RuntimeStub*) \ + static_field(SharedRuntime, _deopt_blob, DeoptimizationBlob*) \ \ /***************************************/ \ /* PcDesc and other compiled code info */ \ @@ -856,16 +918,18 @@ typedef CompactHashtable SymbolCompactHashTable; /* CodeBlobs (NOTE: incomplete, but only a little) */ \ /***************************************************/ \ \ - nonstatic_field(CodeBlob, _name, const char*) \ - nonstatic_field(CodeBlob, _size, int) \ - nonstatic_field(CodeBlob, _header_size, int) \ - nonstatic_field(CodeBlob, _relocation_size, int) \ - nonstatic_field(CodeBlob, _content_offset, int) \ - nonstatic_field(CodeBlob, _code_offset, int) \ - nonstatic_field(CodeBlob, _frame_complete_offset, int) \ - nonstatic_field(CodeBlob, _data_offset, int) \ - nonstatic_field(CodeBlob, _frame_size, int) \ - nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \ + nonstatic_field(CodeBlob, _name, const char*) \ + nonstatic_field(CodeBlob, _size, int) \ + nonstatic_field(CodeBlob, _header_size, int) \ + nonstatic_field(CodeBlob, _relocation_size, int) \ + nonstatic_field(CodeBlob, _content_offset, int) \ + nonstatic_field(CodeBlob, _code_offset, int) \ + nonstatic_field(CodeBlob, _frame_complete_offset, int) \ + nonstatic_field(CodeBlob, _data_offset, int) \ + nonstatic_field(CodeBlob, _frame_size, int) \ + nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \ + \ + nonstatic_field(DeoptimizationBlob, _unpack_offset, int) \ \ nonstatic_field(RuntimeStub, _caller_must_gc_arguments, bool) \ \ @@ -905,6 +969,17 @@ typedef CompactHashtable SymbolCompactHashTable; \ unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \ \ + nonstatic_field(Deoptimization::UnrollBlock, _size_of_deoptimized_frame, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _caller_adjustment, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _number_of_frames, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _total_frame_sizes, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _frame_sizes, intptr_t*) \ + nonstatic_field(Deoptimization::UnrollBlock, _frame_pcs, address*) \ + nonstatic_field(Deoptimization::UnrollBlock, _register_block, intptr_t*) \ + nonstatic_field(Deoptimization::UnrollBlock, _return_type, BasicType) \ + nonstatic_field(Deoptimization::UnrollBlock, _initial_info, intptr_t) \ + nonstatic_field(Deoptimization::UnrollBlock, _caller_actual_parameters, int) \ + \ /********************************/ \ /* JavaCalls (NOTE: incomplete) */ \ /********************************/ \ @@ -1294,6 +1369,7 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(CompileTask, _osr_bci, int) \ nonstatic_field(CompileTask, _comp_level, int) \ nonstatic_field(CompileTask, _compile_id, uint) \ + nonstatic_field(CompileTask, _num_inlined_bytecodes, int) \ nonstatic_field(CompileTask, _next, CompileTask*) \ nonstatic_field(CompileTask, _prev, CompileTask*) \ \ @@ -1473,6 +1549,8 @@ typedef CompactHashtable SymbolCompactHashTable; declare_type(MethodCounters, MetaspaceObj) \ declare_type(ConstMethod, MetaspaceObj) \ \ + declare_toplevel_type(narrowKlass) \ + \ declare_toplevel_type(vtableEntry) \ \ declare_toplevel_type(Symbol) \ @@ -1527,8 +1605,7 @@ typedef CompactHashtable SymbolCompactHashTable; declare_type(CardTableModRefBS, ModRefBarrierSet) \ declare_type(CardTableModRefBSForCTRS, CardTableModRefBS) \ declare_toplevel_type(BarrierSet::Name) \ - declare_toplevel_type(GenRemSet) \ - declare_type(CardTableRS, GenRemSet) \ + declare_toplevel_type(CardTableRS) \ declare_toplevel_type(BlockOffsetSharedArray) \ declare_toplevel_type(BlockOffsetTable) \ declare_type(BlockOffsetArray, BlockOffsetTable) \ @@ -1544,7 +1621,6 @@ typedef CompactHashtable SymbolCompactHashTable; declare_toplevel_type(MemRegion) \ declare_toplevel_type(ThreadLocalAllocBuffer) \ declare_toplevel_type(VirtualSpace) \ - declare_toplevel_type(WaterMark) \ declare_toplevel_type(ObjPtrQueue) \ declare_toplevel_type(DirtyCardQueue) \ \ @@ -1552,7 +1628,6 @@ typedef CompactHashtable SymbolCompactHashTable; \ declare_toplevel_type(BarrierSet*) \ declare_toplevel_type(BlockOffsetSharedArray*) \ - declare_toplevel_type(GenRemSet*) \ declare_toplevel_type(CardTableRS*) \ declare_toplevel_type(CardTableModRefBS*) \ declare_toplevel_type(CardTableModRefBS**) \ @@ -1572,6 +1647,8 @@ typedef CompactHashtable SymbolCompactHashTable; declare_toplevel_type(TenuredGeneration*) \ declare_toplevel_type(ThreadLocalAllocBuffer*) \ \ + declare_toplevel_type(BarrierSet::FakeRtti) \ + \ /************************/ \ /* PerfMemory - jvmstat */ \ /************************/ \ @@ -1694,6 +1771,7 @@ typedef CompactHashtable SymbolCompactHashTable; declare_toplevel_type(Dependencies) \ declare_toplevel_type(CompileTask) \ declare_toplevel_type(Deoptimization) \ + declare_toplevel_type(Deoptimization::UnrollBlock) \ \ /************************/ \ /* OopMap and OopMapSet */ \ @@ -1991,7 +2069,6 @@ typedef CompactHashtable SymbolCompactHashTable; declare_c2_type(TanDNode, Node) \ declare_c2_type(AtanDNode, Node) \ declare_c2_type(SqrtDNode, Node) \ - declare_c2_type(ExpDNode, Node) \ declare_c2_type(LogDNode, Node) \ declare_c2_type(Log10DNode, Node) \ declare_c2_type(PowDNode, Node) \ @@ -2276,6 +2353,8 @@ typedef CompactHashtable SymbolCompactHashTable; \ declare_constant(CardTableRS::youngergen_card) \ \ + declare_constant(G1SATBCardTableModRefBS::g1_young_gen) \ + \ declare_constant(CollectedHeap::GenCollectedHeap) \ declare_constant(CollectedHeap::ParallelScavengeHeap) \ declare_constant(CollectedHeap::G1CollectedHeap) \ @@ -2334,6 +2413,36 @@ typedef CompactHashtable SymbolCompactHashTable; declare_constant(JVM_ACC_PROMOTED_FLAGS) \ declare_constant(JVM_ACC_FIELD_ACCESS_WATCHED) \ declare_constant(JVM_ACC_FIELD_MODIFICATION_WATCHED) \ + declare_constant(JVM_ACC_FIELD_INTERNAL) \ + declare_constant(JVM_ACC_FIELD_STABLE) \ + declare_constant(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) \ + \ + declare_constant(JVM_CONSTANT_Utf8) \ + declare_constant(JVM_CONSTANT_Unicode) \ + declare_constant(JVM_CONSTANT_Integer) \ + declare_constant(JVM_CONSTANT_Float) \ + declare_constant(JVM_CONSTANT_Long) \ + declare_constant(JVM_CONSTANT_Double) \ + declare_constant(JVM_CONSTANT_Class) \ + declare_constant(JVM_CONSTANT_String) \ + declare_constant(JVM_CONSTANT_Fieldref) \ + declare_constant(JVM_CONSTANT_Methodref) \ + declare_constant(JVM_CONSTANT_InterfaceMethodref) \ + declare_constant(JVM_CONSTANT_NameAndType) \ + declare_constant(JVM_CONSTANT_MethodHandle) \ + declare_constant(JVM_CONSTANT_MethodType) \ + declare_constant(JVM_CONSTANT_InvokeDynamic) \ + declare_constant(JVM_CONSTANT_ExternalMax) \ + \ + declare_constant(JVM_CONSTANT_Invalid) \ + declare_constant(JVM_CONSTANT_InternalMin) \ + declare_constant(JVM_CONSTANT_UnresolvedClass) \ + declare_constant(JVM_CONSTANT_ClassIndex) \ + declare_constant(JVM_CONSTANT_StringIndex) \ + declare_constant(JVM_CONSTANT_UnresolvedClassInError) \ + declare_constant(JVM_CONSTANT_MethodHandleInError) \ + declare_constant(JVM_CONSTANT_MethodTypeInError) \ + declare_constant(JVM_CONSTANT_InternalMax) \ \ /*****************************/ \ /* Thread::SuspendFlags enum */ \ @@ -2364,6 +2473,7 @@ typedef CompactHashtable SymbolCompactHashTable; /******************************/ \ \ declare_constant(Klass::_primary_super_limit) \ + declare_constant(Klass::_lh_neutral_value) \ declare_constant(Klass::_lh_instance_slow_path_bit) \ declare_constant(Klass::_lh_log2_element_size_shift) \ declare_constant(Klass::_lh_log2_element_size_mask) \ @@ -2385,6 +2495,10 @@ typedef CompactHashtable SymbolCompactHashTable; declare_constant(Method::_dont_inline) \ declare_constant(Method::_hidden) \ \ + declare_constant(Method::nonvirtual_vtable_index) \ + \ + declare_constant(Method::extra_stack_entries_for_jsr292) \ + \ declare_constant(ConstMethod::_has_linenumber_table) \ declare_constant(ConstMethod::_has_checked_exceptions) \ declare_constant(ConstMethod::_has_localvariable_table) \ @@ -2401,6 +2515,20 @@ typedef CompactHashtable SymbolCompactHashTable; /**************/ \ \ declare_constant(DataLayout::cell_size) \ + declare_constant(DataLayout::no_tag) \ + declare_constant(DataLayout::bit_data_tag) \ + declare_constant(DataLayout::counter_data_tag) \ + declare_constant(DataLayout::jump_data_tag) \ + declare_constant(DataLayout::receiver_type_data_tag) \ + declare_constant(DataLayout::virtual_call_data_tag) \ + declare_constant(DataLayout::ret_data_tag) \ + declare_constant(DataLayout::branch_data_tag) \ + declare_constant(DataLayout::multi_branch_data_tag) \ + declare_constant(DataLayout::arg_info_data_tag) \ + declare_constant(DataLayout::call_type_data_tag) \ + declare_constant(DataLayout::virtual_call_type_data_tag) \ + declare_constant(DataLayout::parameters_type_data_tag) \ + declare_constant(DataLayout::speculative_trap_data_tag) \ \ /*************************************/ \ /* InstanceKlass enum */ \ @@ -2454,13 +2582,14 @@ typedef CompactHashtable SymbolCompactHashTable; \ declare_constant(Symbol::max_symbol_length) \ \ - /*************************************************/ \ - /* ConstantPool* layout enum for InvokeDynamic */ \ - /*************************************************/ \ + /***********************************************/ \ + /* ConstantPool* layout enum for InvokeDynamic */ \ + /***********************************************/ \ \ - declare_constant(ConstantPool::_indy_bsm_offset) \ - declare_constant(ConstantPool::_indy_argc_offset) \ - declare_constant(ConstantPool::_indy_argv_offset) \ + declare_constant(ConstantPool::_indy_bsm_offset) \ + declare_constant(ConstantPool::_indy_argc_offset) \ + declare_constant(ConstantPool::_indy_argv_offset) \ + declare_constant(ConstantPool::CPCACHE_INDEX_TAG) \ \ /********************************/ \ /* ConstantPoolCacheEntry enums */ \ @@ -2555,6 +2684,18 @@ typedef CompactHashtable SymbolCompactHashTable; \ declare_constant(DEFAULT_CACHE_LINE_SIZE) \ \ + declare_constant(Deoptimization::Unpack_deopt) \ + declare_constant(Deoptimization::Unpack_exception) \ + declare_constant(Deoptimization::Unpack_uncommon_trap) \ + declare_constant(Deoptimization::Unpack_reexecute) \ + \ + declare_constant(Deoptimization::_action_bits) \ + declare_constant(Deoptimization::_reason_bits) \ + declare_constant(Deoptimization::_debug_id_bits) \ + declare_constant(Deoptimization::_action_shift) \ + declare_constant(Deoptimization::_reason_shift) \ + declare_constant(Deoptimization::_debug_id_shift) \ + \ /*********************/ \ /* Matcher (C2 only) */ \ /*********************/ \ @@ -2567,6 +2708,18 @@ typedef CompactHashtable SymbolCompactHashTable; \ declare_constant(InvocationEntryBci) \ \ + /*************/ \ + /* CompLevel */ \ + /*************/ \ + \ + declare_constant(CompLevel_any) \ + declare_constant(CompLevel_all) \ + declare_constant(CompLevel_none) \ + declare_constant(CompLevel_simple) \ + declare_constant(CompLevel_limited_profile) \ + declare_constant(CompLevel_full_profile) \ + declare_constant(CompLevel_full_optimization) \ + \ /***************/ \ /* OopMapValue */ \ /***************/ \ @@ -2581,7 +2734,6 @@ typedef CompactHashtable SymbolCompactHashTable; declare_constant(OopMapValue::register_mask_in_place) \ declare_constant(OopMapValue::unused_value) \ declare_constant(OopMapValue::oop_value) \ - declare_constant(OopMapValue::value_value) \ declare_constant(OopMapValue::narrowoop_value) \ declare_constant(OopMapValue::callee_saved_value) \ declare_constant(OopMapValue::derived_oop_value) \ @@ -2698,9 +2850,39 @@ typedef CompactHashtable SymbolCompactHashTable; /* Constants in markOop used by CMS. */ \ declare_constant(markOopDesc::cms_shift) \ declare_constant(markOopDesc::cms_mask) \ - declare_constant(markOopDesc::size_shift) + declare_constant(markOopDesc::size_shift) \ + \ + /* InvocationCounter constants */ \ + declare_constant(InvocationCounter::count_increment) \ + declare_constant(InvocationCounter::count_shift) +//-------------------------------------------------------------------------------- +// VM_ADDRESSES +// + +#define VM_ADDRESSES(declare_address, declare_preprocessor_address, declare_function) \ + \ + declare_function(SharedRuntime::register_finalizer) \ + declare_function(SharedRuntime::exception_handler_for_return_address) \ + declare_function(SharedRuntime::OSR_migration_end) \ + declare_function(SharedRuntime::dsin) \ + declare_function(SharedRuntime::dcos) \ + declare_function(SharedRuntime::dtan) \ + declare_function(SharedRuntime::dexp) \ + declare_function(SharedRuntime::dlog) \ + declare_function(SharedRuntime::dlog10) \ + declare_function(SharedRuntime::dpow) \ + \ + declare_function(os::dll_load) \ + declare_function(os::dll_lookup) \ + declare_function(os::javaTimeMillis) \ + declare_function(os::javaTimeNanos) \ + \ + declare_function(Deoptimization::fetch_unroll_info) \ + COMPILER2_PRESENT(declare_function(Deoptimization::uncommon_trap)) \ + declare_function(Deoptimization::unpack_frames) + //-------------------------------------------------------------------------------- // Macros operating on the above lists //-------------------------------------------------------------------------------- @@ -2932,6 +3114,23 @@ typedef CompactHashtable SymbolCompactHashTable; # define GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) #endif /* COMPILER1 */ +//-------------------------------------------------------------------------------- +// VMAddressEntry macros +// + +#define GENERATE_VM_ADDRESS_ENTRY(name) \ + { QUOTE(name), (void*) (name) }, + +#define GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY(name, value) \ + { name, (void*) (value) }, + +#define GENERATE_VM_FUNCTION_ENTRY(name) \ + { QUOTE(name), CAST_FROM_FN_PTR(void*, &(name)) }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_ADDRESS_LAST_ENTRY() \ + { NULL, NULL } + // // Instantiation of VMStructEntries, VMTypeEntries and VMIntConstantEntries // @@ -2950,6 +3149,11 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = { GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) +#if INCLUDE_JVMCI + VM_STRUCTS_JVMCI(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY) +#endif + #if INCLUDE_ALL_GCS VM_STRUCTS_PARALLELGC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) @@ -2970,6 +3174,15 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = { VM_STRUCTS_EXT(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) + VM_STRUCTS_OS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, + GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, @@ -3002,6 +3215,11 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { GENERATE_C2_VM_TYPE_ENTRY, GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) +#if INCLUDE_JVMCI + VM_TYPES_JVMCI(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY) +#endif + #if INCLUDE_ALL_GCS VM_TYPES_PARALLELGC(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) @@ -3023,6 +3241,15 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { VM_TYPES_EXT(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) + VM_TYPES_OS(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_OOP_VM_TYPE_ENTRY, + GENERATE_INTEGER_VM_TYPE_ENTRY, + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, + GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_C2_VM_TYPE_ENTRY, + GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + VM_TYPES_CPU(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_OOP_VM_TYPE_ENTRY, @@ -3052,6 +3279,12 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { GENERATE_C2_VM_INT_CONSTANT_ENTRY, GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) +#if INCLUDE_JVMCI + VM_INT_CONSTANTS_JVMCI(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + +#endif + #if INCLUDE_ALL_GCS VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY) @@ -3062,6 +3295,12 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { VM_INT_CONSTANTS_TRACE(GENERATE_VM_INT_CONSTANT_ENTRY) #endif + VM_INT_CONSTANTS_OS(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, + GENERATE_C1_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, GENERATE_C1_VM_INT_CONSTANT_ENTRY, @@ -3085,6 +3324,12 @@ VMLongConstantEntry VMStructs::localHotSpotVMLongConstants[] = { GENERATE_C2_VM_LONG_CONSTANT_ENTRY, GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + VM_LONG_CONSTANTS_OS(GENERATE_VM_LONG_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, + GENERATE_C1_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + VM_LONG_CONSTANTS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, GENERATE_C1_VM_LONG_CONSTANT_ENTRY, @@ -3100,6 +3345,25 @@ VMLongConstantEntry VMStructs::localHotSpotVMLongConstants[] = { GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() }; +VMAddressEntry VMStructs::localHotSpotVMAddresses[] = { + + VM_ADDRESSES(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) + + VM_ADDRESSES_OS(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) + +#if INCLUDE_JVMCI + VM_ADDRESSES_JVMCI(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) +#endif + + GENERATE_VM_ADDRESS_LAST_ENTRY() +}; + // This is used both to check the types of referenced fields and, in // debug builds, to ensure that all of the field types are present. void @@ -3308,6 +3572,11 @@ JNIEXPORT VMLongConstantEntry* gHotSpotVMLongConstants = VMStructs::localHot ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMLongConstantEntryNameOffset, VMLongConstantEntry, name); ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMLongConstantEntryValueOffset, VMLongConstantEntry, value); ASSIGN_STRIDE_TO_64BIT_VAR(gHotSpotVMLongConstantEntryArrayStride, gHotSpotVMLongConstants); + +JNIEXPORT VMAddressEntry* gHotSpotVMAddresses = VMStructs::localHotSpotVMAddresses; +ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMAddressEntryNameOffset, VMAddressEntry, name); +ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMAddressEntryValueOffset, VMAddressEntry, value); +ASSIGN_STRIDE_TO_64BIT_VAR(gHotSpotVMAddressEntryArrayStride, gHotSpotVMAddresses); } #ifdef ASSERT @@ -3415,6 +3684,11 @@ void VMStructs::test() { &long_last_entry, sizeof(VMLongConstantEntry)) == 0, "Incorrect last entry in localHotSpotVMLongConstants"); + static VMAddressEntry address_last_entry = GENERATE_VM_ADDRESS_LAST_ENTRY(); + assert(memcmp(&localHotSpotVMAddresses[sizeof(localHotSpotVMAddresses) / sizeof(VMAddressEntry) - 1], + &address_last_entry, + sizeof(VMAddressEntry)) == 0, "Incorrect last entry in localHotSpotVMAddresses"); + // Check for duplicate entries in type array for (int i = 0; localHotSpotVMTypes[i].typeName != NULL; i++) { diff --git a/hotspot/src/share/vm/runtime/vmStructs.hpp b/hotspot/src/share/vm/runtime/vmStructs.hpp index 5c4c93a1f77..369ff9e9426 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.hpp +++ b/hotspot/src/share/vm/runtime/vmStructs.hpp @@ -95,6 +95,11 @@ typedef struct { uint64_t value; // Value of constant } VMLongConstantEntry; +typedef struct { + const char* name; // Name of address (example: "SharedRuntime::register_finalizer") + void* value; // Value of address +} VMAddressEntry; + // This class is a friend of most classes, to be able to access // private fields class VMStructs { @@ -117,6 +122,11 @@ public: // the fact that it has a NULL typeName static VMLongConstantEntry localHotSpotVMLongConstants[]; + /** + * Table of addresses. + */ + static VMAddressEntry localHotSpotVMAddresses[]; + // This is used to run any checking code necessary for validation of // the data structure (debug build only) static void init(); diff --git a/hotspot/src/share/vm/runtime/vmThread.cpp b/hotspot/src/share/vm/runtime/vmThread.cpp index 927b25545f4..bb2e3a058a2 100644 --- a/hotspot/src/share/vm/runtime/vmThread.cpp +++ b/hotspot/src/share/vm/runtime/vmThread.cpp @@ -41,8 +41,6 @@ #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Dummy VM operation to act as first element in our circular double-linked list class VM_Dummy: public VM_Operation { VMOp_Type type() const { return VMOp_Dummy; } @@ -410,7 +408,7 @@ void VMThread::loop() { !_cur_vm_operation->evaluate_concurrently()) { long stall = os::javaTimeMillis() - _cur_vm_operation->timestamp(); if (stall > 0) - tty->print_cr("%s stall: %Ld", _cur_vm_operation->name(), stall); + tty->print_cr("%s stall: %ld", _cur_vm_operation->name(), stall); } while (!should_terminate() && _cur_vm_operation == NULL) { @@ -421,7 +419,7 @@ void VMThread::loop() { // Support for self destruction if ((SelfDestructTimer != 0) && !is_error_reported() && - (os::elapsedTime() > SelfDestructTimer * 60)) { + (os::elapsedTime() > (double)SelfDestructTimer * 60.0)) { tty->print_cr("VM self-destructed"); exit(-1); } @@ -630,8 +628,8 @@ void VMThread::execute(VM_Operation* op) { // Check the VM operation allows nested VM operation. This normally not the case, e.g., the compiler // does not allow nested scavenges or compiles. if (!prev_vm_operation->allow_nested_vm_operations()) { - fatal(err_msg("Nested VM operation %s requested by operation %s", - op->name(), vm_operation()->name())); + fatal("Nested VM operation %s requested by operation %s", + op->name(), vm_operation()->name()); } op->set_calling_thread(prev_vm_operation->calling_thread(), prev_vm_operation->priority()); } diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp index 75954adffd9..a760ccb80cc 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.cpp +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp @@ -42,8 +42,6 @@ #include "services/threadService.hpp" #include "trace/tracing.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #define VM_OP_NAME_INITIALIZE(name) #name, const char* VM_Operation::_names[VM_Operation::VMOp_Terminating] = \ @@ -79,14 +77,14 @@ const char* VM_Operation::mode_to_string(Mode mode) { } // Called by fatal error handler. void VM_Operation::print_on_error(outputStream* st) const { - st->print("VM_Operation (" PTR_FORMAT "): ", this); + st->print("VM_Operation (" PTR_FORMAT "): ", p2i(this)); st->print("%s", name()); const char* mode = mode_to_string(evaluation_mode()); st->print(", mode: %s", mode); if (calling_thread()) { - st->print(", requested by thread " PTR_FORMAT, calling_thread()); + st->print(", requested by thread " PTR_FORMAT, p2i(calling_thread())); } } @@ -117,14 +115,16 @@ void VM_MarkActiveNMethods::doit() { NMethodSweeper::mark_active_nmethods(); } -VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id) { +VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason) { _thread = thread; _id = id; + _reason = reason; } void VM_DeoptimizeFrame::doit() { - Deoptimization::deoptimize_frame_internal(_thread, _id); + assert(_reason > Deoptimization::Reason_none && _reason < Deoptimization::Reason_LIMIT, "invalid deopt reason"); + Deoptimization::deoptimize_frame_internal(_thread, _id, (Deoptimization::DeoptReason)_reason); } diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index 71f8a141cd5..ac53ea63913 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -272,7 +272,8 @@ class VM_DeoptimizeFrame: public VM_Operation { private: JavaThread* _thread; intptr_t* _id; - VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id); + int _reason; + VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason); public: VMOp_Type type() const { return VMOp_DeoptimizeFrame; } diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index d5f8683ef48..18cf83e2e2a 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.cpp @@ -85,7 +85,7 @@ bool Abstract_VM_Version::_parallel_worker_threads_initialized = false; #ifdef ASSERT static void assert_digits(const char * s, const char * message) { for (int i = 0; s[i] != '\0'; i++) { - assert(isdigit(s[i]), message); + assert(isdigit(s[i]), "%s", message); } } #endif @@ -154,7 +154,6 @@ const char* Abstract_VM_Version::vm_vendor() { #endif } - const char* Abstract_VM_Version::vm_info_string() { if (CodeCacheExtensions::use_pregenerated_interpreter()) { return "interpreted mode, pregenerated"; diff --git a/hotspot/src/share/vm/services/classLoadingService.cpp b/hotspot/src/share/vm/services/classLoadingService.cpp index 08c23c76182..1525188d1a7 100644 --- a/hotspot/src/share/vm/services/classLoadingService.cpp +++ b/hotspot/src/share/vm/services/classLoadingService.cpp @@ -182,7 +182,7 @@ bool ClassLoadingService::set_verbose(bool verbose) { // verbose will be set to the previous value Flag::Error error = CommandLineFlags::boolAtPut("TraceClassLoading", &verbose, Flag::MANAGEMENT); - assert(error==Flag::SUCCESS, err_msg("Setting TraceClassLoading flag failed with error %s", Flag::flag_error_str(error))); + assert(error==Flag::SUCCESS, "Setting TraceClassLoading flag failed with error %s", Flag::flag_error_str(error)); reset_trace_class_unloading(); return verbose; @@ -193,7 +193,7 @@ void ClassLoadingService::reset_trace_class_unloading() { assert(Management_lock->owned_by_self(), "Must own the Management_lock"); bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose(); Flag::Error error = CommandLineFlags::boolAtPut("TraceClassUnloading", &value, Flag::MANAGEMENT); - assert(error==Flag::SUCCESS, err_msg("Setting TraceClassUnLoading flag failed with error %s", Flag::flag_error_str(error))); + assert(error==Flag::SUCCESS, "Setting TraceClassUnLoading flag failed with error %s", Flag::flag_error_str(error)); } GrowableArray* LoadedClassesEnumerator::_loaded_classes = NULL; diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index 8c326cf73f5..11a14889b68 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -39,8 +39,6 @@ #include "utilities/macros.hpp" #include "oops/objArrayOop.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void DCmdRegistrant::register_dcmds(){ // Registration of the diagnostic commands // First argument specifies which interfaces will export the command @@ -695,12 +693,17 @@ void JMXStartRemoteDCmd::execute(DCmdSource source, TRAPS) { // command line with -D or by managmenent.properties // file. #define PUT_OPTION(a) \ - if ( (a).is_set() ){ \ - options.print(\ - ( *((a).type()) == 'I' ) ? "%scom.sun.management.%s=%d" : "%scom.sun.management.%s=%s",\ - comma, (a).name(), (a).value()); \ - comma[0] = ','; \ - } + do { \ + if ( (a).is_set() ){ \ + if ( *((a).type()) == 'I' ) { \ + options.print("%scom.sun.management.%s=" JLONG_FORMAT, comma, (a).name(), (jlong)((a).value())); \ + } else { \ + options.print("%scom.sun.management.%s=%s", comma, (a).name(), (char*)((a).value())); \ + } \ + comma[0] = ','; \ + }\ + } while(0); + PUT_OPTION(_config_file); PUT_OPTION(_jmxremote_port); diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp index 81f49cde2ae..937d909b6f4 100644 --- a/hotspot/src/share/vm/services/heapDumper.cpp +++ b/hotspot/src/share/vm/services/heapDumper.cpp @@ -724,7 +724,7 @@ void DumperSupport::dump_field_value(DumpWriter* writer, char type, address addr // reflection and sun.misc.Unsafe classes may have a reference to a // Klass* so filter it out. - assert(o->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(o))); + assert(o->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(o)); writer->write_objectID(o); break; } diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index 1a8dfbc86af..f47d3892301 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -58,8 +58,6 @@ #include "services/threadService.hpp" #include "utilities/macros.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - PerfVariable* Management::_begin_vm_creation_time = NULL; PerfVariable* Management::_end_vm_creation_time = NULL; PerfVariable* Management::_vm_init_done_time = NULL; @@ -752,7 +750,7 @@ JVM_ENTRY(jlong, jmm_SetPoolThreshold(JNIEnv* env, jobject obj, jmmThresholdType if ((size_t)threshold > max_uintx) { stringStream st; - st.print("Invalid valid threshold value. Threshold value (" UINT64_FORMAT ") > max value of size_t (" SIZE_FORMAT ")", (size_t)threshold, max_uintx); + st.print("Invalid valid threshold value. Threshold value (" JLONG_FORMAT ") > max value of size_t (" UINTX_FORMAT ")", threshold, max_uintx); THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), st.as_string(), -1); } diff --git a/hotspot/src/share/vm/services/management.hpp b/hotspot/src/share/vm/services/management.hpp index e9a21980dcd..139e44a811d 100644 --- a/hotspot/src/share/vm/services/management.hpp +++ b/hotspot/src/share/vm/services/management.hpp @@ -118,6 +118,10 @@ public: void start() { _timer.update_to(0); _begin_time = os::javaTimeMillis(); } + jlong begin_time() const { + return _begin_time; + } + /** * Only call this if initialization completes successfully; it will * crash if PerfMemory_exit() has already been called (usually by diff --git a/hotspot/src/share/vm/services/memoryService.cpp b/hotspot/src/share/vm/services/memoryService.cpp index 06fafdfeea1..dddea1589fe 100644 --- a/hotspot/src/share/vm/services/memoryService.cpp +++ b/hotspot/src/share/vm/services/memoryService.cpp @@ -518,7 +518,7 @@ bool MemoryService::set_verbose(bool verbose) { MutexLocker m(Management_lock); // verbose will be set to the previous value Flag::Error error = CommandLineFlags::boolAtPut("PrintGC", &verbose, Flag::MANAGEMENT); - assert(error==Flag::SUCCESS, err_msg("Setting PrintGC flag failed with error %s", Flag::flag_error_str(error))); + assert(error==Flag::SUCCESS, "Setting PrintGC flag failed with error %s", Flag::flag_error_str(error)); ClassLoadingService::reset_trace_class_unloading(); return verbose; diff --git a/hotspot/src/share/vm/services/nmtCommon.cpp b/hotspot/src/share/vm/services/nmtCommon.cpp index 0934e96dd7f..cffce8c7099 100644 --- a/hotspot/src/share/vm/services/nmtCommon.cpp +++ b/hotspot/src/share/vm/services/nmtCommon.cpp @@ -40,6 +40,7 @@ const char* NMTUtil::_memory_type_names[] = { "Arena Chunk", "Test", "Tracing", + "Logging", "Unknown" }; diff --git a/hotspot/src/share/vm/services/threadService.cpp b/hotspot/src/share/vm/services/threadService.cpp index 31dd8668190..0551deff70c 100644 --- a/hotspot/src/share/vm/services/threadService.cpp +++ b/hotspot/src/share/vm/services/threadService.cpp @@ -39,8 +39,6 @@ #include "runtime/vm_operations.hpp" #include "services/threadService.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // TODO: we need to define a naming convention for perf counters // to distinguish counters for: // - standard JSR174 use @@ -508,7 +506,7 @@ void StackFrameInfo::print_on(outputStream* st) const { for (int i = 0; i < len; i++) { oop o = _locked_monitors->at(i); InstanceKlass* ik = InstanceKlass::cast(o->klass()); - st->print_cr("\t- locked <" INTPTR_FORMAT "> (a %s)", (address)o, ik->external_name()); + st->print_cr("\t- locked <" INTPTR_FORMAT "> (a %s)", p2i(o), ik->external_name()); } } @@ -732,7 +730,7 @@ void ConcurrentLocksDump::print_locks_on(JavaThread* t, outputStream* st) { for (int i = 0; i < locks->length(); i++) { instanceOop obj = locks->at(i); InstanceKlass* ik = InstanceKlass::cast(obj->klass()); - st->print_cr("\t- <" INTPTR_FORMAT "> (a %s)", (address)obj, ik->external_name()); + st->print_cr("\t- <" INTPTR_FORMAT "> (a %s)", p2i(obj), ik->external_name()); } st->cr(); } @@ -885,10 +883,10 @@ void DeadlockCycle::print_on(outputStream* st) const { st->print_cr("\"%s\":", currentThread->get_thread_name()); const char* owner_desc = ",\n which is held by"; if (waitingToLockMonitor != NULL) { - st->print(" waiting to lock monitor " INTPTR_FORMAT, waitingToLockMonitor); + st->print(" waiting to lock monitor " INTPTR_FORMAT, p2i(waitingToLockMonitor)); oop obj = (oop)waitingToLockMonitor->object(); if (obj != NULL) { - st->print(" (object " INTPTR_FORMAT ", a %s)", (address)obj, + st->print(" (object " INTPTR_FORMAT ", a %s)", p2i(obj), (InstanceKlass::cast(obj->klass()))->external_name()); if (!currentThread->current_pending_monitor_is_from_java()) { @@ -907,12 +905,12 @@ void DeadlockCycle::print_on(outputStream* st) const { // if it is not findable, then the previous currentThread is // blocked permanently. st->print("%s UNKNOWN_owner_addr=" PTR_FORMAT, owner_desc, - (address)waitingToLockMonitor->owner()); + p2i(waitingToLockMonitor->owner())); continue; } } else { st->print(" waiting for ownable synchronizer " INTPTR_FORMAT ", (a %s)", - (address)waitingToLockBlocker, + p2i(waitingToLockBlocker), (InstanceKlass::cast(waitingToLockBlocker->klass()))->external_name()); assert(waitingToLockBlocker->is_a(SystemDictionary::abstract_ownable_synchronizer_klass()), "Must be an AbstractOwnableSynchronizer"); diff --git a/hotspot/src/share/vm/services/writeableFlags.cpp b/hotspot/src/share/vm/services/writeableFlags.cpp index 22454f8a041..4dda4b3e981 100644 --- a/hotspot/src/share/vm/services/writeableFlags.cpp +++ b/hotspot/src/share/vm/services/writeableFlags.cpp @@ -89,10 +89,7 @@ static void print_flag_error_message_if_needed(Flag::Error error, const char* na break; } - PRAGMA_DIAG_PUSH - PRAGMA_FORMAT_NONLITERAL_IGNORED_INTERNAL - err_msg.print(buffer); - PRAGMA_DIAG_POP + err_msg.print("%s", buffer); } // set a boolean global flag @@ -295,7 +292,8 @@ Flag::Error WriteableFlags::set_flag_from_char(Flag* f, const void* value, Flag: } // a writeable flag setter accepting 'jvalue' values -Flag::Error WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, + FormatBuffer<80>& err_msg) { jvalue new_value = *(jvalue*)value; if (f->is_bool()) { bool bvalue = (new_value.z == JNI_TRUE ? true : false); diff --git a/hotspot/src/share/vm/shark/sharkCacheDecache.cpp b/hotspot/src/share/vm/shark/sharkCacheDecache.cpp index 809322f9d40..b63ffeffac9 100644 --- a/hotspot/src/share/vm/shark/sharkCacheDecache.cpp +++ b/hotspot/src/share/vm/shark/sharkCacheDecache.cpp @@ -150,8 +150,10 @@ void SharkDecacher::process_local_slot(int index, void SharkDecacher::end_frame() { // Record the scope + methodHandle null_mh; debug_info()->describe_scope( pc_offset(), + null_mh, target(), bci(), true, diff --git a/hotspot/src/share/vm/utilities/array.hpp b/hotspot/src/share/vm/utilities/array.hpp index 3d575498f05..8df72304ef0 100644 --- a/hotspot/src/share/vm/utilities/array.hpp +++ b/hotspot/src/share/vm/utilities/array.hpp @@ -341,13 +341,13 @@ protected: assert(is_size_aligned(left, sizeof(T)), "Must be"); size_t elements = left / sizeof(T); - assert(elements <= (size_t)INT_MAX, err_msg("number of elements " SIZE_FORMAT "doesn't fit into an int.", elements)); + assert(elements <= (size_t)INT_MAX, "number of elements " SIZE_FORMAT "doesn't fit into an int.", elements); int length = (int)elements; assert((size_t)size(length) * BytesPerWord == bytes, - err_msg("Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, - bytes, (size_t)size(length) * BytesPerWord)); + "Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, + bytes, (size_t)size(length) * BytesPerWord); return length; } @@ -380,9 +380,9 @@ protected: // sort the array. bool contains(const T& x) const { return index_of(x) >= 0; } - T at(int i) const { assert(i >= 0 && i< _length, err_msg("oob: 0 <= %d < %d", i, _length)); return _data[i]; } - void at_put(const int i, const T& x) { assert(i >= 0 && i< _length, err_msg("oob: 0 <= %d < %d", i, _length)); _data[i] = x; } - T* adr_at(const int i) { assert(i >= 0 && i< _length, err_msg("oob: 0 <= %d < %d", i, _length)); return &_data[i]; } + T at(int i) const { assert(i >= 0 && i< _length, "oob: 0 <= %d < %d", i, _length); return _data[i]; } + void at_put(const int i, const T& x) { assert(i >= 0 && i< _length, "oob: 0 <= %d < %d", i, _length); _data[i] = x; } + T* adr_at(const int i) { assert(i >= 0 && i< _length, "oob: 0 <= %d < %d", i, _length); return &_data[i]; } int find(const T& x) { return index_of(x); } T at_acquire(const int which) { return OrderAccess::load_acquire(adr_at(which)); } diff --git a/hotspot/src/share/vm/utilities/chunkedList.hpp b/hotspot/src/share/vm/utilities/chunkedList.hpp index 06c5295b03c..e2ebaa512ed 100644 --- a/hotspot/src/share/vm/utilities/chunkedList.hpp +++ b/hotspot/src/share/vm/utilities/chunkedList.hpp @@ -73,7 +73,7 @@ template class ChunkedList : public CHeapObj { } T at(size_t i) { - assert(i < size(), err_msg("IOOBE i: " SIZE_FORMAT " size(): " SIZE_FORMAT, i, size())); + assert(i < size(), "IOOBE i: " SIZE_FORMAT " size(): " SIZE_FORMAT, i, size()); return _values[i]; } }; diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index 233921ec129..fa1c625d334 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -78,13 +78,11 @@ # endif #endif // PRODUCT -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - FormatBufferResource::FormatBufferResource(const char * format, ...) - : FormatBufferBase((char*)resource_allocate_bytes(RES_BUFSZ)) { + : FormatBufferBase((char*)resource_allocate_bytes(FormatBufferBase::BufferSize)) { va_list argp; va_start(argp, format); - jio_vsnprintf(_buf, RES_BUFSZ, format, argp); + jio_vsnprintf(_buf, FormatBufferBase::BufferSize, format, argp); va_end(argp); } @@ -207,26 +205,36 @@ bool error_is_suppressed(const char* file_name, int line_no) { #endif // !PRODUCT -void report_vm_error(const char* file, int line, const char* error_msg, - const char* detail_msg) +void report_vm_error(const char* file, int line, const char* error_msg) { - if (Debugging || error_is_suppressed(file, line)) return; - Thread* const thread = ThreadLocalStorage::get_thread_slow(); - VMError err(thread, file, line, error_msg, detail_msg); - err.report_and_die(); + report_vm_error(file, line, error_msg, "%s", ""); } -void report_fatal(const char* file, int line, const char* message) +void report_vm_error(const char* file, int line, const char* error_msg, const char* detail_fmt, ...) { - report_vm_error(file, line, "fatal error", message); + if (Debugging || error_is_suppressed(file, line)) return; + va_list detail_args; + va_start(detail_args, detail_fmt); + VMError::report_and_die(ThreadLocalStorage::get_thread_slow(), file, line, error_msg, detail_fmt, detail_args); + va_end(detail_args); +} + +void report_fatal(const char* file, int line, const char* detail_fmt, ...) +{ + if (Debugging || error_is_suppressed(file, line)) return; + va_list detail_args; + va_start(detail_args, detail_fmt); + VMError::report_and_die(ThreadLocalStorage::get_thread_slow(), file, line, "fatal error", detail_fmt, detail_args); + va_end(detail_args); } void report_vm_out_of_memory(const char* file, int line, size_t size, - VMErrorType vm_err_type, const char* message) { + VMErrorType vm_err_type, const char* detail_fmt, ...) { if (Debugging) return; - - Thread* thread = ThreadLocalStorage::get_thread_slow(); - VMError(thread, file, line, size, vm_err_type, message).report_and_die(); + va_list detail_args; + va_start(detail_args, detail_fmt); + VMError::report_and_die(ThreadLocalStorage::get_thread_slow(), file, line, size, vm_err_type, detail_fmt, detail_args); + va_end(detail_args); // The UseOSErrorReporting option in report_and_die() may allow a return // to here. If so then we'll have to figure out how to handle it. @@ -295,8 +303,7 @@ void report_java_out_of_memory(const char* message) { } if (OnOutOfMemoryError && OnOutOfMemoryError[0]) { - VMError err(message); - err.report_java_out_of_memory(); + VMError::report_java_out_of_memory(message); } } } @@ -365,22 +372,22 @@ void controlled_crash(int how) { char * const dataPtr = NULL; // bad data pointer const void (*funcPtr)(void) = (const void(*)()) 0xF; // bad function pointer - // Keep this in sync with test/runtime/6888954/vmerrors.sh. + // Keep this in sync with test/runtime/ErrorHandling/ErrorHandler.java switch (how) { case 1: vmassert(str == NULL, "expected null"); case 2: vmassert(num == 1023 && *str == 'X', - err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); + "num=" SIZE_FORMAT " str=\"%s\"", num, str); case 3: guarantee(str == NULL, "expected null"); case 4: guarantee(num == 1023 && *str == 'X', - err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); + "num=" SIZE_FORMAT " str=\"%s\"", num, str); case 5: fatal("expected null"); - case 6: fatal(err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); - case 7: fatal(err_msg("%s%s# %s%s# %s%s# %s%s# %s%s# " - "%s%s# %s%s# %s%s# %s%s# %s%s# " - "%s%s# %s%s# %s%s# %s%s# %s", - msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, - msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, - msg, eol, msg, eol, msg, eol, msg, eol, msg)); + case 6: fatal("num=" SIZE_FORMAT " str=\"%s\"", num, str); + case 7: fatal("%s%s# %s%s# %s%s# %s%s# %s%s# " + "%s%s# %s%s# %s%s# %s%s# %s%s# " + "%s%s# %s%s# %s%s# %s%s# %s", + msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, + msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, + msg, eol, msg, eol, msg, eol, msg, eol, msg); case 8: vm_exit_out_of_memory(num, OOM_MALLOC_ERROR, "ChunkPool::allocate"); case 9: ShouldNotCallThis(); case 10: ShouldNotReachHere(); @@ -515,7 +522,7 @@ extern "C" void pp(void* p) { oop obj = oop(p); obj->print(); } else { - tty->print(PTR_FORMAT, p); + tty->print(PTR_FORMAT, p2i(p)); } } @@ -550,7 +557,7 @@ extern "C" void ps() { // print stack frame f = os::current_frame(); RegisterMap reg_map(p); f = f.sender(®_map); - tty->print("(guessing starting frame id=%#p based on current fp)\n", f.id()); + tty->print("(guessing starting frame id=" PTR_FORMAT " based on current fp)\n", p2i(f.id())); p->trace_stack_from(vframe::new_vframe(&f, ®_map, p)); pd_ps(f); #endif // PRODUCT diff --git a/hotspot/src/share/vm/utilities/debug.hpp b/hotspot/src/share/vm/utilities/debug.hpp index 48551112260..64e587351d4 100644 --- a/hotspot/src/share/vm/utilities/debug.hpp +++ b/hotspot/src/share/vm/utilities/debug.hpp @@ -36,21 +36,21 @@ class FormatBufferBase { char* _buf; inline FormatBufferBase(char* buf) : _buf(buf) {} public: + static const int BufferSize = 256; operator const char *() const { return _buf; } }; // Use resource area for buffer -#define RES_BUFSZ 256 class FormatBufferResource : public FormatBufferBase { public: FormatBufferResource(const char * format, ...) ATTRIBUTE_PRINTF(2, 3); }; // Use stack for buffer -template +template class FormatBuffer : public FormatBufferBase { public: - inline FormatBuffer(const char * format, ...) ATTRIBUTE_PRINTF(2, 3); + inline FormatBuffer(const char* format, ...) ATTRIBUTE_PRINTF(2, 3); inline void append(const char* format, ...) ATTRIBUTE_PRINTF(2, 3); inline void print(const char* format, ...) ATTRIBUTE_PRINTF(2, 3); inline void printv(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0); @@ -105,27 +105,29 @@ void FormatBuffer::append(const char* format, ...) { va_end(argp); } -// Used to format messages for vmassert(), guarantee(), fatal(), etc. +// Used to format messages. typedef FormatBuffer<> err_msg; -typedef FormatBufferResource err_msg_res; // assertions #ifndef ASSERT -#define vmassert(p, msg) +#define vmassert(p, ...) #else // Note: message says "assert" rather than "vmassert" for backward // compatibility with tools that parse/match the message text. -#define vmassert(p, msg) \ -do { \ - if (!(p)) { \ - report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg); \ - BREAKPOINT; \ - } \ +// Note: The signature is vmassert(p, format, ...), but the solaris +// compiler can't handle an empty ellipsis in a macro without a warning. +#define vmassert(p, ...) \ +do { \ + if (!(p)) { \ + report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", __VA_ARGS__); \ + BREAKPOINT; \ + } \ } while (0) + #endif // For backward compatibility. -#define assert(p, msg) vmassert(p, msg) +#define assert(p, ...) vmassert(p, __VA_ARGS__) // This version of vmassert is for use with checking return status from // library calls that return actual error values eg. EINVAL, @@ -135,7 +137,7 @@ do { \ // an extra arg and use strerror to convert it to a meaningful string // like "Invalid argument", "out of memory" etc #define vmassert_status(p, status, msg) \ - vmassert(p, err_msg("error %s(%d), %s", strerror(status), status, msg)) + vmassert(p, "error %s(%d), %s", strerror(status), status, msg) // For backward compatibility. #define assert_status(p, status, msg) vmassert_status(p, status, msg) @@ -143,49 +145,49 @@ do { \ // guarantee is like vmassert except it's always executed -- use it for // cheap tests that catch errors that would otherwise be hard to find. // guarantee is also used for Verify options. -#define guarantee(p, msg) \ -do { \ - if (!(p)) { \ - report_vm_error(__FILE__, __LINE__, "guarantee(" #p ") failed", msg); \ - BREAKPOINT; \ - } \ +#define guarantee(p, ...) \ +do { \ + if (!(p)) { \ + report_vm_error(__FILE__, __LINE__, "guarantee(" #p ") failed", __VA_ARGS__); \ + BREAKPOINT; \ + } \ } while (0) -#define fatal(msg) \ -do { \ - report_fatal(__FILE__, __LINE__, msg); \ - BREAKPOINT; \ +#define fatal(...) \ +do { \ + report_fatal(__FILE__, __LINE__, __VA_ARGS__); \ + BREAKPOINT; \ } while (0) // out of memory -#define vm_exit_out_of_memory(size, vm_err_type, msg) \ -do { \ - report_vm_out_of_memory(__FILE__, __LINE__, size, vm_err_type, msg); \ - BREAKPOINT; \ +#define vm_exit_out_of_memory(size, vm_err_type, ...) \ +do { \ + report_vm_out_of_memory(__FILE__, __LINE__, size, vm_err_type, __VA_ARGS__); \ + BREAKPOINT; \ } while (0) -#define ShouldNotCallThis() \ -do { \ - report_should_not_call(__FILE__, __LINE__); \ - BREAKPOINT; \ +#define ShouldNotCallThis() \ +do { \ + report_should_not_call(__FILE__, __LINE__); \ + BREAKPOINT; \ } while (0) -#define ShouldNotReachHere() \ -do { \ - report_should_not_reach_here(__FILE__, __LINE__); \ - BREAKPOINT; \ +#define ShouldNotReachHere() \ +do { \ + report_should_not_reach_here(__FILE__, __LINE__); \ + BREAKPOINT; \ } while (0) -#define Unimplemented() \ -do { \ - report_unimplemented(__FILE__, __LINE__); \ - BREAKPOINT; \ +#define Unimplemented() \ +do { \ + report_unimplemented(__FILE__, __LINE__); \ + BREAKPOINT; \ } while (0) -#define Untested(msg) \ -do { \ - report_untested(__FILE__, __LINE__, msg); \ - BREAKPOINT; \ +#define Untested(msg) \ +do { \ + report_untested(__FILE__, __LINE__, msg); \ + BREAKPOINT; \ } while (0); @@ -197,11 +199,19 @@ enum VMErrorType { }; // error reporting helper functions +void report_vm_error(const char* file, int line, const char* error_msg); +#if !defined(__GNUC__) || defined (__clang_major__) || (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || __GNUC__ > 4) +// ATTRIBUTE_PRINTF works with gcc >= 4.8 and any other compiler. void report_vm_error(const char* file, int line, const char* error_msg, - const char* detail_msg = NULL); -void report_fatal(const char* file, int line, const char* message); -void report_vm_out_of_memory(const char* file, int line, size_t size, - VMErrorType vm_err_type, const char* message); + const char* detail_fmt, ...) ATTRIBUTE_PRINTF(4, 5); +#else +// GCC < 4.8 warns because of empty format string. Warning can not be switched off selectively. +void report_vm_error(const char* file, int line, const char* error_msg, + const char* detail_fmt, ...); +#endif +void report_fatal(const char* file, int line, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(3, 4); +void report_vm_out_of_memory(const char* file, int line, size_t size, VMErrorType vm_err_type, + const char* detail_fmt, ...) ATTRIBUTE_PRINTF(5, 6); void report_should_not_call(const char* file, int line); void report_should_not_reach_here(const char* file, int line); void report_unimplemented(const char* file, int line); diff --git a/hotspot/src/share/vm/utilities/exceptions.cpp b/hotspot/src/share/vm/utilities/exceptions.cpp index cf475036eee..0d5a12debb7 100644 --- a/hotspot/src/share/vm/utilities/exceptions.cpp +++ b/hotspot/src/share/vm/utilities/exceptions.cpp @@ -35,8 +35,6 @@ #include "utilities/events.hpp" #include "utilities/exceptions.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Implementation of ThreadShadow void check_ThreadShadow() { const ByteSize offset1 = byte_offset_of(ThreadShadow, _pending_exception); @@ -85,7 +83,7 @@ bool Exceptions::special_exception(Thread* thread, const char* file, int line, H #endif // ASSERT if (thread->is_VM_thread() - || thread->is_Compiler_thread() + || !thread->can_call_java() || DumpSharedSpaces ) { // We do not care what kind of exception we get for the vm-thread or a thread which // is compiling. We just install a dummy exception object @@ -112,7 +110,7 @@ bool Exceptions::special_exception(Thread* thread, const char* file, int line, S } if (thread->is_VM_thread() - || thread->is_Compiler_thread() + || !thread->can_call_java() || DumpSharedSpaces ) { // We do not care what kind of exception we get for the vm-thread or a thread which // is compiling. We just install a dummy exception object @@ -144,10 +142,10 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc "thrown [%s, line %d]\nfor thread " INTPTR_FORMAT, h_exception->print_value_string(), message ? ": " : "", message ? message : "", - (address)h_exception(), file, line, thread); + p2i(h_exception()), file, line, p2i(thread)); } // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort(h_exception, message)); + Exceptions::debug_check_abort(h_exception, message); // Check for special boot-strapping/vm-thread handling if (special_exception(thread, file, line, h_exception)) { @@ -167,7 +165,7 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc if (LogEvents){ Events::log_exception(thread, "Exception <%s%s%s> (" INTPTR_FORMAT ") thrown at [%s, line %d]", h_exception->print_value_string(), message ? ": " : "", message ? message : "", - (address)h_exception(), file, line); + p2i(h_exception()), file, line); } } @@ -479,28 +477,30 @@ ExceptionMark::~ExceptionMark() { // ---------------------------------------------------------------------------------------- -#ifndef PRODUCT // caller frees value_string if necessary void Exceptions::debug_check_abort(const char *value_string, const char* message) { if (AbortVMOnException != NULL && value_string != NULL && strstr(value_string, AbortVMOnException)) { - if (AbortVMOnExceptionMessage == NULL || message == NULL || - strcmp(message, AbortVMOnExceptionMessage) == 0) { - fatal(err_msg("Saw %s, aborting", value_string)); + if (AbortVMOnExceptionMessage == NULL || (message != NULL && + strstr(message, AbortVMOnExceptionMessage))) { + fatal("Saw %s, aborting", value_string); } } } void Exceptions::debug_check_abort(Handle exception, const char* message) { if (AbortVMOnException != NULL) { - ResourceMark rm; - if (message == NULL && exception->is_a(SystemDictionary::Throwable_klass())) { - oop msg = java_lang_Throwable::message(exception); - if (msg != NULL) { - message = java_lang_String::as_utf8_string(msg); - } - } - debug_check_abort(InstanceKlass::cast(exception()->klass())->external_name(), message); + debug_check_abort_helper(exception, message); } } -#endif + +void Exceptions::debug_check_abort_helper(Handle exception, const char* message) { + ResourceMark rm; + if (message == NULL && exception->is_a(SystemDictionary::Throwable_klass())) { + oop msg = java_lang_Throwable::message(exception); + if (msg != NULL) { + message = java_lang_String::as_utf8_string(msg); + } + } + debug_check_abort(InstanceKlass::cast(exception()->klass())->external_name(), message); +} diff --git a/hotspot/src/share/vm/utilities/exceptions.hpp b/hotspot/src/share/vm/utilities/exceptions.hpp index 79c87c57d04..6575090f1f4 100644 --- a/hotspot/src/share/vm/utilities/exceptions.hpp +++ b/hotspot/src/share/vm/utilities/exceptions.hpp @@ -174,8 +174,9 @@ class Exceptions { static void print_exception_counts_on_error(outputStream* st); // for AbortVMOnException flag - NOT_PRODUCT(static void debug_check_abort(Handle exception, const char* message = NULL);) - NOT_PRODUCT(static void debug_check_abort(const char *value_string, const char* message = NULL);) + static void debug_check_abort(Handle exception, const char* message = NULL); + static void debug_check_abort_helper(Handle exception, const char* message = NULL); + static void debug_check_abort(const char *value_string, const char* message = NULL); }; diff --git a/hotspot/src/share/vm/utilities/fakeRttiSupport.hpp b/hotspot/src/share/vm/utilities/fakeRttiSupport.hpp index e6a155aced4..42c42a3e242 100644 --- a/hotspot/src/share/vm/utilities/fakeRttiSupport.hpp +++ b/hotspot/src/share/vm/utilities/fakeRttiSupport.hpp @@ -50,6 +50,7 @@ // with. template class FakeRttiSupport VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; public: // Construct with the indicated concrete tag, and include the // concrete tag in the associated tag set. @@ -76,8 +77,8 @@ public: FakeRttiSupport add_tag(TagType tag) const { uintx tbit = tag_bit(tag); assert((_tag_set & tbit) == 0, - err_msg("Tag " UINTX_FORMAT " is already present in tag set: " UINTX_FORMAT, - (uintx)tag, _tag_set)); + "Tag " UINTX_FORMAT " is already present in tag set: " UINTX_FORMAT, + (uintx)tag, _tag_set); return FakeRttiSupport(_concrete_tag, _tag_set | tbit); } @@ -90,9 +91,9 @@ private: } static TagType validate_tag(TagType tag) { - assert(0 <= tag, err_msg("Tag " INTX_FORMAT " is negative", (intx)tag)); + assert(0 <= tag, "Tag " INTX_FORMAT " is negative", (intx)tag); assert(tag < BitsPerWord, - err_msg("Tag " UINTX_FORMAT " is too large", (uintx)tag)); + "Tag " UINTX_FORMAT " is too large", (uintx)tag); return tag; } }; diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.cpp b/hotspot/src/share/vm/utilities/globalDefinitions.cpp index 20c11862ead..8f8f3865c5a 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.cpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.cpp @@ -50,7 +50,7 @@ int LogMinObjAlignmentInBytes = -1; uint64_t OopEncodingHeapMax = 0; void basic_fatal(const char* msg) { - fatal(msg); + fatal("%s", msg); } // Something to help porters sleep at night diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 3b84a896101..5d8ea9b5129 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -60,9 +60,6 @@ #ifndef PRAGMA_FORMAT_NONLITERAL_IGNORED_EXTERNAL #define PRAGMA_FORMAT_NONLITERAL_IGNORED_EXTERNAL #endif -#ifndef PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC -#define PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC -#endif #ifndef ATTRIBUTE_PRINTF #define ATTRIBUTE_PRINTF(fmt, vargs) #endif @@ -903,20 +900,20 @@ enum CompLevel { CompLevel_simple = 1, // C1 CompLevel_limited_profile = 2, // C1, invocation & backedge counters CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo - CompLevel_full_optimization = 4, // C2 or Shark + CompLevel_full_optimization = 4, // C2, Shark or JVMCI -#if defined(COMPILER2) || defined(SHARK) - CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered +#if defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI + CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered or JVMCI and tiered #elif defined(COMPILER1) - CompLevel_highest_tier = CompLevel_simple, // pure C1 + CompLevel_highest_tier = CompLevel_simple, // pure C1 or JVMCI #else CompLevel_highest_tier = CompLevel_none, #endif #if defined(TIERED) CompLevel_initial_compile = CompLevel_full_profile // tiered -#elif defined(COMPILER1) - CompLevel_initial_compile = CompLevel_simple // pure C1 +#elif defined(COMPILER1) || INCLUDE_JVMCI + CompLevel_initial_compile = CompLevel_simple // pure C1 or JVMCI #elif defined(COMPILER2) || defined(SHARK) CompLevel_initial_compile = CompLevel_full_optimization // pure C2 #else @@ -1413,14 +1410,6 @@ template static void swap(T& a, T& b) { #define UINTX_FORMAT_W(width) "%" #width PRIuPTR -// Enable zap-a-lot if in debug version. - -# ifdef ASSERT -# ifdef COMPILER2 -# define ENABLE_ZAP_DEAD_LOCALS -#endif /* COMPILER2 */ -# endif /* ASSERT */ - #define ARRAY_SIZE(array) (sizeof(array)/sizeof((array)[0])) // Dereference vptr diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp index 286b2899783..5324d987f09 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp @@ -301,10 +301,6 @@ inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); } #define PRAGMA_FORMAT_NONLITERAL_IGNORED_INTERNAL #endif -#ifndef __clang_major__ -#define PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC _Pragma("GCC diagnostic ignored \"-Wformat\"") _Pragma("GCC diagnostic error \"-Wformat-nonliteral\"") _Pragma("GCC diagnostic error \"-Wformat-security\"") -#endif - #if (__GNUC__ == 2) && (__GNUC_MINOR__ < 95) #define TEMPLATE_TABLE_BUG #endif diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp index d855278bebc..6e8c0e17f7a 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp @@ -171,6 +171,12 @@ const jlong max_jlong = CONST64(0x7fffffffffffffff); #define strdup _strdup #endif +// Visual Studio 2013 introduced strtoull(); before, one has to use _strtoui64() instead. +#if _MSC_VER < 1800 +#define strtoull _strtoui64 +#endif + + #pragma warning( disable : 4100 ) // unreferenced formal parameter #pragma warning( disable : 4127 ) // conditional expression is constant #pragma warning( disable : 4514 ) // unreferenced inline function has been removed diff --git a/hotspot/src/share/vm/utilities/growableArray.hpp b/hotspot/src/share/vm/utilities/growableArray.hpp index 5d0ca20d052..e4a414a0cdc 100644 --- a/hotspot/src/share/vm/utilities/growableArray.hpp +++ b/hotspot/src/share/vm/utilities/growableArray.hpp @@ -374,6 +374,40 @@ template class GrowableArray : public GenericGrowableArray { void sort(int f(E*,E*), int stride) { qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f); } + + // Binary search and insertion utility. Search array for element + // matching key according to the static compare function. Insert + // that element is not already in the list. Assumes the list is + // already sorted according to compare function. + template E insert_sorted(E& key) { + bool found; + int location = find_sorted(key, found); + if (!found) { + insert_before(location, key); + } + return at(location); + } + + template int find_sorted(const K& key, bool& found) { + found = false; + int min = 0; + int max = length() - 1; + + while (max >= min) { + int mid = (max + min) / 2; + E value = at(mid); + int diff = compare(key, value); + if (diff > 0) { + min = mid + 1; + } else if (diff < 0) { + max = mid - 1; + } else { + found = true; + return mid; + } + } + return min; + } }; // Global GrowableArray methods (one instance in the library per each 'E' type). diff --git a/hotspot/src/share/vm/utilities/macros.hpp b/hotspot/src/share/vm/utilities/macros.hpp index 852190a2c07..ccdb90813b7 100644 --- a/hotspot/src/share/vm/utilities/macros.hpp +++ b/hotspot/src/share/vm/utilities/macros.hpp @@ -173,6 +173,20 @@ #define INCLUDE_TRACE 1 #endif // INCLUDE_TRACE +#ifndef INCLUDE_JVMCI +#define INCLUDE_JVMCI 1 +#endif + +#if INCLUDE_JVMCI +#define JVMCI_ONLY(code) code +#define NOT_JVMCI(code) +#define NOT_JVMCI_RETURN /* next token must be ; */ +#else +#define JVMCI_ONLY(code) +#define NOT_JVMCI(code) code +#define NOT_JVMCI_RETURN {} +#endif // INCLUDE_JVMCI + // COMPILER1 variant #ifdef COMPILER1 #ifdef COMPILER2 @@ -195,7 +209,7 @@ #ifdef TIERED #define TIERED_ONLY(code) code #define NOT_TIERED(code) -#else +#else // TIERED #define TIERED_ONLY(code) #define NOT_TIERED(code) code #endif // TIERED diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp index de44a359491..f0e127f4307 100644 --- a/hotspot/src/share/vm/utilities/ostream.cpp +++ b/hotspot/src/share/vm/utilities/ostream.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "compiler/compileLog.hpp" #include "gc/shared/gcId.hpp" +#include "gc/shared/gcId.hpp" #include "oops/oop.inline.hpp" #include "runtime/arguments.hpp" #include "runtime/os.hpp" @@ -238,11 +239,11 @@ void outputStream::date_stamp(bool guard, return; } -void outputStream::gclog_stamp(const GCId& gc_id) { +void outputStream::gclog_stamp() { date_stamp(PrintGCDateStamps); stamp(PrintGCTimeStamps); if (PrintGCID) { - print("#%u: ", gc_id.id()); + print("#%u: ", GCId::current()); } } @@ -543,7 +544,7 @@ void test_loggc_filename() { memset(longest_name, 'a', sizeof(longest_name)); longest_name[JVM_MAXPATHLEN - 1] = '\0'; o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); - assert(strcmp(longest_name, o_result) == 0, err_msg("longest name does not match. expected '%s' but got '%s'", longest_name, o_result)); + assert(strcmp(longest_name, o_result) == 0, "longest name does not match. expected '%s' but got '%s'", longest_name, o_result); FREE_C_HEAP_ARRAY(char, o_result); } @@ -554,7 +555,7 @@ void test_loggc_filename() { memset(too_long_name, 'a', too_long_length); too_long_name[too_long_length - 1] = '\0'; o_result = make_log_name_internal((const char*)&too_long_name, NULL, pid, tms); - assert(o_result == NULL, err_msg("Too long file name should return NULL, but got '%s'", o_result)); + assert(o_result == NULL, "Too long file name should return NULL, but got '%s'", o_result); } { @@ -565,7 +566,7 @@ void test_loggc_filename() { longest_name[JVM_MAXPATHLEN - 2] = 't'; longest_name[JVM_MAXPATHLEN - 1] = '\0'; o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); - assert(o_result == NULL, err_msg("Too long file name after timestamp expansion should return NULL, but got '%s'", o_result)); + assert(o_result == NULL, "Too long file name after timestamp expansion should return NULL, but got '%s'", o_result); } { @@ -576,7 +577,7 @@ void test_loggc_filename() { longest_name[JVM_MAXPATHLEN - 2] = 'p'; longest_name[JVM_MAXPATHLEN - 1] = '\0'; o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); - assert(o_result == NULL, err_msg("Too long file name after pid expansion should return NULL, but got '%s'", o_result)); + assert(o_result == NULL, "Too long file name after pid expansion should return NULL, but got '%s'", o_result); } } #endif // PRODUCT @@ -1440,3 +1441,14 @@ bool networkStream::connect(const char *ip, short port) { } #endif + +void logStream::write(const char* s, size_t len) { + if (len > 0 && s[len - 1] == '\n') { + _current_line.write(s, len - 1); + _log_func(_current_line.as_string()); + _current_line.reset(); + } else { + _current_line.write(s, len); + update_position(s, len); + } +} diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp index 29cc6b991f1..a9447b64c60 100644 --- a/hotspot/src/share/vm/utilities/ostream.hpp +++ b/hotspot/src/share/vm/utilities/ostream.hpp @@ -108,7 +108,7 @@ class outputStream : public ResourceObj { void date_stamp(bool guard) { date_stamp(guard, "", ": "); } - void gclog_stamp(const GCId& gc_id); + void gclog_stamp(); // portable printing of 64 bit integers void print_jlong(jlong value); @@ -235,6 +235,18 @@ class fdStream : public outputStream { void flush() {}; }; +class logStream : public outputStream { +private: + stringStream _current_line; + void (*_log_func)(const char* fmt, ...); +public: + void write(const char* s, size_t len); + logStream(void (*log_func)(const char* fmt, ...)) : _log_func(log_func) {} + ~logStream() { + guarantee(_current_line.size() == 0, "Buffer not flushed. Missing call to print_cr()?"); + } +}; + class gcLogFileStream : public fileStream { protected: const char* _file_name; diff --git a/hotspot/src/share/vm/utilities/top.hpp b/hotspot/src/share/vm/utilities/top.hpp index 2d294cc2e20..de26d52bc02 100644 --- a/hotspot/src/share/vm/utilities/top.hpp +++ b/hotspot/src/share/vm/utilities/top.hpp @@ -42,6 +42,9 @@ #ifdef COMPILER2 #include "opto/c2_globals.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmci_globals.hpp" +#endif // THIS FILE IS INTESIONALLY LEFT EMPTY // IT IS USED TO MINIMIZE THE NUMBER OF DEPENDENCIES IN includeDB diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index 10f7b0873cb..45cc47152f8 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" #include "compiler/compileBroker.hpp" +#include "compiler/disassembler.hpp" #include "gc/shared/collectedHeap.hpp" #include "prims/whitebox.hpp" #include "runtime/arguments.hpp" @@ -45,8 +46,6 @@ #include "utilities/top.hpp" #include "utilities/vmError.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // List of environment variables that should be reported in error log file. const char *env_list[] = { // All platforms @@ -71,108 +70,6 @@ const char *env_list[] = { (const char *)0 }; -// Fatal error handler for internal errors and crashes. -// -// The default behavior of fatal error handler is to print a brief message -// to standard out (defaultStream::output_fd()), then save detailed information -// into an error report file (hs_err_pid.log) and abort VM. If multiple -// threads are having troubles at the same time, only one error is reported. -// The thread that is reporting error will abort VM when it is done, all other -// threads are blocked forever inside report_and_die(). - -// Constructor for crashes -VMError::VMError(Thread* thread, unsigned int sig, address pc, void* siginfo, void* context) { - _thread = thread; - _id = sig; - _pc = pc; - _siginfo = siginfo; - _context = context; - - _verbose = false; - _current_step = 0; - _current_step_info = NULL; - - _message = NULL; - _detail_msg = NULL; - _filename = NULL; - _lineno = 0; - - _size = 0; -} - -// Constructor for internal errors -VMError::VMError(Thread* thread, const char* filename, int lineno, - const char* message, const char * detail_msg) -{ - _thread = thread; - _id = INTERNAL_ERROR; // Value that's not an OS exception/signal - _filename = filename; - _lineno = lineno; - _message = message; - _detail_msg = detail_msg; - - _verbose = false; - _current_step = 0; - _current_step_info = NULL; - - _pc = NULL; - _siginfo = NULL; - _context = NULL; - - _size = 0; -} - -// Constructor for OOM errors -VMError::VMError(Thread* thread, const char* filename, int lineno, size_t size, - VMErrorType vm_err_type, const char* message) { - _thread = thread; - _id = vm_err_type; // Value that's not an OS exception/signal - _filename = filename; - _lineno = lineno; - _message = message; - _detail_msg = NULL; - - _verbose = false; - _current_step = 0; - _current_step_info = NULL; - - _pc = NULL; - _siginfo = NULL; - _context = NULL; - - _size = size; -} - - -// Constructor for non-fatal errors -VMError::VMError(const char* message) { - _thread = NULL; - _id = INTERNAL_ERROR; // Value that's not an OS exception/signal - _filename = NULL; - _lineno = 0; - _message = message; - _detail_msg = NULL; - - _verbose = false; - _current_step = 0; - _current_step_info = NULL; - - _pc = NULL; - _siginfo = NULL; - _context = NULL; - - _size = 0; -} - -// -XX:OnError=, where can be a list of commands, separated -// by ';'. "%p" is replaced by current process id (pid); "%%" is replaced by -// a single "%". Some examples: -// -// -XX:OnError="pmap %p" // show memory map -// -XX:OnError="gcore %p; dbx - %p" // dump core and launch debugger -// -XX:OnError="cat hs_err_pid%p.log | mail my_email@sun.com" -// -XX:OnError="kill -9 %p" // ?#!@# - // A simple parser for -XX:OnError, usage: // ptr = OnError; // while ((cmd = next_OnError_command(buffer, sizeof(buffer), &ptr) != NULL) @@ -196,7 +93,6 @@ static char* next_OnError_command(char* buf, int buflen, const char** ptr) { return buf; } - static void print_bug_submit_message(outputStream *out, Thread *thread) { if (out == NULL) return; out->print_raw_cr("# If you would like to submit a bug report, please visit:"); @@ -223,7 +119,6 @@ void VMError::record_coredump_status(const char* message, bool status) { coredump_message[sizeof(coredump_message)-1] = 0; } - // Return a string to describe the error char* VMError::error_string(char* buf, int buflen) { char signame_buf[64]; @@ -243,9 +138,9 @@ char* VMError::error_string(char* buf, int buflen) { p ? p + 1 : _filename, _lineno, os::current_process_id(), os::current_thread_id()); if (n >= 0 && n < buflen && _message) { - if (_detail_msg) { + if (strlen(_detail_msg) > 0) { jio_snprintf(buf + n, buflen - n, "%s%s: %s", - os::line_separator(), _message, _detail_msg); + os::line_separator(), _message, _detail_msg); } else { jio_snprintf(buf + n, buflen - n, "%sError: %s", os::line_separator(), _message); @@ -357,7 +252,11 @@ const char* VMError::gc_mode() { // thread can report error, so large buffers are statically allocated in data // segment. -void VMError::report(outputStream* st) { +int VMError::_current_step; +const char* VMError::_current_step_info; + +void VMError::report(outputStream* st, bool _verbose) { + # define BEGIN if (_current_step == 0) { _current_step = 1; # define STEP(n, s) } if (_current_step < n) { _current_step = n; _current_step_info = s; # define END } @@ -384,14 +283,14 @@ void VMError::report(outputStream* st) { // error handler after a secondary crash works. STEP(20, "(test secondary crash 1)") if (_verbose && TestCrashInErrorHandler != 0) { - st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", + st->print_cr("Will crash now (TestCrashInErrorHandler=" UINTX_FORMAT ")...", TestCrashInErrorHandler); controlled_crash(TestCrashInErrorHandler); } STEP(30, "(test secondary crash 2)") if (_verbose && TestCrashInErrorHandler != 0) { - st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", + st->print_cr("Will crash now (TestCrashInErrorHandler=" UINTX_FORMAT ")...", TestCrashInErrorHandler); controlled_crash(TestCrashInErrorHandler); } @@ -429,15 +328,15 @@ void VMError::report(outputStream* st) { jio_snprintf(buf, sizeof(buf), SIZE_FORMAT, _size); st->print("%s", buf); st->print(" bytes"); - if (_message != NULL) { + if (strlen(_detail_msg) > 0) { st->print(" for "); - st->print("%s", _message); + st->print("%s", _detail_msg); } st->cr(); } else { - if (_message != NULL) { + if (strlen(_detail_msg) > 0) { st->print("# "); - st->print_cr("%s", _message); + st->print_cr("%s", _detail_msg); } } // In error file give some solutions @@ -460,7 +359,7 @@ void VMError::report(outputStream* st) { if (os::exception_name(_id, buf, sizeof(buf))) { st->print("%s", buf); st->print(" (0x%x)", _id); // signal number - st->print(" at pc=" PTR_FORMAT, _pc); + st->print(" at pc=" PTR_FORMAT, p2i(_pc)); } else { if (should_report_bug(_id)) { st->print("Internal Error"); @@ -493,12 +392,12 @@ void VMError::report(outputStream* st) { if (should_report_bug(_id)) { // already printed the message. // error message - if (_detail_msg) { + if (strlen(_detail_msg) > 0) { st->print_cr("# %s: %s", _message ? _message : "Error", _detail_msg); } else if (_message) { st->print_cr("# Error: %s", _message); } - } + } STEP(90, "(printing Java version string)") @@ -511,11 +410,17 @@ void VMError::report(outputStream* st) { JDK_Version::runtime_version() : ""; st->print_cr("# JRE version: %s (%s) (build %s)", runtime_name, buf, runtime_version); // This is the long version with some default settings added - st->print_cr("# Java VM: %s (%s, %s%s%s, %s, %s)", + st->print_cr("# Java VM: %s (%s, %s%s%s%s%s, %s, %s)", Abstract_VM_Version::vm_name(), Abstract_VM_Version::vm_release(), Abstract_VM_Version::vm_info_string(), TieredCompilation ? ", tiered" : "", +#if INCLUDE_JVMCI + EnableJVMCI ? ", jvmci" : "", + UseJVMCICompiler ? ", jvmci compiler" : "", +#else + "", "", +#endif UseCompressedOops ? ", compressed oops" : "", gc_mode(), Abstract_VM_Version::vm_platform_string() @@ -595,7 +500,7 @@ void VMError::report(outputStream* st) { // current thread if (_verbose) { if (_thread) { - st->print("Current thread (" PTR_FORMAT "): ", _thread); + st->print("Current thread (" PTR_FORMAT "): ", p2i(_thread)); _thread->print_on_error(st, buf, sizeof(buf)); st->cr(); } else { @@ -634,13 +539,13 @@ void VMError::report(outputStream* st) { } address stack_bottom = stack_top - stack_size; - st->print("[" PTR_FORMAT "," PTR_FORMAT "]", stack_bottom, stack_top); + st->print("[" PTR_FORMAT "," PTR_FORMAT "]", p2i(stack_bottom), p2i(stack_top)); frame fr = _context ? os::fetch_frame_from_context(_context) : os::current_frame(); if (fr.sp()) { - st->print(", sp=" PTR_FORMAT, fr.sp()); + st->print(", sp=" PTR_FORMAT, p2i(fr.sp())); size_t free_stack_size = pointer_delta(fr.sp(), stack_bottom, 1024); st->print(", free space=" SIZE_FORMAT "k", free_stack_size); } @@ -674,7 +579,7 @@ void VMError::report(outputStream* st) { if (_verbose && _thread && (_thread->is_Named_thread())) { JavaThread* jt = ((NamedThread *)_thread)->processed_thread(); if (jt != NULL) { - st->print_cr("JavaThread " PTR_FORMAT " (nid = " UINTX_FORMAT ") was being processed", jt, jt->osthread()->thread_id()); + st->print_cr("JavaThread " PTR_FORMAT " (nid = %d) was being processed", p2i(jt), jt->osthread()->thread_id()); print_stack_trace(st, jt, buf, sizeof(buf), true); } } @@ -704,6 +609,31 @@ void VMError::report(outputStream* st) { st->cr(); } + STEP(265, "(printing code blob if possible)") + + if (_verbose && _context) { + CodeBlob* cb = CodeCache::find_blob(_pc); + if (cb != NULL) { + if (Interpreter::contains(_pc)) { + // The interpreter CodeBlob is very large so try to print the codelet instead. + InterpreterCodelet* codelet = Interpreter::codelet_containing(_pc); + if (codelet != NULL) { + codelet->print_on(st); + Disassembler::decode(codelet->code_begin(), codelet->code_end(), st); + } + } else { + StubCodeDesc* desc = StubCodeDesc::desc_for(_pc); + if (desc != NULL) { + desc->print_on(st); + Disassembler::decode(desc->begin(), desc->end(), st); + } else { + Disassembler::decode(cb, st); + st->cr(); + } + } + } + } + STEP(270, "(printing VM operation)" ) if (_verbose && _thread && _thread->is_VM_thread()) { @@ -786,7 +716,7 @@ void VMError::report(outputStream* st) { Universe::heap()->print_on_error(st); st->cr(); - st->print_cr("Polling page: " INTPTR_FORMAT, os::get_polling_page()); + st->print_cr("Polling page: " INTPTR_FORMAT, p2i(os::get_polling_page())); st->cr(); } @@ -896,8 +826,7 @@ void VMError::report(outputStream* st) { # undef END } -VMError* volatile VMError::first_error = NULL; -volatile jlong VMError::first_error_tid = -1; +volatile intptr_t VMError::first_error_tid = -1; // An error could happen before tty is initialized or after it has been // destroyed. Here we use a very simple unbuffered fdStream for printing. @@ -958,7 +887,59 @@ static int prepare_log_file(const char* pattern, const char* default_pattern, ch return fd; } -void VMError::report_and_die() { +int VMError::_id; +const char* VMError::_message; +char VMError::_detail_msg[1024]; +Thread* VMError::_thread; +address VMError::_pc; +void* VMError::_siginfo; +void* VMError::_context; +const char* VMError::_filename; +int VMError::_lineno; +size_t VMError::_size; + +void VMError::report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo, + void* context, const char* detail_fmt, ...) +{ + va_list detail_args; + va_start(detail_args, detail_fmt); + report_and_die(sig, NULL, detail_fmt, detail_args, thread, pc, siginfo, context, NULL, 0, 0); + va_end(detail_args); +} + +void VMError::report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo, void* context) +{ + report_and_die(thread, sig, pc, siginfo, context, "%s", ""); +} + +void VMError::report_and_die(const char* message, const char* detail_fmt, ...) +{ + va_list detail_args; + va_start(detail_args, detail_fmt); + report_and_die(INTERNAL_ERROR, message, detail_fmt, detail_args, NULL, NULL, NULL, NULL, NULL, 0, 0); + va_end(detail_args); +} + +void VMError::report_and_die(const char* message) +{ + report_and_die(message, "%s", ""); +} + +void VMError::report_and_die(Thread* thread, const char* filename, int lineno, const char* message, + const char* detail_fmt, va_list detail_args) +{ + report_and_die(INTERNAL_ERROR, message, detail_fmt, detail_args, thread, NULL, NULL, NULL, filename, lineno, 0); +} + +void VMError::report_and_die(Thread* thread, const char* filename, int lineno, size_t size, + VMErrorType vm_err_type, const char* detail_fmt, va_list detail_args) { + report_and_die(vm_err_type, NULL, detail_fmt, detail_args, thread, NULL, NULL, NULL, filename, lineno, size); +} + +void VMError::report_and_die(int id, const char* message, const char* detail_fmt, va_list detail_args, + Thread* thread, address pc, void* siginfo, void* context, const char* filename, + int lineno, size_t size) +{ // Don't allocate large buffer on stack static char buffer[O_BUFLEN]; @@ -974,12 +955,22 @@ void VMError::report_and_die() { if (SuppressFatalErrorMessage) { os::abort(CreateCoredumpOnCrash); } - jlong mytid = os::current_thread_id(); - if (first_error == NULL && - Atomic::cmpxchg_ptr(this, &first_error, NULL) == NULL) { + intptr_t mytid = os::current_thread_id(); + if (first_error_tid == -1 && + Atomic::cmpxchg_ptr(mytid, &first_error_tid, -1) == -1) { + + _id = id; + _message = message; + _thread = thread; + _pc = pc; + _siginfo = siginfo; + _context = context; + _filename = filename; + _lineno = lineno; + _size = size; + jio_vsnprintf(_detail_msg, sizeof(_detail_msg), detail_fmt, detail_args); // first time - first_error_tid = mytid; set_error_reported(); if (ShowMessageBoxOnError || PauseAtExit) { @@ -1007,7 +998,7 @@ void VMError::report_and_die() { if (first_error_tid != mytid) { char msgbuf[64]; jio_snprintf(msgbuf, sizeof(msgbuf), - "[thread " INT64_FORMAT " also had an error]", + "[thread " INTX_FORMAT " also had an error]", mytid); out.print_raw_cr(msgbuf); @@ -1022,8 +1013,7 @@ void VMError::report_and_die() { jio_snprintf(buffer, sizeof(buffer), "[error occurred during error reporting %s, id 0x%x]", - first_error ? first_error->_current_step_info : "", - _id); + _current_step_info, _id); if (log.is_open()) { log.cr(); log.print_raw_cr(buffer); @@ -1038,21 +1028,17 @@ void VMError::report_and_die() { // print to screen if (!out_done) { - first_error->_verbose = false; - staticBufferStream sbs(buffer, sizeof(buffer), &out); - first_error->report(&sbs); + report(&sbs, false); out_done = true; - first_error->_current_step = 0; // reset current_step - first_error->_current_step_info = ""; // reset current_step string + _current_step = 0; + _current_step_info = ""; } // print to error log file if (!log_done) { - first_error->_verbose = true; - // see if log file is already open if (!log.is_open()) { // open log file @@ -1072,12 +1058,12 @@ void VMError::report_and_die() { } staticBufferStream sbs(buffer, O_BUFLEN, &log); - first_error->report(&sbs); - first_error->_current_step = 0; // reset current_step - first_error->_current_step_info = ""; // reset current_step string + report(&sbs, true); + _current_step = 0; + _current_step_info = ""; // Run error reporting to determine whether or not to report the crash. - if (!transmit_report_done && should_report_bug(first_error->_id)) { + if (!transmit_report_done && should_report_bug(_id)) { transmit_report_done = true; const int fd2 = ::dup(log.fd()); FILE* const hs_err = ::fdopen(fd2, "r"); @@ -1149,7 +1135,7 @@ void VMError::report_and_die() { } } - static bool skip_bug_url = !should_report_bug(first_error->_id); + static bool skip_bug_url = !should_report_bug(_id); if (!skip_bug_url) { skip_bug_url = true; @@ -1162,7 +1148,7 @@ void VMError::report_and_die() { static bool skip_os_abort = false; if (!skip_os_abort) { skip_os_abort = true; - bool dump_core = should_report_bug(first_error->_id); + bool dump_core = should_report_bug(_id); os::abort(dump_core && CreateCoredumpOnCrash, _siginfo, _context); } @@ -1177,10 +1163,10 @@ void VMError::report_and_die() { */ class VM_ReportJavaOutOfMemory : public VM_Operation { private: - VMError *_err; + const char* _message; public: - VM_ReportJavaOutOfMemory(VMError *err) { _err = err; } - VMOp_Type type() const { return VMOp_ReportJavaOutOfMemory; } + VM_ReportJavaOutOfMemory(const char* message) { _message = message; } + VMOp_Type type() const { return VMOp_ReportJavaOutOfMemory; } void doit(); }; @@ -1189,7 +1175,7 @@ void VM_ReportJavaOutOfMemory::doit() { static char buffer[O_BUFLEN]; tty->print_cr("#"); - tty->print_cr("# java.lang.OutOfMemoryError: %s", _err->message()); + tty->print_cr("# java.lang.OutOfMemoryError: %s", _message); tty->print_cr("# -XX:OnOutOfMemoryError=\"%s\"", OnOutOfMemoryError); // make heap parsability @@ -1212,10 +1198,10 @@ void VM_ReportJavaOutOfMemory::doit() { } } -void VMError::report_java_out_of_memory() { +void VMError::report_java_out_of_memory(const char* message) { if (OnOutOfMemoryError && OnOutOfMemoryError[0]) { MutexLocker ml(Heap_lock); - VM_ReportJavaOutOfMemory op(this); + VM_ReportJavaOutOfMemory op(message); VMThread::execute(&op); } } diff --git a/hotspot/src/share/vm/utilities/vmError.hpp b/hotspot/src/share/vm/utilities/vmError.hpp index 24b31d7a291..aa1d89ecea6 100644 --- a/hotspot/src/share/vm/utilities/vmError.hpp +++ b/hotspot/src/share/vm/utilities/vmError.hpp @@ -30,39 +30,40 @@ class Decoder; class VM_ReportJavaOutOfMemory; -class VMError : public StackObj { +class VMError : public AllStatic { friend class VM_ReportJavaOutOfMemory; friend class Decoder; - int _id; // Solaris/Linux signals: 0 - SIGRTMAX - // Windows exceptions: 0xCxxxxxxx system errors - // 0x8xxxxxxx system warnings + static int _id; // Solaris/Linux signals: 0 - SIGRTMAX + // Windows exceptions: 0xCxxxxxxx system errors + // 0x8xxxxxxx system warnings - const char * _message; - const char * _detail_msg; - - Thread * _thread; // NULL if it's native thread + static const char* _message; + static char _detail_msg[1024]; + static Thread* _thread; // NULL if it's native thread // additional info for crashes - address _pc; // faulting PC - void * _siginfo; // ExceptionRecord on Windows, - // siginfo_t on Solaris/Linux - void * _context; // ContextRecord on Windows, - // ucontext_t on Solaris/Linux + static address _pc; // faulting PC + static void* _siginfo; // ExceptionRecord on Windows, + // siginfo_t on Solaris/Linux + static void* _context; // ContextRecord on Windows, + // ucontext_t on Solaris/Linux // additional info for VM internal errors - const char * _filename; - int _lineno; + static const char* _filename; + static int _lineno; + + // used by reporting about OOM + static size_t _size; // used by fatal error handler - int _current_step; - const char * _current_step_info; - int _verbose; - // First error, and its thread id. We must be able to handle native thread, + static int _current_step; + static const char* _current_step_info; + + // Thread id of the first error. We must be able to handle native thread, // so use thread id instead of Thread* to identify thread. - static VMError* volatile first_error; - static volatile jlong first_error_tid; + static volatile intptr_t first_error_tid; // Core dump status, false if we have been unable to write a core/minidump for some reason static bool coredump_status; @@ -72,18 +73,16 @@ class VMError : public StackObj { // no core/minidump has been written to disk static char coredump_message[O_BUFLEN]; - // used by reporting about OOM - size_t _size; // set signal handlers on Solaris/Linux or the default exception filter // on Windows, to handle recursive crashes. - void reset_signal_handlers(); + static void reset_signal_handlers(); // handle -XX:+ShowMessageBoxOnError. buf is used to format the message string - void show_message_box(char* buf, int buflen); + static void show_message_box(char* buf, int buflen); // generate an error report - void report(outputStream* st); + static void report(outputStream* st, bool verbose); // generate a stack trace static void print_stack_trace(outputStream* st, JavaThread* jt, @@ -92,42 +91,44 @@ class VMError : public StackObj { static const char* gc_mode(); static void print_oom_reasons(outputStream* st); - // accessor - const char* message() const { return _message; } - const char* detail_msg() const { return _detail_msg; } - bool should_report_bug(unsigned int id) { + static bool should_report_bug(unsigned int id) { return (id != OOM_MALLOC_ERROR) && (id != OOM_MMAP_ERROR); } + static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo, + void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7); + static void report_and_die(const char* message, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(2, 3); + static fdStream out; static fdStream log; // error log used by VMError::report_and_die() public: - // Constructor for crashes - VMError(Thread* thread, unsigned int sig, address pc, void* siginfo, - void* context); - // Constructor for VM internal errors - VMError(Thread* thread, const char* filename, int lineno, - const char* message, const char * detail_msg); - - // Constructor for VM OOM errors - VMError(Thread* thread, const char* filename, int lineno, size_t size, - VMErrorType vm_err_type, const char* message); - // Constructor for non-fatal errors - VMError(const char* message); - // return a string to describe the error - char *error_string(char* buf, int buflen); + static char* error_string(char* buf, int buflen); // Record status of core/minidump static void record_coredump_status(const char* message, bool status); // main error reporting function - void report_and_die(); + static void report_and_die(int id, const char* message, const char* detail_fmt, va_list detail_args, + Thread* thread, address pc, void* siginfo, void* context, + const char* filename, int lineno, size_t size) ATTRIBUTE_PRINTF(3, 0); + + static void report_and_die(Thread* thread, unsigned int sig, address pc, + void* siginfo, void* context); + + static void report_and_die(Thread* thread,const char* filename, int lineno, const char* message, + const char* detail_fmt, va_list detail_args) ATTRIBUTE_PRINTF(5, 0); + + static void report_and_die(Thread* thread, const char* filename, int lineno, size_t size, + VMErrorType vm_err_type, const char* detail_fmt, + va_list detail_args) ATTRIBUTE_PRINTF(6, 0); + + static void report_and_die(const char* message); // reporting OutOfMemoryError - void report_java_out_of_memory(); + static void report_java_out_of_memory(const char* message); // returns original flags for signal, if it was resetted, or -1 if // signal was not changed by error reporter @@ -138,11 +139,9 @@ public: static address get_resetted_sighandler(int sig); // check to see if fatal error reporting is in progress - static bool fatal_error_in_progress() { return first_error != NULL; } + static bool fatal_error_in_progress() { return first_error_tid != -1; } - static jlong get_first_error_tid() { - return first_error_tid; - } + static intptr_t get_first_error_tid() { return first_error_tid; } }; #endif // SHARE_VM_UTILITIES_VMERROR_HPP diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index 5b1f9adf6b6..ab2b89acaf8 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -319,7 +319,7 @@ hotspot_gc_gcold = \ hotspot_runtime = \ runtime/ \ - -runtime/6888954/vmerrors.sh \ + -runtime/ErrorHandling/ErrorHandler.java \ -runtime/RedefineObject/TestRedefineObject.java \ -runtime/8003720/Test8003720.java \ -runtime/Metaspace/FragmentMetaspace.java \ @@ -327,6 +327,7 @@ hotspot_runtime = \ -runtime/Thread/TestThreadDumpMonitorContention.java \ -runtime/SharedArchiveFile/SharedBaseAddress.java \ -runtime/memory/ReserveMemory.java \ + -runtime/memory/RunUnitTestsConcurrently.java \ -runtime/Unsafe/RangeCheck.java \ -runtime/SharedArchiveFile/CdsSameObjectAlignment.java \ -runtime/SharedArchiveFile/DefaultUseWithClient.java \ diff --git a/hotspot/test/compiler/c2/5057225/Test5057225.java b/hotspot/test/compiler/c2/5057225/Test5057225.java index 3e6df408a52..106d390b850 100644 --- a/hotspot/test/compiler/c2/5057225/Test5057225.java +++ b/hotspot/test/compiler/c2/5057225/Test5057225.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * 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,11 +25,11 @@ * @test * @bug 5057225 * @summary Remove useless I2L conversions - * + * @library /testlibrary * @run main/othervm -Xcomp -XX:CompileOnly=Test5057225.doload Test5057225 */ -import java.net.URLClassLoader; +import jdk.test.lib.Utils; public class Test5057225 { static byte[] ba = new byte[] { -1 }; @@ -89,8 +89,9 @@ public class Test5057225 { static void loadAndRunClass(String classname) throws Exception { Class cl = Class.forName(classname); - URLClassLoader apploader = (URLClassLoader) cl.getClassLoader(); - ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent()); + ClassLoader apploader = cl.getClassLoader(); + ClassLoader loader + = Utils.getTestClassPathURLClassLoader(apploader.getParent()); Class c = loader.loadClass(classname); Runnable r = (Runnable) c.newInstance(); r.run(); diff --git a/hotspot/test/compiler/c2/5091921/Test7005594.sh b/hotspot/test/compiler/c2/5091921/Test7005594.sh index cd6fd807b9d..6350a08ac9b 100644 --- a/hotspot/test/compiler/c2/5091921/Test7005594.sh +++ b/hotspot/test/compiler/c2/5091921/Test7005594.sh @@ -78,7 +78,7 @@ cp ${TESTSRC}/Test7005594.sh . ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test7005594.java -${TESTJAVA}/bin/java ${TESTOPTS} -Xmx1600m -Xms1600m -XX:+IgnoreUnrecognizedVMOptions -XX:-ZapUnusedHeapArea -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 > test.out 2>&1 +${TESTJAVA}/bin/java ${TESTOPTS} -Xmx1600m -Xms1600m -XX:+IgnoreUnrecognizedVMOptions -XX:-ZapUnusedHeapArea -Xcomp -XX:CompileOnly=Test7005594.test -XX:CompileCommand=quiet Test7005594 > test.out 2>&1 result=$? diff --git a/hotspot/test/compiler/c2/6603011/Test.java b/hotspot/test/compiler/c2/6603011/Test.java index 74c1062d948..bc457073517 100644 --- a/hotspot/test/compiler/c2/6603011/Test.java +++ b/hotspot/test/compiler/c2/6603011/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 6603011 * @summary long/int division by constant - * + * @library /testlibrary * @run main/othervm -Xcomp -Xbatch -XX:-Inline Test */ @@ -36,7 +36,7 @@ // dividend and divisor combinations are tested // -import java.net.*; +import jdk.test.lib.Utils; class s { static int divi(int dividend, int divisor) { return dividend / divisor; } @@ -189,10 +189,10 @@ public class Test implements Runnable { // This allows the JIT to see q.DIVISOR as a final constant, and change // any divisions or mod operations into multiplies. public static void test_divisor(int divisor, - URLClassLoader apploader) throws Exception { + ClassLoader apploader) throws Exception { System.setProperty("divisor", "" + divisor); - ClassLoader loader = new URLClassLoader(apploader.getURLs(), - apploader.getParent()); + ClassLoader loader + = Utils.getTestClassPathURLClassLoader(apploader.getParent()); Class c = loader.loadClass("Test"); Runnable r = (Runnable)c.newInstance(); r.run(); @@ -200,7 +200,7 @@ public class Test implements Runnable { public static void main(String[] args) throws Exception { Class cl = Class.forName("Test"); - URLClassLoader apploader = (URLClassLoader)cl.getClassLoader(); + ClassLoader apploader = cl.getClassLoader(); // Test every divisor between -100 and 100. diff --git a/hotspot/test/compiler/c2/6800154/Test6800154.java b/hotspot/test/compiler/c2/6800154/Test6800154.java index 559db2c26b8..05ad662d69d 100644 --- a/hotspot/test/compiler/c2/6800154/Test6800154.java +++ b/hotspot/test/compiler/c2/6800154/Test6800154.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * 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,11 +25,11 @@ * @test * @bug 6800154 * @summary Add comments to long_by_long_mulhi() for better understandability - * + * @library /testlibrary * @run main/othervm -Xcomp -XX:CompileOnly=Test6800154.divcomp Test6800154 */ -import java.net.URLClassLoader; +import jdk.test.lib.Utils; public class Test6800154 implements Runnable { static final long[] DIVIDENDS = { @@ -78,12 +78,13 @@ public class Test6800154 implements Runnable { public static void main(String[] args) throws Exception { Class cl = Class.forName("Test6800154"); - URLClassLoader apploader = (URLClassLoader) cl.getClassLoader(); + ClassLoader apploader = cl.getClassLoader(); // Iterate over all divisors. for (int i = 0; i < DIVISORS.length; i++) { System.setProperty("divisor", "" + DIVISORS[i]); - ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent()); + ClassLoader loader + = Utils.getTestClassPathURLClassLoader(apploader.getParent()); Class c = loader.loadClass("Test6800154"); Runnable r = (Runnable) c.newInstance(); r.run(); diff --git a/hotspot/test/compiler/c2/6805724/Test6805724.java b/hotspot/test/compiler/c2/6805724/Test6805724.java index 9e881cb21ed..922b297dbd8 100644 --- a/hotspot/test/compiler/c2/6805724/Test6805724.java +++ b/hotspot/test/compiler/c2/6805724/Test6805724.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,12 +24,13 @@ /** * @test * @bug 6805724 - * @summary ModLNode::Ideal() generates functionally incorrect graph when divisor is any (2^k-1) constant. - * + * @summary ModLNode::Ideal() generates functionally incorrect graph + * when divisor is any (2^k-1) constant. + * @library /testlibrary * @run main/othervm -Xcomp -XX:CompileOnly=Test6805724.fcomp Test6805724 */ -import java.net.URLClassLoader; +import jdk.test.lib.Utils; public class Test6805724 implements Runnable { // Initialize DIVISOR so that it is final in this class. @@ -65,13 +66,14 @@ public class Test6805724 implements Runnable { public static void main(String args[]) throws Exception { Class cl = Class.forName("Test6805724"); - URLClassLoader apploader = (URLClassLoader) cl.getClassLoader(); + ClassLoader apploader = cl.getClassLoader(); // Iterate over all 2^k-1 divisors. for (int k = 1; k < Long.SIZE; k++) { long divisor = (1L << k) - 1; System.setProperty("divisor", "" + divisor); - ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent()); + ClassLoader loader + = Utils.getTestClassPathURLClassLoader(apploader.getParent()); Class c = loader.loadClass("Test6805724"); Runnable r = (Runnable) c.newInstance(); r.run(); diff --git a/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java b/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java index 6f3dc395f62..2269f3a4228 100644 --- a/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java +++ b/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java @@ -21,6 +21,7 @@ * questions. */ +import compiler.testlibrary.CompilerUtils; import jdk.test.lib.Asserts; import jdk.test.lib.JDKToolFinder; import jdk.test.lib.OutputAnalyzer; @@ -47,7 +48,7 @@ import java.util.stream.Collectors; * @test SegmentedCodeCacheDtraceTest * @bug 8015774 * @requires os.family=="solaris" - * @library /testlibrary /compiler/testlibrary /../../test/lib + * @library /testlibrary / /../../test/lib * @build SegmentedCodeCacheDtraceTestWorker * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/hotspot/test/compiler/codegen/6823354/Test6823354.java b/hotspot/test/compiler/codegen/6823354/Test6823354.java index a1294108483..6f9bc0203be 100644 --- a/hotspot/test/compiler/codegen/6823354/Test6823354.java +++ b/hotspot/test/compiler/codegen/6823354/Test6823354.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * 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,11 +25,11 @@ * @test * @bug 6823354 * @summary These methods can be instrinsified by using bit scan, bit test, and population count instructions. - * + * @library /testlibrary * @run main/othervm -Xcomp -XX:CompileOnly=Test6823354.lzcomp,Test6823354.tzcomp,.dolzcomp,.dotzcomp Test6823354 */ -import java.net.URLClassLoader; +import jdk.test.lib.Utils; public class Test6823354 { // Arrays of corner case values. @@ -197,8 +197,9 @@ public class Test6823354 { static void loadandrunclass(String classname) throws Exception { Class cl = Class.forName(classname); - URLClassLoader apploader = (URLClassLoader) cl.getClassLoader(); - ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent()); + ClassLoader apploader = cl.getClassLoader(); + ClassLoader loader + = Utils.getTestClassPathURLClassLoader(apploader.getParent()); Class c = loader.loadClass(classname); Runnable r = (Runnable) c.newInstance(); r.run(); diff --git a/hotspot/test/compiler/compilercontrol/matcher/MethodMatcherTest.java b/hotspot/test/compiler/compilercontrol/matcher/MethodMatcherTest.java new file mode 100644 index 00000000000..eff00e272db --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/matcher/MethodMatcherTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.compilercontrol.matcher; + +import jdk.test.lib.Pair; +import compiler.compilercontrol.share.method.MethodDescriptor; +import compiler.compilercontrol.share.method.MethodGenerator; +import pool.PoolHelper; +import sun.hotspot.WhiteBox; + +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/* + * @test + * @bug 8135068 + * @summary Tests CompilerCommand's method matcher + * @library /testlibrary /../../test/lib /compiler/whitebox ../share / + * @build MethodMatcherTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI compiler.compilercontrol.matcher.MethodMatcherTest + */ +public class MethodMatcherTest { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final PoolHelper POOL = new PoolHelper(); + private static final List>> METHODS = + POOL.getAllMethods(); + private static final int AMOUNT = Integer.parseInt(System + .getProperty("test.amount", "25")); + + public static void main(String[] args) { + MethodGenerator gen = new MethodGenerator(); + List>> testMethods = + POOL.getAllMethods(PoolHelper.METHOD_FILTER); + for (Pair> pair : testMethods) { + for (int i = 0; i < AMOUNT; i++) { + MethodDescriptor md = gen.generateRandomDescriptor(pair.first); + check(md); + } + } + } + + /** + * Check method matcher with given test case + * + * @param methodDescriptor method descriptor to check matcher's pattern + */ + private static void check(MethodDescriptor methodDescriptor) { + System.out.println("Test case: " + methodDescriptor.getString()); + System.out.println("Regex: " + methodDescriptor.getRegexp()); + Pattern pattern = Pattern.compile(methodDescriptor.getRegexp()); + boolean isValidDesc = methodDescriptor.isValid(); + List failList = new ArrayList<>(); + // walk through all methods in pool to check match with test pattern + for (Pair> pair : METHODS) { + MethodDescriptor m = MethodGenerator.commandDescriptor(pair.first); + Matcher matcher = pattern.matcher(m.getCanonicalString()); + // get expected result + MatcherResult expected; + if (isValidDesc) { + expected = matcher.matches() ? + MatcherResult.MATCH : MatcherResult.NO_MATCH; + } else { + expected = MatcherResult.PARSING_FAILURE; + } + // get MethodMatcher's result + MatcherResult matchResult = MatcherResult.fromCode(WB.matchesMethod( + pair.first, methodDescriptor.getString())); + // compare + if (matchResult != expected) { + System.out.printf("- Method: %s%n-- FAILED: result: %s, " + + "but expected: %s%n", m.getCanonicalString(), + matchResult, expected); + failList.add(m); + } + } + int size = failList.size(); + if (size != 0) { + System.err.println("FAILED test case: " + methodDescriptor + .getString()); + if (size == METHODS.size()) { + System.err.println("-- All methods failed to match"); + } else { + for (MethodDescriptor md : failList) { + System.err.println("-- FAILED match: " + md.getString()); + } + } + throw new AssertionError("FAIL: " + methodDescriptor.getString()); + } + System.out.println("--PASSED"); + } + + /** + * Represents MethodMatcher's matching result + */ + public enum MatcherResult { + PARSING_FAILURE(-1, "Parsing failed"), + NO_MATCH(0, "No match"), + MATCH(1, "Match"); + + public final int code; + private final String message; + + private MatcherResult(int code, String message) { + this.code = code; + this.message = message; + } + + public static MatcherResult fromCode(int code) { + switch (code) { + case -1: return PARSING_FAILURE; + case 0: return NO_MATCH; + case 1: return MATCH; + default: + throw new IllegalArgumentException("MATCHER FAILURE:" + + "Wrong code: " + code); + } + } + + @Override + public String toString() { + return message; + } + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/method/ClassType.java b/hotspot/test/compiler/compilercontrol/share/method/ClassType.java new file mode 100644 index 00000000000..651a1d8960c --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/method/ClassType.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.compilercontrol.share.method; + +import java.lang.reflect.Executable; +import java.util.Arrays; +import java.util.stream.Collectors; + +/** + * Element represents class in method descriptor + * that consist from class package and class itself + */ +public class ClassType extends MethodElementType { + private final String[] packageDirs; + private final Class aClass; + private boolean setPackage; + + public ClassType(Executable method) { + // Use pack/subpack/Class::method separators style + super(MethodDescriptor.Separator.SLASH); + // Get package + aClass = method.getDeclaringClass(); + Package aPackage = method.getDeclaringClass().getPackage(); + if (aPackage != null) { + // split into directories + packageDirs = aPackage.getName().split("\\."); + } else { + packageDirs = null; + } + setPackage = true; + buildElement(setPackage); + } + + @Override + public boolean isValid() { + if (element.isEmpty()) { + return false; + } + boolean separatorMet = false; + char separatorChar = 0; + char[] charArray = element.toCharArray(); + for (int i = 0; i < charArray.length; i++) { + char ch = charArray[i]; + switch (ch) { + case '/': + case '.': + if (separatorMet) { + if (ch != separatorChar) { + // there are two different separators + return false; + } + } else { + separatorChar = ch; + separatorMet = true; + } + break; + case ':': + if (++i != charArray.length) { + if (charArray[i] == ':') { + // :: is invalid separator + separator = MethodDescriptor.Separator.DOUBLECOLON; + return false; + } + } + break; + // Invalid separators + case ',': + case ' ': + return false; + } + } + // set correct separator + switch (separatorChar) { + case '.': + separator = MethodDescriptor.Separator.DOT; + break; + case '/': + separator = MethodDescriptor.Separator.SLASH; + break; + default: + separator = MethodDescriptor.Separator.NONE; + break; + } + return super.isValid(); + } + + @Override + public void setSeparator(MethodDescriptor.Separator separator) { + this.separator = separator; + buildElement(setPackage); + } + + @Override + public void setPattern(MethodDescriptor.PatternType patternType) { + switch (patternType) { + case EXACT: + break; + case PREFIX: + // For prefix pattern use only class name without package + buildElement(false); + regexp = ".*" + regexp; + element = "*" + element; + break; + case ANY: + regexp = ".*"; + element = "*"; + break; + case SUFFIX: + regexp = regexp + ".*"; + element = element + "*"; + break; + case SUBSTRING: + setPattern(MethodDescriptor.PatternType.PREFIX); + setPattern(MethodDescriptor.PatternType.SUFFIX); + break; + default: + throw new IllegalArgumentException("ERROR: wrong pattern type " + + patternType); + } + } + + /** + * Builds element string and regexp. + * + * @param setPackage shows that element should have a package name + */ + private void buildElement(boolean setPackage) { + this.setPackage = setPackage; + StringBuilder elementBuilder = new StringBuilder(); + if (packageDirs != null && setPackage) { + elementBuilder.append(Arrays.stream(packageDirs) + .collect(Collectors.joining(separator.symbol))); + elementBuilder.append(separator.symbol); + } + String className = aClass.getSimpleName(); + if (setPackage) { + // Add outer classes if any + Class enclosingClass = aClass.getEnclosingClass(); + while (enclosingClass != null) { + className = enclosingClass.getSimpleName() + "$" + className; + enclosingClass = enclosingClass.getEnclosingClass(); + } + } + elementBuilder.append(className); + element = elementBuilder.toString(); + if (separator == MethodDescriptor.Separator.DOT) { + // Replace . with / to make regexp look like CommandSignature + regexp = element.replace(".", "/"); + } else { + regexp = element; + } + regexp = regexp.replace("$", "\\$"); + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/method/MethodDescriptor.java b/hotspot/test/compiler/compilercontrol/share/method/MethodDescriptor.java new file mode 100644 index 00000000000..11848d8b1b6 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/method/MethodDescriptor.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.compilercontrol.share.method; + +import jdk.test.lib.Triple; + +import java.lang.reflect.Executable; +import java.util.function.Function; +import java.util.regex.Pattern; + +/** + * Method descriptor for Compiler Control commands. + * It represents method pattern used for matching in Compiler Control + * and CompileCommand option + */ +public class MethodDescriptor { + public final ClassType aClass; // Represents class and package + public final MethodType aMethod; // Represents method + public final SignatureType aSignature; // Represents signature + + /** + * Constructor + * + * @param method executable to build method descriptor from + */ + public MethodDescriptor(Executable method) { + aClass = new ClassType(method); + aMethod = new MethodType(method); + aSignature = new SignatureType(method); + } + + /** + * Sets signature separators for all elements + */ + public void setSeparators( + Triple separators) { + aClass.setSeparator(separators.getFirst()); + aMethod.setSeparator(separators.getSecond()); + aSignature.setSeparator(separators.getThird()); + } + + /** + * Sets custom strings for each element + */ + public void setStrings(Triple strings) { + aClass.setElement(strings.getFirst()); + aMethod.setElement(strings.getSecond()); + aSignature.setElement(strings.getThird()); + } + + /** + * Sets patterns for all elements + */ + public void setPatterns( + Triple patterns) { + aClass.setPattern(patterns.getFirst()); + aMethod.setPattern(patterns.getSecond()); + aSignature.setPattern(patterns.getThird()); + } + + /** + * Separates elements in the MethodDescriptor + */ + public static enum Separator { + SLASH("/"), + DOT("."), + COMMA(","), + DOUBLECOLON("::"), + SPACE(" "), + NONE(""); + + public final String symbol; + + Separator(String symbol) { + this.symbol = symbol; + } + + /** + * Validates method descriptor separators + * + * @param md method descriptor to validate + * @return true if descriptor's separators are valid + */ + public static boolean isValid(MethodDescriptor md) { + Separator cls = md.getClassSeparator(); + Separator method = md.getMethodSeparator(); + Separator sign = md.getSignatureSeparator(); + if (sign == SPACE || sign == NONE || sign == COMMA) { + // if it looks like java/lang/String.indexOf + if ((cls == SLASH || cls == NONE) + // allow space and comma instead of dot + && (method == DOT || method == SPACE + || method == COMMA)) { + return true; + } + // if it looks like java.lang.String::indexOf + if ((cls == DOT || cls == NONE) && method == DOUBLECOLON) { + return true; + } + } + return false; + } + } + + /** + * Type of the pattern + */ + public static enum PatternType { + PREFIX, + ANY, + SUFFIX, + SUBSTRING, + EXACT + } + + public Separator getClassSeparator() { + return aClass.getSeparator(); + } + + public Separator getMethodSeparator() { + return aMethod.getSeparator(); + } + + public Separator getSignatureSeparator() { + return aSignature.getSeparator(); + } + + /** + * Gets regular expression to match methods + * + * @return string representation of the regular expression + */ + public String getRegexp() { + // regexp should have a . as a method separator + // and / as a package/class separator + return aClass.getRegexp().replaceAll("\\.", "/") + .replaceAll("/\\*", ".*") + + Pattern.quote(Separator.DOT.symbol) + + aMethod.getRegexp() + aSignature.getRegexp(); + } + + /** + * Gets method descriptor string representation. + * This string is used as a pattern in CompilerControl and CompileCommand + */ + public String getString() { + return aClass.getElement() + getMethodSeparator().symbol + + aMethod.getElement() + getSignatureSeparator().symbol + + aSignature.getElement(); + } + + /** + * Convert method descriptor to be regexp-compatible + * + * @return string representation of the method signature + */ + public String getCanonicalString() { + return aClass.getElement().replaceAll("\\.", "/") + Separator.DOT.symbol + + aMethod.getElement() + aSignature.getElement(); + } + + /** + * Shows if this descriptor is a valid pattern for CompilerControl + * + * @return true, if descriptor is valid, false otherwise + */ + public boolean isValid() { + return aClass.isValid() && aMethod.isValid() && aSignature.isValid() + && Separator.isValid(this); + } + + /** + * Sets custom string from element mutate function + * to the appropriate element of method descriptor + */ + public void applyMutates(Triple, + Function, + Function> mutators) { + String elementString = aClass.getElement(); + aClass.setElement(mutators.getFirst().apply(elementString)); + elementString = aMethod.getElement(); + aMethod.setElement(mutators.getSecond().apply(elementString)); + elementString = aSignature.getElement(); + aSignature.setElement(mutators.getThird().apply(elementString)); + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/method/MethodElementType.java b/hotspot/test/compiler/compilercontrol/share/method/MethodElementType.java new file mode 100644 index 00000000000..47f94bf3393 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/method/MethodElementType.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.compilercontrol.share.method; + +import java.util.regex.Pattern; + +/** + * Class represents an element of the MethodDescriptor + * used as pattern for CompilerCommand method strings + */ +public abstract class MethodElementType { + private static final char[] INVALID_CHARS = { ';', '[', '(', ')', ']', + '<', '>'}; + protected String element; + protected String regexp; + protected MethodDescriptor.Separator separator; + + /** + * Constructor + */ + protected MethodElementType(MethodDescriptor.Separator separator) { + this.separator = separator; + } + + /** + * Gets element's separator + * + * @return separator instance + */ + public MethodDescriptor.Separator getSeparator() { + return separator; + } + + /** + * Sets separator for this element + * + * @param separator separator type + */ + public void setSeparator(MethodDescriptor.Separator separator) { + this.separator = separator; + } + + /** + * Gets String representation of the element + * + * @return element string + */ + public String getElement() { + return element; + } + + /** + * Sets String representation of the element + * + * @param element custom string to be used as an element + */ + public void setElement(String element) { + this.element = element; + this.regexp = Pattern.quote(element); + } + + /** + * Shows that the element is valid according to CompilerControl and JVMS specs + * + * @return true, if the element is a valid string + */ + public boolean isValid() { + for (char ch : INVALID_CHARS) { + if (element.indexOf(ch) != -1) { + return false; + } + } + // Check for * usage + if (element.equals("**")) { + return false; + } + for (int i = 0; i < element.length(); i++) { + char c = element.charAt(i); + if (c == '*' && i > 0 && i < element.length() - 1) { + // Embedded * isn't allowed + return false; + } + } + return true; + } + + /** + * Creates pattern of a given type + * + * @param patternType type of the pattern + */ + public void setPattern(MethodDescriptor.PatternType patternType) { + switch (patternType) { + case EXACT: + break; + case PREFIX: + regexp = ".*" + regexp; + element = "*" + element; + break; + case ANY: + regexp = ".*"; + element = "*"; + break; + case SUFFIX: + regexp = regexp + ".*"; + element = element + "*"; + break; + case SUBSTRING: + setPattern(MethodDescriptor.PatternType.PREFIX); + setPattern(MethodDescriptor.PatternType.SUFFIX); + break; + default: + throw new IllegalArgumentException("ERROR: wrong pattern type" + + patternType); + } + } + + /** + * Gets regular expression of this element + * + * @return string representation of regexp + */ + public String getRegexp() { + return regexp; + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/method/MethodGenerator.java b/hotspot/test/compiler/compilercontrol/share/method/MethodGenerator.java new file mode 100644 index 00000000000..34435a5408c --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/method/MethodGenerator.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.compilercontrol.share.method; + +import compiler.compilercontrol.share.method.MethodDescriptor.PatternType; +import compiler.compilercontrol.share.method.MethodDescriptor.Separator; +import jdk.test.lib.Pair; +import jdk.test.lib.Triple; +import jdk.test.lib.Utils; +import pool.PoolHelper; + +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.function.Function; + +/** + * Generates combinations of method descriptors from the pool of methods + */ +public class MethodGenerator { + private static final List>> METHODS = + new PoolHelper().getAllMethods(PoolHelper.METHOD_FILTER); + // Different combinations of patterns + private static final List> PATTERNS_LIST; + // Different combinations of separators + private static final List> SEPARATORS_LIST; + // List of functions that modify elements + private static final List> ELEMENT_MUTATORS; + + static { + PATTERNS_LIST = + generate(EnumSet.allOf(PatternType.class), + EnumSet.allOf(PatternType.class), + EnumSet.of(PatternType.ANY, PatternType.EXACT)); + SEPARATORS_LIST = + generate(EnumSet.of(Separator.SLASH, Separator.DOT), + EnumSet.complementOf(EnumSet.of(Separator.NONE)), + EnumSet.of(Separator.COMMA, Separator.SPACE, + Separator.NONE)); + ELEMENT_MUTATORS = generateMutators(); + } + + // Test method + public static void main(String[] args) { + MethodGenerator methodGenerator = new MethodGenerator(); + List tests = methodGenerator.getTests(); + tests.forEach(System.out::println); + } + + /** + * Generates random method descriptor + * + * @param executable executable used to generate descriptor + * @return MethodDescriptor instance + */ + public MethodDescriptor generateRandomDescriptor(Executable executable) { + Combination patterns = + Utils.getRandomElement(PATTERNS_LIST); + Combination separators = + Utils.getRandomElement(SEPARATORS_LIST); + // Create simple mutators for signature generation + List> signMutators = new ArrayList<>(); + signMutators.add(input -> input); + signMutators.add(input -> ""); + Combination> mutators = new Combination<>( + Utils.getRandomElement(ELEMENT_MUTATORS), + Utils.getRandomElement(ELEMENT_MUTATORS), + // use only this type of mutators + Utils.getRandomElement(signMutators)); + return makeMethodDescriptor(executable, patterns, + separators, mutators); + } + + /** + * Compile command signature that looks like java/lang/String.indexOf + * http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html#BABDDFII + * + * @param executable executable used to generate descriptor + * @return MethodDescriptor instance + */ + public static MethodDescriptor commandDescriptor(Executable executable) { + MethodDescriptor md = new MethodDescriptor(executable); + md.aClass.setSeparator(Separator.SLASH); + md.aMethod.setSeparator(Separator.DOT); + md.aSignature.setSeparator(Separator.NONE); + return md; + } + + /** + * Compile command signature that looks like java.lang.String::indexOf + * + * @param executable executable used to generate descriptor + * @return MethodDescriptor instance + */ + public static MethodDescriptor logDescriptor(Executable executable) { + MethodDescriptor md = new MethodDescriptor(executable); + md.aClass.setSeparator(Separator.DOT); + md.aMethod.setSeparator(Separator.DOUBLECOLON); + md.aSignature.setSeparator(Separator.NONE); + return md; + } + + /** + * Generates a list of method patterns from the pool of methods + * + * @return a list of test cases + */ + public List getTests() { + List list = new ArrayList<>(); + METHODS.forEach(pair -> list.addAll(getTests(pair.first))); + return list; + } + + /** + * Generates all combinations of method descriptors for a given executable + * + * @param executable executable for which the different combination is built + * @return list of method descriptors + */ + public List getTests(Executable executable) { + List list = new ArrayList<>(); + for (Combination patterns : PATTERNS_LIST) { + for (Combination separators : SEPARATORS_LIST) { + for (Function classGen : ELEMENT_MUTATORS) { + for (Function methodGen : + ELEMENT_MUTATORS) { + for (Function signatureGen : + ELEMENT_MUTATORS) { + list.add(makeMethodDescriptor(executable, + patterns, separators, + new Combination<>(classGen, methodGen, + signatureGen))); + } + } + } + } + } + return list; + } + + /** + * Creates method descriptor from the given executable, + * patterns and separators for its elements + */ + private MethodDescriptor makeMethodDescriptor( + Executable executable, + Combination patterns, + Combination separators, + Combination> mutators) { + MethodDescriptor methodDescriptor = new MethodDescriptor(executable); + methodDescriptor.setSeparators(separators); + methodDescriptor.applyMutates(mutators); + methodDescriptor.setPatterns(patterns); + return methodDescriptor; + } + + /** + * Creates a list of functions that change given string + */ + private static List> generateMutators() { + List> elements = new ArrayList<>(); + // Use the input itself + elements.add(input -> input); + // Use half of the input string + elements.add(input -> input.substring(input.length() / 2)); + // Add nonexistent element + elements.add(input -> "nonexistent"); + // Use left and right angle brackets + elements.add(input -> "<" + input + ">"); + // Embed * inside + elements.add(input -> embed(input, "*")); + // ** as a whole element + elements.add(input -> "**"); + // Embed JLS-invalid letters + elements.add(input -> embed(input, "@%")); + elements.add(input -> embed(input, "]")); + // Use JLS-invalid letters + elements.add(input -> "-"); + elements.add(input -> "+"); + elements.add(input -> ")" + input); + elements.add(input -> "{" + input + "}"); + // Add valid Java identifier start char + elements.add(input -> "_" + input); + elements.add(input -> "$" + input); + elements.add(input -> "0" + input); + // Unicode characters + elements.add(input -> embed(input, "\u0001")); + elements.add(input -> embed(input, "\u007F")); + // Combining character + elements.add(input -> embed(input, "\u0300")); + elements.add(input -> embed(input, "\u0306")); + // Supplementary character + elements.add(input -> new String(Character.toChars(0x1F64C))); + return elements; + } + + /** + * Embeds one string inside another one + * + * @param target target source string + * @param element string to be embedded into target string + * @return result string + */ + private static String embed(String target, String element) { + int mid = target.length() / 2; + String begin = target.substring(0, mid); + String end = target.substring(mid); + return begin + element + end; + } + + /** + * Generates triples from the given enum sets + * for each of the method elements + * + * @param classSet set of allowed elements for class + * @param methodSet set of allowed elements for method + * @param signSet set of allowed elements for signature + * @param type of generated triples + * @return list of triples + */ + private static > List> generate( + EnumSet classSet, EnumSet methodSet, EnumSet signSet) { + List> list = new ArrayList<>(); + classSet.forEach(clsElement -> + methodSet.forEach(methodElement -> + signSet.forEach(signElement -> + list.add(new Combination<>(clsElement, methodElement, + signElement)) + ) + ) + ); + return list; + } + + private static class Combination extends Triple { + public Combination(T first, T second, T third) { + super(first, second, third); + } + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/method/MethodType.java b/hotspot/test/compiler/compilercontrol/share/method/MethodType.java new file mode 100644 index 00000000000..ee992335abd --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/method/MethodType.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.compilercontrol.share.method; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; + +/** + * Represents a method in CompileControl method signature + */ +public class MethodType extends MethodElementType { + private static final char[] INVALID_CHARS = { '.', '/' }; + + public MethodType(Executable method) { + // Use pack/subpack/Class::method separators style + super(MethodDescriptor.Separator.DOT); + if (method instanceof Constructor) { + element = ""; + } else { + element = method.getName(); + } + regexp = element; + } + + @Override + public boolean isValid() { + for (char ch : INVALID_CHARS) { + if (element.indexOf(ch) != -1) { + return false; + } + } + if (element.isEmpty()) { + // Shouldn't be empty + return false; + } + if (element.contains("<") || element.contains(">")) { + return element.matches("(\\*)?<(cl)?init>(\\*)?"); + } + return super.isValid(); + } + + @Override + public void setPattern(MethodDescriptor.PatternType patternType) { + switch (patternType) { + case EXACT: + break; + case PREFIX: + regexp = ".*" + regexp; + element = "*" + element; + break; + case ANY: + regexp = "[^(]*"; + element = "*"; + break; + case SUFFIX: + regexp = regexp + "[^(]*"; + element = element + "*"; + break; + case SUBSTRING: + setPattern(MethodDescriptor.PatternType.PREFIX); + setPattern(MethodDescriptor.PatternType.SUFFIX); + break; + default: + throw new IllegalArgumentException("ERROR: wrong pattern type " + + patternType); + } + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/method/SignatureType.java b/hotspot/test/compiler/compilercontrol/share/method/SignatureType.java new file mode 100644 index 00000000000..588af8e3131 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/method/SignatureType.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.compilercontrol.share.method; + +import jdk.test.lib.Utils; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.Arrays; + +/** + * This class represents a signature of the method + */ +public class SignatureType extends MethodElementType { + public SignatureType(Executable method) { + super(MethodDescriptor.Separator.NONE); + // Get parameters + Class[] types = method.getParameterTypes(); + String[] parameterTypes = new String[types.length]; + for (int i = 0; i < types.length; i++) { + parameterTypes[i] = Utils.toJVMTypeSignature(types[i]); + } + // Get return value + String returnType; + if (method instanceof Method) { + returnType = Utils.toJVMTypeSignature(((Method) method) + .getReturnType()); + } else if (method instanceof Constructor) { + // Constructor returns void in VM + returnType = Utils.toJVMTypeSignature(void.class); + } else { + throw new Error(String.format("TESTBUG: wrong type of executable " + + "%s of class %s", method, method.getClass())); + } + // Create signature + setElement("(" + String.join("", parameterTypes)+ ")" + returnType); + regexp = element; + setPattern(MethodDescriptor.PatternType.EXACT); + separator = MethodDescriptor.Separator.NONE; + } + + @Override + public void setElement(String element) { + if (element.isEmpty()) { + setPattern(MethodDescriptor.PatternType.ANY); + } else { + super.setElement(element); + } + } + + @Override + public boolean isValid() { + if (element.isEmpty()) { + return true; + } + // Allowed primitive types + char[] baseTypes = {'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z'}; // sorted + // Parsing states + boolean isArray = false; + boolean isInsideSig = false; + boolean isClass = false; + + for (char ch : element.toCharArray()) { + if (ch == '(') { + if (isInsideSig) { + // Met another ( inside + return false; + } + isInsideSig = true; + } else if (ch == ')') { + if (!isInsideSig) { + // met another ) outside + return false; + } + isInsideSig = false; + } else if (ch == 'V') { + if (isInsideSig) { + // void type is allowed only as a return value + return false; + } + } else if (ch == 'L') { + // this is a beginning of class/interface + isClass = true; + // met actual type of array + isArray = false; + } else if (ch == '[') { + isArray = true; + } else if (isClass) { + if (!Character.isJavaIdentifierPart(ch)) { + if (ch == '/' || ch == '.') { + // separator met + } else if (ch == ';') { + // end of class/interface + isClass = false; + } else { + return false; + } + } + } else if (Arrays.binarySearch(baseTypes, ch) < 0) { + // if it doesn't belong to base types + return false; + } else { + // array of a base type + isArray = false; + } + } + return !(isArray || isInsideSig || isClass); + } + + @Override + public void setPattern(MethodDescriptor.PatternType patternType) { + switch (patternType) { + case PREFIX: + case SUFFIX: + case SUBSTRING: + // These patterns are not supported in Compiler Control + // Just use ANY pattern instead + case ANY: + regexp = "\\(.*\\).*"; + element = ""; + break; + case EXACT: + break; + default: + throw new IllegalArgumentException("ERROR: wrong pattern type " + + patternType); + } + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/pool/MethodHolder.java b/hotspot/test/compiler/compilercontrol/share/pool/MethodHolder.java new file mode 100644 index 00000000000..26002b0f9a1 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/pool/MethodHolder.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pool; + +import jdk.test.lib.Pair; + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +/** + * Represents a holder that contains test methods + */ +public abstract class MethodHolder { + /** + * Helper method to get executable for the specified method + * + * @param holder class that holds specified method + * @param name method name + * @param parameterTypes parameter types of the specified method + * @return {@link Method} instance + */ + public Method getMethod(MethodHolder holder, + String name, + Class... parameterTypes) { + try { + return holder.getClass().getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException e) { + throw new Error("TESTBUG: Can't get method " + name, e); + } + } + + /** + * Gets all test methods + * + * @return pairs of Executable and appropriate Callable + */ + public List>> getAllMethods() { + Class aClass = this.getClass(); + Object classInstance; + try { + classInstance = aClass.newInstance(); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG: unable to get new instance", e); + } + List>> pairs = new ArrayList<>(); + { + Method method = getMethod(this, "method", int.class, String[].class, + Integer.class, byte[].class, double[][].class); + Pair> pair = new Pair<>(method, + () -> { + // Make args + int a = 0; + String[] ss = {"a", "b", "c", "d"}; + Integer i = 1; + byte[] bb = {1, 2}; + double[][] dd = { + {1.618033, 3.141592}, + {2.718281, 0.007874} + }; + // Invoke method + method.invoke(classInstance, a, ss, i, bb, dd); + return true; + }); + pairs.add(pair); + } + { + Method method = getMethod(this, "method"); + Pair> pair = new Pair<>(method, + () -> { + method.invoke(classInstance); + return true; + }); + pairs.add(pair); + } + { + Method method = getMethod(this, "smethod"); + Pair> pair = new Pair<>(method, + () -> method.invoke(classInstance)); + pairs.add(pair); + } + { + Method method = getMethod(this, "smethod", int.class, int[].class); + Pair> pair = new Pair<>(method, + () -> { + int[] array = {1, 2, 3}; + return method.invoke(classInstance, 42, array); + }); + pairs.add(pair); + } + { + Method method = getMethod(this, "smethod", Integer.class); + Pair> pair = new Pair<>(method, + () -> method.invoke(classInstance, 100)); + pairs.add(pair); + } + return pairs; + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/pool/PoolHelper.java b/hotspot/test/compiler/compilercontrol/share/pool/PoolHelper.java new file mode 100644 index 00000000000..10918ed132f --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/pool/PoolHelper.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pool; + +import jdk.test.lib.Pair; +import pool.MethodHolder; +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * This is a helper class that provides tests with methods + */ +public class PoolHelper extends MethodHolder { + private static final List>> METHODS; + + /** + * Filters only those methods who belong to Klass or its internal class + * Internal and named as "method" or is a constructor + */ + public static final Predicate METHOD_FILTER = executable -> { + String methodName = executable.getName(); + String className = executable.getDeclaringClass().getName(); + return className.matches(".*(Klass)(\\$Internal)?") && + (methodName.equals("method") || + methodName.equals(className)); // if method is + }; + + static { + METHODS = new ArrayList<>(); + List holders = new ArrayList<>(); + holders.add(new pool.sub.Klass()); + holders.add(new pool.sub.KlassDup()); + holders.add(new pool.subpack.Klass()); + holders.add(new pool.subpack.KlassDup()); + holders.add(new pool.sub.Klass.Internal()); + holders.add(new pool.subpack.KlassDup.Internal()); + for (MethodHolder holder : holders) { + METHODS.addAll(holder.getAllMethods()); + } + } + + /** + * Gets all methods from the pool using specified filter + * + * @param filter method filter + * @return pairs of Executable and appropriate Callable + */ + public List>> getAllMethods( + Predicate filter) { + return getAllMethods().stream() + .filter(pair -> filter.test(pair.first)) + .collect(Collectors.toList()); + } + + /** + * Gets all methods from the pool + * + * @return pairs of Executable and appropriate Callable + */ + @Override + public List>> getAllMethods() { + return METHODS; + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/pool/sub/Klass.java b/hotspot/test/compiler/compilercontrol/share/pool/sub/Klass.java new file mode 100644 index 00000000000..9d677544e74 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/pool/sub/Klass.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pool.sub; + +import jdk.test.lib.Pair; +import pool.MethodHolder; + +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +/** + * Simple class with methods to test signatures + */ +public class Klass extends MethodHolder { + public void method(int a, String[] ss, Integer i, byte[] bb, double[][] dd) { } + + public void method() { } + + public static String smethod() { + return "ABC"; + } + + public static String smethod(int iarg, int[] aarg) { + return "ABC"; + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } + + // Internal class and constructor + public static class Internal extends MethodHolder { + public Internal() { } + + public Double method(Float fl) { return Double.valueOf(fl); } + + public Double methodDup() { + return Math.exp(1.0); + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } + + @Override + public List>> getAllMethods() { + List>> pairs = new ArrayList<>(); + Pair> pair = new Pair<> + (getMethod(this, "method", Float.class), + () -> this.method(3.141592f)); + pairs.add(pair); + pair = new Pair<>(getMethod(this, "methodDup"), this::methodDup); + pairs.add(pair); + pair = new Pair<>(getMethod(this, "smethod", Integer.class), + () -> smethod(1024)); + pairs.add(pair); + try { + pair = new Pair<>(this.getClass().getConstructor(), + Internal::new); + pairs.add(pair); + } catch (NoSuchMethodException e) { + throw new Error("TESTBUG: unable to get constructor"); + } + return pairs; + } + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/pool/sub/KlassDup.java b/hotspot/test/compiler/compilercontrol/share/pool/sub/KlassDup.java new file mode 100644 index 00000000000..6ddcdba7bee --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/pool/sub/KlassDup.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pool.sub; + +import pool.MethodHolder; + +/** + * Simple class with methods to test signatures + * This class has Dup suffix in the name to test suffix patterns like Klass*. + * Such patterns should match both Klass and KlassDup + */ +public class KlassDup extends MethodHolder { + public void method(int a, String[] ss, Integer i, byte[] bb, double[][] dd) { } + + public void method() { } + + public static String smethod() { + return "ABC"; + } + + public static String smethod(int iarg, int[] aarg) { + return "ABC"; + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/pool/subpack/Klass.java b/hotspot/test/compiler/compilercontrol/share/pool/subpack/Klass.java new file mode 100644 index 00000000000..59506e9d0b3 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/pool/subpack/Klass.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pool.subpack; + +import pool.MethodHolder; + +/** + * Simple class with methods to test signatures + * This is a clone of the pool.sub.Klass, but without inner class + * This class has different package name to test prefix patterns like *Klass. + * *Klass patern should match both pool.sub.Klass and pool.subpack.Klass + */ +public class Klass extends MethodHolder { + public void method(int a, String[] ss, Integer i, byte[] bb, double[][] dd) { } + + public void method() { } + + public static String smethod() { + return "ABC"; + } + + public static String smethod(int iarg, int[] aarg) { + return "ABC"; + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/pool/subpack/KlassDup.java b/hotspot/test/compiler/compilercontrol/share/pool/subpack/KlassDup.java new file mode 100644 index 00000000000..6349abdc167 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/pool/subpack/KlassDup.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pool.subpack; + +import jdk.test.lib.Pair; +import pool.MethodHolder; + +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +/** + * This is a clone of the pool.sub.Klass used to test pattern matching + * Full class name contains both suffix (Dup) and prefix (pool.subpack) + */ +public class KlassDup extends MethodHolder { + public void method(int a, String[] ss, Integer i, byte[] bb, double[][] dd) { } + + public void method() { } + + public static String smethod() { + return "ABC"; + } + + public static String smethod(int iarg, int[] aarg) { + return "ABC"; + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } + + // Internal class and constructor + public static class Internal extends MethodHolder { + public Internal() { } + + public Double method(Float fl) { return Double.valueOf(fl); } + + public Double methodDup() { + return Math.exp(1.0); + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } + + @Override + public List>> getAllMethods() { + List>> pairs = new ArrayList<>(); + Pair> pair = new Pair<> + (getMethod(this, "method", Float.class), + () -> this.method(3.141592f)); + pairs.add(pair); + pair = new Pair<>(getMethod(this, "methodDup"), this::methodDup); + pairs.add(pair); + pair = new Pair<>(getMethod(this, "smethod", Integer.class), + () -> smethod(1024)); + pairs.add(pair); + try { + pair = new Pair<>(this.getClass().getConstructor(), + Internal::new); + pairs.add(pair); + } catch (NoSuchMethodException e) { + throw new Error("TESTBUG: unable to get constructor"); + } + return pairs; + } + } +} diff --git a/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java b/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java new file mode 100644 index 00000000000..d31b62cf505 --- /dev/null +++ b/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary / + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Dcompiler.jvmci.JVM_GetJVMCIRuntimeTest.positive=true + * -XX:+EnableJVMCI + * compiler.jvmci.JVM_GetJVMCIRuntimeTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Dcompiler.jvmci.JVM_GetJVMCIRuntimeTest.positive=false + * -XX:-EnableJVMCI + * compiler.jvmci.JVM_GetJVMCIRuntimeTest + + */ + +package compiler.jvmci; + +import jdk.vm.ci.runtime.JVMCI; +import jdk.test.lib.Asserts; + +import java.lang.reflect.Method; + +public class JVM_GetJVMCIRuntimeTest { + private static final boolean IS_POSITIVE = Boolean.getBoolean( + "compiler.jvmci.JVM_GetJVMCIRuntimeTest.positive"); + + private final Method initializeRuntime; + + public static void main(String[] args) { + new JVM_GetJVMCIRuntimeTest().runTest(); + } + + private void runTest() { + Object result; + try { + result = invoke(); + } catch (InternalError e) { + if (IS_POSITIVE) { + throw new AssertionError("unexpected exception", e); + } + return; + } + if (!IS_POSITIVE) { + throw new AssertionError("didn't get expected exception"); + } + Asserts.assertNotNull(result, + "initializeRuntime returned null"); + Asserts.assertEQ(result, invoke(), + "initializeRuntime returns different results"); + + } + private Object invoke() { + Object result; + try { + result = initializeRuntime.invoke(JVMCI.class); + } catch (ReflectiveOperationException e) { + throw new Error("can't invoke initializeRuntime", e); + } + return result; + } + + private JVM_GetJVMCIRuntimeTest() { + Method method; + try { + method = JVMCI.class.getDeclaredMethod("initializeRuntime"); + method.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new Error("can't find JVMCI::initializeRuntime", e); + } + initializeRuntime = method; + } +} diff --git a/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java b/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java new file mode 100644 index 00000000000..c6e40a8cb9d --- /dev/null +++ b/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.SecurityRestrictionsTest + * NO_SEC_MAN + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.SecurityRestrictionsTest + * NO_PERM + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.SecurityRestrictionsTest + * ALL_PERM + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.SecurityRestrictionsTest + * NO_JVMCI_ACCESS_PERM + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * compiler.jvmci.SecurityRestrictionsTest + * NO_JVMCI + */ + +package compiler.jvmci; + +import jdk.vm.ci.hotspot.CompilerToVM; +import jdk.test.lib.Utils; +import java.lang.InternalError; +import java.security.AccessControlException; +import java.security.Permission; +import java.util.PropertyPermission; +import java.util.function.Consumer; + +public class SecurityRestrictionsTest { + + public static void main(String[] args) { + try { + // to init Utils before call SecurityManager + Class.forName(Utils.class.getName(), true, + Utils.class.getClassLoader()); + } catch (ClassNotFoundException e) { + throw new Error("[TEST BUG]: jdk.test.lib.Utils not found", e); + } + try { + TestCase mode = TestCase.valueOf(args[0]); + mode.run(); + } catch (IllegalArgumentException e) { + throw new Error("[TEST BUG]: Unknown mode " + args[0], e); + } + } + + private enum TestCase { + NO_SEC_MAN, + NO_JVMCI { + @Override + public Class getExpectedException() { + return InternalError.class; + } + }, + ALL_PERM { + @Override + public SecurityManager getSecurityManager() { + return new SecurityManager() { + @Override + public void checkPermission(Permission perm) { + } + }; + } + }, + NO_PERM { + @Override + public SecurityManager getSecurityManager() { + return new SecurityManager(); + } + + @Override + public Class getExpectedException() { + return AccessControlException.class; + } + }, + NO_JVMCI_ACCESS_PERM { + @Override + public SecurityManager getSecurityManager() { + return new SecurityManager() { + @Override + public void checkPermission(Permission perm) { + if (isJvmciPermission(perm)) { + super.checkPermission(perm); + } + } + + @Override + public void checkPropertyAccess(String key) { + if (key.startsWith(JVMCI_PROP_START)) { + super.checkPropertyAccess(key); + } + } + }; + } + + private boolean isJvmciPermission(Permission perm) { + String name = perm.getName(); + boolean isJvmciRuntime = perm instanceof RuntimePermission + && (JVMCI_SERVICES.equals(name) + || name.startsWith(JVMCI_RT_PERM_START)); + boolean isJvmciProperty = perm instanceof PropertyPermission + && name.startsWith(JVMCI_PROP_START); + return isJvmciRuntime || isJvmciProperty; + } + + @Override + public Class getExpectedException() { + return AccessControlException.class; + } + }; + + public void run() { + System.setSecurityManager(getSecurityManager()); + Consumer exceptionCheck = e -> { + if (e == null) { + if (getExpectedException() != null) { + String message = name() + ": Didn't get expected exception " + + getExpectedException(); + throw new AssertionError(message); + } + } else { + String message = name() + ": Got unexpected exception " + + e.getClass().getSimpleName(); + if (getExpectedException() == null){ + throw new AssertionError(message, e); + } + + Throwable t = e; + while (t.getCause() != null) { + t = t.getCause(); + } + if (!getExpectedException().isAssignableFrom(t.getClass())) { + message += " instead of " + getExpectedException() + .getSimpleName(); + throw new AssertionError(message, e); + } + } + }; + Utils.runAndCheckException(CompilerToVM::new, exceptionCheck); + } + + public SecurityManager getSecurityManager() { + return null; + } + + public Class getExpectedException() { + return null; + } + + private static final String JVMCI_RT_PERM_START + = "accessClassInPackage.jdk.vm.ci"; + private static final String JVMCI_SERVICES = "jvmciServices"; + private static final String JVMCI_PROP_START = "jvmci."; + + } +} diff --git a/hotspot/test/compiler/jvmci/common/CTVMUtilities.java b/hotspot/test/compiler/jvmci/common/CTVMUtilities.java new file mode 100644 index 00000000000..02fa6b1cf19 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/CTVMUtilities.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common; + +import java.lang.reflect.Field; +import java.lang.reflect.Executable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; + +public class CTVMUtilities { + /* + * A method to return HotSpotResolvedJavaMethod object using class object + * and method as input + */ + public static HotSpotResolvedJavaMethodImpl getResolvedMethod(Class cls, + Executable method) { + if (!(method instanceof Method || method instanceof Constructor)) { + throw new Error("wrong executable type " + method.getClass()); + } + Field slotField; + int slot; + try { + slotField = method.getClass().getDeclaredField("slot"); + boolean old = slotField.isAccessible(); + slotField.setAccessible(true); + slot = slotField.getInt(method); + slotField.setAccessible(old); + } catch (ReflectiveOperationException e) { + throw new Error("TEST BUG: Can't get slot field", e); + } + return CompilerToVMHelper.getResolvedJavaMethodAtSlot(cls, slot); + } + + public static HotSpotResolvedJavaMethodImpl getResolvedMethod( + Executable method) { + return getResolvedMethod(method.getDeclaringClass(), method); + } +} diff --git a/hotspot/test/compiler/jvmci/common/CompilerToVMHelper.java b/hotspot/test/compiler/jvmci/common/CompilerToVMHelper.java new file mode 100644 index 00000000000..2e12233a486 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/CompilerToVMHelper.java @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.SpeculationLog; + +/* + * A simple "proxy" class to get test access to CompilerToVM package-private methods + */ +public class CompilerToVMHelper { + public static final CompilerToVM CTVM = new CompilerToVM(); + + public static byte[] getBytecode(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getBytecode(method); + } + + public static int getExceptionTableLength(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getExceptionTableLength(method); + } + + public static long getExceptionTableStart(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getExceptionTableStart(method); + } + + public static boolean canInlineMethod(HotSpotResolvedJavaMethodImpl method) { + return CTVM.canInlineMethod(method); + } + + public static boolean shouldInlineMethod(HotSpotResolvedJavaMethodImpl method) { + return CTVM.shouldInlineMethod(method); + } + + public static HotSpotResolvedJavaMethodImpl findUniqueConcreteMethod( + HotSpotResolvedObjectTypeImpl actualHolderType, + HotSpotResolvedJavaMethodImpl method) { + return CTVM.findUniqueConcreteMethod(actualHolderType, method); + } + + public static HotSpotResolvedObjectTypeImpl getImplementor(HotSpotResolvedObjectTypeImpl type) { + return CTVM.getImplementor(type); + } + + public static boolean methodIsIgnoredBySecurityStackWalk(HotSpotResolvedJavaMethodImpl method) { + return CTVM.methodIsIgnoredBySecurityStackWalk(method); + } + + public static HotSpotResolvedObjectTypeImpl lookupType(String name, + Class accessingClass, boolean resolve) { + return CTVM.lookupType(name, accessingClass, resolve); + } + + public static Object resolveConstantInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.resolveConstantInPool(constantPool, cpi); + } + + public static Object resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.resolvePossiblyCachedConstantInPool(constantPool, cpi); + } + + public static int lookupNameAndTypeRefIndexInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupNameAndTypeRefIndexInPool(constantPool, cpi); + } + + public static String lookupNameInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupNameInPool(constantPool, cpi); + } + + public static String lookupSignatureInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupSignatureInPool(constantPool, cpi); + } + + public static int lookupKlassRefIndexInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupKlassRefIndexInPool(constantPool, cpi); + } + + public static Object lookupKlassInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupKlassInPool(constantPool, cpi); + } + + public static HotSpotResolvedJavaMethodImpl lookupMethodInPool( + HotSpotConstantPool constantPool, int cpi, byte opcode) { + return CTVM.lookupMethodInPool(constantPool, cpi, opcode); + } + + public static void resolveInvokeDynamicInPool(HotSpotConstantPool constantPool, int cpi) { + CTVM.resolveInvokeDynamicInPool(constantPool, cpi); + } + + public static void resolveInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi) { + CTVM.resolveInvokeHandleInPool(constantPool, cpi); + } + + public static HotSpotResolvedObjectTypeImpl resolveTypeInPool( + HotSpotConstantPool constantPool, int cpi) throws LinkageError { + return CTVM.resolveTypeInPool(constantPool, cpi); + } + + public static HotSpotResolvedObjectTypeImpl resolveFieldInPool( + HotSpotConstantPool constantPool, int cpi, byte opcode, long[] info) { + return CTVM.resolveFieldInPool(constantPool, cpi, opcode, info); + } + + public static int constantPoolRemapInstructionOperandFromCache( + HotSpotConstantPool constantPool, int cpci) { + return CTVM.constantPoolRemapInstructionOperandFromCache(constantPool, cpci); + } + + public static Object lookupAppendixInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupAppendixInPool(constantPool, cpi); + } + + public static int installCode(TargetDescription target, + HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog) { + return CTVM.installCode(target, compiledCode, code, speculationLog); + } + + public static int getMetadata(TargetDescription target, + HotSpotCompiledCode compiledCode, HotSpotMetaData metaData) { + return CTVM.getMetadata(target, compiledCode, metaData); + } + + public static void notifyCompilationStatistics(int id, + HotSpotResolvedJavaMethodImpl method, boolean osr, + int processedBytecodes, long time, long timeUnitsPerSecond, + InstalledCode installedCode) { + CTVM.notifyCompilationStatistics(id, method, osr, processedBytecodes, + time, timeUnitsPerSecond, installedCode); + } + + public static void resetCompilationStatistics() { + CTVM.resetCompilationStatistics(); + } + + public static long initializeConfiguration() { + return CTVM.initializeConfiguration(); + } + + public static HotSpotResolvedJavaMethodImpl resolveMethod( + HotSpotResolvedObjectTypeImpl exactReceiver, + HotSpotResolvedJavaMethodImpl method, + HotSpotResolvedObjectTypeImpl caller) { + return CTVM.resolveMethod(exactReceiver, method, caller); + } + + public static HotSpotResolvedJavaMethodImpl getClassInitializer( + HotSpotResolvedObjectTypeImpl type) { + return CTVM.getClassInitializer(type); + } + + public static boolean hasFinalizableSubclass(HotSpotResolvedObjectTypeImpl type) { + return CTVM.hasFinalizableSubclass(type); + } + + public static HotSpotResolvedJavaMethodImpl getResolvedJavaMethodAtSlot(Class holder, + int slot) { + return CTVM.getResolvedJavaMethodAtSlot(holder, slot); + } + + public static long getMaxCallTargetOffset(long address) { + return CTVM.getMaxCallTargetOffset(address); + } + + public static String disassembleCodeBlob(long codeBlob) { + return CTVM.disassembleCodeBlob(codeBlob); + } + + public static StackTraceElement getStackTraceElement( + HotSpotResolvedJavaMethodImpl method, int bci) { + return CTVM.getStackTraceElement(method, bci); + } + + public static Object executeInstalledCode(Object[] args, + InstalledCode installedCode) throws InvalidInstalledCodeException { + return CTVM.executeInstalledCode(args, installedCode); + } + + public static long[] getLineNumberTable(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getLineNumberTable(method); + } + + public static int getLocalVariableTableLength(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getLocalVariableTableLength(method); + } + + public static long getLocalVariableTableStart(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getLocalVariableTableStart(method); + } + + public static Object readUncompressedOop(long address) { + return CTVM.readUncompressedOop(address); + } + + public static void doNotInlineOrCompile(HotSpotResolvedJavaMethodImpl method) { + CTVM.doNotInlineOrCompile(method); + } + + public static void reprofile(HotSpotResolvedJavaMethodImpl method) { + CTVM.reprofile(method); + } + + public static void invalidateInstalledCode(InstalledCode installedCode) { + CTVM.invalidateInstalledCode(installedCode); + } + + public static long[] collectCounters() { + return CTVM.collectCounters(); + } + + public static boolean isMature(long metaspaceMethodData) { + return CTVM.isMature(metaspaceMethodData); + } + + public static int allocateCompileId(HotSpotResolvedJavaMethodImpl method, + int entryBCI) { + return CTVM.allocateCompileId(method, entryBCI); + } + + public static boolean hasCompiledCodeForOSR( + HotSpotResolvedJavaMethodImpl method, int entryBCI, int level) { + return CTVM.hasCompiledCodeForOSR(method, entryBCI, level); + } + + public static String getSymbol(long metaspaceSymbol) { + return CTVM.getSymbol(metaspaceSymbol); + } + + public static HotSpotStackFrameReference getNextStackFrame( + HotSpotStackFrameReference frame, + HotSpotResolvedJavaMethodImpl[] methods, int initialSkip) { + return CTVM.getNextStackFrame(frame, methods, initialSkip); + } + + public static void materializeVirtualObjects( + HotSpotStackFrameReference stackFrame, boolean invalidate) { + CTVM.materializeVirtualObjects(stackFrame, invalidate); + } + + public static int getVtableIndexForInterfaceMethod(HotSpotResolvedObjectTypeImpl type, + HotSpotResolvedJavaMethodImpl method) { + return CTVM.getVtableIndexForInterfaceMethod(type, method); + } + + public static boolean shouldDebugNonSafepoints() { + return CTVM.shouldDebugNonSafepoints(); + } + + public static void writeDebugOutput(byte[] bytes, int offset, int length) { + CTVM.writeDebugOutput(bytes, offset, length); + } + + public static void flushDebugOutput() { + CTVM.flushDebugOutput(); + } + + public static HotSpotResolvedJavaMethodImpl getResolvedJavaMethod(Object base, + long displacement) { + return CTVM.getResolvedJavaMethod(base, displacement); + } + + public static HotSpotConstantPool getConstantPool(Object base, long displacement) { + return CTVM.getConstantPool(base, displacement); + } + + public static HotSpotResolvedObjectTypeImpl getResolvedJavaType(Object base, + long displacement, boolean compressed) { + return CTVM.getResolvedJavaType(base, displacement, compressed); + } +} diff --git a/hotspot/test/compiler/jvmci/common/JVMCIHelpers.java b/hotspot/test/compiler/jvmci/common/JVMCIHelpers.java new file mode 100644 index 00000000000..9b80bf809d5 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/JVMCIHelpers.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; +import jdk.vm.ci.compiler.Compiler; +import jdk.vm.ci.compiler.CompilerFactory; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.runtime.JVMCIRuntime; + +/* + * A stub classes to be able to use jvmci + */ +public class JVMCIHelpers { + + public static class EmptyVMEventListener implements HotSpotVMEventListener { + // just empty, using default interface methods + } + + public static class EmptyHotspotCompiler implements Compiler { + + @Override + public void compileMethod(ResolvedJavaMethod method, int entryBCI, + long jvmciEnv, int id) { + // do nothing + } + } + + public static class EmptyCompilerFactory implements CompilerFactory { + + @Override + public String getCompilerName() { + return "EmptyCompiler"; + } + + @Override + public Architecture initializeArchitecture(Architecture arch) { + return arch; + } + + @Override + public Compiler createCompiler(JVMCIRuntime runtime) { + return new EmptyHotspotCompiler(); + } + } +} diff --git a/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.compiler.Compiler b/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.compiler.Compiler new file mode 100644 index 00000000000..c1b6ffcd621 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.compiler.Compiler @@ -0,0 +1 @@ +compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler diff --git a/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.compiler.CompilerFactory b/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.compiler.CompilerFactory new file mode 100644 index 00000000000..5a88a1f4914 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.compiler.CompilerFactory @@ -0,0 +1 @@ +compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory diff --git a/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.hotspot.HotSpotVMEventListener b/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.hotspot.HotSpotVMEventListener new file mode 100644 index 00000000000..2b70db58445 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.hotspot.HotSpotVMEventListener @@ -0,0 +1 @@ +compiler.jvmci.common.JVMCIHelpers$EmptyVMEventListener diff --git a/hotspot/test/compiler/jvmci/common/testcases/AbstractClass.java b/hotspot/test/compiler/jvmci/common/testcases/AbstractClass.java new file mode 100644 index 00000000000..ebe39ce33c7 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/AbstractClass.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public abstract class AbstractClass { + public static final long initTime = System.currentTimeMillis(); + public abstract void abstractMethod(); +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/AbstractClassExtender.java b/hotspot/test/compiler/jvmci/common/testcases/AbstractClassExtender.java new file mode 100644 index 00000000000..cec76b2cf3d --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/AbstractClassExtender.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class AbstractClassExtender extends AbstractClass { + @Override + public void abstractMethod() { + // empty + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/AnotherSingleImplementer.java b/hotspot/test/compiler/jvmci/common/testcases/AnotherSingleImplementer.java new file mode 100644 index 00000000000..95d10a1c4cc --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/AnotherSingleImplementer.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class AnotherSingleImplementer implements AnotherSingleImplementerInterface { + + @Override + public void interfaceMethod() { + // empty + } + + public void nonInterfaceMethod() { + // empty + } + + @Override + public void finalize() throws Throwable { + super.finalize(); + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/AnotherSingleImplementerInterface.java b/hotspot/test/compiler/jvmci/common/testcases/AnotherSingleImplementerInterface.java new file mode 100644 index 00000000000..52e66b1a341 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/AnotherSingleImplementerInterface.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public interface AnotherSingleImplementerInterface { + public static final long initTime = System.currentTimeMillis(); + + default void defaultMethod() { + // empty + } + + void interfaceMethod(); + + void finalize() throws Throwable; +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/DoNotExtendClass.java b/hotspot/test/compiler/jvmci/common/testcases/DoNotExtendClass.java new file mode 100644 index 00000000000..97e27bf5003 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/DoNotExtendClass.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class DoNotExtendClass { + // empty +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/DoNotImplementInterface.java b/hotspot/test/compiler/jvmci/common/testcases/DoNotImplementInterface.java new file mode 100644 index 00000000000..fb721a35df4 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/DoNotImplementInterface.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public interface DoNotImplementInterface { + // empty +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClass.java b/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClass.java new file mode 100644 index 00000000000..080b1ec61b2 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClass.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class MultiSubclassedClass { + // empty +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClassSubclass1.java b/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClassSubclass1.java new file mode 100644 index 00000000000..d1b25ddca07 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClassSubclass1.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class MultiSubclassedClassSubclass1 extends MultiSubclassedClass { + // empty +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClassSubclass2.java b/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClassSubclass2.java new file mode 100644 index 00000000000..f39564e4543 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClassSubclass2.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class MultiSubclassedClassSubclass2 extends MultiSubclassedClass { + // empty +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java new file mode 100644 index 00000000000..d90b5285c02 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public abstract class MultipleAbstractImplementer + implements MultipleImplementersInterface { + + public abstract void abstractMethod(); + + @Override + public void finalize() throws Throwable { + super.finalize(); + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer1.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer1.java new file mode 100644 index 00000000000..ba58d924773 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer1.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class MultipleImplementer1 implements MultipleImplementersInterface { + + @Override + public void defaultMethod() { + // empty + } + + @Override + public void testMethod() { + // empty + } + @Override + public void finalize() throws Throwable { + super.finalize(); + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java new file mode 100644 index 00000000000..274df6b5c0f --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class MultipleImplementer2 implements MultipleImplementersInterface { + + private static int intStaticField = INT_CONSTANT; + static long longStaticField = LONG_CONSTANT; + static float floatStaticField = FLOAT_CONSTANT; + static double doubleStaticField = DOUBLE_CONSTANT; + public static String stringStaticField = STRING_CONSTANT; + protected static Object objectStaticField = OBJECT_CONSTANT; + + public int intField = INT_CONSTANT; + private long longField = LONG_CONSTANT; + protected float floatField = FLOAT_CONSTANT; + double doubleField = DOUBLE_CONSTANT; + String stringField = STRING_CONSTANT; + Object objectField = OBJECT_CONSTANT; + + public MultipleImplementer2() { + intField = Integer.MAX_VALUE; + longField = Long.MAX_VALUE; + floatField = Float.MAX_VALUE; + doubleField = Double.MAX_VALUE; + stringField = "Message"; + objectField = new Object(); + } + + @Override + public void testMethod() { + // empty + } + + @Override + public void finalize() throws Throwable { + super.finalize(); + } + + public void interfaceMethodReferral2(MultipleImplementersInterface obj) { + obj.interfaceMethodReferral(obj); + } + + public void lambdaUsingMethod2() { + Thread t = new Thread(this::testMethod); + t.start(); + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java new file mode 100644 index 00000000000..9ce4e792bc6 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public interface MultipleImplementersInterface { + + int INT_CONSTANT = Integer.MAX_VALUE; + long LONG_CONSTANT = Long.MAX_VALUE; + float FLOAT_CONSTANT = Float.MAX_VALUE; + double DOUBLE_CONSTANT = Double.MAX_VALUE; + String STRING_CONSTANT = "Hello"; + Object OBJECT_CONSTANT = new Object(); + + default void defaultMethod() { + // empty + } + + void testMethod(); + + default void finalize() throws Throwable { + // empty + } + + default void interfaceMethodReferral(MultipleImplementersInterface obj) { + obj.defaultMethod(); + } + + default void lambdaUsingMethod() { + Thread t = new Thread(this::defaultMethod); + t.start(); + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterfaceExtender.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterfaceExtender.java new file mode 100644 index 00000000000..5091a4bc382 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterfaceExtender.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public interface MultipleImplementersInterfaceExtender + extends MultipleImplementersInterface { + // provide default implementation for parent interface + @Override + default void testMethod() { + // empty + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/PackagePrivateClass.java b/hotspot/test/compiler/jvmci/common/testcases/PackagePrivateClass.java new file mode 100644 index 00000000000..25099b28e80 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/PackagePrivateClass.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +class PackagePrivateClass { + // empty +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/SimpleClass.java b/hotspot/test/compiler/jvmci/common/testcases/SimpleClass.java new file mode 100644 index 00000000000..e2b4172e25c --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/SimpleClass.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +// just a most common simple class with method "testMethod" to use anywhere +public class SimpleClass { + + public void testMethod() { + // empty + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/SingleImplementer.java b/hotspot/test/compiler/jvmci/common/testcases/SingleImplementer.java new file mode 100644 index 00000000000..b8f81593931 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/SingleImplementer.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class SingleImplementer implements SingleImplementerInterface { + public static final long initTime = System.currentTimeMillis(); + + @Override + public void interfaceMethod() { + // empty + } + + public void nonInterfaceMethod() { + // empty + } + + @Override + public void finalize() throws Throwable { + super.finalize(); + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/SingleImplementerInterface.java b/hotspot/test/compiler/jvmci/common/testcases/SingleImplementerInterface.java new file mode 100644 index 00000000000..de7ae981d34 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/SingleImplementerInterface.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public interface SingleImplementerInterface { + public static final long initTime = System.currentTimeMillis(); + + default void defaultMethod() { + // empty + } + + void interfaceMethod(); + + void finalize() throws Throwable; +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/SingleSubclass.java b/hotspot/test/compiler/jvmci/common/testcases/SingleSubclass.java new file mode 100644 index 00000000000..86eca3fb4a2 --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/SingleSubclass.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class SingleSubclass extends SingleSubclassedClass { + public void usualMethod() { + // empty + } + + @Override + public void overridenMethod() { + // empty + } + + private void privateMethod() { + // empty + } + + public static void staticMethod() { + // empty + } + + protected void protectedMethod() { + // empty + } + + void defaultAccessMethod() { + // empty + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/SingleSubclassedClass.java b/hotspot/test/compiler/jvmci/common/testcases/SingleSubclassedClass.java new file mode 100644 index 00000000000..215c3ed36cd --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/SingleSubclassedClass.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.common.testcases; + +public class SingleSubclassedClass { + public void inheritedMethod() { + // empty + } + + public void overridenMethod() { + //empty + } +} diff --git a/hotspot/test/compiler/jvmci/common/testcases/TestCase.java b/hotspot/test/compiler/jvmci/common/testcases/TestCase.java new file mode 100644 index 00000000000..d08fe31317b --- /dev/null +++ b/hotspot/test/compiler/jvmci/common/testcases/TestCase.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package compiler.jvmci.common.testcases; + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.ArrayList; +import java.util.Set; + +/** + * A test case for tests in compiler.jvmci.compilerToVM package. + */ +public class TestCase { + private static final Class[] CLASSES = { + AbstractClass.class, + AbstractClassExtender.class, + AnotherSingleImplementer.class, + AnotherSingleImplementerInterface.class, + DoNotExtendClass.class, + DoNotImplementInterface.class, + MultipleAbstractImplementer.class, + MultipleImplementer1.class, + MultipleImplementer2.class, + MultipleImplementersInterface.class, + MultipleImplementersInterfaceExtender.class, + MultiSubclassedClass.class, + MultiSubclassedClassSubclass1.class, + MultiSubclassedClassSubclass2.class, + PackagePrivateClass.class, + SimpleClass.class, + SingleImplementer.class, + SingleImplementerInterface.class, + SingleSubclass.class, + SingleSubclassedClass.class + }; + + public static Collection> getAllClasses() { + return Arrays.asList(CLASSES); + } + + public static Collection getAllExecutables() { + Set result = new HashSet<>(); + for (Class aClass : CLASSES) { + result.addAll(Arrays.asList(aClass.getMethods())); + result.addAll(Arrays.asList(aClass.getConstructors())); + } + return result; + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java new file mode 100644 index 00000000000..eb09de4fdc0 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:-BackgroundCompilation + * compiler.jvmci.compilerToVM.AllocateCompileIdTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.HashSet; + +import compiler.jvmci.common.testcases.TestCase; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Pair; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; + +public class AllocateCompileIdTest { + + private final HashSet ids = new HashSet<>(); + + public static void main(String[] args) { + AllocateCompileIdTest test = new AllocateCompileIdTest(); + createTestCasesCorrectBci().forEach(test::runSanityCorrectTest); + createTestCasesIncorrectBci().forEach(test::runSanityIncorrectTest); + } + + + private static List createTestCasesCorrectBci() { + List result = new ArrayList<>(); + try { + Class aClass = DummyClass.class; + Method method = aClass.getMethod("withLoop"); + result.add(new CompileCodeTestCase(method, 17)); + result.add(new CompileCodeTestCase(method, -1)); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG : " + e, e); + } + return result; + } + + + private static List>> + createTestCasesIncorrectBci() { + List>> result + = new ArrayList<>(); + + try { + Class aClass = DummyClass.class; + Method method = aClass.getMethod("dummyInstanceFunction"); + // greater than bytecode.length + int[] bcis = new int[] {30, 50, 200}; + for (int bci : bcis) { + result.add(new Pair<>(new CompileCodeTestCase(method, bci), + IllegalArgumentException.class)); + } + bcis = new int[] {-4, -50, -200}; + for (int bci : bcis) { + result.add(new Pair<>(new CompileCodeTestCase(method, bci), + IllegalArgumentException.class)); + } + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG : " + e.getMessage(), e); + } + return result; + } + + private void runSanityCorrectTest(CompileCodeTestCase testCase) { + System.out.println(testCase); + Executable aMethod = testCase.executable; + int bci = testCase.bci; + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + int wbCompileID = getWBCompileID(testCase); + int id = CompilerToVMHelper.allocateCompileId(method, bci); + Asserts.assertNE(id, 0, testCase + " : zero compile id"); + + if (wbCompileID > 0) { + Asserts.assertGT(id, wbCompileID, testCase + + " : allocated 'compile id' not greater than existed"); + if (!ids.add(wbCompileID)) { + throw new AssertionError(String.format( + "%s : vm compilation allocated existed id -- %d", + testCase, id)); + } + } + if (!ids.add(id)) { + throw new AssertionError(String.format( + "%s : allocateCompileId returned existed id %d", + testCase, id)); + } + } + + private void runSanityIncorrectTest( + Pair> testCase) { + System.out.println(testCase); + Class exception = testCase.second; + Executable aMethod = testCase.first.executable; + int bci = testCase.first.bci; + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + Utils.runAndCheckException( + () -> CompilerToVMHelper.allocateCompileId(method, bci), + exception); + } + + private int getWBCompileID(CompileCodeTestCase testCase) { + NMethod nm = testCase.deoptimizeAndCompile(); + if (nm == null) { + throw new Error("[TEST BUG] cannot compile method " + testCase); + } + return nm.compile_id; + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java new file mode 100644 index 00000000000..9b164dade4e --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.CanInlineMethodTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +public class CanInlineMethodTest { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String[] args) { + List testCases = createTestCases(); + testCases.forEach(CanInlineMethodTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + boolean canInline = CompilerToVMHelper.canInlineMethod(method); + boolean expectedCanInline = !WB.testSetDontInlineMethod(aMethod, + true); + Asserts.assertEQ(canInline, expectedCanInline, "Unexpected initial " + + "value of property 'can inline'"); + + canInline = CompilerToVMHelper.canInlineMethod(method); + Asserts.assertFalse(canInline, aMethod + "Unexpected value of " + + "property 'can inline' after setting 'do not inline' to true"); + WB.testSetDontInlineMethod(aMethod, false); + canInline = CompilerToVMHelper.canInlineMethod(method); + Asserts.assertTrue(canInline, "Unexpected value of " + + "property 'can inline' after setting 'do not inline' to false"); + } + + private static List createTestCases() { + List testCases = new ArrayList<>(); + + Class aClass = DummyClass.class; + testCases.addAll(Arrays.asList(aClass.getDeclaredMethods())); + testCases.addAll(Arrays.asList(aClass.getDeclaredConstructors())); + return testCases; + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java b/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java new file mode 100644 index 00000000000..be23e77ff2e --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib/ + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.CollectCountersTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI -Xbootclasspath/a:. + * -XX:JVMCICounterSize=0 + * -Dcompiler.jvmci.compilerToVM.CollectCountersTest.expected=0 + * compiler.jvmci.compilerToVM.CollectCountersTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI -Xbootclasspath/a:. + * -XX:JVMCICounterSize=11 + * -Dcompiler.jvmci.compilerToVM.CollectCountersTest.expected=11 + * compiler.jvmci.compilerToVM.CollectCountersTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class CollectCountersTest { + private static final int EXPECTED = Integer.getInteger( + "compiler.jvmci.compilerToVM.CollectCountersTest.expected"); + public static void main(String args[]) { + new CollectCountersTest().runTest(); + } + + private void runTest() { + long[] counters = CompilerToVMHelper.collectCounters(); + Asserts.assertNotNull(counters, "Expected not-null counters array"); + int ctvmData = counters.length; + Asserts.assertEQ(EXPECTED, ctvmData, "Unexpected counters amount"); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/CompileCodeTestCase.java b/hotspot/test/compiler/jvmci/compilerToVM/CompileCodeTestCase.java new file mode 100644 index 00000000000..00be80ea3ab --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/CompileCodeTestCase.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package compiler.jvmci.compilerToVM; + +import compiler.testlibrary.CompilerUtils; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; + +import java.lang.reflect.Executable; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A test case for tests which require compiled code. + */ +public final class CompileCodeTestCase { + public static final Map, Object> RECEIVERS; + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final int COMP_LEVEL; + static { + int[] levels = CompilerUtils.getAvailableCompilationLevels(); + if (levels.length == 0) { + throw new Error("TESTBUG: no compilers available"); + } + COMP_LEVEL = levels[levels.length - 1]; + } + private static final Class[] CLASSES = { + Interface.class, + Dummy.class, + DummyEx.class}; + + public final Executable executable; + public final int bci; + private final boolean isOsr; + + public CompileCodeTestCase(Executable executable, int bci) { + this.executable = executable; + this.bci = bci; + isOsr = bci >= 0; + } + + public NMethod compile() { + return compile(COMP_LEVEL); + } + + public NMethod compile(int level) { + boolean enqueued = WB.enqueueMethodForCompilation(executable, + level, bci); + if (!enqueued) { + throw new Error(String.format( + "%s can't be enqueued for %scompilation on level %d", + executable, bci >= 0 ? "osr-" : "", level)); + } + Utils.waitForCondition(() -> WB.isMethodCompiled(executable, isOsr)); + return NMethod.get(executable, isOsr); + } + + public static List generate(int bci) { + ArrayList result = new ArrayList<>(); + for (Class aClass : CLASSES) { + for (Executable m : aClass.getDeclaredConstructors()) { + result.add(new CompileCodeTestCase(m, bci)); + } + Arrays.stream(aClass.getDeclaredMethods()) + .filter(m -> !Modifier.isAbstract(m.getModifiers())) + .filter(m -> !Modifier.isNative(m.getModifiers())) + .map(m -> new CompileCodeTestCase(m, bci)) + .forEach(result::add); + } + return result; + } + + public NMethod toNMethod() { + return NMethod.get(executable, isOsr); + } + + @Override + public String toString() { + return "CompileCodeTestCase{" + + "executable=" + executable + + ", bci=" + bci + + '}'; + } + + public void deoptimize() { + WB.deoptimizeMethod(executable, isOsr); + } + + public NMethod deoptimizeAndCompile() { + deoptimize(); + return compile(); + } + + // classes which are used as "input" data in test cases + private static interface Interface { + Interface interfaceMethod(); + default Long defaultOverriddenMethod(Interface[] array) { + return array == null ? 0L : array.length; + } + default int defaultMethod(Object o) { + return o != null ? o.hashCode() : 0; + } + } + + private static abstract class Dummy implements Interface { + protected Dummy() { + } + + private static void staticMethod() { + } + + Dummy instanceMethod(int i) { + return null; + } + + abstract Object abstractMethod(double d); + + @Override + public Long defaultOverriddenMethod(Interface[] array) { + return 0L; + } + } + + public static class DummyEx extends Dummy { + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return 0; + } + + public DummyEx() { + } + + protected Dummy instanceMethod(int i) { + if (i == 0) { + return this; + } + return null; + } + + @Override + Object abstractMethod(double d) { + return this; + } + + @Override + public Interface interfaceMethod() { + return null; + } + } + + static { + Map, Object> map = new HashMap<>();; + map.put(CompileCodeTestCase.DummyEx.class, + new CompileCodeTestCase.DummyEx()); + map.put(CompileCodeTestCase.Dummy.class, + new CompileCodeTestCase.Dummy() { + @Override + public CompileCodeTestCase.Interface interfaceMethod() { + throw new AbstractMethodError(); + } + + @Override + Object abstractMethod(double d) { + throw new AbstractMethodError(); + } + }); + map.put(CompileCodeTestCase.Interface.class, + new CompileCodeTestCase.Interface() { + @Override + public CompileCodeTestCase.Interface interfaceMethod() { + throw new AbstractMethodError(); + } + }); + RECEIVERS = Collections.unmodifiableMap(map); + } + +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java new file mode 100644 index 00000000000..9f5409e551d --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package compiler.jvmci.compilerToVM; + +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.internal.misc.SharedSecrets; +import sun.reflect.ConstantPool; + +/** + * Common class for jdk.vm.ci.hotspot.CompilerToVM constant pool tests + */ +public class ConstantPoolTestCase { + + private final Map typeTests; + + public static interface Validator { + void validate(HotSpotConstantPool constantPoolCTVM, ConstantPool constantPoolSS, + ConstantPoolTestsHelper.DummyClasses dummyClass, int index); + } + + public ConstantPoolTestCase(Map typeTests) { + this.typeTests = new HashMap<>(); + this.typeTests.putAll(typeTests); + } + + private void messageOnFail(Throwable t, + ConstantPoolTestsHelper.ConstantTypes cpType, + ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = SharedSecrets.getJavaLangAccess(). + getConstantPool(dummyClass.klass); + String msg = String.format("Test for %s constant pool entry of" + + " type %s", + dummyClass.klass, cpType.name()); + switch (cpType) { + case CONSTANT_CLASS: + case CONSTANT_STRING: + case CONSTANT_METHODTYPE: + String utf8 = constantPoolSS + .getUTF8At((int) dummyClass.cp.get(index).value); + msg = String.format("%s (%s) failed with %s", msg, utf8, t); + break; + case CONSTANT_INTEGER: + int intValue = constantPoolSS.getIntAt(index); + msg = String.format("%s (%d) failed with %s", msg, intValue, t); + break; + case CONSTANT_LONG: + long longValue = constantPoolSS.getLongAt(index); + msg = String.format("%s (%d) failed with %s", msg, longValue, t); + break; + case CONSTANT_FLOAT: + float floatValue = constantPoolSS.getFloatAt(index); + msg = String.format("%s (%E) failed with %s", msg, floatValue, t); + break; + case CONSTANT_DOUBLE: + double doubleValue = constantPoolSS.getDoubleAt(index); + msg = String.format("%s (%E) failed with %s", msg, doubleValue, t); + break; + case CONSTANT_UTF8: + String utf8Value = constantPoolSS.getUTF8At(index); + msg = String.format("%s (%s) failed with %s", msg, utf8Value, t); + break; + case CONSTANT_INVOKEDYNAMIC: + index = ((int[]) dummyClass.cp.get(index).value)[1]; + case CONSTANT_NAMEANDTYPE: + String name = constantPoolSS + .getUTF8At(((int[]) dummyClass.cp.get(index).value)[0]); + String type = constantPoolSS + .getUTF8At(((int[]) dummyClass.cp.get(index).value)[1]); + msg = String.format("%s (%s:%s) failed with %s", + msg, name, type, t); + break; + case CONSTANT_METHODHANDLE: + index = ((int[]) dummyClass.cp.get(index).value)[1]; + case CONSTANT_METHODREF: + case CONSTANT_INTERFACEMETHODREF: + case CONSTANT_FIELDREF: + int classIndex = ((int[]) dummyClass.cp.get(index).value)[0]; + int nameAndTypeIndex = ((int[]) dummyClass.cp.get(index).value)[1]; + String cName = constantPoolSS + .getUTF8At((int) dummyClass.cp.get(classIndex).value); + String mName = constantPoolSS + .getUTF8At(((int[]) dummyClass.cp.get(nameAndTypeIndex).value)[0]); + String mType = constantPoolSS + .getUTF8At(((int[]) dummyClass.cp.get(nameAndTypeIndex).value)[1]); + msg = String.format("%s (%s.%s:%s) failed with %s ", + msg, cName, mName, mType, t); + break; + default: + msg = String.format("Test bug: unknown constant type %s ", cpType); + } + throw new Error(msg + t.getMessage(), t); + } + + public void test() { + for (ConstantPoolTestsHelper.DummyClasses dummyClass + : ConstantPoolTestsHelper.DummyClasses.values()) { + System.out.printf("%nTesting dummy %s%n", dummyClass.klass); + HotSpotResolvedObjectTypeImpl holder = HotSpotResolvedObjectTypeImpl + .fromObjectClass(dummyClass.klass); + HotSpotConstantPool constantPoolCTVM = holder.getConstantPool(); + ConstantPool constantPoolSS = SharedSecrets.getJavaLangAccess(). + getConstantPool(dummyClass.klass); + for (Integer i : dummyClass.cp.keySet()) { + ConstantPoolTestsHelper.ConstantTypes cpType + = dummyClass.cp.get(i).type; + if (!typeTests.keySet().contains(cpType)) { + continue; + } + try { + typeTests.get(cpType).validate(constantPoolCTVM, + constantPoolSS, dummyClass, i); + } catch (Throwable t) { + messageOnFail(t, cpType, dummyClass, i); + } + } + } + } +} + diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java new file mode 100644 index 00000000000..777b848fd8b --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.MultipleImplementer2; +import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import java.util.HashMap; +import java.util.Map; + +/** + * Class contains hard-coded constant pool tables for dummy classes used for + * jdk.vm.ci.hotspot.CompilerToVM constant pool methods + */ +public class ConstantPoolTestsHelper { + + public enum ConstantTypes { + CONSTANT_CLASS, + CONSTANT_FIELDREF, + CONSTANT_METHODREF, + CONSTANT_INTERFACEMETHODREF, + CONSTANT_STRING, + CONSTANT_INTEGER, + CONSTANT_FLOAT, + CONSTANT_LONG, + CONSTANT_DOUBLE, + CONSTANT_NAMEANDTYPE, + CONSTANT_UTF8, + CONSTANT_METHODHANDLE, + CONSTANT_METHODTYPE, + CONSTANT_INVOKEDYNAMIC; + } + + public enum DummyClasses { + DUMMY_CLASS(MultipleImplementer2.class, CP_MAP_FOR_CLASS), + DUMMY_INTERFACE(MultipleImplementersInterface.class, CP_MAP_FOR_INTERFACE); + + public final Class klass; + public final Map cp; + + DummyClasses(Class klass, Map cp) { + this.klass = klass; + this.cp = cp; + } + } + + public static class ConstantPoolEntry { + + public final ConstantTypes type; + public final Object value; + + public ConstantPoolEntry(ConstantTypes type, Object value) { + this.type = type; + this.value = value; + } + } + + private static final Map CP_MAP_FOR_CLASS + = new HashMap<>(); + static { + CP_MAP_FOR_CLASS.put(1, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{22, 68})); + CP_MAP_FOR_CLASS.put(2, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 69)); + CP_MAP_FOR_CLASS.put(3, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTEGER, 2147483647)); + CP_MAP_FOR_CLASS.put(4, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{35, 70})); + CP_MAP_FOR_CLASS.put(5, new ConstantPoolEntry(ConstantTypes.CONSTANT_LONG, 9223372036854775807L)); + CP_MAP_FOR_CLASS.put(8, new ConstantPoolEntry(ConstantTypes.CONSTANT_FLOAT, 3.4028235E38F)); + CP_MAP_FOR_CLASS.put(10, new ConstantPoolEntry(ConstantTypes.CONSTANT_DOUBLE, 1.7976931348623157E308D)); + CP_MAP_FOR_CLASS.put(13, new ConstantPoolEntry(ConstantTypes.CONSTANT_STRING, 74)); + CP_MAP_FOR_CLASS.put(22, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 83)); + CP_MAP_FOR_CLASS.put(23, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{22, 84})); + CP_MAP_FOR_CLASS.put(24, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTERFACEMETHODREF, new int[]{2, 85})); + CP_MAP_FOR_CLASS.put(26, new ConstantPoolEntry(ConstantTypes.CONSTANT_INVOKEDYNAMIC, new int[]{0, 91})); + CP_MAP_FOR_CLASS.put(29, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{35, 94})); + CP_MAP_FOR_CLASS.put(35, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 100)); + CP_MAP_FOR_CLASS.put(68, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{54, 55})); + CP_MAP_FOR_CLASS.put(70, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{48, 37})); + CP_MAP_FOR_CLASS.put(84, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{59, 55})); + CP_MAP_FOR_CLASS.put(85, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{103, 63})); + CP_MAP_FOR_CLASS.put(91, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{106, 107})); + CP_MAP_FOR_CLASS.put(94, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{36, 37})); + CP_MAP_FOR_CLASS.put(104, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{110, 111})); + CP_MAP_FOR_CLASS.put(105, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{35, 112})); + CP_MAP_FOR_CLASS.put(110, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 113)); + CP_MAP_FOR_CLASS.put(111, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{114, 118})); + CP_MAP_FOR_CLASS.put(112, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{58, 55})); + } + + private static final Map CP_MAP_FOR_INTERFACE + = new HashMap<>(); + static { + CP_MAP_FOR_INTERFACE.put(1, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 48)); + CP_MAP_FOR_INTERFACE.put(5, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTERFACEMETHODREF, new int[]{13, 52})); + CP_MAP_FOR_INTERFACE.put(6, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 53)); + CP_MAP_FOR_INTERFACE.put(7, new ConstantPoolEntry(ConstantTypes.CONSTANT_INVOKEDYNAMIC, new int[]{0, 58})); + CP_MAP_FOR_INTERFACE.put(8, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{6, 59})); + CP_MAP_FOR_INTERFACE.put(9, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{6, 60})); + CP_MAP_FOR_INTERFACE.put(12, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{13, 63})); + CP_MAP_FOR_INTERFACE.put(13, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 64)); + CP_MAP_FOR_INTERFACE.put(17, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTEGER, 2147483647)); + CP_MAP_FOR_INTERFACE.put(20, new ConstantPoolEntry(ConstantTypes.CONSTANT_LONG, 9223372036854775807l)); + CP_MAP_FOR_INTERFACE.put(24, new ConstantPoolEntry(ConstantTypes.CONSTANT_FLOAT, 3.4028235E38f)); + CP_MAP_FOR_INTERFACE.put(27, new ConstantPoolEntry(ConstantTypes.CONSTANT_DOUBLE, 1.7976931348623157E308d)); + CP_MAP_FOR_INTERFACE.put(31, new ConstantPoolEntry(ConstantTypes.CONSTANT_STRING, 65)); + CP_MAP_FOR_INTERFACE.put(52, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{34, 35})); + CP_MAP_FOR_INTERFACE.put(55, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODHANDLE, new int[]{6, 67})); + CP_MAP_FOR_INTERFACE.put(56, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODTYPE, 35)); + CP_MAP_FOR_INTERFACE.put(57, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODHANDLE, new int[]{9, 5})); + CP_MAP_FOR_INTERFACE.put(58, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{68, 69})); + CP_MAP_FOR_INTERFACE.put(59, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{70, 71})); + CP_MAP_FOR_INTERFACE.put(60, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{72, 35})); + CP_MAP_FOR_INTERFACE.put(63, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{32, 33})); + CP_MAP_FOR_INTERFACE.put(67, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{73, 74})); + CP_MAP_FOR_INTERFACE.put(73, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 75)); + CP_MAP_FOR_INTERFACE.put(74, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{76, 80})); + CP_MAP_FOR_INTERFACE.put(77, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 82)); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java new file mode 100644 index 00000000000..31d4ac0a293 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run driver compiler.jvmci.compilerToVM.DebugOutputTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.ProcessTools; +import java.util.Arrays; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Utils; + +public class DebugOutputTest { + public static void main(String[] args) { + new DebugOutputTest().test(); + } + + private void test() { + for (TestCaseData testCase : TestCaseData.values()) { + System.out.println(testCase); + OutputAnalyzer oa; + try { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + /* use test options = */ true, + "-XX:+UnlockExperimentalVMOptions", + "-XX:+EnableJVMCI", + "-Xbootclasspath/a:.", + DebugOutputTest.Worker.class.getName(), + testCase.name()); + oa = ProcessTools.executeProcess(pb); + } catch (Exception e) { + e.printStackTrace(); + throw new Error("Problems running child process", e); + } + if (testCase.expectedException != null) { + oa.shouldHaveExitValue(1); + oa.shouldContain(testCase.expectedException.getName()); + } else { + oa.shouldHaveExitValue(0); + oa.shouldContain(new String(testCase.getExpected())); + } + } + } + + /** + * A list of test cases that are executed in forked VM + */ + private enum TestCaseData { + PART_ARRAY(100, 50), + FULL_ARRAY(0, 255), + EMPTY(0, 0), + NEGATIVE_LENGTH(0, Integer.MIN_VALUE, + ArrayIndexOutOfBoundsException.class), + NEGATIVE_OFFSET(-1, 255, + ArrayIndexOutOfBoundsException.class), + LEFT_BOUND(Integer.MIN_VALUE, 100, + ArrayIndexOutOfBoundsException.class), + RIGHT_BOUND(Integer.MAX_VALUE, 100, + ArrayIndexOutOfBoundsException.class), + BIG_LENGTH(0, Integer.MAX_VALUE, + ArrayIndexOutOfBoundsException.class), + NULL_POINTER(0, 0, + NullPointerException.class), + ; + + private static final int SIZE = 255; + private static final byte[] DATA = generate(); + public final int offset; + public final int length; + public final Class expectedException; + + private TestCaseData(int offset, int length, + Class expectedException) { + this.offset = offset; + this.length = length; + this.expectedException = expectedException; + } + + private TestCaseData(int offset, int length) { + this(offset, length, null); + } + + private static byte[] generate() { + byte[] byteArray = new byte[SIZE]; + for (int i = 0; i < SIZE; i++) { + byteArray[i] = (byte) (i + 1); + } + return byteArray; + } + + public byte[] getExpected() { + if (expectedException != null) { + return new byte[0]; + } + return Arrays.copyOfRange(TestCaseData.DATA, offset, + offset + length); + } + + @Override + public String toString() { + return "CASE: " + this.name(); + } + + public byte[] getData() { + if (equals(NULL_POINTER)) { + return null; + } else { + return DATA; + } + } + } + + public static class Worker { + public static void main(String[] args) { + for (String arg : args) { + TestCaseData tcase = TestCaseData.valueOf(arg); + CompilerToVMHelper.writeDebugOutput(tcase.getData(), + tcase.offset, tcase.length); + CompilerToVMHelper.flushDebugOutput(); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java new file mode 100644 index 00000000000..10ab70bc5d2 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @ignore 8139700 + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.DisassembleCodeBlobTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.DisassembleCodeBlobTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import sun.hotspot.code.NMethod; + +import java.util.List; + +public class DisassembleCodeBlobTest { + + public static void main(String[] args) { + DisassembleCodeBlobTest test + = new DisassembleCodeBlobTest(); + List testCases + = CompileCodeTestCase.generate(/* bci = */ -1); + testCases.addAll(CompileCodeTestCase.generate(/* bci = */ 0)); + testCases.forEach(test::check); + test.checkNull(); + } + + private void checkNull() { + String str = CompilerToVMHelper.disassembleCodeBlob(0L); + Asserts.assertNull(str, "not null string returned for null pointer"); + } + + private void check(CompileCodeTestCase testCase) { + System.out.println(testCase); + // to have a clean state + NMethod nMethod = testCase.deoptimizeAndCompile(); + if (nMethod == null) { + throw new Error(testCase + " : method is not compiled"); + } + String str = CompilerToVMHelper.disassembleCodeBlob(nMethod.address); + if (str != null) { + Asserts.assertGT(str.length(), 0, + testCase + " : returned string has to be non-zero length"); + } + String str2 = CompilerToVMHelper.disassembleCodeBlob(nMethod.address); + Asserts.assertEQ(str, str2, + testCase + " : 2nd invocation returned different value"); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java new file mode 100644 index 00000000000..b3f513c73de --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.DoNotInlineOrCompileTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +public class DoNotInlineOrCompileTest { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String[] args) { + List testCases = createTestCases(); + testCases.forEach(DoNotInlineOrCompileTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + boolean canInline = CompilerToVMHelper.canInlineMethod(method); + Asserts.assertTrue(canInline, "Unexpected initial " + + "value of property 'can inline'"); + CompilerToVMHelper.doNotInlineOrCompile(method); + canInline = CompilerToVMHelper.canInlineMethod(method); + Asserts.assertFalse(canInline, aMethod + + " : can be inlined even after doNotInlineOrCompile'"); + } + + private static List createTestCases() { + List testCases = new ArrayList<>(); + + Class aClass = DummyClass.class; + testCases.addAll(Arrays.asList(aClass.getDeclaredMethods())); + testCases.addAll(Arrays.asList(aClass.getDeclaredConstructors())); + return testCases; + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DummyAbstractClass.java b/hotspot/test/compiler/jvmci/compilerToVM/DummyAbstractClass.java new file mode 100644 index 00000000000..5e6a25d348c --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/DummyAbstractClass.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package compiler.jvmci.compilerToVM; + +abstract class DummyAbstractClass implements DummyInterface { + public abstract int dummyAbstractFunction(); +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DummyClass.java b/hotspot/test/compiler/jvmci/compilerToVM/DummyClass.java new file mode 100644 index 00000000000..c31fa22c4da --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/DummyClass.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package compiler.jvmci.compilerToVM; + +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; + +import java.util.Random; + +class DummyClass extends DummyAbstractClass { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + int p1 = 5; + int p2 = 6; + + public int dummyInstanceFunction() { + String str1 = "123123123"; + double x = 3.14; + int y = Integer.parseInt(str1); + + return y / (int) x; + } + + public int dummyEmptyInstanceFunction() { + return 42; + } + + public static int dummyEmptyStaticFunction() { + return -42; + } + + @Override + public int dummyAbstractFunction() { + int z = p1 * p2; + return (int) (Math.cos(p2 - p1 + z) * 100); + } + + @Override + public void dummyFunction() { + dummyEmptyInstanceFunction(); + } + + public void withLoop() { + long tier4 = (Long) WB.getVMFlag("Tier4BackEdgeThreshold"); + for (long i = 0; i < tier4; ++i) { + randomProfile(); + } + } + + private double randomProfile() { + String str1 = "123123123"; + double x = 3.14; + int y = Integer.parseInt(str1); + + Random rnd = Utils.getRandomInstance(); + if (rnd.nextDouble() > 0.2) { + return y / (int) x; + } else { + return x / y; + } + } + +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DummyInterface.java b/hotspot/test/compiler/jvmci/compilerToVM/DummyInterface.java new file mode 100644 index 00000000000..72e34cf24f4 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/DummyInterface.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package compiler.jvmci.compilerToVM; + +interface DummyInterface { + void dummyFunction(); + + default int dummyDefaultFunction(int x, int y) { + int z = x * y; + return (int) (Math.cos(x - y + z) * 100); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java new file mode 100644 index 00000000000..6e64d079370 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java @@ -0,0 +1,176 @@ +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import jdk.test.lib.Pair; +import sun.hotspot.code.NMethod; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest + */ + +public class ExecuteInstalledCodeTest { + + + public static void main(String[] args) { + ExecuteInstalledCodeTest test = new ExecuteInstalledCodeTest(); + List testCases = new ArrayList<>(); + testCases.addAll(CompileCodeTestCase.generate(/* bci = */ -1)); + testCases .stream() + // ignore of abstract class -- 8138793 + .filter(e -> !(e.executable instanceof Constructor + && Modifier.isAbstract( + e.executable.getDeclaringClass() + .getModifiers()))) + .forEach(test::checkSanity); + } + + private void checkSanity(CompileCodeTestCase testCase) { + System.out.println(testCase); + // to have a clean state + testCase.deoptimize(); + Pair reflectionResult; + Object[] args = getArguments(testCase.executable); + reflectionResult = invoke(testCase, args); + NMethod nMethod = testCase.compile(); + if (nMethod == null) { + throw new Error(testCase + " : nmethod is null"); + } + InstalledCode installedCode = new InstalledCode( + testCase.executable.getName()); + installedCode.setAddress(nMethod.address); + Object result = null; + Throwable expectedException = reflectionResult.second; + boolean gotException = true; + try { + args = addReceiver(testCase, args); + result = CompilerToVMHelper.executeInstalledCode( + args, installedCode); + if (testCase.executable instanceof Constructor) { + // doesn't have return value, it changes receiver + result = args[0]; + } + gotException = false; + } catch (InvalidInstalledCodeException e) { + throw new AssertionError( + testCase + " : unexpected InvalidInstalledCodeException", e); + } catch (Throwable t) { + if (expectedException == null) { + throw new AssertionError(testCase + + " : got unexpected execption : " + t.getMessage(), t); + } + + if (expectedException.getClass() != t.getClass()) { + System.err.println("exception from CompilerToVM:"); + t.printStackTrace(); + System.err.println("exception from reflection:"); + expectedException.printStackTrace(); + throw new AssertionError(String.format( + "%s : got unexpected different exceptions : %s != %s", + testCase, expectedException.getClass(), t.getClass())); + } + } + + Asserts.assertEQ(reflectionResult.first, result, testCase + + " : different return value"); + if (!gotException) { + Asserts.assertNull(expectedException, testCase + + " : expected exception hasn't been thrown"); + } + } + + private Object[] addReceiver(CompileCodeTestCase testCase, Object[] args) { + if (!Modifier.isStatic(testCase.executable.getModifiers())) { + // add instance as 0th arg + Object[] newArgs = new Object[args.length + 1]; + newArgs[0] = getReciever(testCase); + System.arraycopy(args, 0, newArgs, 1, args.length); + args = newArgs; + } + return args; + } + + private Object getReciever(CompileCodeTestCase testCase) { + return CompileCodeTestCase.RECEIVERS.get( + testCase.executable.getDeclaringClass()); + } + + public Pair invoke( + CompileCodeTestCase testCase, Object[] args) { + Executable executable = testCase.executable; + boolean old = executable.isAccessible(); + executable.setAccessible(true); + try { + try { + if (executable instanceof Method) { + Method m = (Method) executable; + return new Pair<>(m.invoke(getReciever(testCase), args), null); + } + + if (executable instanceof Constructor) { + Constructor c = (Constructor) executable; + return new Pair<>(c.newInstance(args), null); + } + } catch (InvocationTargetException e) { + return new Pair<>(null, e.getCause()); + } catch (Throwable e) { + return new Pair<>(null, e); + } + } finally { + executable.setAccessible(old); + } + throw new Error(executable + " has unsupported type " + + executable.getClass()); + } + + private Object[] getArguments(Executable method) { + Class[] params = method.getParameterTypes(); + Object[] result = new Object[params.length]; + int i = 0; + for (Class aClass : params) { + result[i++] = getArgument(aClass); + } + return result; + } + private static Map, Object> DEFAULT_VALUES = new HashMap<>(); + static { + DEFAULT_VALUES.put(boolean.class, false); + DEFAULT_VALUES.put(byte.class, (byte) 0); + DEFAULT_VALUES.put(short.class, (short) 0); + DEFAULT_VALUES.put(char.class, '\0'); + DEFAULT_VALUES.put(int.class, 0); + DEFAULT_VALUES.put(long.class, 0L); + DEFAULT_VALUES.put(float.class, 0.0f); + DEFAULT_VALUES.put(double.class, 0.0d); + } + private Object getArgument(Class aClass) { + if (aClass.isPrimitive()) { + return DEFAULT_VALUES.get(aClass); + } + return null; + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java new file mode 100644 index 00000000000..15ae1b74212 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.FindUniqueConcreteMethodTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.FindUniqueConcreteMethodTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.MultipleImplementer1; +import compiler.jvmci.common.testcases.SingleImplementer; +import compiler.jvmci.common.testcases.SingleSubclass; +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class FindUniqueConcreteMethodTest { + public static void main(String args[]) { + FindUniqueConcreteMethodTest test = new FindUniqueConcreteMethodTest(); + try { + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find method", e); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + // a public method + result.add(new TestCase(true, SingleSubclass.class, + SingleSubclass.class, "usualMethod")); + // overriden method + result.add(new TestCase(true, SingleSubclass.class, + SingleSubclass.class, "overridenMethod")); + // private method + result.add(new TestCase(true, SingleSubclass.class, + SingleSubclass.class, "privateMethod")); + // protected method + result.add(new TestCase(true, SingleSubclass.class, + SingleSubclass.class, "protectedMethod")); + // default(package-private) method + result.add(new TestCase(true, SingleSubclass.class, + SingleSubclass.class, "defaultAccessMethod")); + // default interface method redefined in implementer + result.add(new TestCase(true, MultipleImplementer1.class, + MultipleImplementer1.class, "defaultMethod")); + // interface method + result.add(new TestCase(true, MultipleImplementer1.class, + MultipleImplementer1.class, "testMethod")); + // default interface method not redefined in implementer + result.add(new TestCase(true, SingleImplementer.class, + SingleImplementerInterface.class, "defaultMethod")); + // static method + result.add(new TestCase(false, SingleSubclass.class, + SingleSubclass.class, "staticMethod")); + return result; + } + + private void runTest(TestCase tcase) throws NoSuchMethodException { + System.out.println(tcase); + Method method = tcase.holder.getDeclaredMethod(tcase.methodName); + HotSpotResolvedJavaMethodImpl testMethod = CTVMUtilities + .getResolvedMethod(tcase.reciever, method); + HotSpotResolvedObjectTypeImpl resolvedType = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.reciever), getClass(), + /* resolve = */ true); + HotSpotResolvedJavaMethodImpl concreteMethod = CompilerToVMHelper + .findUniqueConcreteMethod(resolvedType, testMethod); + Asserts.assertEQ(concreteMethod, tcase.isPositive ? testMethod : null, + "Unexpected concrete method for " + tcase.methodName); + } + + private static class TestCase { + public final Class reciever; + public final Class holder; + public final String methodName; + public final boolean isPositive; + + public TestCase(boolean isPositive, Class clazz, Class holder, + String methodName) { + this.reciever = clazz; + this.methodName = methodName; + this.isPositive = isPositive; + this.holder = holder; + } + + @Override + public String toString() { + return String.format("CASE: reciever=%s, holder=%s, method=%s," + + " isPositive=%s", reciever.getName(), + holder.getName(), methodName, isPositive); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java new file mode 100644 index 00000000000..b3c16002580 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.GetBytecodeTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.TestCase; +import java.lang.reflect.Executable; +import java.lang.reflect.Modifier; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.test.lib.Asserts; + +public class GetBytecodeTest { + + public static void main(String[] args) { + TestCase.getAllExecutables() + .forEach(GetBytecodeTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + byte[] bytecode = CompilerToVMHelper.getBytecode(method); + + int mods = aMethod.getModifiers(); + boolean shouldHasZeroLength = Modifier.isAbstract(mods) + || Modifier.isNative(mods); + boolean correctLength = (bytecode.length == 0 && shouldHasZeroLength) + || (bytecode.length > 0 && !shouldHasZeroLength); + + Asserts.assertTrue(correctLength, "Bytecode of '" + aMethod + "' has " + + bytecode.length + " length"); + + if (!shouldHasZeroLength) { + Asserts.assertTrue(containsReturn(bytecode), "Bytecode of '" + + aMethod + "' doesn't have any return statement"); + } + } + + private static boolean containsReturn(byte[] bytecode) { + for (byte b : bytecode) { + // cast unsigned byte to int + int value = (int) b & 0x000000FF; + switch (value) { + case Opcodes.RET: + case Opcodes.ARETURN: + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.RETURN: + return true; + } + } + return false; + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java new file mode 100644 index 00000000000..6525b115ddd --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetClassInitializerTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetClassInitializerTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.AbstractClass; +import compiler.jvmci.common.testcases.AbstractClassExtender; +import compiler.jvmci.common.testcases.DoNotExtendClass; +import compiler.jvmci.common.testcases.MultipleImplementersInterfaceExtender; +import compiler.jvmci.common.testcases.SingleImplementer; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import java.util.HashSet; +import java.util.Set; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class GetClassInitializerTest { + + public static void main(String args[]) { + GetClassInitializerTest test = new GetClassInitializerTest(); + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + // a simple class with initializer + result.add(new TestCase(SingleImplementer.class, true)); + // an interface with initializer + result.add(new TestCase(SingleImplementerInterface.class, true)); + // an abstract class with initializer + result.add(new TestCase(AbstractClass.class, true)); + // a class without initializer, extending class with initializer + result.add(new TestCase(AbstractClassExtender.class, false)); + // an interface without initializer + result.add(new TestCase(MultipleImplementersInterfaceExtender.class, false)); + // a class without initializer + result.add(new TestCase(DoNotExtendClass.class, false)); + return result; + } + + private void runTest(TestCase tcase) { + System.out.println(tcase); + String className = tcase.holder.getName(); + HotSpotResolvedObjectTypeImpl resolvedClazz = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.holder), + getClass(), /* resolve = */ true); + HotSpotResolvedJavaMethodImpl initializer = CompilerToVMHelper + .getClassInitializer(resolvedClazz); + if (tcase.isPositive) { + Asserts.assertNotNull(initializer, "Couldn't get initializer for " + + className); + Asserts.assertEQ(initializer.getName(), "", + "Unexpected initializer name for " + className); + } else { + Asserts.assertNull(initializer, "Unexpected: found initializer for " + + className); + } + } + + private static class TestCase { + public final Class holder; + public final boolean isPositive; + + public TestCase(Class clazz, boolean isPositive) { + this.holder = clazz; + this.isPositive = isPositive; + } + + @Override + public String toString() { + return "CASE: clazz=" + holder.getName() + + ", isPositive=" + isPositive; + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java new file mode 100644 index 00000000000..68185a9b06b --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.GetConstantPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetConstantPoolTest + */ +package compiler.jvmci.compilerToVM; + +import java.lang.reflect.Field; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.vm.ci.hotspot.MetaspaceWrapperObject; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; + +/** + * Tests for jdk.vm.ci.hotspot.CompilerToVM::getConstantPool method + */ +public class GetConstantPoolTest { + private static enum TestCase { + NULL_BASE { + @Override + HotSpotConstantPool getConstantPool() { + return CompilerToVMHelper.getConstantPool(null, + getPtrToCpAddress()); + } + }, + JAVA_METHOD_BASE { + @Override + HotSpotConstantPool getConstantPool() { + HotSpotResolvedJavaMethodImpl methodInstance + = CompilerToVMHelper.getResolvedJavaMethodAtSlot( + TEST_CLASS, 0); + Field field; + try { + field = HotSpotResolvedJavaMethodImpl + .class.getDeclaredField("metaspaceMethod"); + field.setAccessible(true); + field.set(methodInstance, getPtrToCpAddress()); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + + return CompilerToVMHelper.getConstantPool(methodInstance, 0L); + } + }, + CONSTANT_POOL_BASE { + @Override + HotSpotConstantPool getConstantPool() { + HotSpotConstantPool cpInst; + try { + cpInst = CompilerToVMHelper.getConstantPool(null, + getPtrToCpAddress()); + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, getPtrToCpAddress()); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getConstantPool(cpInst, 0L); + } + }, + CONSTANT_POOL_BASE_IN_TWO { + @Override + HotSpotConstantPool getConstantPool() { + long ptr = getPtrToCpAddress(); + HotSpotConstantPool cpInst; + try { + cpInst = CompilerToVMHelper.getConstantPool(null, ptr); + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, ptr / 2L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getConstantPool(cpInst, + ptr - ptr / 2L); + } + }, + CONSTANT_POOL_BASE_ZERO { + @Override + HotSpotConstantPool getConstantPool() { + long ptr = getPtrToCpAddress(); + HotSpotConstantPool cpInst; + try { + cpInst = CompilerToVMHelper.getConstantPool(null, ptr); + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, 0L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getConstantPool(cpInst, ptr); + } + }, + OBJECT_TYPE_BASE { + @Override + HotSpotConstantPool getConstantPool() { + HotSpotResolvedObjectTypeImpl type + = HotSpotResolvedObjectTypeImpl.fromObjectClass( + OBJECT_TYPE_BASE.getClass()); + long ptrToClass = UNSAFE.getKlassPointer(OBJECT_TYPE_BASE); + return CompilerToVMHelper.getConstantPool(type, + getPtrToCpAddress() - ptrToClass); + } + }, + ; + abstract HotSpotConstantPool getConstantPool(); + } + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final Unsafe UNSAFE = Utils.getUnsafe(); + private static final Class TEST_CLASS = GetConstantPoolTest.class; + private static final long CP_ADDRESS + = WB.getConstantPool(GetConstantPoolTest.class); + + public void test(TestCase testCase) { + System.out.println(testCase.name()); + HotSpotConstantPool cp = testCase.getConstantPool(); + String cpStringRep = cp.toString(); + if (!cpStringRep.contains(HotSpotConstantPool.class.getSimpleName()) + || !cpStringRep.contains(TEST_CLASS.getName())) { + String msg = String.format("%s : " + + " Constant pool is not valid." + + " String representation should contain \"%s\" and \"%s\"", + testCase.name(), + HotSpotConstantPool.class.getSimpleName(), + TEST_CLASS.getName()); + throw new AssertionError(msg); + } + } + + public static void main(String[] args) { + GetConstantPoolTest test = new GetConstantPoolTest(); + for (TestCase testCase : TestCase.values()) { + test.test(testCase); + } + testObjectBase(); + testMetaspaceWrapperBase(); + } + + private static void testObjectBase() { + try { + HotSpotConstantPool cp + = CompilerToVMHelper.getConstantPool(new Object(), 0L); + throw new AssertionError("Test OBJECT_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } + private static void testMetaspaceWrapperBase() { + try { + HotSpotConstantPool cp = CompilerToVMHelper.getConstantPool( + new MetaspaceWrapperObject() { + @Override + public long getMetaspacePointer() { + return getPtrToCpAddress(); + } + }, 0L); + throw new AssertionError("Test METASPACE_WRAPPER_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } + + private static long getPtrToCpAddress() { + Field field; + try { + field = TEST_CLASS.getDeclaredField("CP_ADDRESS"); + } catch (NoSuchFieldException nsfe) { + throw new Error("TESTBUG : cannot find field \"CP_ADDRESS\" : " + + nsfe.getMessage(), nsfe); + } + Object base = UNSAFE.staticFieldBase(field); + return WB.getObjectAddress(base) + UNSAFE.staticFieldOffset(field); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java new file mode 100644 index 00000000000..9d928d3d045 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.GetExceptionTableTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.io.IOException; +import java.lang.reflect.Executable; +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class GetExceptionTableTest { + + public static final int TRY_CATCH_COUNT = 3; + public static final int TRY_CATCH_FINALLY_COUNT = 8; + public static final int TRY_WITH_RESOURCES_COUNT = 6; + public static final int EMPTY_COUNT = 0; + + public static void main(String[] args) { + Map testCases = createTestCases(); + testCases.forEach(GetExceptionTableTest::runSanityTest); + } + + private static Map createTestCases() { + HashMap methods = new HashMap<>(); + try { + Class aClass = GetExceptionTableTest.DummyClass.class; + methods.put(aClass.getMethod("tryCatchDummy"), TRY_CATCH_COUNT); + methods.put(aClass.getMethod("tryCatchFinallyDummy"), + TRY_CATCH_FINALLY_COUNT); + methods.put(aClass.getMethod("tryWithResourcesDummy"), + TRY_WITH_RESOURCES_COUNT); + methods.put(aClass.getMethod("emptyFunction"), EMPTY_COUNT); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG", e); + } + return methods; + } + + private static void runSanityTest(Executable aMethod, + Integer expectedTableLength) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + int tableLength = CompilerToVMHelper.getExceptionTableLength(method); + Asserts.assertEQ(tableLength, expectedTableLength, aMethod + + " incorrect exception table length."); + + long tableStart = CompilerToVMHelper.getExceptionTableStart(method); + if (tableLength > 0) { + Asserts.assertNE(tableStart, 0L, aMethod + " exception table starts " + + "at 0."); + } + } + + private static class DummyClass { + public static void emptyFunction() {} + public static void tryCatchDummy() throws Throwable { + try { + throw new Exception("Dummy exception"); + } catch (ArithmeticException ex) { + throw new IOException(ex.getMessage()); + } catch (IOException ex) { + throw new Exception(ex); + } catch (Exception ex) { + throw new Exception(ex); + } + } + + public int tryCatchFinallyDummy() { + // 4 times catch/finally = 8 catch-blocks and finally-blocks + try { + throw new Exception("Dummy exception"); + } catch (IndexOutOfBoundsException ex) { + return 1; + } catch (ArithmeticException ex) { + return 2; + } catch (IOException ex) { + return 3; + } catch (Exception ex) { + return 4; + } finally { + return 0; + } + } + + public static int tryWithResourcesDummy() throws Throwable { + try (Socket socket = new Socket()) { + throw new Exception("Dummy exception"); + } catch (ArithmeticException ex) { + return 1; + } catch (IOException ex) { + return 2; + } catch (Exception ex) { + return 3; + } + } + } +} + diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java new file mode 100644 index 00000000000..aab452fd58a --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib/ + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetImplementorTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetImplementorTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.AbstractClass; +import compiler.jvmci.common.testcases.AbstractClassExtender; +import compiler.jvmci.common.testcases.DoNotImplementInterface; +import compiler.jvmci.common.testcases.DoNotExtendClass; +import compiler.jvmci.common.testcases.MultipleImplementer1; +import compiler.jvmci.common.testcases.MultipleImplementer2; +import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.common.testcases.SingleImplementer; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import compiler.jvmci.common.testcases.SingleSubclass; +import compiler.jvmci.common.testcases.SingleSubclassedClass; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class GetImplementorTest { + public static void main(String args[]) { + GetImplementorTest test = new GetImplementorTest(); + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + Stream.of( + SingleSubclass.class, + AbstractClassExtender.class, + MultipleImplementer2.class, + MultipleImplementer1.class, + MultipleImplementersInterface.class, + DoNotImplementInterface.class, + DoNotExtendClass.class, + AbstractClass.class, + SingleSubclassedClass.class) + .forEach(Utils::ensureClassIsLoaded); + // an interface with single class implementing it + result.add(new TestCase(SingleImplementerInterface.class, + SingleImplementer.class)); + /* an interface with multiple implementers. According to getImplementor + javadoc, an itself should be returned in case of more than one + implementor + */ + result.add(new TestCase(MultipleImplementersInterface.class, + MultipleImplementersInterface.class)); + // an interface with no implementors + result.add(new TestCase(DoNotImplementInterface.class, null)); + // an abstract class with extender class + result.add(new TestCase(AbstractClass.class, null)); + // a simple class, which is not extended + result.add(new TestCase(DoNotExtendClass.class, null)); + // a usual class, which is extended + result.add(new TestCase(SingleSubclassedClass.class, null)); + return result; + } + + private void runTest(TestCase tcase) { + System.out.println(tcase); + HotSpotResolvedObjectTypeImpl resolvedIface = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.anInterface), + getClass(), /* resolve = */ true); + HotSpotResolvedObjectTypeImpl resolvedImplementer = CompilerToVMHelper + .getImplementor(resolvedIface); + HotSpotResolvedObjectTypeImpl resolvedExpected = null; + if (tcase.expectedImplementer != null) { + resolvedExpected = CompilerToVMHelper.lookupType(Utils + .toJVMTypeSignature(tcase.expectedImplementer), + getClass(), /* resolve = */ true); + } + Asserts.assertEQ(resolvedImplementer, resolvedExpected, + "Unexpected implementer for " + tcase.anInterface.getName()); + } + + private static class TestCase { + public final Class anInterface; + public final Class expectedImplementer; + + public TestCase(Class iface, Class expectedImplementer) { + this.anInterface = iface; + this.expectedImplementer = expectedImplementer; + } + + @Override + public String toString() { + return String.format("CASE: interface=%s, expected=%s", + anInterface.getName(), + expectedImplementer == null + ? null + : expectedImplementer.getName()); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java new file mode 100644 index 00000000000..1b3dcdcd60d --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.GetLineNumberTableTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.TestCase; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.tree.ClassNode; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +public class GetLineNumberTableTest { + public static void main(String[] args) { + TestCase.getAllExecutables() + .forEach(GetLineNumberTableTest::runSanityTest); + } + + public static void runSanityTest(Executable aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + long[] lineNumbers = CompilerToVMHelper.getLineNumberTable(method); + long[] expectedLineNumbers = getExpectedLineNumbers(aMethod); + + Asserts.assertTrue(Arrays.equals(lineNumbers, expectedLineNumbers), + String.format("%s : unequal table values : %n%s%n%s%n", + aMethod, + Arrays.toString(lineNumbers), + Arrays.toString(expectedLineNumbers))); + } + + public static long[] getExpectedLineNumbers(Executable aMethod) { + try { + ClassReader cr = new ClassReader(aMethod.getDeclaringClass() + .getName()); + ClassNode cn = new ClassNode(); + cr.accept(cn, ClassReader.EXPAND_FRAMES); + + Map lineNumbers = new HashMap<>(); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + ClassVisitor cv = new ClassVisitorForLabels(cw, lineNumbers, + aMethod); + cr.accept(cv, ClassReader.EXPAND_FRAMES); + + long[] result = null; + if (!lineNumbers.isEmpty()) { + Map labels = new TreeMap<>(); + lineNumbers.forEach((k, v) -> labels.put(k.getOffset(), v)); + + result = new long[2 * labels.size()]; + int i = 0; + for (Integer key : labels.keySet()) { + result[i++] = key.longValue(); + result[i++] = labels.get(key).longValue(); + } + } + // compilerToVM::getLineNumberTable returns null in case empty table + return result; + } catch (IOException e) { + throw new Error("TEST BUG " + e, e); + } + } + + private static class ClassVisitorForLabels extends ClassVisitor { + private final Map lineNumbers; + private final String targetName; + private final String targetDesc; + + public ClassVisitorForLabels(ClassWriter cw, Map lines, + Executable target) { + super(Opcodes.ASM5, cw); + this.lineNumbers = lines; + + StringBuilder builder = new StringBuilder("("); + for (Parameter parameter : target.getParameters()) { + builder.append(Utils.toJVMTypeSignature(parameter.getType())); + } + builder.append(")"); + if (target instanceof Constructor) { + targetName = ""; + builder.append("V"); + } else { + targetName = target.getName(); + builder.append(Utils.toJVMTypeSignature( + ((Method) target).getReturnType())); + } + targetDesc = builder.toString(); + } + + @Override + public final MethodVisitor visitMethod(int access, String name, + String desc, String signature, + String[] exceptions) { + MethodVisitor mv = cv.visitMethod(access, name, desc, signature, + exceptions); + if (targetDesc.equals(desc) && targetName.equals(name)) { + return new MethodVisitor(Opcodes.ASM5, mv) { + @Override + public void visitLineNumber(int i, Label label) { + super.visitLineNumber(i, label); + lineNumbers.put(label, i); + } + }; + } + return mv; + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java new file mode 100644 index 00000000000..9bdb8525414 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @clean compiler.jvmci.compilerToVM.* + * @compile -g DummyInterface.java + * @compile -g DummyAbstractClass.java + * @compile -g DummyClass.java + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.GetLocalVariableTableTest + * @clean compiler.jvmci.compilerToVM.* + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +import java.lang.reflect.Executable; +import java.util.HashMap; +import java.util.Map; + +public class GetLocalVariableTableTest { + + public static final int MAIN_LOCALS_COUNT = 0; + public static final int INSTANCE_LOCALS_COUNT = 4; + public static final int EMPTY_INSTANCE_COUNT = 1; + public static final int EMPTY_STATIC_COUNT = 0; + public static final int ABSTRACT_INHERIT_LOCALS_COUNT = 2; + public static final int DEFAULTFUNC_LOCALS_COUNT = 4; + + public static void main(String[] args) { + Map testCases = createTestCases(); + testCases.forEach(GetLocalVariableTableTest::runSanityTest); + } + + private static Map createTestCases() { + HashMap methods = new HashMap<>(); + try { + Class aClass; + + aClass = GetLocalVariableTableTest.class; + methods.put(aClass.getDeclaredMethod("main", String[].class), + MAIN_LOCALS_COUNT); + + aClass = DummyClass.class; + methods.put(aClass.getMethod("dummyInstanceFunction"), + INSTANCE_LOCALS_COUNT); + methods.put(aClass.getMethod("dummyEmptyInstanceFunction"), + EMPTY_INSTANCE_COUNT); + methods.put(aClass.getMethod("dummyEmptyStaticFunction"), + EMPTY_STATIC_COUNT); + methods.put(aClass.getMethod("dummyFunction"), + EMPTY_INSTANCE_COUNT); + methods.put(aClass.getMethod("dummyAbstractFunction"), + ABSTRACT_INHERIT_LOCALS_COUNT); + + aClass = DummyInterface.class; + methods.put(aClass.getMethod("dummyFunction"), EMPTY_STATIC_COUNT); + methods.put(aClass.getMethod("dummyDefaultFunction", int.class, + int.class), DEFAULTFUNC_LOCALS_COUNT); + + aClass = DummyAbstractClass.class; + methods.put(aClass.getMethod("dummyAbstractFunction"), 0); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG", e); + } + return methods; + } + + private static void runSanityTest(Executable aMethod, + Integer expectedTableLength) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + + int tblLength = CompilerToVMHelper.getLocalVariableTableLength(method); + Asserts.assertEQ(tblLength, expectedTableLength, aMethod + " : incorrect " + + "local variable table length."); + + long tblStart = CompilerToVMHelper.getLocalVariableTableStart(method); + if (tblLength > 0) { + Asserts.assertNE(tblStart, 0L, aMethod + " : local variable table starts" + + " at 0 with length " + tblLength); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java new file mode 100644 index 00000000000..e18581ee6d4 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib/ + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetMaxCallTargetOffsetTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetMaxCallTargetOffsetTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class GetMaxCallTargetOffsetTest { + public static void main(String args[]) { + new GetMaxCallTargetOffsetTest().runTest(); + } + + private void runTest() { + long offset1 = CompilerToVMHelper.getMaxCallTargetOffset(0L); + Asserts.assertNE(offset1, 0L, + "Unexpected maxCallTargetOffset for 0L"); + long offset2 = CompilerToVMHelper.getMaxCallTargetOffset(100L); + Asserts.assertNE(offset2, 0L, + "Unexpected maxCallTargetOffset for 100L"); + long offset3 = CompilerToVMHelper.getMaxCallTargetOffset(1000000L); + Asserts.assertNE(offset3, 0L, + "Unexpected maxCallTargetOffset for 1000000L"); + // there can be 2 same offsets, but not 3 + Asserts.assertFalse(offset1 == offset2 && offset2 == offset3, + "All 3 offsets are unexpectedly equal: " + offset1); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java new file mode 100644 index 00000000000..4a7e3fa7adb --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetNextStackFrameTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Method; +import jdk.vm.ci.hotspot.CompilerToVM; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotStackFrameReference; +import jdk.test.lib.Asserts; + +public class GetNextStackFrameTest { + private static final int RECURSION_AMOUNT = 3; + private static final HotSpotResolvedJavaMethodImpl REC_FRAME_METHOD; + private static final HotSpotResolvedJavaMethodImpl FRAME1_METHOD; + private static final HotSpotResolvedJavaMethodImpl FRAME2_METHOD; + private static final HotSpotResolvedJavaMethodImpl FRAME3_METHOD; + private static final HotSpotResolvedJavaMethodImpl FRAME4_METHOD; + private static final HotSpotResolvedJavaMethodImpl RUN_METHOD; + + static { + Method method; + try { + Class aClass = GetNextStackFrameTest.class; + method = aClass.getDeclaredMethod("recursiveFrame", int.class); + REC_FRAME_METHOD = CTVMUtilities.getResolvedMethod(method); + method = aClass.getDeclaredMethod("frame1"); + FRAME1_METHOD = CTVMUtilities.getResolvedMethod(method); + method = aClass.getDeclaredMethod("frame2"); + FRAME2_METHOD = CTVMUtilities.getResolvedMethod(method); + method = aClass.getDeclaredMethod("frame3"); + FRAME3_METHOD = CTVMUtilities.getResolvedMethod(method); + method = aClass.getDeclaredMethod("frame4"); + FRAME4_METHOD = CTVMUtilities.getResolvedMethod(method); + method = Thread.class.getDeclaredMethod("run"); + RUN_METHOD = CTVMUtilities.getResolvedMethod(Thread.class, method); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find a test method", e); + } + } + + public static void main(String[] args) { + new GetNextStackFrameTest().test(); + } + + private void test() { + // Create new thread to get new clean stack + Thread thread = new Thread(() -> recursiveFrame(RECURSION_AMOUNT)); + thread.start(); + try { + thread.join(); + } catch (InterruptedException e) { + throw new Error("Interrupted while waiting to join", e); + } + } + + // Helper methods for a longer stack + private void recursiveFrame(int recursionAmount) { + if (--recursionAmount != 0) { + recursiveFrame(recursionAmount); + } else { + frame1(); + } + } + + private void frame1() { + frame2(); + } + + private void frame2() { + frame3(); + } + + private void frame3() { + frame4(); + } + + private void frame4() { + check(); + } + + private void check() { + findFirst(); + walkThrough(); + skipAll(); + findNextSkipped(); + findYourself(); + } + + /** + * Finds the first topmost frame from the list of methods to search + */ + private void findFirst() { + checkNextFrameFor(null /* topmost frame */, + new HotSpotResolvedJavaMethodImpl[] + {FRAME2_METHOD, FRAME3_METHOD, FRAME4_METHOD}, + FRAME4_METHOD, 0); + } + + /** + * Walks through whole stack and checks that every frame could be found + * while going down the stack till the end + */ + private void walkThrough() { + // Check that we would get a frame 4 starting from the topmost frame + HotSpotStackFrameReference nextStackFrame = checkNextFrameFor( + null /* topmost frame */, + new HotSpotResolvedJavaMethodImpl[] {FRAME4_METHOD}, + FRAME4_METHOD, 0); + // Check that we would get a frame 3 starting from frame 4 when we try + // to search one of the next two frames + nextStackFrame = checkNextFrameFor(nextStackFrame, + new HotSpotResolvedJavaMethodImpl[] {FRAME3_METHOD, + FRAME2_METHOD}, + FRAME3_METHOD, 0); + // Check that we would get a frame 1 + nextStackFrame = checkNextFrameFor(nextStackFrame, + new HotSpotResolvedJavaMethodImpl[] {FRAME1_METHOD}, + FRAME1_METHOD, 0); + // Check that we would skip (RECURSION_AMOUNT - 1) methods and find a + // recursionFrame starting from frame 1 + nextStackFrame = checkNextFrameFor(nextStackFrame, + new HotSpotResolvedJavaMethodImpl[] {REC_FRAME_METHOD}, + REC_FRAME_METHOD, RECURSION_AMOUNT - 1); + // Check that we would get a Thread::run method frame; + nextStackFrame = checkNextFrameFor(nextStackFrame, + new HotSpotResolvedJavaMethodImpl[] {RUN_METHOD}, + RUN_METHOD, 0); + // Check that there are no more frames after thread's run method + nextStackFrame = CompilerToVMHelper.getNextStackFrame(nextStackFrame, + null /* any */, 0); + Asserts.assertNull(nextStackFrame, + "Found stack frame after Thread::run"); + } + + /** + * Skips all frames to get null at the end of the stack + */ + private void skipAll() { + // Skip all frames (stack size) + 2 (getNextStackFrame() itself + // and from CompilerToVMHelper) + int initialSkip = Thread.currentThread().getStackTrace().length + 2; + HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper + .getNextStackFrame(null /* topmost frame */, null /* any */, + initialSkip); + Asserts.assertNull(nextStackFrame, "Unexpected frame"); + } + + /** + * Search for any frame skipping one frame + */ + private void findNextSkipped() { + // Get frame 4 + HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper + .getNextStackFrame(null /* topmost frame */, + new HotSpotResolvedJavaMethodImpl[] {FRAME4_METHOD}, 0); + // Get frame 2 by skipping one method starting from frame 4 + checkNextFrameFor(nextStackFrame, null /* any */, + FRAME2_METHOD , 1 /* skip one */); + } + + /** + * Finds test method in the stack + */ + private void findYourself() { + Method method; + try { + method = CompilerToVM.class.getDeclaredMethod("getNextStackFrame", + HotSpotStackFrameReference.class, + HotSpotResolvedJavaMethodImpl[].class, int.class); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find getNextStackFrame method"); + } + HotSpotResolvedJavaMethodImpl self + = CTVMUtilities.getResolvedMethod(CompilerToVM.class, method); + checkNextFrameFor(null /* topmost frame */, null /* any */, self, 0); + } + + /** + * Searches next frame and checks that it equals to expected + * + * @param currentFrame start frame to search from + * @param searchMethods a list of methods to search + * @param expected expected frame + * @param skip amount of frames to be skipped + * @return frame reference + */ + private HotSpotStackFrameReference checkNextFrameFor( + HotSpotStackFrameReference currentFrame, + HotSpotResolvedJavaMethodImpl[] searchMethods, + HotSpotResolvedJavaMethodImpl expected, + int skip) { + HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper + .getNextStackFrame(currentFrame, searchMethods, skip); + Asserts.assertNotNull(nextStackFrame); + Asserts.assertTrue(nextStackFrame.isMethod(expected), + "Unexpected next frame: " + nextStackFrame + + " from current frame: " + currentFrame); + return nextStackFrame; + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java new file mode 100644 index 00000000000..db8d0c6fc25 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.GetResolvedJavaMethodAtSlotTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import java.util.HashMap; +import java.util.Map; + +public class GetResolvedJavaMethodAtSlotTest { + + private static class A { + { + System.out.println("Dummy"); + } + public void f1() {} + public int f2() { return 0; } + public String f3() { return ""; } + } + + + private static class S { + static { + System.out.println("Dummy static"); + } + public S() {} + public void f1() {} + public int f2() { return 0; } + public String f3() { return ""; } + } + + private class B extends A { + public void f4() {} + } + + private interface I { + void f1(); + int f2(); + String f3(); + } + + public static void main(String[] args) { + Map, Integer> testCases = getTestCases(); + testCases.forEach(GetResolvedJavaMethodAtSlotTest::test); + } + + private static Map, Integer> getTestCases() { + Map, Integer> testCases = new HashMap<>(); + testCases.put(A.class, 5); // ctor, init, f1, f2, f3 + testCases.put(S.class, 5); // ctor, cinit, f1, f2, f3 + testCases.put(I.class, 3); // f1, f2, f3 + testCases.put(B.class, 2); // ctor, f4 + return testCases; + } + + private static void test(Class aClass, int methodNumber) { + testSlotBigger(aClass); + testCorrectMethods(aClass, methodNumber); + } + + private static void testSlotBigger(Class holder) { + HotSpotResolvedJavaMethodImpl method + = CompilerToVMHelper.getResolvedJavaMethodAtSlot(holder, 50); + Asserts.assertNull(method, "Got method for non existing slot 50 in " + + holder); + } + + private static void testCorrectMethods(Class holder, int methodsNumber) { + for (int i = 0; i < methodsNumber; i++) { + HotSpotResolvedJavaMethodImpl method = CompilerToVMHelper + .getResolvedJavaMethodAtSlot(holder, i); + Asserts.assertNotNull(method, "Did not got method for slot " + i + + " in class " + holder.getCanonicalName()); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java new file mode 100644 index 00000000000..e1d22fae3ce --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetResolvedJavaMethodTest + * @run main ClassFileInstaller + * sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.jvmci.compilerToVM.GetResolvedJavaMethodTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.MetaspaceWrapperObject; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +public class GetResolvedJavaMethodTest { + private static enum TestCase { + NULL_BASE { + @Override + HotSpotResolvedJavaMethodImpl getResolvedJavaMethod() { + return CompilerToVMHelper.getResolvedJavaMethod( + null, getPtrToMethod()); + } + }, + JAVA_METHOD_BASE { + @Override + HotSpotResolvedJavaMethodImpl getResolvedJavaMethod() { + HotSpotResolvedJavaMethodImpl methodInstance + = CompilerToVMHelper.getResolvedJavaMethodAtSlot( + TEST_CLASS, 0); + Field field; + try { + field = HotSpotResolvedJavaMethodImpl + .class.getDeclaredField("metaspaceMethod"); + field.setAccessible(true); + field.set(methodInstance, getPtrToMethod()); + } catch (ReflectiveOperationException e) { + throw new Error("TEST BUG : " + e, e); + } + return CompilerToVMHelper.getResolvedJavaMethod( + methodInstance, 0L); + } + }, + JAVA_METHOD_BASE_IN_TWO { + @Override + HotSpotResolvedJavaMethodImpl getResolvedJavaMethod() { + long ptr = getPtrToMethod(); + HotSpotResolvedJavaMethodImpl methodInstance + = CompilerToVMHelper.getResolvedJavaMethodAtSlot( + TEST_CLASS, 0); + Field field; + try { + field = HotSpotResolvedJavaMethodImpl + .class.getDeclaredField("metaspaceMethod"); + field.setAccessible(true); + field.set(methodInstance, ptr / 2L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getResolvedJavaMethod(methodInstance, + ptr - ptr / 2L); + } + }, + JAVA_METHOD_BASE_ZERO { + @Override + HotSpotResolvedJavaMethodImpl getResolvedJavaMethod() { + long ptr = getPtrToMethod(); + HotSpotResolvedJavaMethodImpl methodInstance + = CompilerToVMHelper.getResolvedJavaMethodAtSlot( + TEST_CLASS, 0); + Field field; + try { + field = HotSpotResolvedJavaMethodImpl + .class.getDeclaredField("metaspaceMethod"); + field.setAccessible(true); + field.set(methodInstance, 0L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getResolvedJavaMethod(methodInstance, + ptr); + } + } + ; + abstract HotSpotResolvedJavaMethodImpl getResolvedJavaMethod(); + } + + private static final Unsafe UNSAFE = Utils.getUnsafe(); + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final Class TEST_CLASS = GetResolvedJavaMethodTest.class; + private static final long PTR; + static { + HotSpotResolvedJavaMethodImpl method + = CompilerToVMHelper.getResolvedJavaMethodAtSlot(TEST_CLASS, 0); + PTR = method.getMetaspacePointer(); + } + + private static long getPtrToMethod() { + Field field; + try { + field = TEST_CLASS.getDeclaredField("PTR"); + } catch (NoSuchFieldException e) { + throw new Error("TEST BUG : " + e, e); + } + Object base = UNSAFE.staticFieldBase(field); + return WB.getObjectAddress(base) + UNSAFE.staticFieldOffset(field); + } + + public void test(TestCase testCase) { + System.out.println(testCase.name()); + HotSpotResolvedJavaMethodImpl result = testCase.getResolvedJavaMethod(); + Asserts.assertNotNull(result, testCase + " : got null"); + Asserts.assertEQ(result.getDeclaringClass().mirror(), TEST_CLASS, + testCase + " : returned method has unexpected declaring class"); + } + + public static void main(String[] args) { + GetResolvedJavaMethodTest test = new GetResolvedJavaMethodTest(); + for (TestCase testCase : TestCase.values()) { + test.test(testCase); + } + testObjectBase(); + testMetaspaceWrapperBase(); + } + + private static void testMetaspaceWrapperBase() { + try { + HotSpotResolvedJavaMethodImpl method + = CompilerToVMHelper.getResolvedJavaMethod( + new MetaspaceWrapperObject() { + @Override + public long getMetaspacePointer() { + return getPtrToMethod(); + } + }, 0L); + throw new AssertionError("Test METASPACE_WRAPPER_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } + + private static void testObjectBase() { + try { + HotSpotResolvedJavaMethodImpl method + = CompilerToVMHelper.getResolvedJavaMethod(new Object(), 0L); + throw new AssertionError("Test OBJECT_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java new file mode 100644 index 00000000000..cc5f6bfff25 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest + * @run main ClassFileInstaller + * sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UseCompressedOops + * compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:-UseCompressedOops + * compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest + */ + +package compiler.jvmci.compilerToVM; + +import java.lang.reflect.Field; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.vm.ci.hotspot.MetaspaceWrapperObject; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; + +public class GetResolvedJavaTypeTest { + private static enum TestCase { + NULL_BASE { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + return CompilerToVMHelper.getResolvedJavaType( + null, getPtrToKlass(), COMPRESSED); + } + }, + JAVA_METHOD_BASE { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + HotSpotResolvedJavaMethodImpl methodInstance + = CompilerToVMHelper.getResolvedJavaMethodAtSlot( + TEST_CLASS, 0); + Field field; + try { + field = HotSpotResolvedJavaMethodImpl + .class.getDeclaredField("metaspaceMethod"); + field.setAccessible(true); + field.set(methodInstance, getPtrToKlass()); + } catch (ReflectiveOperationException e) { + throw new Error("TEST BUG : " + e, e); + } + + return CompilerToVMHelper.getResolvedJavaType(methodInstance, + 0L, COMPRESSED); + } + }, + CONSTANT_POOL_BASE { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + HotSpotConstantPool cpInst; + try { + cpInst = CompilerToVMHelper.getConstantPool(null, + getPtrToKlass()); + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, getPtrToKlass()); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getResolvedJavaType(cpInst, + 0L, COMPRESSED); + } + }, + CONSTANT_POOL_BASE_IN_TWO { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + long ptr = getPtrToKlass(); + HotSpotConstantPool cpInst = HotSpotResolvedObjectTypeImpl + .fromObjectClass(TEST_CLASS).getConstantPool(); + try { + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, ptr / 2L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getResolvedJavaType(cpInst, + ptr - ptr / 2L, COMPRESSED); + } + }, + CONSTANT_POOL_BASE_ZERO { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + long ptr = getPtrToKlass(); + HotSpotConstantPool cpInst = HotSpotResolvedObjectTypeImpl + .fromObjectClass(TEST_CLASS).getConstantPool(); + try { + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, 0L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getResolvedJavaType(cpInst, + ptr, COMPRESSED); + } + }, + OBJECT_TYPE_BASE { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + HotSpotResolvedObjectTypeImpl type + = HotSpotResolvedObjectTypeImpl.fromObjectClass( + OBJECT_TYPE_BASE.getClass()); + long ptrToClass = UNSAFE.getKlassPointer(OBJECT_TYPE_BASE); + return CompilerToVMHelper.getResolvedJavaType(type, + getPtrToKlass() - ptrToClass, COMPRESSED); + } + }, + ; + abstract HotSpotResolvedObjectTypeImpl getResolvedJavaType(); + } + + private static final Unsafe UNSAFE = Utils.getUnsafe(); + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final long PTR = UNSAFE.getKlassPointer( + new GetResolvedJavaTypeTest()); + private static final Class TEST_CLASS = GetResolvedJavaTypeTest.class; + /* a compressed parameter for tested method is set to false because + unsafe.getKlassPointer always returns uncompressed pointer */ + private static final boolean COMPRESSED = false; + // = WB.getBooleanVMFlag("UseCompressedClassPointers"); + + private static long getPtrToKlass() { + Field field; + try { + field = TEST_CLASS.getDeclaredField("PTR"); + } catch (NoSuchFieldException e) { + throw new Error("TEST BUG : " + e, e); + } + Object base = UNSAFE.staticFieldBase(field); + return WB.getObjectAddress(base) + UNSAFE.staticFieldOffset(field); + } + + public void test(TestCase testCase) { + System.out.println(testCase.name()); + HotSpotResolvedObjectTypeImpl type = testCase.getResolvedJavaType(); + Asserts.assertEQ(type.mirror(), TEST_CLASS, testCase + + " Unexpected Class returned by getResolvedJavaType"); + } + + public static void main(String[] args) { + GetResolvedJavaTypeTest test = new GetResolvedJavaTypeTest(); + for (TestCase testCase : TestCase.values()) { + test.test(testCase); + } + testObjectBase(); + testMetaspaceWrapperBase(); + } + + private static void testMetaspaceWrapperBase() { + try { + HotSpotResolvedObjectTypeImpl type + = CompilerToVMHelper.getResolvedJavaType( + new MetaspaceWrapperObject() { + @Override + public long getMetaspacePointer() { + return getPtrToKlass(); + } + }, 0L, COMPRESSED); + throw new AssertionError("Test METASPACE_WRAPPER_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } + + private static void testObjectBase() { + try { + HotSpotResolvedObjectTypeImpl type + = CompilerToVMHelper.getResolvedJavaType(new Object(), 0L, + COMPRESSED); + throw new AssertionError("Test OBJECT_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java new file mode 100644 index 00000000000..389fb66a6a2 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. compiler.jvmci.compilerToVM.GetStackTraceElementTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class GetStackTraceElementTest { + + public static void main(String[] args) { + Map testCases = createTestCases(); + testCases.forEach(GetStackTraceElementTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod, int[] bcis) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + String className = aMethod.getDeclaringClass().getName(); + int lastDot = className.lastIndexOf('.'); + int firstDol = className.contains("$") + ? className.indexOf('$') + : className.length(); + String fileName = className.substring(lastDot + 1, firstDol) + ".java"; + for (int bci : bcis) { + StackTraceElement ste = CompilerToVMHelper + .getStackTraceElement(method, bci); + Asserts.assertNotNull(ste); + Asserts.assertEQ(ste.getClassName(), className); + Asserts.assertEQ(ste.getFileName(), fileName); + Asserts.assertEQ(ste.getMethodName(), aMethod.getName()); + Asserts.assertEQ(ste.isNativeMethod(), Modifier + .isNative(aMethod.getModifiers())); + } + + } + + private static Map createTestCases() { + Map testCases = new HashMap<>(); + + try { + Class aClass = DummyClass.class; + Method aMethod = aClass.getDeclaredMethod("dummyInstanceFunction"); + int[] bci = new int[] {0, 2, 3, 6, 7, 8, 11, 13, 15, 16, 17, 18}; + testCases.put(aMethod, bci); + + aMethod = aClass.getDeclaredMethod("dummyEmptyFunction"); + bci = new int[] {0}; + testCases.put(aMethod, bci); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG : test method not found", e); + } + return testCases; + } + + private class DummyClass { + public int dummyInstanceFunction() { + String str1 = "123123123"; + double x = 3.14; + int y = Integer.parseInt(str1); + + return y / (int)x; + } + + public void dummyEmptyFunction() {} + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java new file mode 100644 index 00000000000..2a2d2664350 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetSymbolTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * compiler.jvmci.common.testcases.SingleImplementer + * compiler.jvmci.common.testcases.SingleImplementerInterface + * compiler.jvmci.compilerToVM.GetSymbolTest + * compiler.jvmci.common.CTVMUtilities + * jdk.test.lib.Utils + * jdk.test.lib.Asserts + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. compiler.jvmci.compilerToVM.GetSymbolTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.SingleImplementer; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.meta.ConstantPool; +import jdk.test.lib.Utils; + +public class GetSymbolTest { + private static final int CONSTANT_POOL_UTF8_TAG = 1; // see jvms, section 4.4 + + private static final Function> NAMES = members -> + Stream.of(members) + .map(Member::getName) + .collect(Collectors.toList()); + + public static void main(String[] args) { + new GetSymbolTest().test(SingleImplementer.class); + } + + private void test(Class aClass) { + Utils.ensureClassIsLoaded(aClass); + Method method; + try { + method = aClass.getDeclaredMethod("nonInterfaceMethod"); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find test method", e); + } + HotSpotResolvedJavaMethodImpl resolvedMethod + = CTVMUtilities.getResolvedMethod(aClass, method); + List symbols; + try { + symbols = getSymbols(resolvedMethod); + } catch (ReflectiveOperationException e) { + throw new Error("TEST BUG: can't access private members", e); + } + List classSymbols = new ArrayList<>(); + classSymbols.addAll(NAMES.apply(aClass.getDeclaredFields())); + classSymbols.addAll(NAMES.apply(aClass.getDeclaredMethods())); + // Check that all members of test class have symbols from constant pool + for (String s : classSymbols) { + if (!symbols.contains(s)) { + // failed. print all symbols found by getSymbol + System.out.println("getSymbol data:"); + for (String ctvmValue : symbols) { + System.out.println(ctvmValue); + } + throw new AssertionError("Unable to find symbol " + s + + " using CompilerToVM.getSymbol"); + } + } + } + + private List getSymbols(HotSpotResolvedJavaMethodImpl + metaspaceMethod) throws ReflectiveOperationException { + List symbols = new ArrayList<>(); + ConstantPool pool = metaspaceMethod.getConstantPool(); + long length = pool.length(); + // jvms-4.1: The constant_pool table is indexed from 1 ... + for (int i = 1; i < length; i++) { + if (getTag(pool, i) == CONSTANT_POOL_UTF8_TAG) { + long entryPointer; + Method getEntryAt = pool.getClass() + .getDeclaredMethod("getEntryAt", int.class); + getEntryAt.setAccessible(true); + entryPointer = (Long) getEntryAt.invoke(pool, i); + String symbol = CompilerToVMHelper.getSymbol(entryPointer); + symbols.add(symbol); + } + } + return symbols; + } + + private int getTag(ConstantPool pool, int index) + throws ReflectiveOperationException { + Object jvmConstant; + Method getTag = pool.getClass().getDeclaredMethod("getTagAt", + int.class); + getTag.setAccessible(true); + jvmConstant = getTag.invoke(pool, index); + Field tagCode = jvmConstant.getClass().getDeclaredField("tag"); + tagCode.setAccessible(true); + return tagCode.getInt(jvmConstant); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java new file mode 100644 index 00000000000..682b9a0fa86 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.AbstractClass; +import compiler.jvmci.common.testcases.DoNotExtendClass; +import compiler.jvmci.common.testcases.MultipleAbstractImplementer; +import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.common.testcases.MultipleImplementersInterfaceExtender; +import compiler.jvmci.common.testcases.SingleImplementer; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import compiler.jvmci.common.testcases.SingleSubclass; +import compiler.jvmci.common.testcases.SingleSubclassedClass; +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.AnotherSingleImplementer; +import compiler.jvmci.common.testcases.AnotherSingleImplementerInterface; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class GetVtableIndexForInterfaceTest { + private static final int INVALID_VTABLE_INDEX = -4; // see method.hpp: VtableIndexFlag + + public static void main(String args[]) { + GetVtableIndexForInterfaceTest test + = new GetVtableIndexForInterfaceTest(); + try { + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find requested method", e); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + Stream.of( + AbstractClass.class, + SingleImplementer.class, + SingleImplementerInterface.class, + MultipleImplementersInterface.class, + MultipleImplementersInterfaceExtender.class, + SingleSubclass.class, + SingleSubclassedClass.class, + DoNotExtendClass.class, + MultipleAbstractImplementer.class + ) + .forEach(Utils::ensureClassIsLoaded); + // non iface method + result.add(new TestCase(SingleImplementer.class, + SingleImplementer.class, "nonInterfaceMethod", + false, InternalError.class)); + // iface method w/o default implementation + result.add(new TestCase(SingleImplementer.class, + SingleImplementerInterface.class, "interfaceMethod", false)); + /* another iface which provides default implementation for the + original iface*/ + result.add(new TestCase(MultipleImplementersInterfaceExtender.class, + MultipleImplementersInterface.class, "testMethod", false, + InternalError.class)); + // iface method w/ default implementation + result.add(new TestCase(SingleImplementer.class, + SingleImplementerInterface.class, "defaultMethod", true)); + // non iface class + result.add(new TestCase(SingleSubclass.class, + SingleSubclassedClass.class, "inheritedMethod", false, + InternalError.class)); + // class not implementing iface + result.add(new TestCase(DoNotExtendClass.class, + SingleImplementerInterface.class, "defaultMethod", false)); + // abstract class which doesn't implement iface + result.add(new TestCase(AbstractClass.class, + SingleImplementerInterface.class, "defaultMethod", false)); + // abstract class which implements iface + result.add(new TestCase(MultipleAbstractImplementer.class, + MultipleImplementersInterface.class, "defaultMethod", true)); + // class not initialized + result.add(new TestCase(AnotherSingleImplementer.class, + AnotherSingleImplementerInterface.class, "defaultMethod", + false, InternalError.class)); + return result; + } + + private void runTest(TestCase tcase) throws NoSuchMethodException { + System.out.println(tcase); + Method method = tcase.holder.getDeclaredMethod(tcase.methodName); + HotSpotResolvedObjectTypeImpl metaspaceKlass = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.receiver), + getClass(), /* resolve = */ true); + HotSpotResolvedJavaMethodImpl metaspaceMethod = CTVMUtilities + .getResolvedMethod(tcase.holder, method); + int index = 0; + try { + index = CompilerToVMHelper + .getVtableIndexForInterfaceMethod(metaspaceKlass, + metaspaceMethod); + } catch (Throwable t) { + if (tcase.isPositive || tcase.expectedException == null) { + throw new Error("Caught unexpected exception " + t); + } + if (!tcase.expectedException.equals(t.getClass())) { + throw new Error(String.format("Caught %s while expected %s", + t.getClass().getName(), + tcase.expectedException.getName())); + } + return; + } + if (tcase.expectedException != null) { + throw new AssertionError("Expected exception wasn't caught: " + + tcase.expectedException.getName()); + } + if (tcase.isPositive) { + Asserts.assertNE(index, INVALID_VTABLE_INDEX, + "Unexpected: got invalid index"); + } else { + Asserts.assertEQ(index, INVALID_VTABLE_INDEX, + "Unexpected: got valid index "); + } + } + + private static class TestCase { + public final Class receiver; + public final Class holder; + public final String methodName; + public final boolean isPositive; + public final Class expectedException; + + public TestCase(Class receiver, Class holder, String methodName, + boolean isPositive, + Class expectedException) { + this.receiver = receiver; + this.holder = holder; + this.methodName = methodName; + this.isPositive = isPositive; + this.expectedException = expectedException; + } + + public TestCase(Class receiver, Class holder, String methodName, + boolean isPositive) { + this(receiver, holder, methodName, isPositive, null); + } + + @Override + public String toString() { + return String.format("CASE: receiver=%s, holder=%s, method=%s," + + " isPositive=%s%n", receiver.getName(), holder.getName(), + methodName, isPositive); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java b/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java new file mode 100644 index 00000000000..7db6ef08141 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:-BackgroundCompilation + * compiler.jvmci.compilerToVM.HasCompiledCodeForOSRTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import compiler.testlibrary.CompilerUtils; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; + +public class HasCompiledCodeForOSRTest { + public static void main(String[] args) { + ListtestCases = createTestCases(); + testCases.forEach(HasCompiledCodeForOSRTest::runSanityTest); + } + + public static List createTestCases() { + List testCases = new ArrayList<>(); + + try { + Class aClass = DummyClass.class; + testCases.add(new CompileCodeTestCase( + aClass.getMethod("withLoop"), 17)); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG : " + e.getMessage(), e); + } + return testCases; + } + + private static void runSanityTest(CompileCodeTestCase testCase) { + System.out.println(testCase); + Executable aMethod = testCase.executable; + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + testCase.deoptimize(); + int[] levels = CompilerUtils.getAvailableCompilationLevels(); + // not compiled + for (int level : levels) { + boolean isCompiled = CompilerToVMHelper.hasCompiledCodeForOSR( + method, testCase.bci, level); + Asserts.assertFalse(isCompiled, String.format( + "%s : unexpected return value for non-compiled method at " + + "level %d", testCase, level)); + } + NMethod nm = testCase.compile(); + if (nm == null) { + throw new Error(String.format( + "TEST BUG : %s : cannot compile method", testCase)); + } + + boolean isCompiled; + int level = nm.comp_level; + for (int i : levels) { + isCompiled = CompilerToVMHelper.hasCompiledCodeForOSR( + method, testCase.bci, i); + Asserts.assertEQ(isCompiled, level == i, String.format( + "%s : unexpected return value for compiled method at " + + "level %d", testCase, i)); + } + + for (int i : new int[] {-1, +1}) { + int bci = testCase.bci + i; + isCompiled = CompilerToVMHelper.hasCompiledCodeForOSR( + method, bci, level); + Asserts.assertFalse(isCompiled, String.format( + "%s : unexpected return value for compiled method at " + + "level %d with bci = %d ", + testCase, level, bci)); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java new file mode 100644 index 00000000000..4a52691a9be --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.HasFinalizableSubclassTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.HasFinalizableSubclassTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.AbstractClass; +import compiler.jvmci.common.testcases.AbstractClassExtender; +import compiler.jvmci.common.testcases.DoNotImplementInterface; +import compiler.jvmci.common.testcases.MultipleImplementer1; +import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class HasFinalizableSubclassTest { + public static void main(String args[]) { + HasFinalizableSubclassTest test = new HasFinalizableSubclassTest(); + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } + + private static Set createTestCases() { + Stream.of( + AbstractClassExtender.class, + SingleImplementerInterface.class, + MultipleImplementersInterface.class, + MultipleImplementer1.class, + DoNotImplementInterface.class) + .forEach(Utils::ensureClassIsLoaded); + Set result = new HashSet<>(); + // iface with finalize method + result.add(new TestCase(SingleImplementerInterface.class, false)); + // iface with default finalize method + result.add(new TestCase(MultipleImplementersInterface.class, false)); + // class which implements iface w/ default finalize method + result.add(new TestCase(MultipleImplementer1.class, true)); + // abstract class with finalizeable subclass + result.add(new TestCase(AbstractClass.class, true)); + // non-implemented iface + result.add(new TestCase(DoNotImplementInterface.class, false)); + return result; + } + + private void runTest(TestCase tcase) { + System.out.println(tcase); + HotSpotResolvedObjectTypeImpl metaspaceKlass = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.aClass), + getClass(), /* resolve = */ true); + Asserts.assertEQ(tcase.expected, + CompilerToVMHelper.hasFinalizableSubclass(metaspaceKlass), + "Unexpected finalizableSubclass state for " + + tcase.aClass.getName()); + } + + private static class TestCase { + public final Class aClass; + public final boolean expected; + + public TestCase(Class clazz, boolean expected) { + this.aClass = clazz; + this.expected = expected; + } + @Override + public String toString() { + return "CASE: class= " + aClass.getName() + ", expected=" + expected; + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java b/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java new file mode 100644 index 00000000000..0655d4c1d43 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.InitializeConfigurationTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.InitializeConfigurationTest + */ + +package compiler.jvmci.compilerToVM; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Consumer; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.misc.Unsafe; + +public class InitializeConfigurationTest { + private static final Unsafe UNSAFE = Utils.getUnsafe(); + + public static void main(String args[]) { + new InitializeConfigurationTest().runTest(generateTestCases()); + } + + private static List generateTestCases() { + List result = new ArrayList<>(); + result.add(new TestCase("CodeCache", "_high_bound", "address", + InitializeConfigurationTest::verifyLongIsNotZero)); + result.add(new TestCase("StubRoutines", "_jint_arraycopy", "address", + InitializeConfigurationTest::verifyLongIsNotZero)); + return result; + } + + private static void verifyLongIsNotZero(Object o) { + Asserts.assertNotNull(o, "Got null value"); + Asserts.assertEQ(o.getClass(), Long.class, "Unexpected value type"); + Asserts.assertNE(o, 0L, "Got null address"); + } + + private void runTest(List tcases) { + VMStructDataReader reader = new VMStructDataReader( + CompilerToVMHelper.initializeConfiguration()); + while (reader.hasNext()) { + VMFieldData data = reader.next(); + for (TestCase tcase : tcases) { + tcase.check(data); + } + } + // now check if all passed + for (TestCase tcase: tcases) { + Asserts.assertTrue(tcase.isFound(), "Case failed: " + tcase); + } + } + + private static class VMStructDataReader implements Iterator { + // see jvmciCompilerToVM:105 static uintptr_t ciHotSpotVMData[28]; + private static final int HOTSPOT_VM_DATA_INDEX_COUNT = 28; + private final long addresses[]; + private final long vmStructsBase; + private final long entityNameFieldOffset; + private final long nameFieldOffset; + private final long typeStringFieldOffset; + private final long addressOffset; + private final long entrySize; + private long nextElementAddress; + private VMFieldData nextElement; + + public VMStructDataReader(long gHotSpotVMData) { + Asserts.assertNE(gHotSpotVMData, 0L, "Got null base address"); + addresses = new long[HOTSPOT_VM_DATA_INDEX_COUNT]; + for (int i = 0; i < HOTSPOT_VM_DATA_INDEX_COUNT; i++) { + addresses[i] = UNSAFE.getAddress( + gHotSpotVMData + Unsafe.ADDRESS_SIZE * i); + } + vmStructsBase = addresses[0]; + entityNameFieldOffset = addresses[1]; + nameFieldOffset = addresses[2]; + typeStringFieldOffset = addresses[3]; + addressOffset = addresses[6]; + entrySize = addresses[7]; + nextElementAddress = vmStructsBase; + nextElement = read(); + } + + @Override + public boolean hasNext() { + return nextElement != null; + } + + @Override + public VMFieldData next() { + if (nextElement == null) { + throw new NoSuchElementException("Next element is null"); + } + VMFieldData toReturn = nextElement; + nextElementAddress += entrySize; + nextElement = read(); + return toReturn; + } + + private VMFieldData read() { + String entityFieldName = readCString( + UNSAFE.getAddress(nextElementAddress + nameFieldOffset)); + if (entityFieldName == null) { + return null; + } + String fieldType = readCString(UNSAFE.getAddress( + nextElementAddress + typeStringFieldOffset)); + String entityName = readCString(UNSAFE.getAddress( + nextElementAddress + entityNameFieldOffset)); + Object value; + if ("address".equals(fieldType)) { + long address = UNSAFE.getAddress( + nextElementAddress + addressOffset); + value = address; + } else { + // non-address cases are not supported + value = null; + } + return new VMFieldData(entityName, entityFieldName, fieldType, + value); + } + + private static String readCString(long address) { + if (address == 0) { + return null; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0;; i++) { + char c = (char) UNSAFE.getByte(address + i); + if (c == 0) { + break; + } + sb.append(c); + } + return sb.toString(); + } + } + + private static class VMFieldData { + public final String entityFieldName; + public final String entityName; + public final String fieldType; + public final Object value; + + private VMFieldData(String entityName, String entityFieldName, + String fieldType, Object value) { + this.entityName = entityName; + this.entityFieldName = entityFieldName; + this.fieldType = fieldType; + this.value = value; + } + } + + private static class TestCase { + public final String entityName; + public final String fieldType; + public final String entityFieldName; + public final Consumer consumer; + private boolean found; + + public TestCase(String entityName, String entityFieldName, + String fieldType, Consumer predicate) { + Objects.requireNonNull(entityName, "Got null entityName"); + Objects.requireNonNull(entityFieldName, "Got null entityFieldName"); + Objects.requireNonNull(fieldType, "Got null type"); + if (!"address".equals(fieldType)) { + throw new Error("TESTBUG: unsupported testcase with fieldType=" + + fieldType); + } + this.entityName = entityName; + this.fieldType = fieldType; + this.entityFieldName = entityFieldName; + this.consumer = predicate; + this.found = false; + } + + public void check(VMFieldData data) { + if (entityFieldName.equals(data.entityFieldName) + && entityName.equals(data.entityName) + && fieldType.equals(data.fieldType)) { + Asserts.assertFalse(found, "Found 2 entries of " + this); + found = true; + consumer.accept(data.value); + } + } + + @Override + public String toString() { + return "CASE: entityName=" + entityName + " entityFieldName=" + + entityFieldName + " fieldType=" + fieldType; + } + + public boolean isFound() { + return found; + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java new file mode 100644 index 00000000000..1db21f10718 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @ignore 8139700 + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import sun.hotspot.code.NMethod; + +import java.util.List; + +public class InvalidateInstalledCodeTest { + public static void main(String[] args) { + InvalidateInstalledCodeTest test + = new InvalidateInstalledCodeTest(); + List testCases + = CompileCodeTestCase.generate(/* bci = */ 0); + testCases.addAll(CompileCodeTestCase.generate(/* bci = */ -1)); + testCases.forEach(test::check); + test.checkNull(); + } + + private void checkNull() { + InstalledCode installedCode = new InstalledCode(""); + installedCode.setAddress(0); + CompilerToVMHelper.invalidateInstalledCode(installedCode); + } + + private void check(CompileCodeTestCase testCase) { + System.out.println(testCase); + // to have a clean state + NMethod beforeInvalidation = testCase.deoptimizeAndCompile(); + if (beforeInvalidation == null) { + throw new Error("method is not compiled, testCase " + testCase); + } + + // run twice to verify how it works if method is already invalidated + for (int i = 0; i < 2; ++i) { + InstalledCode installedCode = new InstalledCode( + testCase.executable.getName()); + installedCode.setAddress(beforeInvalidation.address); + + CompilerToVMHelper.invalidateInstalledCode(installedCode); + NMethod afterInvalidation = testCase.toNMethod(); + if (afterInvalidation != null) { + System.err.println("before: " + beforeInvalidation); + System.err.println("after: " + afterInvalidation); + throw new AssertionError(testCase + + " : method hasn't been invalidated, i = " + i); + } + Asserts.assertFalse(installedCode.isValid(), testCase + + " : code is valid after invalidation, i = " + i); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java b/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java new file mode 100644 index 00000000000..214b9153e7d --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox IsMatureTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.IsMatureTest + */ +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.SimpleClass; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +import java.lang.reflect.Executable; + +public class IsMatureTest { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String[] args) throws Exception { + new IsMatureTest().test(); + } + + public void test() throws Exception { + SimpleClass sclass = new SimpleClass(); + Executable method = SimpleClass.class.getDeclaredMethod("testMethod"); + long metaspaceMethodData = WB.getMethodData(method); + Asserts.assertEQ(metaspaceMethodData, 0L, "MDO should be null for " + + "never invoked method"); + boolean isMature = CompilerToVMHelper.isMature(metaspaceMethodData); + Asserts.assertFalse(isMature, "null MDO can't be mature"); + for (int i = 0; i < 1000; i++) { + sclass.testMethod(); + } + // warmed up, mdo should be ready for now + metaspaceMethodData = WB.getMethodData(method); + Asserts.assertNE(metaspaceMethodData, 0L, + "MDO should be available after 1000 calls"); + for (int i = 0; i < 100_000; i++) { + sclass.testMethod(); + } + isMature = CompilerToVMHelper.isMature(metaspaceMethodData); + Asserts.assertTrue(isMature, + "a 100_000 times invoked method should be mature"); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java b/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java new file mode 100644 index 00000000000..ddbc028be0a --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary / + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Dcompiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives.positive=true + * -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Dcompiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives.positive=false + * -XX:-EnableJVMCI + * compiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives + + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVM; +import jdk.vm.ci.runtime.JVMCI; +import jdk.test.lib.Asserts; + +import java.lang.reflect.Method; + +public class JVM_RegisterJVMCINatives { + private static final boolean IS_POSITIVE = Boolean.getBoolean( + "compiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives.positive"); + + private final Method registerNatives; + + public static void main(String[] args) { + new JVM_RegisterJVMCINatives().runTest(); + } + + private void runTest() { + Object result; + try { + result = invoke(); + } catch (InternalError e) { + if (IS_POSITIVE) { + throw new AssertionError("unexpected exception", e); + } + return; + } + if (!IS_POSITIVE) { + throw new AssertionError("didn't get expected exception"); + } + Asserts.assertNull(result, + "registerNatives()V returned non-null"); + Asserts.assertEQ(result, invoke(), + "registerNatives returns different results"); + + } + private Object invoke() { + Object result; + try { + result = registerNatives.invoke(JVMCI.class); + } catch (ReflectiveOperationException e) { + throw new Error("can't invoke registerNatives", e); + } + return result; + } + + private JVM_RegisterJVMCINatives() { + Method method; + try { + method = CompilerToVM.class.getDeclaredMethod("registerNatives"); + method.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new Error("can't find CompilerToVM::registerNatives", e); + } + registerNatives = method; + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java new file mode 100644 index 00000000000..1db92682d43 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @summary Testing compiler.jvmci.CompilerToVM.lookupKlassInPool method + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.common.testcases.MultipleImplementersInterface + * compiler.jvmci.common.testcases.MultipleImplementer2 + * compiler.jvmci.compilerToVM.ConstantPoolTestsHelper + * compiler.jvmci.compilerToVM.ConstantPoolTestCase + * compiler.jvmci.compilerToVM.LookupKlassInPoolTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.LookupKlassInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import sun.reflect.ConstantPool; + +/** + * Test for {@code compiler.jvmci.CompilerToVM.lookupKlassInPool} method + */ +public class LookupKlassInPoolTest { + + public static void main(String[] args) { + Map typeTests = new HashMap<>(1); + typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_CLASS, + LookupKlassInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + } + + public static void validate(HotSpotConstantPool constantPoolCTVM, + ConstantPool constantPoolSS, + ConstantPoolTestsHelper.DummyClasses dummyClass, int i) { + Object classToVerify = CompilerToVMHelper + .lookupKlassInPool(constantPoolCTVM, i); + if (!(classToVerify instanceof HotSpotResolvedObjectTypeImpl) + && !(classToVerify instanceof String)) { + String msg = String.format("Output of method" + + " CTVM.lookupKlassInPool is neither" + + " a HotSpotResolvedObjectTypeImpl, nor a String"); + throw new AssertionError(msg); + } + int classNameIndex = (int) dummyClass.cp.get(i).value; + String classNameToRefer + = constantPoolSS.getUTF8At(classNameIndex); + String outputToVerify = classToVerify.toString(); + if (!outputToVerify.contains(classNameToRefer)) { + String msg = String.format("Wrong class accessed by constant" + + " pool index %d: %s, but should be %s", + i, outputToVerify, classNameToRefer); + throw new AssertionError(msg); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java new file mode 100644 index 00000000000..50142e50e69 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.LookupTypeTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.LookupTypeTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.DoNotExtendClass; +import compiler.jvmci.common.testcases.MultiSubclassedClass; +import compiler.jvmci.common.testcases.SingleSubclass; +import java.util.HashSet; +import java.util.Set; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class LookupTypeTest { + public static void main(String args[]) { + LookupTypeTest test = new LookupTypeTest(); + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + // a primitive class + result.add(new TestCase(Utils.toJVMTypeSignature(int.class), + LookupTypeTest.class, true, false, InternalError.class)); + // lookup not existing class + result.add(new TestCase("Lsome_not_existing;", LookupTypeTest.class, + true, false, ClassNotFoundException.class)); + // lookup invalid classname + result.add(new TestCase("L!@#$%^&**()[]{}?;", LookupTypeTest.class, + true, false, ClassNotFoundException.class)); + // lookup package private class + result.add(new TestCase( + "Lcompiler/jvmci/compilerToVM/testcases/PackagePrivateClass;", + LookupTypeTest.class, true, false, + ClassNotFoundException.class)); + // lookup usual class with resolve=true + result.add(new TestCase(Utils.toJVMTypeSignature(SingleSubclass.class), + LookupTypeTest.class, true, true)); + // lookup usual class with resolve=false + result.add(new TestCase( + Utils.toJVMTypeSignature(DoNotExtendClass.class), + LookupTypeTest.class, false, true)); + // lookup usual class with null accessor + result.add(new TestCase( + Utils.toJVMTypeSignature(MultiSubclassedClass.class), null, + false, false, NullPointerException.class)); + return result; + } + + private void runTest(TestCase tcase) { + System.out.println(tcase); + HotSpotResolvedObjectTypeImpl metaspaceKlass; + try { + metaspaceKlass = CompilerToVMHelper.lookupType(tcase.className, + tcase.accessing, tcase.resolve); + } catch (Throwable t) { + Asserts.assertNotNull(tcase.expectedException, + "Assumed no exception, but got " + t); + Asserts.assertFalse(tcase.isPositive, + "Got unexpected exception " + t); + Asserts.assertEQ(t.getClass(), tcase.expectedException, + "Unexpected exception"); + // passed + return; + } + if (tcase.expectedException != null) { + throw new AssertionError("Expected exception was not thrown: " + + tcase.expectedException.getName()); + } + if (tcase.isPositive) { + Asserts.assertNotNull(metaspaceKlass, + "Unexpected null metaspace klass"); + Asserts.assertEQ(metaspaceKlass.getName(), tcase.className, + "Got unexpected resolved class name"); + } else { + Asserts.assertNull(metaspaceKlass, "Unexpected metaspace klass"); + } + } + + private static class TestCase { + public final String className; + public final Class accessing; + public final boolean resolve; + public final boolean isPositive; + public final Class expectedException; + + public TestCase(String className, Class accessing, boolean resolve, + boolean isPositive, + Class expectedException) { + this.className = className; + this.accessing = accessing; + this.resolve = resolve; + this.isPositive = isPositive; + this.expectedException = expectedException; + } + + public TestCase(String className, Class accessing, boolean resolve, + boolean isPositive) { + this.className = className; + this.accessing = accessing; + this.resolve = resolve; + this.isPositive = isPositive; + this.expectedException = null; + } + + @Override + public String toString() { + return String.format("CASE: class=%s, accessing=%s," + + " resolve=%s, positive=%s, expectedException=%s", className, + accessing, resolve, isPositive, expectedException); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java b/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java new file mode 100644 index 00000000000..2f63fcdc0ba --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @ignore 8139703 + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox MaterializeVirtualObjectTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:CompileCommand=exclude,*::check -XX:+DoEscapeAnalysis -Xbatch + * -Dcompiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.invalidate=false + * compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:CompileCommand=exclude,*::check -XX:+DoEscapeAnalysis -Xbatch + * -Dcompiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.invalidate=true + * compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import compiler.testlibrary.CompilerUtils; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; +import java.lang.reflect.Method; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotStackFrameReference; + +public class MaterializeVirtualObjectTest { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final Method METHOD; + private static final HotSpotResolvedJavaMethodImpl RESOLVED_METHOD; + private static final boolean INVALIDATE = Boolean.getBoolean( + "compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.invalidate"); + + static { + try { + METHOD = MaterializeVirtualObjectTest.class.getDeclaredMethod( + "testFrame", String.class, boolean.class); + } catch (NoSuchMethodException e) { + throw new Error("Can't get executable for test method", e); + } + RESOLVED_METHOD = CTVMUtilities.getResolvedMethod(METHOD); + } + + public static void main(String[] args) { + int levels[] = CompilerUtils.getAvailableCompilationLevels(); + // we need compilation level 4 to use EscapeAnalysis + if (levels.length < 1 || levels[levels.length - 1] != 4) { + System.out.println("INFO: Test needs compilation level 4 to" + + " be available. Skipping."); + } else { + new MaterializeVirtualObjectTest().test(); + } + } + + private static String getName() { + return "CASE: invalidate=" + INVALIDATE; + } + + private void test() { + System.out.println(getName()); + Asserts.assertFalse(WB.isMethodCompiled(METHOD), getName() + + " : method unexpectedly compiled"); + /* need to call testFrame at least once to be able to compile it, so + calling with materialize=false, because testFrame is not compiled */ + testFrame("someString", /* materialize= */ false); + WB.enqueueMethodForCompilation(METHOD, 4); + Asserts.assertTrue(WB.isMethodCompiled(METHOD), getName() + + "Method unexpectedly not compiled"); + // calling with materialize=true to materialize compiled testFrame + testFrame("someString", /* materialize= */ true); + } + + private void testFrame(String str, boolean materialize) { + Helper helper = new Helper(str); + check(materialize); + Asserts.assertTrue((helper.string != null) && (this != null) + && (helper != null), getName() + " : some locals are null"); + } + + private void check(boolean materialize) { + // Materialize virtual objects on last invocation + if (materialize) { + HotSpotStackFrameReference hsFrame = CompilerToVMHelper + .getNextStackFrame(/* topmost frame */ null, + new HotSpotResolvedJavaMethodImpl[]{ + RESOLVED_METHOD}, /* don't skip any */ 0); + Asserts.assertNotNull(hsFrame, getName() + " : got null frame"); + Asserts.assertTrue(WB.isMethodCompiled(METHOD), getName() + + "Test method should be compiled"); + Asserts.assertTrue(hsFrame.hasVirtualObjects(), getName() + + ": has no virtual object before materialization"); + CompilerToVMHelper.materializeVirtualObjects(hsFrame, INVALIDATE); + Asserts.assertFalse(hsFrame.hasVirtualObjects(), getName() + + " : has virtual object after materialization"); + Asserts.assertEQ(WB.isMethodCompiled(METHOD), !INVALIDATE, getName() + + " : unexpected compiled status"); + } + } + + private class Helper { + public String string; + + public Helper(String s) { + this.string = s; + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java new file mode 100644 index 00000000000..746d5ee9100 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.MethodIsIgnoredBySecurityStackWalkTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Method; +import java.lang.reflect.Executable; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class MethodIsIgnoredBySecurityStackWalkTest { + + public static void main(String[] args) { + Map testCases = createTestCases(); + testCases.forEach( + MethodIsIgnoredBySecurityStackWalkTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod, Boolean expected) { + HotSpotResolvedJavaMethodImpl method + = CTVMUtilities.getResolvedMethod(aMethod); + boolean isIgnored = CompilerToVMHelper + .methodIsIgnoredBySecurityStackWalk(method); + String msg = String.format("%s is%s ignored but must%s", aMethod, + isIgnored ? "" : " not", + expected ? "" : " not"); + Asserts.assertEQ(isIgnored, expected, msg); + } + + private static Map createTestCases() { + Map testCases = new HashMap<>(); + + try { + Class aClass = Method.class; + testCases.put(aClass.getMethod("invoke", Object.class, + Object[].class), true); + + aClass = Class.forName("sun.reflect.NativeMethodAccessorImpl"); + testCases.put(aClass.getMethod("invoke", Object.class, + Object[].class), true); + testCases.put(aClass.getDeclaredMethod("invoke0", Method.class, + Object.class, Object[].class), true); + + aClass = MethodIsIgnoredBySecurityStackWalkTest.class; + for (Executable method : aClass.getMethods()) { + testCases.put(method, false); + } + for (Executable method : aClass.getDeclaredMethods()) { + testCases.put(method, false); + } + for (Executable method : aClass.getConstructors()) { + testCases.put(method, false); + } + } catch (NoSuchMethodException | ClassNotFoundException e) { + throw new Error("TEST BUG " + e.getMessage(), e); + } + return testCases; + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java new file mode 100644 index 00000000000..db8ab1c3672 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib/ + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.ReadUncompressedOopTest + * @run main ClassFileInstaller + * sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:-UseCompressedOops + * compiler.jvmci.compilerToVM.ReadUncompressedOopTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UseCompressedOops + * compiler.jvmci.compilerToVM.ReadUncompressedOopTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +public class ReadUncompressedOopTest { + + public static void main(String args[]) { + new ReadUncompressedOopTest().runTest(); + } + + private void runTest() { + long ptr = getPtr(); + System.out.printf("calling readUncompressedOop(0x%x)%n", ptr); + Asserts.assertEQ(getClass(), + CompilerToVMHelper.readUncompressedOop(ptr), + String.format("unexpected class returned for 0x%x", ptr)); + } + + private static final Unsafe UNSAFE = Utils.getUnsafe(); + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final Class CLASS = ReadUncompressedOopTest.class; + private static final long PTR = WB.getObjectAddress(CLASS); + + private static long getPtr() { + Field field; + try { + field = CLASS.getDeclaredField("PTR"); + } catch (NoSuchFieldException nsfe) { + throw new Error("TESTBUG : " + nsfe, nsfe); + } + Object base = UNSAFE.staticFieldBase(field); + return WB.getObjectAddress(base) + UNSAFE.staticFieldOffset(field); + } +} + diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java new file mode 100644 index 00000000000..24fa5b589b9 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller + * sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xmixed + * compiler.jvmci.compilerToVM.ReprofileTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ProfilingInfo; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; + +public class ReprofileTest { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String[] args) { + List testCases = createTestCases(); + testCases.forEach(ReprofileTest::runSanityTest); + } + + private static List createTestCases() { + List testCases = new ArrayList<>(); + try { + + Class aClass = DummyClass.class; + testCases.add(aClass.getMethod("withLoop")); + + aClass = DummyClass.class; + testCases.add(aClass.getDeclaredMethod("dummyFunction")); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG " + e.getMessage(), e); + } + return testCases; + } + + private static void runSanityTest(Method aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + ProfilingInfo startProfile = method.getProfilingInfo(); + Asserts.assertFalse(startProfile.isMature(), aMethod + + " : profiling info is mature in the begging"); + + long compileThreshold = (Long) WB.getVMFlag("CompileThreshold"); + // make interpreter to profile this method + try { + Object obj = aMethod.getDeclaringClass().newInstance(); + for (long i = 0; i < compileThreshold; i++) { + aMethod.invoke(obj); + } + } catch (ReflectiveOperationException e) { + throw new Error("TEST BUG : " + e.getMessage(), e); + } + ProfilingInfo compProfile = method.getProfilingInfo(); + + Asserts.assertNE(startProfile.toString(), compProfile.toString(), + String.format("%s : profiling info wasn't changed after " + + "%d invocations", + aMethod, compileThreshold)); + Asserts.assertTrue(compProfile.isMature(), + String.format("%s is not mature after %d invocations", + aMethod, compileThreshold)); + + CompilerToVMHelper.reprofile(method); + ProfilingInfo reprofiledProfile = method.getProfilingInfo(); + + Asserts.assertNE(startProfile.toString(), reprofiledProfile.toString(), + aMethod + " : profiling info wasn't changed after reprofiling"); + Asserts.assertNE(compProfile.toString(), reprofiledProfile.toString(), + aMethod + " : profiling info didn't change after reprofile"); + Asserts.assertFalse(reprofiledProfile.isMature(), aMethod + + " : profiling info is mature after reprofiling"); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java new file mode 100644 index 00000000000..ffbecca7dbf --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.ResolveConstantInPoolTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ResolveConstantInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.test.lib.Asserts; +import sun.reflect.ConstantPool; + +/** + * Test for {@code compiler.jvmci.CompilerToVM.resolveConstantInPool} method + */ +public class ResolveConstantInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(2); + typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_METHODHANDLE, + ResolveConstantInPoolTest::validateMethodHandle); + typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_METHODTYPE, + ResolveConstantInPoolTest::validateMethodType); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + } + + private static void validateMethodHandle(HotSpotConstantPool constantPoolCTVM, + ConstantPool constantPoolSS, + ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { + Object constantInPool = CompilerToVMHelper + .resolveConstantInPool(constantPoolCTVM, index); + if (!(constantInPool instanceof MethodHandle)) { + String msg = String.format( + "Wrong constant pool entry accessed by index" + + " %d: %s, but should be subclass of %s", + index + 1, constantInPool.getClass(), + MethodHandle.class.getName()); + throw new AssertionError(msg); + } + } + + private static void validateMethodType(HotSpotConstantPool constantPoolCTVM, + ConstantPool constantPoolSS, + ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { + Object constantInPool = CompilerToVMHelper + .resolveConstantInPool(constantPoolCTVM, index); + Class mtToVerify = constantInPool.getClass(); + Class mtToRefer = MethodType.class; + String msg = String.format("Wrong %s accessed by constant pool index" + + " %d: %s, but should be %s", "method type class", + index, mtToVerify, mtToRefer); + Asserts.assertEQ(mtToRefer, mtToVerify, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java new file mode 100644 index 00000000000..8881d7a9f9f --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.ResolveMethodTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.ResolveMethodTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.AbstractClass; +import compiler.jvmci.common.testcases.AbstractClassExtender; +import compiler.jvmci.common.testcases.MultipleImplementer1; +import compiler.jvmci.common.testcases.MultipleImplementer2; +import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.common.testcases.SingleImplementer; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import compiler.jvmci.common.testcases.SingleSubclass; +import compiler.jvmci.common.testcases.SingleSubclassedClass; +import compiler.jvmci.common.CTVMUtilities; +import java.util.HashSet; +import java.util.Set; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.misc.Unsafe; + +public class ResolveMethodTest { + private static final Unsafe UNSAFE = Utils.getUnsafe(); + + public static void main(String args[]) { + ResolveMethodTest test = new ResolveMethodTest(); + // positive cases + try { + for (TestCase tcase: createTestCases()) { + test.runTest(tcase); + } + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find requested method", e); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + // a usual class public method + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "usualMethod", ResolveMethodTest.class, true)); + // an array method + result.add(new TestCase(int[].class, Object.class, "toString", + ResolveMethodTest.class, true)); + // a method from base class, which was overriden in tested one + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "overridenMethod", ResolveMethodTest.class, true)); + // a method from base class, which was not overriden in tested one + result.add(new TestCase(SingleSubclass.class, + SingleSubclassedClass.class, "inheritedMethod", + ResolveMethodTest.class, true)); + /* a method from base class, which was overriden in tested one with + base class as holder */ + result.add(new TestCase(SingleSubclass.class, + SingleSubclassedClass.class, "overridenMethod", + ResolveMethodTest.class, true)); + // an interface method + result.add(new TestCase(SingleImplementer.class, + SingleImplementerInterface.class, "interfaceMethod", + ResolveMethodTest.class, true)); + // an interface default method overriden in implementer + result.add(new TestCase(MultipleImplementer1.class, + MultipleImplementersInterface.class, "defaultMethod", + ResolveMethodTest.class, true)); + // an interface default method not overriden in implementer + result.add(new TestCase(MultipleImplementer2.class, + MultipleImplementersInterface.class, "defaultMethod", + ResolveMethodTest.class, true)); + // an abstract method + result.add(new TestCase(AbstractClassExtender.class, AbstractClass.class, + "abstractMethod", ResolveMethodTest.class, true)); + // private method with right accessor + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "privateMethod", SingleSubclass.class, true)); + // package-private method with right accessor + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "defaultAccessMethod", SingleSubclass.class, true)); + + // negative cases + + // private method of another class + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "privateMethod", ResolveMethodTest.class, false)); + // package-private method from another package + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "defaultAccessMethod", ResolveMethodTest.class, false)); + return result; + } + + private void runTest(TestCase tcase) throws NoSuchMethodException { + System.out.println(tcase); + HotSpotResolvedJavaMethodImpl metaspaceMethod = CTVMUtilities + .getResolvedMethod(tcase.holder, + tcase.holder.getDeclaredMethod(tcase.methodName)); + HotSpotResolvedObjectTypeImpl holderMetaspace = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.holder), + getClass(), /* resolve = */ true); + HotSpotResolvedObjectTypeImpl callerMetaspace = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.caller), + getClass(), /* resolve = */ true); + HotSpotResolvedJavaMethodImpl resolvedMetaspaceMethod + = CompilerToVMHelper.resolveMethod(holderMetaspace, + metaspaceMethod, callerMetaspace); + if (tcase.isPositive) { + Asserts.assertNotNull(resolvedMetaspaceMethod, + "Unexpected null resolved method value for " + + tcase.methodName); + Asserts.assertEQ(metaspaceMethod.getName(), tcase.methodName, + "Reflection and c2vm method names doesn't match"); + } else { + Asserts.assertNull(resolvedMetaspaceMethod, + "Method unexpectedly resolved"); + } + } + + private static class TestCase { + public final Class receiver; + public final Class holder; + public final Class caller; + public final String methodName; + public final boolean isPositive; + + public TestCase(Class recv, Class holder, String methodName, + Class caller, boolean isPositive) { + this.receiver = recv; + this.holder = holder; + this.caller = caller; + this.methodName = methodName; + this.isPositive = isPositive; + } + + @Override + public String toString() { + return String.format("CASE: receiver=%s, holder=%s, method=%s," + + "caller=%s, isPositive=%s%n", receiver.getName(), + holder.getName(), methodName, caller.getName(), isPositive); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java new file mode 100644 index 00000000000..3a98e76282c --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @summary Testing compiler.jvmci.CompilerToVM.resolveTypeInPool method + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.common.testcases.MultipleImplementersInterface + * compiler.jvmci.common.testcases.MultipleImplementer2 + * compiler.jvmci.compilerToVM.ConstantPoolTestsHelper + * compiler.jvmci.compilerToVM.ConstantPoolTestCase + * compiler.jvmci.compilerToVM.ResolveTypeInPoolTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.ResolveTypeInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import sun.reflect.ConstantPool; + +/** + * Test for {@code compiler.jvmci.CompilerToVM.resolveTypeInPool} method + */ +public class ResolveTypeInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(1); + typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_CLASS, + ResolveTypeInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + } + + public static void validate(HotSpotConstantPool constantPoolCTVM, + ConstantPool constantPoolSS, + ConstantPoolTestsHelper.DummyClasses dummyClass, int i) { + HotSpotResolvedObjectTypeImpl typeToVerify = CompilerToVMHelper + .resolveTypeInPool(constantPoolCTVM, i); + int classNameIndex = (int) dummyClass.cp.get(i).value; + String classNameToRefer = constantPoolSS.getUTF8At(classNameIndex); + String outputToVerify = typeToVerify.toString(); + if (!outputToVerify.contains(classNameToRefer)) { + String msg = String.format("Wrong class accessed by constant" + + " pool index %d: %s, but should be %s", + i, outputToVerify, classNameToRefer); + throw new AssertionError(msg); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java new file mode 100644 index 00000000000..820ef850171 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib/ + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:+DebugNonSafepoints + * -Dcompiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest.expected=true + * compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest + * @run main/othervm + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:-DebugNonSafepoints + * -Dcompiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest.expected=false + * compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class ShouldDebugNonSafepointsTest { + private static final boolean EXPECTED = Boolean.getBoolean("compiler" + + ".jvmci.compilerToVM.ShouldDebugNonSafepointsTest.expected"); + + public static void main(String args[]) { + new ShouldDebugNonSafepointsTest().runTest(); + } + + private void runTest() { + Asserts.assertEQ(CompilerToVMHelper.shouldDebugNonSafepoints(), + EXPECTED, "Unexpected shouldDebugnonSafepoints value"); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java new file mode 100644 index 00000000000..e709449a8be --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.ShouldInlineMethodTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +public class ShouldInlineMethodTest { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String[] args) { + List testCases = createTestCases(); + testCases.forEach(ShouldInlineMethodTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + boolean shouldInline = CompilerToVMHelper.shouldInlineMethod(method); + boolean expectedShouldInline = WB.testSetForceInlineMethod(aMethod, + true); + Asserts.assertEQ(shouldInline, expectedShouldInline, + "Unexpected value of property 'should inline'"); + + shouldInline = CompilerToVMHelper.shouldInlineMethod(method); + Asserts.assertTrue(shouldInline, "Unexpected value of property " + + "'should inline' after setting 'force inline' to true"); + WB.testSetForceInlineMethod(aMethod, false); + shouldInline = CompilerToVMHelper.shouldInlineMethod(method); + Asserts.assertFalse(shouldInline, "Unexpected value of property " + + "'should inline' after setting 'force inline' to false"); + } + + private static List createTestCases() { + List testCases = new ArrayList<>(); + + Class aClass = DummyClass.class; + testCases.addAll(Arrays.asList(aClass.getDeclaredMethods())); + testCases.addAll(Arrays.asList(aClass.getDeclaredConstructors())); + return testCases; + } +} diff --git a/hotspot/test/compiler/jvmci/events/JvmciCompleteInitializationTest.config b/hotspot/test/compiler/jvmci/events/JvmciCompleteInitializationTest.config new file mode 100644 index 00000000000..f9f1333a238 --- /dev/null +++ b/hotspot/test/compiler/jvmci/events/JvmciCompleteInitializationTest.config @@ -0,0 +1 @@ +compiler.jvmci.events.JvmciCompleteInitializationTest diff --git a/hotspot/test/compiler/jvmci/events/JvmciCompleteInitializationTest.java b/hotspot/test/compiler/jvmci/events/JvmciCompleteInitializationTest.java new file mode 100644 index 00000000000..742878c0dfa --- /dev/null +++ b/hotspot/test/compiler/jvmci/events/JvmciCompleteInitializationTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary + * @build compiler.jvmci.common.JVMCIHelpers + * compiler.jvmci.events.JvmciCompleteInitializationTest + * @run main jdk.test.lib.FileInstaller ../common/services/ ./META-INF/services/ + * @run main jdk.test.lib.FileInstaller ./JvmciCompleteInitializationTest.config + * ./META-INF/services/jdk.vm.ci.hotspot.HotSpotVMEventListener + * @run main ClassFileInstaller + * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler + * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory + * compiler.jvmci.events.JvmciCompleteInitializationTest + * jdk.test.lib.Asserts + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Xbootclasspath/a:. + * -XX:+EnableJVMCI + * -Dcompiler.jvmci.events.JvmciCompleteInitializationTest.positive=true + * compiler.jvmci.events.JvmciCompleteInitializationTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Xbootclasspath/a:. + * -XX:-EnableJVMCI + * -Dcompiler.jvmci.events.JvmciCompleteInitializationTest.positive=false + * compiler.jvmci.events.JvmciCompleteInitializationTest + */ + +package compiler.jvmci.events; + +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; + +public class JvmciCompleteInitializationTest implements HotSpotVMEventListener { + private static final boolean IS_POSITIVE = Boolean.getBoolean( + "compiler.jvmci.events.JvmciCompleteInitializationTest.positive"); + private static volatile int completeInitializationCount = 0; + private static volatile String errorMessage = ""; + + public static void main(String args[]) { + if (completeInitializationCount != 0) { + throw new Error("Unexpected completeInitialization events" + + " count at start"); + } + initializeRuntime(); + int expectedEventCount = IS_POSITIVE ? 1 : 0; + Asserts.assertEQ(completeInitializationCount, expectedEventCount, + "Unexpected completeInitialization events count" + + " after JVMCI init"); + initializeRuntime(); + Asserts.assertEQ(completeInitializationCount, expectedEventCount, + "Unexpected completeInitialization events count" + + " after 2nd JVMCI init"); + Asserts.assertTrue(errorMessage.isEmpty(), errorMessage); + } + + private static void initializeRuntime() { + Error t = null; + try { + /* in case JVMCI disabled, an InternalError on initialization + and NoClassDefFound on 2nd try */ + HotSpotJVMCIRuntime.runtime(); + } catch (Error e) { + t = e; + } + if (IS_POSITIVE) { + Asserts.assertNull(t, "Caught unexpected exception"); + } else { + Asserts.assertNotNull(t, "Got no expected error"); + } + } + + @Override + public void completeInitialization(HotSpotJVMCIRuntime + hotSpotJVMCIRuntime) { + completeInitializationCount++; + if (hotSpotJVMCIRuntime == null) { + errorMessage += " HotSpotJVMCIRuntime is null."; + } + } +} diff --git a/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.config b/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.config new file mode 100644 index 00000000000..494110c8bd2 --- /dev/null +++ b/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.config @@ -0,0 +1 @@ +compiler.jvmci.events.JvmciCreateMetaAccessContextTest diff --git a/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java b/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java new file mode 100644 index 00000000000..e259f24fa15 --- /dev/null +++ b/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary + * @compile ./MetaAccessWrapper.java + * @build compiler.jvmci.common.JVMCIHelpers + * compiler.jvmci.events.JvmciCreateMetaAccessContextTest + * @run main jdk.test.lib.FileInstaller ../common/services/ ./META-INF/services/ + * @run main jdk.test.lib.FileInstaller + * ./JvmciCreateMetaAccessContextTest.config + * ./META-INF/services/jdk.vm.ci.hotspot.HotSpotVMEventListener + * @run main ClassFileInstaller + * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler + * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory + * compiler.jvmci.events.JvmciCreateMetaAccessContextTest + * jdk.vm.ci.hotspot.MetaAccessWrapper + * jdk.test.lib.Asserts + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * -Dcompiler.jvmci.events.JvmciCreateMetaAccessContextTest.providenull=true + * compiler.jvmci.events.JvmciCreateMetaAccessContextTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * -Dcompiler.jvmci.events.JvmciCreateMetaAccessContextTest.providenull=false + * compiler.jvmci.events.JvmciCreateMetaAccessContextTest + */ + +package compiler.jvmci.events; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; +import jdk.vm.ci.hotspot.MetaAccessWrapper; +import jdk.vm.ci.meta.JVMCIMetaAccessContext; +import jdk.test.lib.Asserts; + +public class JvmciCreateMetaAccessContextTest + implements HotSpotVMEventListener { + private static final boolean PROVIDE_NULL_CONTEXT = Boolean.getBoolean( + "compiler.jvmci.events.JvmciCreateMetaAccessContextTest" + + ".providenull"); + private static volatile int createMetaAccessContextCount = 0; + private static volatile String errorMessage = ""; + + public static void main(String args[]) { + if (createMetaAccessContextCount != 0) { + throw new Error("Unexpected createMetaAccessContextevents count" + + " at test start"); + } + JVMCIMetaAccessContext context; + context = HotSpotJVMCIRuntime.runtime().getMetaAccessContext(); + Asserts.assertNotNull(context, + "JVMCIMetaAccessContext is null after 1st request"); + Asserts.assertEQ(createMetaAccessContextCount, 1, + "Unexpected createMetaAccessContext events count after 1st" + + " JVMCI runtime request"); + context = HotSpotJVMCIRuntime.runtime().getMetaAccessContext(); + Asserts.assertNotNull(context, + "JVMCIMetaAccessContext is null after 2nd request"); + Asserts.assertEQ(createMetaAccessContextCount, 1, + "Unexpected createMetaAccessContext events count after 2nd" + + " JVMCI runtime request"); + Asserts.assertTrue(errorMessage.isEmpty(), errorMessage); + if (PROVIDE_NULL_CONTEXT) { + Asserts.assertFalse(context instanceof MetaAccessWrapper, + "Got unexpected context: " + context.getClass()); + } else { + Asserts.assertTrue(context instanceof MetaAccessWrapper, + "Got unexpected context: " + context.getClass()); + } + } + + @Override + public JVMCIMetaAccessContext createMetaAccessContext(HotSpotJVMCIRuntime + hotSpotJVMCIRuntime) { + createMetaAccessContextCount++; + if (hotSpotJVMCIRuntime == null) { + errorMessage += " HotSpotJVMCIRuntime is null."; + } + if (PROVIDE_NULL_CONTEXT) { + return null; + } + return new MetaAccessWrapper(); + } +} diff --git a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.config b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.config new file mode 100644 index 00000000000..70e33b3d74d --- /dev/null +++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.config @@ -0,0 +1 @@ +compiler.jvmci.events.JvmciNotifyInstallEventTest diff --git a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java new file mode 100644 index 00000000000..82591452d8c --- /dev/null +++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.common.JVMCIHelpers + * compiler.jvmci.events.JvmciNotifyInstallEventTest + * @run main jdk.test.lib.FileInstaller ../common/services/ ./META-INF/services/ + * @run main jdk.test.lib.FileInstaller ./JvmciNotifyInstallEventTest.config + * ./META-INF/services/jdk.vm.ci.hotspot.HotSpotVMEventListener + * @run main ClassFileInstaller + * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler + * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory + * compiler.jvmci.events.JvmciNotifyInstallEventTest + * compiler.jvmci.common.CTVMUtilities + * compiler.jvmci.common.testcases.SimpleClass + * jdk.vm.ci.hotspot.CompilerToVMHelper + * jdk.test.lib.Asserts + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Djvmci.compiler=EmptyCompiler -Xbootclasspath/a:. -Xmixed + * -XX:+UseJVMCICompiler -XX:-BootstrapJVMCI + * -Dcompiler.jvmci.events.JvmciNotifyInstallEventTest.noevent=false + * compiler.jvmci.events.JvmciNotifyInstallEventTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-EnableJVMCI + * -Djvmci.compiler=EmptyCompiler -Xbootclasspath/a:. -Xmixed + * -Dcompiler.jvmci.events.JvmciNotifyInstallEventTest.noevent=true + * compiler.jvmci.events.JvmciNotifyInstallEventTest + */ + +package compiler.jvmci.events; + +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.SimpleClass; +import jdk.test.lib.Asserts; +import java.lang.reflect.Method; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; +import jdk.vm.ci.code.CompilationResult; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; + +public class JvmciNotifyInstallEventTest implements HotSpotVMEventListener { + private static final String METHOD_NAME = "testMethod"; + private static final boolean IS_POSITIVE = !Boolean.getBoolean( + "compiler.jvmci.events.JvmciNotifyInstallEventTest.noevent"); + private static volatile int gotInstallNotification = 0; + + public static void main(String args[]) { + new JvmciNotifyInstallEventTest().runTest(); + } + + private void runTest() { + if (gotInstallNotification != 0) { + throw new Error("Got install notification before test actions"); + } + HotSpotCodeCacheProvider codeCache = null; + try { + codeCache = (HotSpotCodeCacheProvider) HotSpotJVMCIRuntime.runtime() + .getHostJVMCIBackend().getCodeCache(); + } catch (InternalError ie) { + if (IS_POSITIVE) { + throw new AssertionError( + "Got unexpected InternalError trying to get code cache", + ie); + } + // passed + return; + } + Asserts.assertTrue(IS_POSITIVE, + "Haven't caught InternalError in negative case"); + Method testMethod; + try { + testMethod = SimpleClass.class.getDeclaredMethod(METHOD_NAME); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: Can't find " + METHOD_NAME, e); + } + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(SimpleClass.class, testMethod); + CompilationResult compResult = new CompilationResult(METHOD_NAME); + // to pass sanity check of default -1 + compResult.setTotalFrameSize(0); + codeCache.installMethod(method, compResult, /* jvmciEnv = */ 0L, + /* isDefault = */ false); + Asserts.assertEQ(gotInstallNotification, 1, + "Got unexpected event count after 1st install attempt"); + // since "empty" compilation result is ok, a second attempt should be ok + codeCache.installMethod(method, compResult, /* jvmciEnv = */ 0L, + /* isDefault = */ false); + Asserts.assertEQ(gotInstallNotification, 2, + "Got unexpected event count after 2nd install attempt"); + } + + @Override + public void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, + InstalledCode installedCode, CompilationResult compResult) { + gotInstallNotification++; + } +} diff --git a/hotspot/test/compiler/jvmci/events/JvmciShutdownEventListener.java b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventListener.java new file mode 100644 index 00000000000..c82cbd10201 --- /dev/null +++ b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventListener.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.events; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; + +public class JvmciShutdownEventListener implements HotSpotVMEventListener { + public static final String MESSAGE = "Shutdown notified"; + public static final String GOT_INTERNAL_ERROR = "Got internal error"; + + public static void main(String args[]) { + try { + HotSpotJVMCIRuntime.runtime(); // let's trigger that lazy jvmci init + } catch (InternalError e) { + System.out.println(GOT_INTERNAL_ERROR); + } + } + + @Override + public void notifyShutdown() { + System.out.println(MESSAGE); + } +} diff --git a/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.config b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.config new file mode 100644 index 00000000000..8faad5ebaf6 --- /dev/null +++ b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.config @@ -0,0 +1 @@ +compiler.jvmci.events.JvmciShutdownEventListener diff --git a/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java new file mode 100644 index 00000000000..5b034a1a549 --- /dev/null +++ b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary / + * @build compiler.jvmci.common.JVMCIHelpers + * compiler.jvmci.events.JvmciShutdownEventListener + * compiler.jvmci.events.JvmciShutdownEventTest + * @run main jdk.test.lib.FileInstaller ../common/services/ ./META-INF/services/ + * @run main jdk.test.lib.FileInstaller ./JvmciShutdownEventTest.config + * ./META-INF/services/jdk.vm.ci.hotspot.HotSpotVMEventListener + * @run main ClassFileInstaller + * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler + * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory + * compiler.jvmci.events.JvmciShutdownEventListener + * @run driver + * compiler.jvmci.events.JvmciShutdownEventTest + */ + +package compiler.jvmci.events; + +import jdk.test.lib.ExitCode; +import jdk.test.lib.cli.CommandLineOptionTest; + +public class JvmciShutdownEventTest { + private final static String[] MESSAGE = new String[]{ + JvmciShutdownEventListener.MESSAGE + }; + + private final static String[] ERROR_MESSAGE = new String[]{ + JvmciShutdownEventListener.GOT_INTERNAL_ERROR + }; + + public static void main(String args[]) throws Throwable { + boolean addTestVMOptions = true; + CommandLineOptionTest.verifyJVMStartup(MESSAGE, ERROR_MESSAGE, + "Unexpected exit code with +EnableJVMCI", + "Unexpected output with +EnableJVMCI", ExitCode.OK, + addTestVMOptions, "-XX:+UnlockExperimentalVMOptions", + "-XX:+EnableJVMCI", "-Xbootclasspath/a:.", + JvmciShutdownEventListener.class.getName() + ); + + CommandLineOptionTest.verifyJVMStartup(ERROR_MESSAGE, MESSAGE, + "Unexpected exit code with -EnableJVMCI", + "Unexpected output with -EnableJVMCI", ExitCode.OK, + addTestVMOptions, "-XX:+UnlockExperimentalVMOptions", + "-XX:-EnableJVMCI", "-Xbootclasspath/a:.", + JvmciShutdownEventListener.class.getName() + ); + } +} diff --git a/hotspot/test/compiler/jvmci/events/MetaAccessWrapper.java b/hotspot/test/compiler/jvmci/events/MetaAccessWrapper.java new file mode 100644 index 00000000000..d1aec4ed9f8 --- /dev/null +++ b/hotspot/test/compiler/jvmci/events/MetaAccessWrapper.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.JVMCIMetaAccessContext; +import jdk.vm.ci.meta.ResolvedJavaType; + +/* + * A JVMCIMetaAccessContext wrapper class to mark context + * being provided/returned + */ +public class MetaAccessWrapper implements JVMCIMetaAccessContext { + private static final HotSpotJVMCIMetaAccessContext CONTEXT + = new HotSpotJVMCIMetaAccessContext(); + @Override + public ResolvedJavaType fromClass(Class clazz) { + return CONTEXT.fromClass(clazz); + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/NestedBooleanOptionValueTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/NestedBooleanOptionValueTest.java new file mode 100644 index 00000000000..a9648ea676e --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/NestedBooleanOptionValueTest.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @run junit jdk.vm.ci.options.test.NestedBooleanOptionValueTest + */ + +package jdk.vm.ci.options.test; + +import static jdk.vm.ci.options.test.NestedBooleanOptionValueTest.Options.*; +import static org.junit.Assert.*; +import jdk.vm.ci.options.*; +import jdk.vm.ci.options.OptionValue.*; + +import org.junit.*; + +public class NestedBooleanOptionValueTest { + + public static class Options { + public static final OptionValue Master0 = new OptionValue<>(true); + public static final OptionValue NestedOption0 = new NestedBooleanOptionValue(Master0, true); + public static final OptionValue Master1 = new OptionValue<>(true); + public static final OptionValue NestedOption1 = new NestedBooleanOptionValue(Master1, true); + public static final OptionValue Master2 = new OptionValue<>(true); + public static final OptionValue NestedOption2 = new NestedBooleanOptionValue(Master2, false); + } + + static final OptionDescriptor master0 = OptionDescriptor.create("Master0", Boolean.class, "", Options.class, "Master0", Master0); + static final OptionDescriptor nestedOption0 = OptionDescriptor.create("NestedOption0", Boolean.class, "", Options.class, "NestedOption0", NestedOption0); + static final OptionDescriptor master1 = OptionDescriptor.create("Master1", Boolean.class, "", Options.class, "Master1", Master1); + static final OptionDescriptor nestedOption1 = OptionDescriptor.create("NestedOption1", Boolean.class, "", Options.class, "NestedOption1", NestedOption1); + static final OptionDescriptor master2 = OptionDescriptor.create("Master2", Boolean.class, "", Options.class, "Master2", Master2); + static final OptionDescriptor nestedOption2 = OptionDescriptor.create("NestedOption2", Boolean.class, "", Options.class, "NestedOption2", NestedOption2); + + @SuppressWarnings("try") + @Test + public void runOverrides() { + assertTrue(Master0.getValue()); + assertTrue(NestedOption0.getValue()); + try (OverrideScope s1 = OptionValue.override(Master0, false)) { + assertFalse(Master0.getValue()); + assertFalse(NestedOption0.getValue()); + try (OverrideScope s2 = OptionValue.override(NestedOption0, false)) { + assertFalse(NestedOption0.getValue()); + } + try (OverrideScope s2 = OptionValue.override(NestedOption0, true)) { + assertTrue(NestedOption0.getValue()); + } + } + assertTrue(Master0.getValue()); + try (OverrideScope s1 = OptionValue.override(NestedOption0, false)) { + assertFalse(NestedOption0.getValue()); + } + try (OverrideScope s1 = OptionValue.override(NestedOption0, true)) { + assertTrue(NestedOption0.getValue()); + } + } + + @Test + public void runDefaultTrue() { + Master1.setValue(true); + assertTrue(Master1.getValue()); + assertTrue(NestedOption1.getValue()); + // nested value unset + Master1.setValue(false); + assertFalse(Master1.getValue()); + assertFalse(NestedOption1.getValue()); + // set false + Master1.setValue(false); + NestedOption1.setValue(false); + assertFalse(Master1.getValue()); + assertFalse(NestedOption1.getValue()); + Master1.setValue(true); + assertTrue(Master1.getValue()); + assertFalse(NestedOption1.getValue()); + // set true + Master1.setValue(false); + NestedOption1.setValue(true); + assertFalse(Master1.getValue()); + assertTrue(NestedOption1.getValue()); + Master1.setValue(true); + assertTrue(Master1.getValue()); + assertTrue(NestedOption1.getValue()); + } + + @Test + public void runDefaultFalse() { + Master2.setValue(true); + assertTrue(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + // nested value unset + Master2.setValue(false); + assertFalse(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + // set false + Master2.setValue(false); + NestedOption2.setValue(false); + assertFalse(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + Master2.setValue(true); + assertTrue(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + // set true + Master2.setValue(false); + NestedOption2.setValue(true); + assertFalse(Master2.getValue()); + assertTrue(NestedOption2.getValue()); + Master2.setValue(true); + assertTrue(Master2.getValue()); + assertTrue(NestedOption2.getValue()); + } + +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/TestOptionValue.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/TestOptionValue.java new file mode 100644 index 00000000000..17135e43e94 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/TestOptionValue.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @run junit jdk.vm.ci.options.test.TestOptionValue + */ + +package jdk.vm.ci.options.test; + +import static jdk.vm.ci.options.test.TestOptionValue.Options.*; +import static org.junit.Assert.*; + +import java.util.*; + +import jdk.vm.ci.options.*; +import jdk.vm.ci.options.OptionValue.*; + +import org.junit.*; + +@SuppressWarnings("try") +public class TestOptionValue { + + public static class Options { + public static final OptionValue Stable = new StableOptionValue<>(true); + public static final OptionValue Mutable = new OptionValue<>("original"); + public static final OptionValue SecondMutable = new OptionValue<>("second"); + } + + static final OptionDescriptor stable = OptionDescriptor.create("Stable", Boolean.class, "", Options.class, "Stable", Stable); + static final OptionDescriptor mutable = OptionDescriptor.create("Mutable", String.class, "", Options.class, "Mutable", Mutable); + static final OptionDescriptor secondMutable = OptionDescriptor.create("SecondMutable", String.class, "", Options.class, "SecondMutable", SecondMutable); + + @Test + public void testMutable() { + assertEquals("original", Mutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals("override1", Mutable.getValue()); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals("override2", Mutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + try (OverrideScope s3 = OptionValue.override(Mutable, "override3")) { + assertEquals("override3", Mutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + } + assertEquals("original", Mutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "original")) { + assertEquals("original", Mutable.getValue()); + } + } + + @Test + public void testMultiple() { + assertEquals("original", Mutable.getValue()); + assertEquals("second", SecondMutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1", SecondMutable, "secondOverride1")) { + assertEquals("override1", Mutable.getValue()); + assertEquals("secondOverride1", SecondMutable.getValue()); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2", SecondMutable, "secondOverride2")) { + assertEquals("override2", Mutable.getValue()); + assertEquals("secondOverride2", SecondMutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + assertEquals("secondOverride1", SecondMutable.getValue()); + try (OverrideScope s3 = OptionValue.override(Mutable, "override3", SecondMutable, "secondOverride3")) { + assertEquals("override3", Mutable.getValue()); + assertEquals("secondOverride3", SecondMutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + assertEquals("secondOverride1", SecondMutable.getValue()); + } + assertEquals("original", Mutable.getValue()); + assertEquals("second", SecondMutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "original", SecondMutable, "second")) { + assertEquals("original", Mutable.getValue()); + assertEquals("second", SecondMutable.getValue()); + } + } + + @Test + public void testStable() { + assertTrue(Stable.getValue()); + try (OverrideScope s = OptionValue.override(Stable, false)) { + fail("cannot override stable option"); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void toStringTest() { + assertEquals("jdk.vm.ci.options.test.TestOptionValue$Options.Mutable=original", Mutable.toString()); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals("jdk.vm.ci.options.test.TestOptionValue$Options.Mutable=override1", Mutable.toString()); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals("jdk.vm.ci.options.test.TestOptionValue$Options.Mutable=override2", Mutable.toString()); + } + } + } + + @Test + public void getValuesTest() { + assertEquals(Arrays.asList("original"), Mutable.getValues(null)); + assertEquals(Arrays.asList(true), Stable.getValues(null)); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals(Arrays.asList("override1", "original"), Mutable.getValues(null)); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals(Arrays.asList("override2", "override1", "original"), Mutable.getValues(null)); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java new file mode 100644 index 00000000000..3aebfec6189 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile ConstantTest.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ConstantTest + */ + +package jdk.vm.ci.runtime.test; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +public class ConstantTest extends FieldUniverse { + + @Test + public void testNegativeZero() { + Assert.assertTrue("Constant for 0.0f must be different from -0.0f", JavaConstant.FLOAT_0 != JavaConstant.forFloat(-0.0F)); + Assert.assertTrue("Constant for 0.0d must be different from -0.0d", JavaConstant.DOUBLE_0 != JavaConstant.forDouble(-0.0d)); + } + + @Test + public void testNullIsNull() { + Assert.assertTrue(JavaConstant.NULL_POINTER.isNull()); + } + + @Test + public void testOne() { + for (JavaKind kind : JavaKind.values()) { + if (kind.isNumericInteger() || kind.isNumericFloat()) { + Assert.assertTrue(JavaConstant.one(kind).getJavaKind() == kind); + } + } + Assert.assertEquals(1, JavaConstant.one(JavaKind.Int).asInt()); + Assert.assertEquals(1L, JavaConstant.one(JavaKind.Long).asLong()); + Assert.assertEquals(1, JavaConstant.one(JavaKind.Byte).asInt()); + Assert.assertEquals(1, JavaConstant.one(JavaKind.Short).asInt()); + Assert.assertEquals(1, JavaConstant.one(JavaKind.Char).asInt()); + Assert.assertTrue(1F == JavaConstant.one(JavaKind.Float).asFloat()); + Assert.assertTrue(1D == JavaConstant.one(JavaKind.Double).asDouble()); + } + + @Test(expected = IllegalArgumentException.class) + public void testIllegalOne() { + JavaConstant.one(JavaKind.Illegal); + } + + @Test(expected = IllegalArgumentException.class) + public void testVoidOne() { + JavaConstant.one(JavaKind.Void); + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java new file mode 100644 index 00000000000..72f64ade918 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.runtime.test; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Context for field related tests. + */ +public class FieldUniverse extends TypeUniverse { + + public static final Map fields = new HashMap<>(); + + { + for (Class c : classes) { + for (Field f : c.getDeclaredFields()) { + ResolvedJavaField field = metaAccess.lookupJavaField(f); + fields.put(f, field); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java new file mode 100644 index 00000000000..f7f59e82c54 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.runtime.test; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Context for method related tests. + */ +public class MethodUniverse extends TypeUniverse { + + public static final Map methods = new HashMap<>(); + public static final Map, ResolvedJavaMethod> constructors = new HashMap<>(); + + { + for (Class c : classes) { + for (Method m : c.getDeclaredMethods()) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + methods.put(m, method); + } + for (Constructor m : c.getDeclaredConstructors()) { + constructors.put(m, metaAccess.lookupJavaMethod(m)); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/NameAndSignature.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/NameAndSignature.java new file mode 100644 index 00000000000..95341f347f3 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/NameAndSignature.java @@ -0,0 +1,87 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.runtime.test; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; + +class NameAndSignature { + + public static final MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + + final String name; + final Class returnType; + final Class[] parameterTypes; + + public NameAndSignature(Method m) { + this.name = m.getName(); + this.returnType = m.getReturnType(); + this.parameterTypes = m.getParameterTypes(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NameAndSignature) { + NameAndSignature s = (NameAndSignature) obj; + return s.returnType == returnType && name.equals(s.name) && Arrays.equals(s.parameterTypes, parameterTypes); + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(name + "("); + String sep = ""; + for (Class p : parameterTypes) { + sb.append(sep); + sep = ", "; + sb.append(p.getName()); + } + return sb.append(')').append(returnType.getName()).toString(); + } + + public boolean signatureEquals(ResolvedJavaMethod m) { + Signature s = m.getSignature(); + ResolvedJavaType declaringClass = m.getDeclaringClass(); + if (!s.getReturnType(declaringClass).resolve(declaringClass).equals(metaAccess.lookupJavaType(returnType))) { + return false; + } + if (s.getParameterCount(false) != parameterTypes.length) { + return false; + } + for (int i = 0; i < parameterTypes.length; i++) { + if (!s.getParameterType(i, declaringClass).resolve(declaringClass).equals(metaAccess.lookupJavaType(parameterTypes[i]))) { + return false; + } + } + return true; + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java new file mode 100644 index 00000000000..84def0f2c77 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile RedefineClassTest.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.RedefineClassTest + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assume.*; + +import java.io.*; +import java.lang.instrument.*; +import java.lang.management.*; +import java.lang.reflect.*; +import java.nio.file.*; +import java.security.*; +import java.util.*; +import java.util.jar.*; + +import javax.tools.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests that {@link ResolvedJavaMethod}s are safe in the context of class redefinition being used + * to redefine the method to which they refer. + */ +public class RedefineClassTest extends TypeUniverse { + + static class Foo { + public static Object getName() { + return "foo"; + } + } + + @Test + public void test() throws Throwable { + + Method fooMethod = Foo.class.getDeclaredMethod("getName"); + + ResolvedJavaMethod foo1 = metaAccess.lookupJavaMethod(fooMethod); + ResolvedJavaMethod foo2 = metaAccess.lookupJavaMethod(fooMethod); + + String foo1Code = Arrays.toString(foo1.getCode()); + String foo2Code = Arrays.toString(foo2.getCode()); + + Assert.assertEquals("foo", Foo.getName()); + + redefineFoo(); + System.gc(); + + // Make sure the transformation happened + Assert.assertEquals("bar", Foo.getName()); + + Assert.assertEquals(foo1Code, Arrays.toString(foo1.getCode())); + Assert.assertEquals(foo2Code, Arrays.toString(foo1.getCode())); + } + + /** + * Adds the class file bytes for a given class to a JAR stream. + */ + static void add(JarOutputStream jar, Class c) throws IOException { + String name = c.getName(); + String classAsPath = name.replace('.', '/') + ".class"; + jar.putNextEntry(new JarEntry(classAsPath)); + + InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath); + + int nRead; + byte[] buf = new byte[1024]; + while ((nRead = stream.read(buf, 0, buf.length)) != -1) { + jar.write(buf, 0, nRead); + } + + jar.closeEntry(); + } + + protected void redefineFoo() throws Exception { + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + Attributes mainAttrs = manifest.getMainAttributes(); + mainAttrs.putValue("Agent-Class", FooAgent.class.getName()); + mainAttrs.putValue("Can-Redefine-Classes", "true"); + mainAttrs.putValue("Can-Retransform-Classes", "true"); + + Path jar = Files.createTempFile("myagent", ".jar"); + try { + JarOutputStream jarStream = new JarOutputStream(new FileOutputStream(jar.toFile()), manifest); + add(jarStream, FooAgent.class); + add(jarStream, FooTransformer.class); + jarStream.close(); + + loadAgent(jar); + } finally { + Files.deleteIfExists(jar); + } + } + + public static void loadAgent(Path agent) throws Exception { + String vmName = ManagementFactory.getRuntimeMXBean().getName(); + int p = vmName.indexOf('@'); + assumeTrue(p != -1); + String pid = vmName.substring(0, p); + ClassLoader cl = ToolProvider.getSystemToolClassLoader(); + Class c = Class.forName("com.sun.tools.attach.VirtualMachine", true, cl); + Method attach = c.getDeclaredMethod("attach", String.class); + Method loadAgent = c.getDeclaredMethod("loadAgent", String.class, String.class); + Method detach = c.getDeclaredMethod("detach"); + Object vm = attach.invoke(null, pid); + loadAgent.invoke(vm, agent.toString(), ""); + detach.invoke(vm); + } + + public static class FooAgent { + + public static void agentmain(@SuppressWarnings("unused") String args, Instrumentation inst) throws Exception { + if (inst.isRedefineClassesSupported() && inst.isRetransformClassesSupported()) { + inst.addTransformer(new FooTransformer(), true); + Class[] allClasses = inst.getAllLoadedClasses(); + for (int i = 0; i < allClasses.length; i++) { + Class c = allClasses[i]; + if (c == Foo.class) { + inst.retransformClasses(new Class[]{c}); + } + } + } + } + } + + /** + * This transformer replaces the first instance of the constant "foo" in the class file for + * {@link Foo} with "bar". + */ + static class FooTransformer implements ClassFileTransformer { + + @Override + public byte[] transform(ClassLoader cl, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + if (Foo.class.equals(classBeingRedefined)) { + String cf = new String(classfileBuffer); + int i = cf.indexOf("foo"); + Assert.assertTrue("cannot find \"foo\" constant in " + Foo.class.getSimpleName() + "'s class file", i > 0); + classfileBuffer[i] = 'b'; + classfileBuffer[i + 1] = 'a'; + classfileBuffer[i + 2] = 'r'; + } + return classfileBuffer; + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java new file mode 100644 index 00000000000..6e7db7c08cc --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ResolvedJavaTypeResolveConcreteMethodTest + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; + +import org.junit.*; + +public class ResolvedJavaTypeResolveConcreteMethodTest { + public final MetaAccessProvider metaAccess; + + public ResolvedJavaTypeResolveConcreteMethodTest() { + metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + } + + protected abstract static class A { + @SuppressWarnings("unused") + private void priv() { + } + + public void v1() { + } + + public void v2() { + } + + public abstract void abs(); + } + + protected static class B extends A implements I { + public void i() { + } + + @Override + public void v2() { + } + + @Override + public void abs() { + + } + } + + protected static class C extends B { + public void d() { + } + } + + protected abstract static class D extends A { + + } + + protected static class E extends D { + @Override + public void abs() { + } + } + + protected interface I { + void i(); + + default void d() { + } + } + + @Test + public void testDefaultMethod() { + ResolvedJavaType i = getType(I.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod di = getMethod(i, "d"); + ResolvedJavaMethod dc = getMethod(c, "d"); + + assertEquals(di, i.resolveConcreteMethod(di, c)); + assertEquals(di, b.resolveConcreteMethod(di, c)); + assertEquals(dc, c.resolveConcreteMethod(di, c)); + } + + @Test + public void testPrivateMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod priv = getMethod(a, "priv"); + + assertNull(a.resolveConcreteMethod(priv, c)); + assertNull(b.resolveConcreteMethod(priv, c)); + } + + @Test + public void testAbstractMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaType d = getType(D.class); + ResolvedJavaType e = getType(E.class); + ResolvedJavaMethod absa = getMethod(a, "abs"); + ResolvedJavaMethod absb = getMethod(b, "abs"); + ResolvedJavaMethod abse = getMethod(e, "abs"); + + assertNull(a.resolveConcreteMethod(absa, c)); + assertNull(d.resolveConcreteMethod(absa, c)); + + assertEquals(absb, b.resolveConcreteMethod(absa, c)); + assertEquals(absb, b.resolveConcreteMethod(absb, c)); + assertEquals(absb, c.resolveConcreteMethod(absa, c)); + assertEquals(absb, c.resolveConcreteMethod(absb, c)); + assertEquals(abse, e.resolveConcreteMethod(absa, c)); + assertNull(e.resolveConcreteMethod(absb, c)); + assertEquals(abse, e.resolveConcreteMethod(abse, c)); + } + + @Test + public void testVirtualMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod v1a = getMethod(a, "v1"); + ResolvedJavaMethod v2a = getMethod(a, "v2"); + ResolvedJavaMethod v2b = getMethod(b, "v2"); + + assertEquals(v1a, a.resolveConcreteMethod(v1a, c)); + assertEquals(v1a, b.resolveConcreteMethod(v1a, c)); + assertEquals(v1a, c.resolveConcreteMethod(v1a, c)); + assertEquals(v2a, a.resolveConcreteMethod(v2a, c)); + assertEquals(v2b, b.resolveConcreteMethod(v2a, c)); + assertEquals(v2b, b.resolveConcreteMethod(v2b, c)); + assertEquals(v2b, c.resolveConcreteMethod(v2a, c)); + assertEquals(v2b, c.resolveConcreteMethod(v2b, c)); + + } + + static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) { + for (ResolvedJavaMethod method : type.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + return method; + } + } + throw new IllegalArgumentException(); + } + + protected ResolvedJavaType getType(Class clazz) { + ResolvedJavaType type = metaAccess.lookupJavaType(clazz); + type.initialize(); + return type; + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java new file mode 100644 index 00000000000..580c353da90 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ResolvedJavaTypeResolveMethodTest + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; + +import org.junit.*; + +public class ResolvedJavaTypeResolveMethodTest { + public final MetaAccessProvider metaAccess; + + public ResolvedJavaTypeResolveMethodTest() { + metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + } + + protected abstract static class A { + @SuppressWarnings("unused") + private void priv() { + } + + public void v1() { + } + + public void v2() { + } + + public abstract void abs(); + } + + protected static class B extends A implements I { + public void i() { + } + + @Override + public void v2() { + } + + @Override + public void abs() { + + } + } + + protected static class C extends B { + public void d() { + } + } + + protected abstract static class D extends A { + + } + + protected static class E extends D { + @Override + public void abs() { + } + } + + protected interface I { + void i(); + + default void d() { + } + } + + @Test + public void testDefaultMethod() { + ResolvedJavaType i = getType(I.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod di = getMethod(i, "d"); + ResolvedJavaMethod dc = getMethod(c, "d"); + + assertEquals(di, i.resolveMethod(di, c)); + assertEquals(di, b.resolveMethod(di, c)); + assertEquals(dc, c.resolveMethod(di, c)); + } + + @Test + public void testPrivateMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod priv = getMethod(a, "priv"); + + assertNull(a.resolveMethod(priv, c)); + assertNull(b.resolveMethod(priv, c)); + } + + @Test + public void testAbstractMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaType d = getType(D.class); + ResolvedJavaType e = getType(E.class); + ResolvedJavaMethod absa = getMethod(a, "abs"); + ResolvedJavaMethod absb = getMethod(b, "abs"); + ResolvedJavaMethod abse = getMethod(e, "abs"); + + assertEquals(absa, a.resolveMethod(absa, c)); + assertEquals(absa, d.resolveMethod(absa, c)); + + assertEquals(absb, b.resolveMethod(absa, c)); + assertEquals(absb, b.resolveMethod(absb, c)); + assertEquals(absb, c.resolveMethod(absa, c)); + assertEquals(absb, c.resolveMethod(absb, c)); + assertEquals(abse, e.resolveMethod(absa, c)); + assertNull(e.resolveMethod(absb, c)); + assertEquals(abse, e.resolveMethod(abse, c)); + } + + @Test + public void testVirtualMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod v1a = getMethod(a, "v1"); + ResolvedJavaMethod v2a = getMethod(a, "v2"); + ResolvedJavaMethod v2b = getMethod(b, "v2"); + + assertEquals(v1a, a.resolveMethod(v1a, c)); + assertEquals(v1a, b.resolveMethod(v1a, c)); + assertEquals(v1a, c.resolveMethod(v1a, c)); + assertEquals(v2a, a.resolveMethod(v2a, c)); + assertEquals(v2b, b.resolveMethod(v2a, c)); + assertEquals(v2b, b.resolveMethod(v2b, c)); + assertEquals(v2b, c.resolveMethod(v2a, c)); + assertEquals(v2b, c.resolveMethod(v2b, c)); + + } + + static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) { + for (ResolvedJavaMethod method : type.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + return method; + } + } + throw new IllegalArgumentException(); + } + + protected ResolvedJavaType getType(Class clazz) { + ResolvedJavaType type = metaAccess.lookupJavaType(clazz); + type.initialize(); + return type; + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java new file mode 100644 index 00000000000..7d5c265ef5e --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestConstantReflectionProvider.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestConstantReflectionProvider + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link ConstantReflectionProvider}. It assumes an implementation of the interface that + * actually returns non-null results for access operations that are possible, i.e., the tests will + * fail for an implementation that spuriously returns null (which is allowed by the specification). + */ +public class TestConstantReflectionProvider extends TypeUniverse { + + @Test + public void constantEqualsTest() { + for (ConstantValue c1 : constants()) { + for (ConstantValue c2 : constants()) { + // test symmetry + assertEquals(constantReflection.constantEquals(c1.value, c2.value), constantReflection.constantEquals(c2.value, c1.value)); + if (c1.value.getJavaKind() != JavaKind.Object && c2.value.getJavaKind() != JavaKind.Object) { + assertEquals(c1.value.equals(c2.value), constantReflection.constantEquals(c2.value, c1.value)); + } + } + } + } + + @Test + public void readArrayLengthTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + Integer actual = constantReflection.readArrayLength(c); + if (c.getJavaKind() != JavaKind.Object || c.isNull() || !cv.boxed.getClass().isArray()) { + assertNull(actual); + } else { + assertNotNull(actual); + int actualInt = actual; + assertEquals(Array.getLength(cv.boxed), actualInt); + } + } + } + + static class PrimitiveConstants { + static final long LONG_CONST = 42; + static final int INT_CONST = 66; + static final byte BYTE_CONST = 123; + static final boolean BOOL_CONST = true; + } + + static class BoxedConstants { + static final Long LONG_CONST = 42L; + static final Integer INT_CONST = 66; + static final Byte BYTE_CONST = 123; + static final Boolean BOOL_CONST = true; + } + + @Test + public void boxTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + JavaConstant boxed = constantReflection.boxPrimitive(c); + if (boxed != null && c.getJavaKind().isPrimitive()) { + assertTrue(boxed.getJavaKind().isObject()); + assertFalse(boxed.isNull()); + } + } + + List primitiveConstants = readConstants(PrimitiveConstants.class); + List boxedConstants = readConstants(BoxedConstants.class); + for (int i = 0; i < primitiveConstants.size(); i++) { + ConstantValue prim = primitiveConstants.get(i); + ConstantValue box = boxedConstants.get(i); + assertEquals(box.value, constantReflection.boxPrimitive(prim.value)); + } + + assertNull(constantReflection.boxPrimitive(JavaConstant.NULL_POINTER)); + } + + @Test + public void unboxTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + JavaConstant unboxed = c.isNull() ? null : constantReflection.unboxPrimitive(c); + if (unboxed != null) { + assertFalse(unboxed.getJavaKind().isObject()); + } + } + List primitiveConstants = readConstants(PrimitiveConstants.class); + List boxedConstants = readConstants(BoxedConstants.class); + for (int i = 0; i < primitiveConstants.size(); i++) { + ConstantValue prim = primitiveConstants.get(i); + ConstantValue box = boxedConstants.get(i); + assert prim.getSimpleName().equals(box.getSimpleName()); + assertEquals(prim.value, constantReflection.unboxPrimitive(box.value)); + } + + assertNull(constantReflection.unboxPrimitive(JavaConstant.NULL_POINTER)); + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java new file mode 100644 index 00000000000..f0a6c7d3657 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestJavaField.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaField + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link JavaField}. + */ +public class TestJavaField extends FieldUniverse { + + @Test + public void getNameTest() { + for (Map.Entry e : fields.entrySet()) { + String expected = e.getKey().getName(); + String actual = e.getValue().getName(); + assertEquals(expected, actual); + } + } + + @Test + public void getTypeTest() { + for (Map.Entry e : fields.entrySet()) { + // Must resolve types first as a resolved types != unresolved types + ResolvedJavaField rf = e.getValue(); + JavaType expected = metaAccess.lookupJavaType(e.getKey().getType()).resolve(rf.getDeclaringClass()); + JavaType actual = rf.getType().resolve(rf.getDeclaringClass()); + assertEquals(expected, actual); + } + } + + @Test + public void getJavaKindTest() { + for (Map.Entry e : fields.entrySet()) { + JavaKind expected = metaAccess.lookupJavaType(e.getKey().getType()).getJavaKind(); + JavaKind actual = e.getValue().getJavaKind(); + assertEquals(expected, actual); + } + } + + @Test + public void getDeclaringClassTest() { + for (Map.Entry e : fields.entrySet()) { + Class expected = e.getKey().getDeclaringClass(); + ResolvedJavaType actual = e.getValue().getDeclaringClass(); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java new file mode 100644 index 00000000000..185bc29fcd1 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java NameAndSignature.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaMethod + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link JavaMethod}. + */ +public class TestJavaMethod extends MethodUniverse { + + @Test + public void getNameTest() { + for (Map.Entry e : methods.entrySet()) { + String expected = e.getKey().getName(); + String actual = e.getValue().getName(); + assertEquals(expected, actual); + } + } + + @Test + public void getDeclaringClassTest() { + for (Map.Entry e : methods.entrySet()) { + Class expected = e.getKey().getDeclaringClass(); + ResolvedJavaType actual = e.getValue().getDeclaringClass(); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + + @Test + public void getSignatureTest() { + for (Map.Entry e : methods.entrySet()) { + assertTrue(new NameAndSignature(e.getKey()).signatureEquals(e.getValue())); + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java new file mode 100644 index 00000000000..62a13a24292 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestJavaType.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaType + */ + +package jdk.vm.ci.runtime.test; + +import jdk.vm.ci.meta.*; +import static org.junit.Assert.*; + +import org.junit.*; + +/** + * Tests for {@link JavaType}. + */ +public class TestJavaType extends TypeUniverse { + + public TestJavaType() { + } + + @Test + public void getJavaKindTest() { + for (Class c : classes) { + JavaType type = metaAccess.lookupJavaType(c); + JavaKind expected = JavaKind.fromJavaClass(c); + JavaKind actual = type.getJavaKind(); + assertEquals(expected, actual); + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java new file mode 100644 index 00000000000..968066d59db --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestMetaAccessProvider.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestMetaAccessProvider + */ + +package jdk.vm.ci.runtime.test; + +import static jdk.vm.ci.meta.MetaUtil.*; +import static org.junit.Assert.*; + +import java.lang.reflect.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link MetaAccessProvider}. + */ +public class TestMetaAccessProvider extends TypeUniverse { + + @Test + public void lookupJavaTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertNotNull(c.toString(), type); + assertEquals(c.toString(), type.getName(), toInternalName(c.getName())); + assertEquals(c.toString(), type.getName(), toInternalName(type.toJavaName())); + assertEquals(c.toString(), c.getName(), type.toClassName()); + if (!type.isArray()) { + assertEquals(c.toString(), c.getName(), type.toJavaName()); + } + } + } + + @Test + public void lookupJavaMethodTest() { + for (Class c : classes) { + for (Method reflect : c.getDeclaredMethods()) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(reflect); + assertNotNull(method); + assertTrue(method.getDeclaringClass().equals(metaAccess.lookupJavaType(reflect.getDeclaringClass()))); + } + } + } + + @Test + public void lookupJavaFieldTest() { + for (Class c : classes) { + for (Field reflect : c.getDeclaredFields()) { + ResolvedJavaField field = metaAccess.lookupJavaField(reflect); + assertNotNull(field); + assertTrue(field.getDeclaringClass().equals(metaAccess.lookupJavaType(reflect.getDeclaringClass()))); + } + } + } + + @Test + public void lookupJavaTypeConstantTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + if (c.getJavaKind() == JavaKind.Object && !c.isNull()) { + Object o = cv.boxed; + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertNotNull(type); + assertTrue(type.equals(metaAccess.lookupJavaType(o.getClass()))); + } else { + assertEquals(metaAccess.lookupJavaType(c), null); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java new file mode 100644 index 00000000000..88b3b5f9751 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestResolvedJavaField.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaField + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link ResolvedJavaField}. + */ +public class TestResolvedJavaField extends FieldUniverse { + + public TestResolvedJavaField() { + } + + @Test + public void getModifiersTest() { + for (Map.Entry e : fields.entrySet()) { + int expected = e.getKey().getModifiers(); + int actual = e.getValue().getModifiers(); + assertEquals(expected, actual); + } + } + + @Test + public void isSyntheticTest() { + for (Map.Entry e : fields.entrySet()) { + boolean expected = e.getKey().isSynthetic(); + boolean actual = e.getValue().isSynthetic(); + assertEquals(expected, actual); + } + } + + @Test + public void getAnnotationsTest() { + for (Map.Entry e : fields.entrySet()) { + Annotation[] expected = e.getKey().getAnnotations(); + Annotation[] actual = e.getValue().getAnnotations(); + assertArrayEquals(expected, actual); + } + } + + @Test + public void getAnnotationTest() { + for (Map.Entry e : fields.entrySet()) { + for (Annotation expected : e.getKey().getAnnotations()) { + if (expected != null) { + Annotation actual = e.getValue().getAnnotation(expected.annotationType()); + assertEquals(expected, actual); + } + } + } + } + + @Test + public void getLocationIdentityTest() { + for (Map.Entry e : fields.entrySet()) { + LocationIdentity identity = e.getValue().getLocationIdentity(); + assertTrue(identity != null); + } + } + + static class ReadConstantValueTestConstants { + String stringField = "field"; + final String constantStringField = "constantField"; + + static final Object CONST1 = new ReadConstantValueTestConstants(); + static final Object CONST2 = null; + static final Object CONST3 = new String(); + } + + @Test + public void readConstantValueTest() throws NoSuchFieldException { + ResolvedJavaField field = metaAccess.lookupJavaField(ReadConstantValueTestConstants.class.getDeclaredField("stringField")); + List receiverConstants = readConstants(ReadConstantValueTestConstants.class); + for (ConstantValue receiver : receiverConstants) { + JavaConstant value = constantReflection.readConstantFieldValue(field, receiver.value); + assertNull(value); + } + + ResolvedJavaField constField = metaAccess.lookupJavaField(ReadConstantValueTestConstants.class.getDeclaredField("constantStringField")); + for (ConstantValue receiver : receiverConstants) { + JavaConstant value = constantReflection.readConstantFieldValue(constField, receiver.value); + if (value != null) { + Object expected = "constantField"; + String actual = ((ReadConstantValueTestConstants) receiver.boxed).constantStringField; + assertTrue(actual + " != " + expected, actual == expected); + } + } + } + + private Method findTestMethod(Method apiMethod) { + String testName = apiMethod.getName() + "Test"; + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { + return m; + } + } + return null; + } + + // @formatter:off + private static final String[] untestedApiMethods = { + "getDeclaringClass", + "isInternal", + "isFinal" + }; + // @formatter:on + + /** + * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written + * for them or are added to {@link #untestedApiMethods}. + */ + @Test + public void testCoverage() { + Set known = new HashSet<>(Arrays.asList(untestedApiMethods)); + for (Method m : ResolvedJavaField.class.getDeclaredMethods()) { + if (m.isSynthetic()) { + continue; + } + if (findTestMethod(m) == null) { + assertTrue("test missing for " + m, known.contains(m.getName())); + } else { + assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java new file mode 100644 index 00000000000..2b0f7b4aab4 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestResolvedJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaMethod + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.annotation.*; +import java.lang.invoke.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link ResolvedJavaMethod}. + */ +public class TestResolvedJavaMethod extends MethodUniverse { + + public TestResolvedJavaMethod() { + } + + /** + * @see ResolvedJavaMethod#getCode() + */ + @Test + public void getCodeTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + byte[] code = m.getCode(); + if (code == null) { + assertTrue(m.getCodeSize() == 0); + } else { + if (m.isAbstract()) { + assertTrue(code.length == 0); + } else if (!m.isNative()) { + assertTrue(code.length > 0); + } + } + } + } + + /** + * @see ResolvedJavaMethod#getCodeSize() + */ + @Test + public void getCodeSizeTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + int codeSize = m.getCodeSize(); + if (m.isAbstract()) { + assertTrue(codeSize == 0); + } else if (!m.isNative()) { + assertTrue(codeSize > 0); + } + } + } + + @Test + public void getModifiersTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + int expected = e.getKey().getModifiers(); + int actual = m.getModifiers(); + assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + int expected = e.getKey().getModifiers(); + int actual = m.getModifiers(); + assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual); + } + } + + /** + * @see ResolvedJavaMethod#isClassInitializer() + */ + @Test + public void isClassInitializerTest() { + for (Map.Entry e : methods.entrySet()) { + // Class initializers are hidden from reflection + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isClassInitializer()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isClassInitializer()); + } + } + + @Test + public void isConstructorTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isConstructor()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.isConstructor()); + } + } + + @Test + public void isSyntheticTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isSynthetic(), m.isSynthetic()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isSynthetic(), m.isSynthetic()); + } + } + + @Test + public void isBridgeTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isBridge(), m.isBridge()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(false, m.isBridge()); + } + } + + @Test + public void isVarArgsTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isVarArgs(), m.isVarArgs()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isVarArgs(), m.isVarArgs()); + } + } + + @Test + public void isSynchronizedTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized()); + } + } + + @Test + public void canBeStaticallyBoundTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey())); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey())); + } + } + + private static boolean canBeStaticallyBound(Member method) { + int modifiers = method.getModifiers(); + return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(method.getDeclaringClass().getModifiers())) && + !Modifier.isAbstract(modifiers); + } + + private static String methodWithExceptionHandlers(String p1, Object o2) { + try { + return p1.substring(100) + o2.toString(); + } catch (IndexOutOfBoundsException e) { + e.printStackTrace(); + } catch (NullPointerException e) { + e.printStackTrace(); + } catch (RuntimeException e) { + e.printStackTrace(); + } + return null; + } + + @Test + public void getExceptionHandlersTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithExceptionHandlers", String.class, Object.class)); + ExceptionHandler[] handlers = method.getExceptionHandlers(); + assertNotNull(handlers); + assertEquals(handlers.length, 3); + handlers[0].getCatchType().equals(metaAccess.lookupJavaType(IndexOutOfBoundsException.class)); + handlers[1].getCatchType().equals(metaAccess.lookupJavaType(NullPointerException.class)); + handlers[2].getCatchType().equals(metaAccess.lookupJavaType(RuntimeException.class)); + } + + private static String nullPointerExceptionOnFirstLine(Object o, String ignored) { + return o.toString() + ignored; + } + + @Test + public void asStackTraceElementTest() throws NoSuchMethodException { + try { + nullPointerExceptionOnFirstLine(null, "ignored"); + Assert.fail("should not reach here"); + } catch (NullPointerException e) { + StackTraceElement expected = e.getStackTrace()[0]; + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); + StackTraceElement actual = method.asStackTraceElement(0); + assertEquals(expected, actual); + } + } + + @Test + public void getConstantPoolTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + ConstantPool cp = m.getConstantPool(); + assertTrue(cp.length() > 0); + } + } + + @Test(timeout = 1000L) + public void getAnnotationTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationTest")); + Test annotation = method.getAnnotation(Test.class); + assertNotNull(annotation); + assertEquals(1000L, annotation.timeout()); + } + + @Test(timeout = 1000L) + public void getAnnotationsTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationsTest")); + Annotation[] annotations = method.getAnnotations(); + assertNotNull(annotations); + assertEquals(1, annotations.length); + assertEquals(1000L, ((Test) annotations[0]).timeout()); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + @interface NonNull { + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + @interface Special { + } + + private static native void methodWithAnnotatedParameters(@NonNull HashMap p1, @Special @NonNull Class p2); + + @Test + public void getParameterAnnotationsTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + Annotation[][] annotations = method.getParameterAnnotations(); + assertEquals(2, annotations.length); + assertEquals(1, annotations[0].length); + assertEquals(NonNull.class, annotations[0][0].annotationType()); + assertEquals(2, annotations[1].length); + assertEquals(Special.class, annotations[1][0].annotationType()); + assertEquals(NonNull.class, annotations[1][1].annotationType()); + } + + @Test + public void getGenericParameterTypesTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + Type[] genericParameterTypes = method.getGenericParameterTypes(); + assertEquals(2, genericParameterTypes.length); + assertEquals("java.util.HashMap", genericParameterTypes[0].toString()); + assertEquals("java.lang.Class", genericParameterTypes[1].toString()); + } + + @Test + public void getMaxLocalsTest() throws NoSuchMethodException { + ResolvedJavaMethod method1 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + ResolvedJavaMethod method2 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); + assertEquals(0, method1.getMaxLocals()); + assertEquals(2, method2.getMaxLocals()); + + } + + @Test + public void getMaxStackSizeTest() throws NoSuchMethodException { + ResolvedJavaMethod method1 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + ResolvedJavaMethod method2 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); + assertEquals(0, method1.getMaxStackSize()); + // some versions of javac produce bytecode with a stacksize of 2 for this method + // JSR 292 also sometimes need one more stack slot + int method2StackSize = method2.getMaxStackSize(); + assertTrue(2 <= method2StackSize && method2StackSize <= 4); + } + + @Test + public void isDefaultTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isDefault(), m.isDefault()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isDefault()); + } + } + + @Test + public void hasReceiverTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasReceiver() != Modifier.isStatic(e.getKey().getModifiers())); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasReceiver()); + } + } + + @Test + public void hasBytecodesTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasBytecodes() == (m.isConcrete() && !m.isNative())); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasBytecodes()); + } + } + + @Test + public void isJavaLangObjectInitTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(Object.class.getConstructor()); + assertTrue(method.isJavaLangObjectInit()); + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isJavaLangObjectInit()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + Constructor key = e.getKey(); + if (key.getDeclaringClass() == Object.class && key.getParameters().length == 0) { + assertTrue(m.isJavaLangObjectInit()); + } else { + assertFalse(m.isJavaLangObjectInit()); + } + } + } + + @Test + public void isSignaturePolymorphicTest() { + ResolvedJavaType methodHandleType = metaAccess.lookupJavaType(MethodHandle.class); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeExact", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invoke", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeBasic", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToVirtual", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToStatic", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToSpecial", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToInterface", metaAccess)); + assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "type", metaAccess)); + assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(metaAccess.lookupJavaType(Object.class), "toString", metaAccess)); + } + + private Method findTestMethod(Method apiMethod) { + String testName = apiMethod.getName() + "Test"; + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { + return m; + } + } + return null; + } + + // @formatter:off + private static final String[] untestedApiMethods = { + "invoke", + "newInstance", + "getDeclaringClass", + "getEncoding", + "getProfilingInfo", + "reprofile", + "getCompilerStorage", + "canBeInlined", + "shouldBeInlined", + "getLineNumberTable", + "getLocalVariableTable", + "isInVirtualMethodTable", + "toParameterTypes", + "getParameterAnnotation", + "getSpeculationLog", + "isFinal", + "$jacocoInit" + }; + // @formatter:on + + /** + * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written + * for them or are added to {@link #untestedApiMethods}. + */ + @Test + public void testCoverage() { + Set known = new HashSet<>(Arrays.asList(untestedApiMethods)); + for (Method m : ResolvedJavaMethod.class.getDeclaredMethods()) { + if (Modifier.isStatic(m.getModifiers())) { + continue; + } + if (findTestMethod(m) == null) { + assertTrue("test missing for " + m, known.contains(m.getName())); + } else { + assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java new file mode 100644 index 00000000000..42520f7d8ea --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -0,0 +1,947 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestResolvedJavaType.java TypeUniverse.java TestMetaAccessProvider.java NameAndSignature.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaType + */ + +package jdk.vm.ci.runtime.test; + +import static java.lang.reflect.Modifier.*; +import static org.junit.Assert.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.*; +import java.util.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.*; + +import org.junit.*; + +import sun.reflect.ConstantPool; + +/** + * Tests for {@link ResolvedJavaType}. + */ +public class TestResolvedJavaType extends TypeUniverse { + + public TestResolvedJavaType() { + } + + @Test + public void findInstanceFieldWithOffsetTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Set reflectionFields = getInstanceFields(c, true); + for (Field f : reflectionFields) { + ResolvedJavaField rf = lookupField(type.getInstanceFields(true), f); + assertNotNull(rf); + long offset = isStatic(f.getModifiers()) ? unsafe.staticFieldOffset(f) : unsafe.objectFieldOffset(f); + ResolvedJavaField result = type.findInstanceFieldWithOffset(offset, rf.getJavaKind()); + assertNotNull(result); + assertTrue(fieldsEqual(f, result)); + } + } + } + + @Test + public void isInterfaceTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = c.isInterface(); + boolean actual = type.isInterface(); + assertEquals(expected, actual); + } + } + + @Test + public void isInstanceClassTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = !c.isArray() && !c.isPrimitive() && !c.isInterface(); + boolean actual = type.isInstanceClass(); + assertEquals(expected, actual); + } + } + + @Test + public void isArrayTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = c.isArray(); + boolean actual = type.isArray(); + assertEquals(expected, actual); + } + } + + @Test + public void getModifiersTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + int expected = c.getModifiers() & ModifiersProvider.jvmClassModifiers(); + int actual = type.getModifiers() & ModifiersProvider.jvmClassModifiers(); + Class elementalType = c; + while (elementalType.isArray()) { + elementalType = elementalType.getComponentType(); + } + if (elementalType.isMemberClass()) { + // member class get their modifiers from the inner-class attribute in the JVM and + // from the classfile header in jvmci + expected &= ~(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED); + actual &= ~(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED); + } + assertEquals(String.format("%s: 0x%x != 0x%x", type, expected, actual), expected, actual); + } + } + + @Test + public void isAssignableFromTest() { + Class[] all = classes.toArray(new Class[classes.size()]); + for (int i = 0; i < all.length; i++) { + Class c1 = all[i]; + for (int j = i; j < all.length; j++) { + Class c2 = all[j]; + ResolvedJavaType t1 = metaAccess.lookupJavaType(c1); + ResolvedJavaType t2 = metaAccess.lookupJavaType(c2); + boolean expected = c1.isAssignableFrom(c2); + boolean actual = t1.isAssignableFrom(t2); + assertEquals(expected, actual); + if (expected && t1 != t2) { + assertFalse(t2.isAssignableFrom(t1)); + } + } + } + } + + @Test + public void isInstanceTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + if (c.getJavaKind() == JavaKind.Object && !c.isNull()) { + ResolvedJavaType cType = metaAccess.lookupJavaType(c); + for (ResolvedJavaType t : javaTypes) { + if (t.isAssignableFrom(cType)) { + assertTrue(t.isInstance(c)); + } else { + assertFalse(t.isInstance(c)); + } + } + } + } + } + + private static Class asExactClass(Class c) { + if (c.isArray()) { + if (asExactClass(c.getComponentType()) != null) { + return c; + } + } else { + if (c.isPrimitive() || Modifier.isFinal(c.getModifiers())) { + return c; + } + } + return null; + } + + @Test + public void asExactTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + ResolvedJavaType exactType = type.asExactType(); + Class expected = asExactClass(c); + if (expected == null) { + assertTrue("exact(" + c.getName() + ") != null", exactType == null); + } else { + assertNotNull(exactType); + assertTrue(exactType.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + @Test + public void getSuperclassTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class expected = c.getSuperclass(); + ResolvedJavaType actual = type.getSuperclass(); + if (expected == null) { + assertTrue(actual == null); + } else { + assertNotNull(actual); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + @Test + public void getInterfacesTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class[] expected = c.getInterfaces(); + ResolvedJavaType[] actual = type.getInterfaces(); + assertEquals(expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + assertTrue(actual[i].equals(metaAccess.lookupJavaType(expected[i]))); + } + } + } + + public Class getSupertype(Class c) { + assert !c.isPrimitive(); + if (c.isArray()) { + Class componentType = c.getComponentType(); + if (componentType.isPrimitive() || componentType == Object.class) { + return Object.class; + } + return getArrayClass(getSupertype(componentType)); + } + if (c.isInterface()) { + return Object.class; + } + return c.getSuperclass(); + } + + public Class findLeastCommonAncestor(Class c1Initial, Class c2Initial) { + if (c1Initial.isPrimitive() || c2Initial.isPrimitive()) { + return null; + } else { + Class c1 = c1Initial; + Class c2 = c2Initial; + while (true) { + if (c1.isAssignableFrom(c2)) { + return c1; + } + if (c2.isAssignableFrom(c1)) { + return c2; + } + c1 = getSupertype(c1); + c2 = getSupertype(c2); + } + } + } + + @Test + public void findLeastCommonAncestorTest() { + Class[] all = classes.toArray(new Class[classes.size()]); + for (int i = 0; i < all.length; i++) { + Class c1 = all[i]; + for (int j = i; j < all.length; j++) { + Class c2 = all[j]; + ResolvedJavaType t1 = metaAccess.lookupJavaType(c1); + ResolvedJavaType t2 = metaAccess.lookupJavaType(c2); + Class expected = findLeastCommonAncestor(c1, c2); + ResolvedJavaType actual = t1.findLeastCommonAncestor(t2); + if (expected == null) { + assertTrue(actual == null); + } else { + assertNotNull(actual); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + } + + private static class Base { + } + + abstract static class Abstract1 extends Base { + } + + interface Interface1 { + } + + static class Concrete1 extends Abstract1 { + } + + static class Concrete2 extends Abstract1 implements Interface1 { + } + + static class Concrete3 extends Concrete2 { + } + + static final class Final1 extends Abstract1 { + } + + abstract static class Abstract4 extends Concrete3 { + } + + void checkConcreteSubtype(ResolvedJavaType type, ResolvedJavaType expected) { + AssumptionResult leafConcreteSubtype = type.findLeafConcreteSubtype(); + if (leafConcreteSubtype == null) { + // findLeafConcreteSubtype() is conservative + } else { + if (expected == null) { + assertNull(leafConcreteSubtype); + } else { + assertTrue(leafConcreteSubtype.getResult().equals(expected)); + } + } + + if (!type.isArray()) { + ResolvedJavaType arrayType = type.getArrayClass(); + AssumptionResult arraySubtype = arrayType.findLeafConcreteSubtype(); + if (arraySubtype != null) { + assertEquals(arraySubtype.getResult(), arrayType); + } else { + // findLeafConcreteSubtype() method is conservative + } + } + } + + @Test + public void findLeafConcreteSubtypeTest() { + ResolvedJavaType base = metaAccess.lookupJavaType(Base.class); + checkConcreteSubtype(base, base); + + ResolvedJavaType a1 = metaAccess.lookupJavaType(Abstract1.class); + ResolvedJavaType c1 = metaAccess.lookupJavaType(Concrete1.class); + + checkConcreteSubtype(base, null); + checkConcreteSubtype(a1, c1); + checkConcreteSubtype(c1, c1); + + ResolvedJavaType i1 = metaAccess.lookupJavaType(Interface1.class); + ResolvedJavaType c2 = metaAccess.lookupJavaType(Concrete2.class); + + checkConcreteSubtype(base, null); + checkConcreteSubtype(a1, null); + checkConcreteSubtype(c1, c1); + checkConcreteSubtype(i1, c2); + checkConcreteSubtype(c2, c2); + + ResolvedJavaType c3 = metaAccess.lookupJavaType(Concrete3.class); + checkConcreteSubtype(c2, null); + checkConcreteSubtype(c3, c3); + + ResolvedJavaType a4 = metaAccess.lookupJavaType(Abstract4.class); + checkConcreteSubtype(c3, null); + checkConcreteSubtype(a4, null); + + ResolvedJavaType a1a = metaAccess.lookupJavaType(Abstract1[].class); + checkConcreteSubtype(a1a, null); + ResolvedJavaType c1a = metaAccess.lookupJavaType(Concrete1[].class); + checkConcreteSubtype(c1a, null); + ResolvedJavaType f1a = metaAccess.lookupJavaType(Final1[].class); + checkConcreteSubtype(f1a, f1a); + + ResolvedJavaType obja = metaAccess.lookupJavaType(Object[].class); + checkConcreteSubtype(obja, null); + + ResolvedJavaType inta = metaAccess.lookupJavaType(int[].class); + checkConcreteSubtype(inta, inta); + } + + interface NoImplementor { + } + + interface SingleImplementorInterface { + } + + static class SingleConcreteImplementor implements SingleImplementorInterface { + } + + interface SingleAbstractImplementorInterface { + } + + abstract static class SingleAbstractImplementor implements SingleAbstractImplementorInterface { + } + + interface MultiImplementorInterface { + } + + static class ConcreteImplementor1 implements MultiImplementorInterface { + } + + static class ConcreteImplementor2 implements MultiImplementorInterface { + } + + interface MultipleAbstractImplementorInterface { + } + + abstract static class MultiAbstractImplementor1 implements MultipleAbstractImplementorInterface { + } + + abstract static class MultiAbstractImplementor2 implements MultipleAbstractImplementorInterface { + } + + interface SingleAbstractImplementorInterface2 { + } + + interface ExtendedSingleImplementorInterface { + } + + abstract static class SingleAbstractImplementor2 implements SingleAbstractImplementorInterface2 { + } + + static class ConcreteTransitiveImplementor1 extends SingleAbstractImplementor2 implements ExtendedSingleImplementorInterface { + } + + static class ConcreteTransitiveImplementor2 extends SingleAbstractImplementor2 implements ExtendedSingleImplementorInterface { + } + + @Test + public void getSingleImplementorTest() { + ResolvedJavaType iNi = metaAccess.lookupJavaType(NoImplementor.class); + assertNull(iNi.getSingleImplementor()); + + ResolvedJavaType iSi = metaAccess.lookupJavaType(SingleImplementorInterface.class); + ResolvedJavaType cSi = metaAccess.lookupJavaType(SingleConcreteImplementor.class); + assertEquals(cSi, iSi.getSingleImplementor()); + + ResolvedJavaType iSai = metaAccess.lookupJavaType(SingleAbstractImplementorInterface.class); + ResolvedJavaType aSai = metaAccess.lookupJavaType(SingleAbstractImplementor.class); + assertEquals(aSai, iSai.getSingleImplementor()); + + ResolvedJavaType iMi = metaAccess.lookupJavaType(MultiImplementorInterface.class); + metaAccess.lookupJavaType(ConcreteImplementor1.class); + metaAccess.lookupJavaType(ConcreteImplementor2.class); + assertEquals(iMi, iMi.getSingleImplementor()); + + ResolvedJavaType iMai = metaAccess.lookupJavaType(MultipleAbstractImplementorInterface.class); + metaAccess.lookupJavaType(MultiAbstractImplementor1.class); + metaAccess.lookupJavaType(MultiAbstractImplementor2.class); + assertEquals(iMai, iMai.getSingleImplementor()); + + ResolvedJavaType iSai2 = metaAccess.lookupJavaType(SingleAbstractImplementorInterface2.class); + ResolvedJavaType aSai2 = metaAccess.lookupJavaType(SingleAbstractImplementor2.class); + metaAccess.lookupJavaType(ConcreteTransitiveImplementor1.class); + metaAccess.lookupJavaType(ConcreteTransitiveImplementor2.class); + assertEquals(aSai2, iSai2.getSingleImplementor()); + } + + @Test(expected = JVMCIError.class) + public void getSingleImplementorTestClassReceiver() { + ResolvedJavaType base = metaAccess.lookupJavaType(Base.class); + base.getSingleImplementor(); + } + + @Test(expected = JVMCIError.class) + public void getSingleImplementorTestPrimitiveReceiver() { + ResolvedJavaType primitive = metaAccess.lookupJavaType(int.class); + primitive.getSingleImplementor(); + } + + @Test + public void getComponentTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class expected = c.getComponentType(); + ResolvedJavaType actual = type.getComponentType(); + if (expected == null) { + assertNull(actual); + } else { + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + @Test + public void getArrayClassTest() { + for (Class c : classes) { + if (c != void.class) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class expected = getArrayClass(c); + ResolvedJavaType actual = type.getArrayClass(); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + static class Declarations { + + final Method implementation; + final Set declarations; + + public Declarations(Method impl) { + this.implementation = impl; + declarations = new HashSet<>(); + } + } + + /** + * See Method + * overriding. + */ + static boolean isOverriderOf(Method impl, Method m) { + if (!isPrivate(m.getModifiers()) && !isFinal(m.getModifiers())) { + if (m.getName().equals(impl.getName())) { + if (m.getReturnType() == impl.getReturnType()) { + if (Arrays.equals(m.getParameterTypes(), impl.getParameterTypes())) { + if (isPublic(m.getModifiers()) || isProtected(m.getModifiers())) { + // m is public or protected + return isPublic(impl.getModifiers()) || isProtected(impl.getModifiers()); + } else { + // m is package-private + return impl.getDeclaringClass().getPackage() == m.getDeclaringClass().getPackage(); + } + } + } + } + } + return false; + } + + static final Map, VTable> vtables = new HashMap<>(); + + static class VTable { + + final Map methods = new HashMap<>(); + } + + static synchronized VTable getVTable(Class c) { + VTable vtable = vtables.get(c); + if (vtable == null) { + vtable = new VTable(); + if (c != Object.class) { + VTable superVtable = getVTable(c.getSuperclass()); + vtable.methods.putAll(superVtable.methods); + } + for (Method m : c.getDeclaredMethods()) { + if (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers())) { + if (isAbstract(m.getModifiers())) { + // A subclass makes a concrete method in a superclass abstract + vtable.methods.remove(new NameAndSignature(m)); + } else { + vtable.methods.put(new NameAndSignature(m), m); + } + } + } + vtables.put(c, vtable); + } + return vtable; + } + + static Set findDeclarations(Method impl, Class c) { + Set declarations = new HashSet<>(); + NameAndSignature implSig = new NameAndSignature(impl); + if (c != null) { + for (Method m : c.getDeclaredMethods()) { + if (new NameAndSignature(m).equals(implSig)) { + declarations.add(m); + break; + } + } + if (!c.isInterface()) { + declarations.addAll(findDeclarations(impl, c.getSuperclass())); + } + for (Class i : c.getInterfaces()) { + declarations.addAll(findDeclarations(impl, i)); + } + } + return declarations; + } + + private static void checkResolveMethod(ResolvedJavaType type, ResolvedJavaType context, ResolvedJavaMethod decl, ResolvedJavaMethod expected) { + ResolvedJavaMethod impl = type.resolveConcreteMethod(decl, context); + assertEquals(expected, impl); + } + + @Test + public void resolveMethodTest() { + ResolvedJavaType context = metaAccess.lookupJavaType(TestResolvedJavaType.class); + for (Class c : classes) { + if (c.isInterface() || c.isPrimitive()) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (Method m : c.getDeclaredMethods()) { + if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) { + ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m); + ResolvedJavaMethod impl = type.resolveMethod(resolved, context); + ResolvedJavaMethod expected = resolved.isDefault() || resolved.isAbstract() ? resolved : null; + assertEquals(m.toString(), expected, impl); + } else { + // As of JDK 8, interfaces can have static and private methods + } + } + } else { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + VTable vtable = getVTable(c); + for (Method impl : vtable.methods.values()) { + Set decls = findDeclarations(impl, c); + for (Method decl : decls) { + ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl); + if (m.isPublic()) { + ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl); + checkResolveMethod(type, context, m, i); + } + } + } + } + } + } + + @Test + public void resolveConcreteMethodTest() { + ResolvedJavaType context = metaAccess.lookupJavaType(TestResolvedJavaType.class); + for (Class c : classes) { + if (c.isInterface() || c.isPrimitive()) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (Method m : c.getDeclaredMethods()) { + if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) { + ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m); + ResolvedJavaMethod impl = type.resolveConcreteMethod(resolved, context); + ResolvedJavaMethod expected = resolved.isDefault() ? resolved : null; + assertEquals(m.toString(), expected, impl); + } else { + // As of JDK 8, interfaces can have static and private methods + } + } + } else { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + VTable vtable = getVTable(c); + for (Method impl : vtable.methods.values()) { + Set decls = findDeclarations(impl, c); + for (Method decl : decls) { + ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl); + if (m.isPublic()) { + ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl); + checkResolveMethod(type, context, m, i); + } + } + } + for (Method m : c.getDeclaredMethods()) { + ResolvedJavaMethod impl = type.resolveConcreteMethod(metaAccess.lookupJavaMethod(m), context); + ResolvedJavaMethod expected = isAbstract(m.getModifiers()) ? null : impl; + assertEquals(type + " " + m.toString(), expected, impl); + } + } + } + } + + @Test + public void findUniqueConcreteMethodTest() throws NoSuchMethodException { + ResolvedJavaMethod thisMethod = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("findUniqueConcreteMethodTest")); + ResolvedJavaMethod ucm = metaAccess.lookupJavaType(getClass()).findUniqueConcreteMethod(thisMethod).getResult(); + assertEquals(thisMethod, ucm); + } + + public static Set getInstanceFields(Class c, boolean includeSuperclasses) { + if (c.isArray() || c.isPrimitive() || c.isInterface()) { + return Collections.emptySet(); + } + Set result = new HashSet<>(); + for (Field f : c.getDeclaredFields()) { + if (!Modifier.isStatic(f.getModifiers())) { + result.add(f); + } + } + if (includeSuperclasses && c != Object.class) { + result.addAll(getInstanceFields(c.getSuperclass(), true)); + } + return result; + } + + public static Set getStaticFields(Class c) { + Set result = new HashSet<>(); + for (Field f : c.getDeclaredFields()) { + if (Modifier.isStatic(f.getModifiers())) { + result.add(f); + } + } + return result; + } + + public boolean fieldsEqual(Field f, ResolvedJavaField rjf) { + return rjf.getDeclaringClass().equals(metaAccess.lookupJavaType(f.getDeclaringClass())) && rjf.getName().equals(f.getName()) && + rjf.getType().resolve(rjf.getDeclaringClass()).equals(metaAccess.lookupJavaType(f.getType())); + } + + public ResolvedJavaField lookupField(ResolvedJavaField[] fields, Field key) { + for (ResolvedJavaField rf : fields) { + if (fieldsEqual(key, rf)) { + return rf; + } + } + return null; + } + + public Field lookupField(Set fields, ResolvedJavaField key) { + for (Field f : fields) { + if (fieldsEqual(f, key)) { + return f; + } + } + return null; + } + + private static boolean isHiddenFromReflection(ResolvedJavaField f) { + if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Throwable.class)) && f.getName().equals("backtrace")) { + return true; + } + if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(ConstantPool.class)) && f.getName().equals("constantPoolOop")) { + return true; + } + if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Class.class)) && f.getName().equals("classLoader")) { + return true; + } + return false; + } + + @Test + public void getInstanceFieldsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (boolean includeSuperclasses : new boolean[]{true, false}) { + Set expected = getInstanceFields(c, includeSuperclasses); + ResolvedJavaField[] actual = type.getInstanceFields(includeSuperclasses); + for (Field f : expected) { + assertNotNull(lookupField(actual, f)); + } + for (ResolvedJavaField rf : actual) { + if (!isHiddenFromReflection(rf)) { + assertEquals(rf.toString(), lookupField(expected, rf) != null, !rf.isInternal()); + } + } + + // Test stability of getInstanceFields + ResolvedJavaField[] actual2 = type.getInstanceFields(includeSuperclasses); + assertArrayEquals(actual, actual2); + } + } + } + + @Test + public void getStaticFieldsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Set expected = getStaticFields(c); + ResolvedJavaField[] actual = type.getStaticFields(); + for (Field f : expected) { + assertNotNull(lookupField(actual, f)); + } + for (ResolvedJavaField rf : actual) { + if (!isHiddenFromReflection(rf)) { + assertEquals(lookupField(expected, rf) != null, !rf.isInternal()); + } + } + + // Test stability of getStaticFields + ResolvedJavaField[] actual2 = type.getStaticFields(); + assertArrayEquals(actual, actual2); + } + } + + @Test + public void getDeclaredMethodsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Method[] raw = c.getDeclaredMethods(); + Set expected = new HashSet<>(); + for (Method m : raw) { + ResolvedJavaMethod resolvedMethod = metaAccess.lookupJavaMethod(m); + assertNotNull(resolvedMethod); + expected.add(resolvedMethod); + } + Set actual = new HashSet<>(Arrays.asList(type.getDeclaredMethods())); + assertEquals(expected, actual); + } + } + + static class A { + static String name = "foo"; + } + + static class B extends A { + } + + static class C { + } + + static class D { + void foo() { + // use of assertions causes the class to have a + assert getClass() != null; + } + } + + static class SubD extends D { + + } + + @Test + public void getClassInitializerTest() { + assertNotNull(metaAccess.lookupJavaType(A.class).getClassInitializer()); + assertNotNull(metaAccess.lookupJavaType(D.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(B.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(C.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(int.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(void.class).getClassInitializer()); + } + + @Test + public void getAnnotationsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertArrayEquals(c.getAnnotations(), type.getAnnotations()); + } + } + + @Test + public void getAnnotationTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (Annotation a : c.getAnnotations()) { + assertEquals(a, type.getAnnotation(a.annotationType())); + } + } + } + + @Test + public void memberClassesTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertEquals(c.isLocalClass(), type.isLocal()); + assertEquals(c.isMemberClass(), type.isMember()); + Class enclc = c.getEnclosingClass(); + ResolvedJavaType enclt = type.getEnclosingType(); + assertFalse(enclc == null ^ enclt == null); + if (enclc != null) { + assertEquals(enclt, metaAccess.lookupJavaType(enclc)); + } + } + } + + @Test + public void classFilePathTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + URL path = type.getClassFilePath(); + if (type.isPrimitive() || type.isArray()) { + assertEquals(null, path); + } else { + assertNotNull(path); + String pathString = path.getPath(); + if (type.isLocal() || type.isMember()) { + assertTrue(pathString.indexOf('$') > 0); + } + } + } + } + + @Test + public void isTrustedInterfaceTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + if (TrustedInterface.class.isAssignableFrom(c)) { + assertTrue(type.isTrustedInterfaceType()); + } + } + } + + @Test + public void isLeafTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + ResolvedJavaType arrayType = c != void.class ? metaAccess.lookupJavaType(getArrayClass(c)) : null; + if (c.isPrimitive()) { + assertTrue(type.isLeaf()); + assertTrue(arrayType == null || arrayType.isLeaf()); + } else { + assertTrue(c.toString(), type.isLeaf() == arrayType.isLeaf()); + if (!c.isArray()) { + assertTrue(c.toString(), type.isLeaf() == Modifier.isFinal(c.getModifiers())); + } + } + } + } + + @Test + public void findMethodTest() { + try { + ResolvedJavaMethod findFoo = metaAccess.lookupJavaType(D.class).findMethod("foo", metaAccess.parseMethodDescriptor("()V")); + ResolvedJavaMethod expectedFoo = metaAccess.lookupJavaMethod(D.class.getDeclaredMethod("foo")); + assertEquals(expectedFoo, findFoo); + + ResolvedJavaMethod wrongReturnTypeFoo = metaAccess.lookupJavaType(D.class).findMethod("foo", metaAccess.parseMethodDescriptor("()I")); + assertNull(wrongReturnTypeFoo); + + ResolvedJavaMethod wrongArgumentsFoo = metaAccess.lookupJavaType(D.class).findMethod("foo", metaAccess.parseMethodDescriptor("(I)V")); + assertNull(wrongArgumentsFoo); + + ResolvedJavaMethod wrongNameFoo = metaAccess.lookupJavaType(D.class).findMethod("bar", metaAccess.parseMethodDescriptor("()V")); + assertNull(wrongNameFoo); + + ResolvedJavaMethod wrongClassFoo = metaAccess.lookupJavaType(SubD.class).findMethod("foo", metaAccess.parseMethodDescriptor("()V")); + assertNull(wrongClassFoo); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException(e); + } + } + + private Method findTestMethod(Method apiMethod) { + String testName = apiMethod.getName() + "Test"; + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { + return m; + } + } + return null; + } + + // @formatter:off + private static final String[] untestedApiMethods = { + "initialize", + "isPrimitive", + "newArray", + "getDeclaredConstructors", + "isInitialized", + "isLinked", + "getJavaClass", + "getObjectHub", + "hasFinalizableSubclass", + "hasFinalizer", + "getSourceFileName", + "getClassFilePath", + "isLocal", + "isJavaLangObject", + "isMember", + "getElementalType", + "getEnclosingType", + "$jacocoInit", + "isCpiSet", + "getCorrespondingCpi", + "setCorrespondingCpi" + }; + // @formatter:on + + /** + * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written + * for them or are added to {@link #untestedApiMethods}. + */ + @Test + public void testCoverage() { + Set known = new HashSet<>(Arrays.asList(untestedApiMethods)); + for (Method m : ResolvedJavaType.class.getDeclaredMethods()) { + if (findTestMethod(m) == null) { + assertTrue("test missing for " + m, known.contains(m.getName())); + } else { + assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java new file mode 100644 index 00000000000..0cb74ed83f4 --- /dev/null +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.runtime.test; + +import static java.lang.reflect.Modifier.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.Queue; +import java.util.stream.*; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; + +import org.junit.*; + +import sun.misc.*; + +//JaCoCo Exclude + +/** + * Context for type related tests. + */ +public class TypeUniverse { + + public static final Unsafe unsafe; + public static final double JAVA_VERSION = Double.valueOf(System.getProperty("java.specification.version")); + + public static final MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + public static final ConstantReflectionProvider constantReflection = JVMCI.getRuntime().getHostJVMCIBackend().getConstantReflection(); + public static final Collection> classes = new HashSet<>(); + public static final Set javaTypes; + public static final Map, Class> arrayClasses = new HashMap<>(); + + private static List constants; + + public class InnerClass { + + } + + public static class InnerStaticClass { + + } + + public static final class InnerStaticFinalClass { + + } + + private class PrivateInnerClass { + + } + + protected class ProtectedInnerClass { + + } + + static { + Unsafe theUnsafe = null; + try { + theUnsafe = Unsafe.getUnsafe(); + } catch (Exception e) { + try { + Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeField.setAccessible(true); + theUnsafe = (Unsafe) theUnsafeField.get(null); + } catch (Exception e1) { + throw (InternalError) new InternalError("unable to initialize unsafe").initCause(e1); + } + } + unsafe = theUnsafe; + + Class[] initialClasses = {void.class, boolean.class, byte.class, short.class, char.class, int.class, float.class, long.class, double.class, Object.class, Class.class, boolean[].class, + byte[].class, short[].class, char[].class, int[].class, float[].class, long[].class, double[].class, Object[].class, Class[].class, List[].class, boolean[][].class, + byte[][].class, short[][].class, char[][].class, int[][].class, float[][].class, long[][].class, double[][].class, Object[][].class, Class[][].class, List[][].class, + ClassLoader.class, String.class, Serializable.class, Cloneable.class, Test.class, TestMetaAccessProvider.class, List.class, Collection.class, Map.class, Queue.class, + HashMap.class, LinkedHashMap.class, IdentityHashMap.class, AbstractCollection.class, AbstractList.class, ArrayList.class, TrustedInterface.class, InnerClass.class, + InnerStaticClass.class, InnerStaticFinalClass.class, PrivateInnerClass.class, ProtectedInnerClass.class}; + for (Class c : initialClasses) { + addClass(c); + } + + javaTypes = Collections.unmodifiableSet(classes.stream().map(c -> metaAccess.lookupJavaType(c)).collect(Collectors.toSet())); + } + + static class ConstantsUniverse { + static final Object[] ARRAYS = classes.stream().map(c -> c != void.class && !c.isArray() ? Array.newInstance(c, 42) : null).filter(o -> o != null).collect(Collectors.toList()).toArray(); + static final Object CONST1 = new ArrayList<>(); + static final Object CONST2 = new ArrayList<>(); + static final Object CONST3 = new IdentityHashMap<>(); + static final Object CONST4 = new LinkedHashMap<>(); + static final Object CONST5 = new TreeMap<>(); + static final Object CONST6 = new ArrayDeque<>(); + static final Object CONST7 = new LinkedList<>(); + static final Object CONST8 = "a string"; + static final Object CONST9 = 42; + static final Object CONST10 = String.class; + static final Object CONST11 = String[].class; + } + + public static List constants() { + if (constants == null) { + List res = readConstants(JavaConstant.class); + res.addAll(readConstants(ConstantsUniverse.class)); + constants = res; + } + return constants; + } + + public static class ConstantValue { + public final String name; + public final JavaConstant value; + public final Object boxed; + + public ConstantValue(String name, JavaConstant value, Object boxed) { + this.name = name; + this.value = value; + this.boxed = boxed; + } + + @Override + public String toString() { + return name + "=" + value; + } + + public String getSimpleName() { + return name.substring(name.lastIndexOf('.') + 1); + } + } + + /** + * Reads the value of all {@code static final} fields from a given class into an array of + * {@link ConstantValue}s. + */ + public static List readConstants(Class fromClass) { + try { + List res = new ArrayList<>(); + for (Field field : fromClass.getDeclaredFields()) { + if (isStatic(field.getModifiers()) && isFinal(field.getModifiers())) { + JavaField javaField = metaAccess.lookupJavaField(field); + Object boxed = field.get(null); + if (boxed instanceof JavaConstant) { + res.add(new ConstantValue(javaField.format("%H.%n"), (JavaConstant) boxed, boxed)); + } else { + JavaConstant value = constantReflection.readConstantFieldValue(javaField, null); + if (value != null) { + res.add(new ConstantValue(javaField.format("%H.%n"), value, boxed)); + if (boxed instanceof Object[]) { + Object[] arr = (Object[]) boxed; + for (int i = 0; i < arr.length; i++) { + JavaConstant element = constantReflection.readArrayElement(value, i); + if (element != null) { + res.add(new ConstantValue(javaField.format("%H.%n[" + i + "]"), element, arr[i])); + } + } + } + } + } + } + } + return res; + } catch (Exception e) { + throw new AssertionError(e); + } + } + + public synchronized Class getArrayClass(Class componentType) { + Class arrayClass = arrayClasses.get(componentType); + if (arrayClass == null) { + arrayClass = Array.newInstance(componentType, 0).getClass(); + arrayClasses.put(componentType, arrayClass); + } + return arrayClass; + } + + public static int dimensions(Class c) { + if (c.getComponentType() != null) { + return 1 + dimensions(c.getComponentType()); + } + return 0; + } + + private static void addClass(Class c) { + if (classes.add(c)) { + if (c.getSuperclass() != null) { + addClass(c.getSuperclass()); + } + for (Class sc : c.getInterfaces()) { + addClass(sc); + } + for (Class dc : c.getDeclaredClasses()) { + addClass(dc); + } + for (Method m : c.getDeclaredMethods()) { + addClass(m.getReturnType()); + for (Class p : m.getParameterTypes()) { + addClass(p); + } + } + + if (c != void.class && dimensions(c) < 2) { + Class arrayClass = Array.newInstance(c, 0).getClass(); + arrayClasses.put(c, arrayClass); + addClass(arrayClass); + } + } + } +} diff --git a/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java b/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java index 4eea5d5e443..af99d6b16dc 100644 --- a/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java +++ b/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java @@ -25,8 +25,8 @@ /** * @test * @bug 8080289 - * @summary Sink stores out of loops if possible - * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+PrintCompilation -XX:CompileCommand=dontinline,TestMoveStoresOutOfLoops::test* TestMoveStoresOutOfLoops + * @summary Move stores out of loops if possible + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestMoveStoresOutOfLoops::test* TestMoveStoresOutOfLoops * */ diff --git a/hotspot/test/compiler/TestMoveStoresOutOfLoopsStoreNoCtrl.java b/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoopsStoreNoCtrl.java similarity index 100% rename from hotspot/test/compiler/TestMoveStoresOutOfLoopsStoreNoCtrl.java rename to hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoopsStoreNoCtrl.java diff --git a/hotspot/test/compiler/loopopts/superword/SumRedAbsNeg_Double.java b/hotspot/test/compiler/loopopts/superword/SumRedAbsNeg_Double.java new file mode 100644 index 00000000000..98e8f0f1fce --- /dev/null +++ b/hotspot/test/compiler/loopopts/superword/SumRedAbsNeg_Double.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8138583 + * @summary Add C2 AArch64 Superword support for scalar sum reduction optimizations : double abs & neg test + * @requires os.arch=="aarch64" + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + */ + +public class SumRedAbsNeg_Double +{ + public static void main(String[] args) throws Exception { + double[] a = new double[256*1024]; + double[] b = new double[256*1024]; + double[] c = new double[256*1024]; + double[] d = new double[256*1024]; + sumReductionInit(a,b,c); + double total = 0; + double valid = 3.6028590866691944E19; + + for(int j = 0; j < 2000; j++) { + total = sumReductionImplement(a,b,c,d,total); + } + + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void sumReductionInit( + double[] a, + double[] b, + double[] c) + { + for(int j = 0; j < 1; j++) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i * 1 + j; + b[i] = i * 1 - j; + c[i] = i + j; + } + } + } + + public static double sumReductionImplement( + double[] a, + double[] b, + double[] c, + double[] d, + double total) + { + for(int i = 0; i < a.length; i++) + { + d[i] = Math.abs(-a[i] * -b[i]) + Math.abs(-a[i] * -c[i]) + Math.abs(-b[i] * -c[i]); + total += d[i]; + } + return total; + } + +} diff --git a/hotspot/test/compiler/loopopts/superword/SumRedAbsNeg_Float.java b/hotspot/test/compiler/loopopts/superword/SumRedAbsNeg_Float.java new file mode 100644 index 00000000000..bbf749461fd --- /dev/null +++ b/hotspot/test/compiler/loopopts/superword/SumRedAbsNeg_Float.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8138583 + * @summary Add C2 AArch64 Superword support for scalar sum reduction optimizations : float abs & neg test + * @requires os.arch=="aarch64" + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + */ + +public class SumRedAbsNeg_Float +{ + public static void main(String[] args) throws Exception { + float[] a = new float[256*1024]; + float[] b = new float[256*1024]; + float[] c = new float[256*1024]; + float[] d = new float[256*1024]; + sumReductionInit(a,b,c); + float total = 0; + float valid = (float)4.611686E18; + + for(int j = 0; j < 2000; j++) { + total = sumReductionImplement(a,b,c,d,total); + } + + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void sumReductionInit( + float[] a, + float[] b, + float[] c) + { + for(int j = 0; j < 1; j++) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i * 1 + j; + b[i] = i * 1 - j; + c[i] = i + j; + } + } + } + + public static float sumReductionImplement( + float[] a, + float[] b, + float[] c, + float[] d, + float total) + { + for(int i = 0; i < a.length; i++) + { + d[i] = Math.abs(-a[i] * -b[i]) + Math.abs(-a[i] * -c[i]) + Math.abs(-b[i] * -c[i]); + total += d[i]; + } + return total; + } + +} diff --git a/hotspot/test/compiler/loopopts/superword/SumRedSqrt_Double.java b/hotspot/test/compiler/loopopts/superword/SumRedSqrt_Double.java index 75a2c14e36f..429e30d6a09 100644 --- a/hotspot/test/compiler/loopopts/superword/SumRedSqrt_Double.java +++ b/hotspot/test/compiler/loopopts/superword/SumRedSqrt_Double.java @@ -24,7 +24,9 @@ /** * @test +* @bug 8135028 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double sqrt test +* @requires os.arch=="x86" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedSqrt_Double * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedSqrt_Double diff --git a/hotspot/test/compiler/oracle/CheckCompileCommandOption.java b/hotspot/test/compiler/oracle/CheckCompileCommandOption.java index ea44c8dfe83..978aad4178f 100644 --- a/hotspot/test/compiler/oracle/CheckCompileCommandOption.java +++ b/hotspot/test/compiler/oracle/CheckCompileCommandOption.java @@ -66,7 +66,6 @@ public class CheckCompileCommandOption { "CompileCommand: option com/oracle/Test.test bool MyBoolOption1 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption2 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption3 = true", - "CompileCommand: option com/oracle/Test.test bool MyBoolOption4 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption5 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption6 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption7 = true", @@ -74,7 +73,6 @@ public class CheckCompileCommandOption { "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption9 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption10 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption11 = true", - "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption12 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption13 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption14 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption15 = true", @@ -96,7 +94,6 @@ public class CheckCompileCommandOption { "-XX:CompileCommand=option,com/oracle/Test.test,MyBoolOption1", "-XX:CompileCommand=option,com/oracle/Test,test,MyBoolOption2", "-XX:CompileCommand=option,com.oracle.Test::test,MyBoolOption3", - "-XX:CompileCommand=option,com/oracle/Test::test,MyBoolOption4", "-XX:CompileCommand=option,com/oracle/Test.test,MyBoolOption5,MyBoolOption6", "-XX:CompileCommand=option,com/oracle/Test,test,MyBoolOption7,MyBoolOption8", "-version" @@ -108,7 +105,6 @@ public class CheckCompileCommandOption { "CompileCommand: option com/oracle/Test.test bool MyBoolOption1 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption2 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption3 = true", - "CompileCommand: option com/oracle/Test.test bool MyBoolOption4 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption5 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption6 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption7 = true", @@ -198,7 +194,7 @@ public class CheckCompileCommandOption { out.shouldContain(expected_output); } - out.shouldNotContain("CompileCommand: An error occured during parsing"); + out.shouldNotContain("CompileCommand: An error occurred during parsing"); out.shouldHaveExitValue(0); } @@ -209,7 +205,7 @@ public class CheckCompileCommandOption { pb = ProcessTools.createJavaProcessBuilder(arguments); out = new OutputAnalyzer(pb.start()); - out.shouldContain("CompileCommand: An error occured during parsing"); + out.shouldContain("CompileCommand: An error occurred during parsing"); out.shouldHaveExitValue(0); } diff --git a/hotspot/test/compiler/oracle/MethodMatcherTest.java b/hotspot/test/compiler/oracle/MethodMatcherTest.java new file mode 100644 index 00000000000..96298d27d62 --- /dev/null +++ b/hotspot/test/compiler/oracle/MethodMatcherTest.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test MethodMatcherTest + * @library /testlibrary /../../test/lib + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI MethodMatcherTest + * @summary Testing of compiler/MethodMatcher + * @bug 8135068 + */ + +import java.lang.reflect.Method; +import java.util.ArrayList; + +import sun.hotspot.WhiteBox; + +public class MethodMatcherTest { + + /** Instance of WhiteBox */ + protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + Method helper; + Method getDate; + Method inner; + Method toString; + + static final int MATCH = 1; + static final int NO_MATCH = 0; + static final int PARSING_FAILURE = -1; + + public MethodMatcherTest() { + } + + public void test() throws Exception { + // instantiate before calling getMethod on innerHelper + TestCases testCases = new TestCases(); + + helper = getMethod(MethodMatcherTest.class, "helper"); + getDate = getMethod(java.util.Date.class, "getDate"); + inner = getMethod(TestCases.class, "innerHelper"); + toString = getMethod(String.class, "toString"); + + testCases.add(helper, "pool/sub/Klass.method(I[Ljava/lang/String;Ljava/lang/Integer;[B[[D)V", NO_MATCH); + + // These should be improved to parsing failed in the future + testCases.add(helper, "*Klass*,*$method*::", NO_MATCH); + testCases.add(helper, "*Klass *+*", NO_MATCH); + testCases.add(helper, "*Klass*::*method*", NO_MATCH); + + testCases.add(helper, "*,**", PARSING_FAILURE); + testCases.add(helper, "*,*(I[Ljava/lang/String;Lj]ava/lang/Integer;[B[[D)V", PARSING_FAILURE); + testCases.add(helper, "*,*)method*.", PARSING_FAILURE); + testCases.add(helper, "{pool.subpack.Klass}* *", PARSING_FAILURE); + testCases.add(helper, "*Klass met]hod/", PARSING_FAILURE); + testCases.add(helper, "pool::su@%b::Klass* *)method.", PARSING_FAILURE); + testCases.add(helper, "0pool/sub/Klass,*{method}*.(I[Ljava/lang/String;Lj]ava/lang/Integer;[B[[D)V", PARSING_FAILURE); + testCases.add(helper, "*Klass nonexistent::)(I[Ljava/lang/String;Ljava/lang/Integer;[B[[D)V", PARSING_FAILURE); + testCases.add(helper, "pool,su]b,Klass*,*)method*/", PARSING_FAILURE); + testCases.add(helper, "_pool,sub,Klass*,met@%hod,(0)V", PARSING_FAILURE); + + testCases.add(helper, "*.*", MATCH); + testCases.add(helper, "MethodMatcherTest.*", MATCH); + testCases.add(helper, "MethodMatcherTest.helper", MATCH); + testCases.add(helper, "MethodMatcherTest.helper()", MATCH); + testCases.add(helper, "MethodMatcherTest.helper()V", MATCH); + testCases.add(helper, "MethodMatcherTest.helper()V;", NO_MATCH); + testCases.add(helper, "MethodMatcherTest.helper()I", NO_MATCH); + testCases.add(helper, "MethodMatcherTest.helperX", NO_MATCH); + testCases.add(helper, "MethodMatcherTestX.helper;", NO_MATCH); + testCases.add(helper, "abc.*", NO_MATCH); + testCases.add(helper, "*.abc", NO_MATCH); + + testCases.add(getDate, "*.*", MATCH); + testCases.add(getDate, "*.getDate", MATCH); + testCases.add(getDate, "java/util/Date.getDate", MATCH); + testCases.add(getDate, "java/util/Date.*", MATCH); + + testCases.add(inner, "*.*", MATCH); + testCases.add(inner, "MethodMatcherTest$TestCases.innerHelper", MATCH); + testCases.add(inner, "MethodMatcherTest*.innerHelper", MATCH); + testCases.add(inner, "MethodMatcherTest$*.innerHelper", MATCH); + testCases.add(inner, "*$TestCases.innerHelper", MATCH); + testCases.add(inner, "*TestCases.innerHelper", MATCH); + testCases.add(inner, "TestCases.innerHelper", NO_MATCH); + testCases.add(inner, "MethodMatcherTest.innerHelper", NO_MATCH); + + testCases.add(toString, "*.*", MATCH); + testCases.add(toString, "java/lang/String.toString", MATCH); + testCases.add(toString, "java.lang.String::toString", MATCH); + + testCases.add(toString, "java/lang/String::toString", PARSING_FAILURE); + testCases.add(toString, "java.lang/String::toString", PARSING_FAILURE); + testCases.add(toString, "java.lang/String.toString", PARSING_FAILURE); + testCases.add(toString, "java::lang::String::toString", PARSING_FAILURE); + + testCases.add(toString, "java/lang/String.toString(*)", PARSING_FAILURE); + testCases.add(toString, "java/lang/String.toString(L*", PARSING_FAILURE); + testCases.add(toString, "java/lang/String.toString*(lsd)l", NO_MATCH); + testCases.add(toString, "java/lang/String.toString(lsd)l", NO_MATCH); + testCases.add(toString, "java/lang/String.toString (", MATCH); + testCases.add(toString, "java/lang/String.toString ()", MATCH); + testCases.add(toString, "java/lang/String.toString ()L", MATCH); + testCases.add(toString, "java/lang/String.toString ()Lj", MATCH); + testCases.add(toString, "java/lang/String.toString ()Ls", NO_MATCH); + testCases.add(toString, "java/lang/String.toString*(", MATCH); + testCases.add(toString, "java/lang/String.toString* (", MATCH); + testCases.add(toString, "java/lang/String.toString*(;", NO_MATCH); + testCases.add(toString, "java/lang/String.toString*();sf", NO_MATCH); + testCases.add(toString, "java/lang/String.toString*()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString ()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString ()Ljava/lang/String", MATCH); + testCases.add(toString, "java/lang/String.toString ()L", MATCH); + testCases.add(toString, "java/lang/String.toString ()I;", NO_MATCH); + + testCases.add(toString, "*Internal.*", NO_MATCH); + testCases.add(toString, "*Internal.**", PARSING_FAILURE); + testCases.add(toString, "*Internal.***", PARSING_FAILURE); + testCases.add(toString, "*Internal.*a**", PARSING_FAILURE); + testCases.add(toString, "*Internal.**a*", PARSING_FAILURE); + + testCases.add(toString, "java.lang.String::(Ljava/lang/String;)V", NO_MATCH); + testCases.add(toString, "java.lang.String::(Ljava/lang/String;)V", NO_MATCH); + testCases.add(toString, "java.lang.String::(Ljava/lang/String;)V", PARSING_FAILURE); + + testCases.add(toString, "java/lang/String.toString()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString()Ljava/lang/String;", PARSING_FAILURE); + testCases.add(toString, "java/lang/.toString()Ljava/lang/String;", PARSING_FAILURE); + testCases.add(toString, "java/lang/.toString()Ljava/lang/String;", PARSING_FAILURE); + + int failures = 0; + for (TestCase t : testCases) { + System.out.println("Test case: " + t.pattern); + if (!t.test()) { + failures++; + System.out.println(" * FAILED"); + } + } + if (failures != 0) { + throw new Exception("There where " + failures + " failures in this test"); + } + } + + public static void main(String... args) throws Exception { + MethodMatcherTest test = new MethodMatcherTest(); + test.test(); + } + + public void helper() { + + } + + private static Method getMethod(Class klass, String name, Class... parameterTypes) { + try { + return klass.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("exception on getting method Helper." + name, e); + } + } + + class TestCase { + String pattern; + Method testTarget; + int expectedResult; + + public TestCase(Method testTarget, String pattern, int expectedResult) { + this.testTarget = testTarget; + this.pattern = pattern; + this.expectedResult = expectedResult; + } + + public String resultAsStr(int errorCode) { + switch (errorCode) { + case PARSING_FAILURE: + return "Parsing failed"; + case NO_MATCH: + return "No match"; + case MATCH: + return "Match"; + default: + return "Unknown error"; + } + } + + boolean test() { + int result = WHITE_BOX.matchesMethod(testTarget, pattern); + if (result != expectedResult) { + System.out + .println("FAIL Wrong result, Got: " + resultAsStr(result) + "\n TestCase: " + this.toString()); + return false; + } + return true; + } + + @Override + public String toString() { + return "Method: '" + testTarget.toString() + "' Pattern: '" + pattern + "' Expected: " + + resultAsStr(expectedResult); + } + + public void innerHelper() { + } + } + + class TestCases extends ArrayList { + private static final long serialVersionUID = 1L; + + public boolean add(Method testTarget, String pattern, int expectedResult) { + return super.add(new TestCase(testTarget, pattern, expectedResult)); + } + + public void innerHelper() { + } + } +} diff --git a/hotspot/test/compiler/oracle/TestCompileCommand.java b/hotspot/test/compiler/oracle/TestCompileCommand.java index 0f02c73473e..cff8ed4e91b 100644 --- a/hotspot/test/compiler/oracle/TestCompileCommand.java +++ b/hotspot/test/compiler/oracle/TestCompileCommand.java @@ -40,7 +40,7 @@ public class TestCompileCommand { private static final String[][] ARGUMENTS = { { - "-XX:CompileCommand=print,*01234567890123456789012345678901234567890123456789,*0123456789012345678901234567890123456789", + "-XX:CompileCommand=print,*01234567890123456789012345678901234567890123456789.*0123456789012345678901234567890123456789", "-version" } }; diff --git a/hotspot/test/compiler/oracle/command1.txt b/hotspot/test/compiler/oracle/command1.txt index aaf7cbdaecf..bc34b00ee0f 100644 --- a/hotspot/test/compiler/oracle/command1.txt +++ b/hotspot/test/compiler/oracle/command1.txt @@ -1,12 +1,10 @@ option,com/oracle/Test.test,MyBoolOption1 option,com/oracle/Test,test,MyBoolOption2 option,com.oracle.Test::test,MyBoolOption3 -option,com/oracle/Test::test,MyBoolOption4 option,com/oracle/Test.test,MyBoolOption5,MyBoolOption6 option,com/oracle/Test,test,MyBoolOption7,MyBoolOption8 option,com/oracle/Test.test(I),MyBoolOption9 option,com/oracle/Test,test,(I),MyBoolOption10 option,com.oracle.Test::test(I),MyBoolOption11 -option,com/oracle/Test::test(I),MyBoolOption12 option,com/oracle/Test.test(I),MyBoolOption13,MyBoolOption14 option,com/oracle/Test,test(I),MyBoolOption15,MyBoolOption16 diff --git a/hotspot/test/compiler/startup/SmallCodeCacheStartup.java b/hotspot/test/compiler/startup/SmallCodeCacheStartup.java index 94de9207bab..89c0c841aae 100644 --- a/hotspot/test/compiler/startup/SmallCodeCacheStartup.java +++ b/hotspot/test/compiler/startup/SmallCodeCacheStartup.java @@ -23,6 +23,7 @@ /* * @test + * @ignore 8134286 * @bug 8023014 * @summary Test ensures that there is no crash if there is not enough ReservedCodeCacheSize * to initialize all compiler threads. The option -Xcomp gives the VM more time to diff --git a/hotspot/test/compiler/testlibrary/CompilerUtils.java b/hotspot/test/compiler/testlibrary/CompilerUtils.java index 43e674992a9..3af7e76c5d3 100644 --- a/hotspot/test/compiler/testlibrary/CompilerUtils.java +++ b/hotspot/test/compiler/testlibrary/CompilerUtils.java @@ -21,6 +21,8 @@ * questions. */ +package compiler.testlibrary; + import jdk.test.lib.Asserts; import jdk.test.lib.Platform; import java.util.stream.IntStream; diff --git a/hotspot/test/gc/arguments/TestG1ConcMarkStepDurationMillis.java b/hotspot/test/gc/arguments/TestG1ConcMarkStepDurationMillis.java new file mode 100644 index 00000000000..baf362f9b6f --- /dev/null +++ b/hotspot/test/gc/arguments/TestG1ConcMarkStepDurationMillis.java @@ -0,0 +1,110 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* + * @test TestG1ConcMarkStepDurationMillis + * @key gc + * @requires vm.gc=="null" | vm.gc=="G1" + * @summary Tests argument processing for double type flag, G1ConcMarkStepDurationMillis + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + */ + +import jdk.test.lib.*; +import java.util.*; +import java.util.regex.*; + +public class TestG1ConcMarkStepDurationMillis { + + static final int PASS = 0; + static final int FAIL_IMPROPER_VALUE = 1; + static final int FAIL_OUT_RANGE = 2; + + static final String DOUBLE_1 = "1.0"; + static final String DOUBLE_MAX = "1.79e+308"; + + static final String DOUBLE_NEG_EXP = "1.0e-30"; + static final String NEG_DOUBLE_1 = "-1.0"; + + static final String DOUBLE_INF = "1.79e+309"; + static final String NEG_DOUBLE_INF = "-1.79e+309"; + static final String DOUBLE_NAN = "abe+309"; + static final String WRONG_DOUBLE_1 = "1.79e+308e"; + static final String WRONG_DOUBLE_2 = "1.79ee+308"; + + public static void main(String args[]) throws Exception { + // Pass cases + runG1ConcMarkStepDurationMillisTest(DOUBLE_1, PASS); + runG1ConcMarkStepDurationMillisTest(DOUBLE_MAX, PASS); + + // Fail cases: out of range + runG1ConcMarkStepDurationMillisTest(DOUBLE_NEG_EXP, FAIL_OUT_RANGE); + runG1ConcMarkStepDurationMillisTest(NEG_DOUBLE_1, FAIL_OUT_RANGE); + + // Fail cases: not double + runG1ConcMarkStepDurationMillisTest(DOUBLE_INF, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(NEG_DOUBLE_INF, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(DOUBLE_NAN, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(WRONG_DOUBLE_1, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(WRONG_DOUBLE_2, FAIL_IMPROPER_VALUE); + } + + private static void runG1ConcMarkStepDurationMillisTest(String expectedValue, int expectedResult) throws Exception { + List vmOpts = new ArrayList<>(); + + Collections.addAll(vmOpts, "-XX:+UseG1GC", "-XX:G1ConcMarkStepDurationMillis="+expectedValue, "-XX:+PrintFlagsFinal", "-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldHaveExitValue(expectedResult == PASS ? 0 : 1); + String stdout = output.getStdout(); + if (expectedResult == PASS) { + checkG1ConcMarkStepDurationMillisConsistency(stdout, expectedValue); + } else if (expectedResult == FAIL_IMPROPER_VALUE) { + output.shouldContain("Improperly specified VM option"); + } else if (expectedResult == FAIL_OUT_RANGE) { + output.shouldContain("outside the allowed range"); + } + } + + private static void checkG1ConcMarkStepDurationMillisConsistency(String output, String expectedValue) { + double actualValue = getDoubleValue("G1ConcMarkStepDurationMillis", output); + + if (Double.parseDouble(expectedValue) != actualValue) { + throw new RuntimeException( + "Actual G1ConcMarkStepDurationMillis(" + Double.toString(actualValue) + + ") is not equal to expected value(" + expectedValue + ")"); + } + } + + public static double getDoubleValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + String match = m.group(); + return Double.parseDouble(match.substring(match.lastIndexOf(" ") + 1, match.length())); + } +} diff --git a/hotspot/test/gc/arguments/TestG1HeapRegionSize.java b/hotspot/test/gc/arguments/TestG1HeapRegionSize.java index 55177bcabf6..d25b19c3439 100644 --- a/hotspot/test/gc/arguments/TestG1HeapRegionSize.java +++ b/hotspot/test/gc/arguments/TestG1HeapRegionSize.java @@ -25,42 +25,59 @@ * @test TestG1HeapRegionSize * @key gc * @bug 8021879 + * @requires vm.gc=="null" | vm.gc=="G1" * @summary Verify that the flag G1HeapRegionSize is updated properly * @modules java.management/sun.management - * @run main/othervm -Xmx64m TestG1HeapRegionSize 1048576 - * @run main/othervm -XX:G1HeapRegionSize=2m -Xmx64m TestG1HeapRegionSize 2097152 - * @run main/othervm -XX:G1HeapRegionSize=3m -Xmx64m TestG1HeapRegionSize 2097152 - * @run main/othervm -XX:G1HeapRegionSize=64m -Xmx256m TestG1HeapRegionSize 33554432 + * @library /testlibrary + * @run main TestG1HeapRegionSize */ -import com.sun.management.HotSpotDiagnosticMXBean; -import com.sun.management.VMOption; -import java.lang.management.ManagementFactory; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import java.util.ArrayList; +import java.util.Arrays; + +import jdk.test.lib.*; public class TestG1HeapRegionSize { - public static void main(String[] args) { - HotSpotDiagnosticMXBean diagnostic = - ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); + private static void checkG1HeapRegionSize(String[] flags, int expectedValue, int exitValue) throws Exception { + ArrayList flagList = new ArrayList(); + flagList.addAll(Arrays.asList(flags)); + flagList.add("-XX:+UseG1GC"); + flagList.add("-XX:+PrintFlagsFinal"); + flagList.add("-version"); - String expectedValue = getExpectedValue(args); - VMOption option = diagnostic.getVMOption("UseG1GC"); - if (option.getValue().equals("false")) { - System.out.println("Skipping this test. It is only a G1 test."); - return; - } + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(flagList.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(exitValue); - option = diagnostic.getVMOption("G1HeapRegionSize"); - if (!expectedValue.equals(option.getValue())) { - throw new RuntimeException("Wrong value for G1HeapRegionSize. Expected " + expectedValue + " but got " + option.getValue()); + if (exitValue == 0) { + String stdout = output.getStdout(); + int flagValue = getFlagValue("G1HeapRegionSize", stdout); + if (flagValue != expectedValue) { + throw new RuntimeException("Wrong value for G1HeapRegionSize. Expected " + expectedValue + " but got " + flagValue); + } } } - private static String getExpectedValue(String[] args) { - if (args.length != 1) { - throw new RuntimeException("Wrong number of arguments. Expected 1 but got " + args.length); + private static int getFlagValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); } - return args[0]; + String match = m.group(); + return Integer.parseInt(match.substring(match.lastIndexOf(" ") + 1, match.length())); } + public static void main(String args[]) throws Exception { + final int M = 1024 * 1024; + + checkG1HeapRegionSize(new String[] { "-Xmx64m" /* default is 1m */ }, 1*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx64m", "-XX:G1HeapRegionSize=2m" }, 2*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx64m", "-XX:G1HeapRegionSize=3m" }, 2*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx256m", "-XX:G1HeapRegionSize=32m" }, 32*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx256m", "-XX:G1HeapRegionSize=64m" }, 32*M, 1); + } } diff --git a/hotspot/test/gc/arguments/TestHeapFreeRatio.java b/hotspot/test/gc/arguments/TestHeapFreeRatio.java index 8bdf9508324..e3cb7ba6a57 100644 --- a/hotspot/test/gc/arguments/TestHeapFreeRatio.java +++ b/hotspot/test/gc/arguments/TestHeapFreeRatio.java @@ -72,7 +72,7 @@ public class TestHeapFreeRatio { output.shouldHaveExitValue(1); break; case COMBINATION_INVALID: - output.shouldContain("must be greater than or equal to MinHeapFreeRatio"); + output.shouldContain("must be less than or equal to MaxHeapFreeRatio"); output.shouldContain("Error"); output.shouldHaveExitValue(1); break; diff --git a/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java b/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java index 325fcfcc122..e9045709c59 100644 --- a/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java +++ b/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java @@ -25,6 +25,7 @@ * @test TestInitialTenuringThreshold * @key gc * @bug 8014765 + * @requires vm.gc=="Parallel" * @summary Tests argument processing for initial tenuring threshold * @library /testlibrary * @modules java.base/sun.misc @@ -39,6 +40,7 @@ public class TestInitialTenuringThreshold { public static void runWithThresholds(int initial, int max, boolean shouldfail) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseParallelGC", "-XX:InitialTenuringThreshold=" + String.valueOf(initial), "-XX:MaxTenuringThreshold=" + String.valueOf(max), "-version" diff --git a/hotspot/test/gc/arguments/TestObjectTenuringFlags.java b/hotspot/test/gc/arguments/TestObjectTenuringFlags.java index b662f041576..e62be2e9f57 100644 --- a/hotspot/test/gc/arguments/TestObjectTenuringFlags.java +++ b/hotspot/test/gc/arguments/TestObjectTenuringFlags.java @@ -25,6 +25,7 @@ * @test TestObjectTenuringFlags * @key gc * @bug 6521376 + * @requires vm.gc=="Parallel" * @summary Tests argument processing for NeverTenure, AlwaysTenure, * and MaxTenuringThreshold * @library /testlibrary @@ -157,7 +158,7 @@ public class TestObjectTenuringFlags { if (tenuringFlags.length > 0) { Collections.addAll(vmOpts, tenuringFlags); } - Collections.addAll(vmOpts, "-XX:+PrintFlagsFinal", "-version"); + Collections.addAll(vmOpts, "-XX:+UseParallelGC", "-XX:+PrintFlagsFinal", "-version"); ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); OutputAnalyzer output = new OutputAnalyzer(pb.start()); diff --git a/hotspot/test/gc/cms/TestCMSScavengeBeforeRemark.java b/hotspot/test/gc/cms/TestCMSScavengeBeforeRemark.java new file mode 100644 index 00000000000..b124541e1e0 --- /dev/null +++ b/hotspot/test/gc/cms/TestCMSScavengeBeforeRemark.java @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* + * @test TestCMSScavengeBeforeRemark + * @key gc + * @bug 8139868 + * @requires vm.gc=="ConcMarkSweep" | vm.gc=="null" + * @summary Run CMS with CMSScavengeBeforeRemark + * @run main/othervm -XX:+UseConcMarkSweepGC -XX:+CMSScavengeBeforeRemark -XX:+ExplicitGCInvokesConcurrent -Xmx256m -XX:+PrintGCDetails TestCMSScavengeBeforeRemark + */ + +public class TestCMSScavengeBeforeRemark { + public static void main(String args[]) throws Exception { + System.gc(); + } +} diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index eeb7157d77b..380d89a46a9 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -23,7 +23,7 @@ /* * @test TestGCLogMessages - * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 + * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 * @summary Ensure that the PrintGCDetails output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -55,6 +55,8 @@ public class TestGCLogMessages { }; private LogMessageWithLevel allLogMessages[] = new LogMessageWithLevel[] { + // Update RS + new LogMessageWithLevel("Scan HCC (ms)", Level.FINER), // Ext Root Scan new LogMessageWithLevel("Thread Roots (ms)", Level.FINEST), new LogMessageWithLevel("StringTable Roots (ms)", Level.FINEST), diff --git a/hotspot/test/gc/g1/mixedgc/TestLogging.java b/hotspot/test/gc/g1/mixedgc/TestLogging.java new file mode 100644 index 00000000000..7d3dc69aa4b --- /dev/null +++ b/hotspot/test/gc/g1/mixedgc/TestLogging.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestLogging + * @summary Check that a mixed GC is reflected in the gc logs + * @requires vm.gc=="G1" | vm.gc=="null" + * @library /testlibrary /../../test/lib + * @ignore 8138607 + * @modules java.management + * @build sun.hotspot.WhiteBox gc.g1.mixedgc.TestLogging + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run driver gc.g1.mixedgc.TestLogging + */ + +package gc.g1.mixedgc; + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; + +/** + * Test spawns MixedGCProvoker in a separate VM and expects to find a message + * telling that a mixed gc has happened + */ +public class TestLogging { + private static final String[] COMMON_OPTIONS = new String[]{ + "-Xbootclasspath/a:.", "-XX:+UseG1GC", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:SurvivorRatio=1", // Survivor-to-eden ratio is 1:1 + "-Xms10M", "-Xmx10M", + "-XX:MaxTenuringThreshold=1", // promote objects after first gc + "-XX:InitiatingHeapOccupancyPercent=0", // marking cycle happens + // each time + "-XX:G1MixedGCCountTarget=4", + "-XX:MaxGCPauseMillis=30000", // to have enough time + "-XX:G1HeapRegionSize=1m", "-XX:G1HeapWastePercent=0", + "-XX:G1MixedGCLiveThresholdPercent=100"}; + + public static final int ALLOCATION_SIZE = 20000; + public static final int ALLOCATION_COUNT = 15; + + public static void main(String args[]) throws Exception { + // Test turns logging on by giving -XX:+PrintGC flag + test("-XX:+PrintGC"); + // Test turns logging on by giving -XX:+PrintGCDetails + test("-XX:+PrintGCDetails"); + } + + private static void test(String vmFlag) throws Exception { + System.out.println(String.format("%s: running with %s flag", TestLogging.class.getSimpleName(), vmFlag)); + OutputAnalyzer output = spawnMixedGCProvoker(vmFlag); + System.out.println(output.getStdout()); + output.shouldHaveExitValue(0); + output.shouldContain("GC pause (G1 Evacuation Pause) (mixed)"); + } + + /** + * Method spawns MixedGCProvoker with addition flags set + * + * @parameter extraFlags -flags to be added to the common options set + */ + private static OutputAnalyzer spawnMixedGCProvoker(String... extraFlags) + throws Exception { + List testOpts = new ArrayList<>(); + Collections.addAll(testOpts, COMMON_OPTIONS); + Collections.addAll(testOpts, extraFlags); + testOpts.add(MixedGCProvoker.class.getName()); + System.out.println(testOpts); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(false, + testOpts.toArray(new String[testOpts.size()])); + return new OutputAnalyzer(pb.start()); + } +} + +/** + * Utility class to guarantee a mixed GC. The class allocates several arrays and + * promotes them to the oldgen. After that it tries to provoke mixed GC by + * allocating new objects. + * + * The necessary condition for guaranteed mixed GC is running MixedGCProvoker is + * running in VM with the following flags: -XX:MaxTenuringThreshold=1, -Xms10M, + * -Xmx10M, -XX:G1MixedGCLiveThresholdPercent=100, -XX:G1HeapWastePercent=0, + * -XX:G1HeapRegionSize=1m + */ +class MixedGCProvoker { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final List liveOldObjects = new ArrayList<>(); + private static final List newObjects = new ArrayList<>(); + + private static void allocateOldObjects() throws Exception { + List deadOldObjects = new ArrayList<>(); + // Allocates buffer and promotes it to the old gen. Mix live and dead old + // objects + for (int i = 0; i < TestLogging.ALLOCATION_COUNT; ++i) { + liveOldObjects.add(new byte[TestLogging.ALLOCATION_SIZE * 10]); + deadOldObjects.add(new byte[TestLogging.ALLOCATION_SIZE * 10]); + } + + // need only 2 promotions to promote objects to the old gen + WB.youngGC(); + WB.youngGC(); + // check it is promoted & keep alive + Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects), + "List of the objects is suppose to be in OldGen"); + Asserts.assertTrue(WB.isObjectInOldGen(deadOldObjects), + "List of the objects is suppose to be in OldGen"); + } + + + /** + * Waits until Concurent Mark Cycle finishes + * @param wb Whitebox instance + * @param sleepTime sleep time + */ + public static void waitTillCMCFinished(WhiteBox wb, int sleepTime) { + while (wb.g1InConcurrentMark()) { + if (sleepTime > -1) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + System.out.println("Got InterruptedException while waiting for ConcMarkCycle to finish"); + } + } + } + } + + + + public static void main(String args[]) throws Exception { + // allocate old objects + allocateOldObjects(); + waitTillCMCFinished(WB, 0); + WB.g1StartConcMarkCycle(); + waitTillCMCFinished(WB, 0); + + WB.youngGC(); + System.out.println("Allocating new objects to provoke mixed GC"); + // allocate more objects to provoke GC + for (int i = 0; i < (TestLogging.ALLOCATION_COUNT * 20); i++) { + newObjects.add(new byte[TestLogging.ALLOCATION_SIZE]); + } + // check that liveOldObjects still alive + Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects), + "List of the objects is suppose to be in OldGen"); + } +} diff --git a/hotspot/test/gc/logging/TestPrintReferences.java b/hotspot/test/gc/logging/TestPrintReferences.java new file mode 100644 index 00000000000..65485708f3f --- /dev/null +++ b/hotspot/test/gc/logging/TestPrintReferences.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestPrintReferences + * @bug 8136991 + * @summary Validate the reference processing logging + * @key gc + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + */ + +import jdk.test.lib.ProcessTools; +import jdk.test.lib.OutputAnalyzer; + +public class TestPrintReferences { + public static void main(String[] args) throws Exception { + ProcessBuilder pb_enabled = + ProcessTools.createJavaProcessBuilder("-XX:+PrintGCDetails", "-XX:+PrintReferenceGC", "-Xmx10M", GCTest.class.getName()); + OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start()); + + String countRegex = "[0-9]+ refs"; + String timeRegex = "[0-9]+[.,][0-9]+ secs"; + + output.shouldMatch( + "#[0-9]+: \\[SoftReference, " + countRegex + ", " + timeRegex + "\\]" + + "#[0-9]+: \\[WeakReference, " + countRegex + ", " + timeRegex + "\\]" + + "#[0-9]+: \\[FinalReference, " + countRegex + ", " + timeRegex + "\\]" + + "#[0-9]+: \\[PhantomReference, " + countRegex + ", " + timeRegex + "\\]" + + "#[0-9]+: \\[JNI Weak Reference, (" + countRegex + ", )?" + timeRegex + "\\]"); + + output.shouldHaveExitValue(0); + } + + static class GCTest { + public static void main(String [] args) { + System.gc(); + } + } +} diff --git a/hotspot/test/runtime/6888954/vmerrors.sh b/hotspot/test/runtime/6888954/vmerrors.sh deleted file mode 100644 index 98540c4d235..00000000000 --- a/hotspot/test/runtime/6888954/vmerrors.sh +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# @test -# @bug 6888954 -# @bug 8015884 -# @summary exercise HotSpot error handling code -# @author John Coomes -# @run shell vmerrors.sh - -# Repeatedly invoke java with a command-line option that causes HotSpot to -# produce an error report and terminate just after initialization. Each -# invocation is identified by a small integer, , which provokes a different -# error (assertion failure, guarantee failure, fatal error, etc.). The output -# from stdout/stderr is written to .out and the hs_err_pidXXX.log file is -# renamed to .log. -# -# The automated checking done by this script is minimal. When updating the -# fatal error handler it is more useful to run it manually or to use the -retain -# option with the jtreg so that test directories are not removed automatically. -# To run stand-alone: -# -# TESTJAVA=/java/home/dir -# TESTVMOPTS=... -# export TESTJAVA TESTVMOPTS -# sh test/runtime/6888954/vmerrors.sh - -if [ "${TESTSRC}" = "" ] -then - TESTSRC=${PWD} - echo "TESTSRC not set. Using "${TESTSRC}" as default" -fi -echo "TESTSRC=${TESTSRC}" - -## Adding common setup Variables for running shell tests. -. ${TESTSRC}/../../test_env.sh - -ulimit -c 0 # no core files - -i=1 -rc=0 - -assert_re='(assert|guarantee)[(](str|num).*failed: *' -# for bad_data_ptr_re: -# EXCEPTION_ACCESS_VIOLATION - Win-* -# SIGILL - MacOS X -# SIGSEGV - Linux-*, Solaris SPARC-*, Solaris X86-* -# -bad_data_ptr_re='(SIGILL|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).* at pc=' -# -# for bad_func_ptr_re: -# EXCEPTION_ACCESS_VIOLATION - Win-* -# SIGBUS - Solaris SPARC-64 -# SIGSEGV - Linux-*, Solaris SPARC-32, Solaris X86-* -# SIGILL - Aix -# -# Note: would like to use "pc=0x00*0f," in the pattern, but Solaris SPARC-* -# gets its signal at a PC in test_error_handler(). -# -bad_func_ptr_re='(SIGBUS|SIGSEGV|SIGILL|EXCEPTION_ACCESS_VIOLATION).* at pc=' -guarantee_re='guarantee[(](str|num).*failed: *' -fatal_re='fatal error: *' -tail_1='.*expected null' -tail_2='.*num=' - -for re in \ - "${assert_re}${tail_1}" "${assert_re}${tail_2}" \ - "${guarantee_re}${tail_1}" "${guarantee_re}${tail_2}" \ - "${fatal_re}${tail_1}" "${fatal_re}${tail_2}" \ - "${fatal_re}.*truncated" "ChunkPool::allocate" \ - "ShouldNotCall" "ShouldNotReachHere" \ - "Unimplemented" "$bad_data_ptr_re" \ - "$bad_func_ptr_re" - -do - i2=$i - [ $i -lt 10 ] && i2=0$i - - "$TESTJAVA/bin/java" $TESTOPTS -XX:+IgnoreUnrecognizedVMOptions \ - -XX:-TransmitErrorReport -XX:-CreateMinidumpOnCrash \ - -XX:ErrorHandlerTest=${i} -version > ${i2}.out 2>&1 - - # If ErrorHandlerTest is ignored (product build), stop. - # - # Using the built-in variable $! to get the pid does not work reliably on - # windows; use a wildcard instead. - mv hs_err_pid*.log ${i2}.log || exit $rc - - for f in ${i2}.log ${i2}.out - do - egrep -- "$re" $f > $$ - if [ $? -ne 0 ] - then - echo "ErrorHandlerTest=$i failed ($f)" - rc=1 - fi - done - rm -f $$ - - i=`expr $i + 1` -done - -exit $rc diff --git a/hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java b/hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java index dc04fd2de58..9d92cf549be 100644 --- a/hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java +++ b/hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java @@ -46,7 +46,7 @@ public class CompilerConfigFileWarning { pb = ProcessTools.createJavaProcessBuilder("-XX:CompileCommandFile=hs_comp.txt", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("CompileCommand: unrecognized command"); - output.shouldContain("aaa aaa"); + output.shouldContain("aaa, aaa"); // Skip on debug builds since we'll always read the file there if (!Platform.isDebugBuild()) { diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java index a4176a9700e..38b3239eb14 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java @@ -51,6 +51,44 @@ public class TestOptionsWithRanges { */ allOptionsAsMap.remove("CICompilerCount"); + /* + * JDK-8136766 + * Temporarily remove ThreadStackSize from testing because Windows can set it to 0 + * (for default OS size) but other platforms insist it must be greater than 0 + */ + allOptionsAsMap.remove("ThreadStackSize"); + + /* + * Exclude MallocMaxTestWords as it is expected to exit VM at small values (>=0) + */ + allOptionsAsMap.remove("MallocMaxTestWords"); + + /* + * Exclude below options as their maximum value would consume too much memory + * and would affect other tests that run in parallel. + */ + allOptionsAsMap.remove("G1ConcRefinementThreads"); + allOptionsAsMap.remove("G1RSetRegionEntries"); + allOptionsAsMap.remove("G1RSetSparseRegionEntries"); + + /* + * Remove parameters controlling the code cache. As these + * parameters have implications on the physical memory + * reserved by the VM, setting them to large values may hang + * the system and/or may cause concurrently executed tests to + * fail. These parameters are rigorously checked when the code + * cache is initialized (see + * hotspot/src/shared/vm/code/codeCache.cpp), therefore + * omitting testing for them does not pose a problem. + */ + allOptionsAsMap.remove("InitialCodeCacheSize"); + allOptionsAsMap.remove("CodeCacheMinimumUseSpace"); + allOptionsAsMap.remove("ReservedCodeCacheSize"); + allOptionsAsMap.remove("NonProfiledCodeHeapSize"); + allOptionsAsMap.remove("ProfiledCodeHeapSize"); + allOptionsAsMap.remove("NonNMethodCodeHeapSize"); + allOptionsAsMap.remove("CodeCacheExpansionSize"); + allOptions = new ArrayList<>(allOptionsAsMap.values()); Asserts.assertGT(allOptions.size(), 0, "Options with ranges not found!"); diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/TestVMOptionsFile.java b/hotspot/test/runtime/CommandLine/VMOptionsFile/TestVMOptionsFile.java new file mode 100644 index 00000000000..12ee773c196 --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/TestVMOptionsFile.java @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8061999 8135195 8136552 + * @summary Test "-XX:VMOptionsFile" VM option + * @library /testlibrary + * @modules jdk.management + * @run main TestVMOptionsFile + */ + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermissions; +import java.nio.file.attribute.AclEntry; +import java.nio.file.attribute.AclEntryPermission; +import java.nio.file.attribute.AclEntryType; +import java.nio.file.attribute.AclFileAttributeView; +import java.nio.file.attribute.UserPrincipal; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import jdk.test.lib.Asserts; +import jdk.test.lib.DynamicVMOption; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class TestVMOptionsFile { + + /* Various valid VM Option files */ + private static final String VM_OPTION_FILE_EMPTY = "optionfile_empty"; + private static final String VM_OPTION_FILE_TABS_AND_SPACES = "optionfile_only_tabsandspaces"; + private static final String VM_OPTION_FILE_1 = "optionfile_1"; + private static final String VM_OPTION_FILE_2 = "optionFILE_2"; + private static final String VM_OPTION_FILE_3 = "optionfile_3"; + private static final String VM_OPTION_FILE_QUOTE = "optionfile_quote"; + private static final String VM_OPTION_FILE_BIG = "optionfile_big"; + private static final int REPEAT_COUNT = 512; + /* Name of the file with flags for VM_OPTION_FILE_2 Option file */ + private static final String FLAGS_FILE = "flags_file"; + /* VM Option file with a lot of options with quote on separate lines */ + private static final String VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE = "optionfile_lot_of_options_quote"; + /* Number of properties defined in VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE */ + private static final int NUM_OF_PROP_IN_FILE_LOT_OF_OPTIONS_QUOTE = 70; + /* VM Option file with long property */ + private static final String VM_OPTION_FILE_WITH_LONG_PROPERTY = "optionfile_long_property"; + private static final String LONG_PROPERTY_NAME = "veryl'" + String.format("%1536s", "").replace(' ', 'o') + "ng'name"; + private static final String LONG_PROPERTY_VALUE = String.format("%2096s", "").replaceAll(" ", "long"); + /* 2 VM Option files with unmatched quotes */ + private static final String VM_OPTION_FILE_UNMATCHED_QUOTE_1 = "optionfile_unmatched_quote_1"; + private static final String VM_OPTION_FILE_UNMATCHED_QUOTE_2 = "optionfile_unmatched_quote_2"; + /* VM Option file with bad option in it */ + private static final String VM_OPTION_FILE_WITH_BAD_OPTION = "optionfile_bad_option"; + /* VM Option file with "-XX:VMOptionsFile=" option in it */ + private static final String VM_OPTION_FILE_WITH_VM_OPTION_FILE = "optionfile_with_optionfile"; + /* VM Option file with "-XX:VMOptionsFile=" option in it, where file is the same option file */ + private static final String VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE = "optionfile_with_same_optionfile"; + /* VM Option file without read permissions(not accessible) */ + private static final String VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS = "optionfile_wo_read_perm"; + /* VM Option file which does not exist */ + private static final String NOT_EXISTING_FILE = "not_exist_junk2123"; + + /* JAVA_TOOL_OPTIONS environment variable */ + private static final String JAVA_TOOL_OPTIONS = "JAVA_TOOL_OPTIONS"; + /* _JAVA_OPTIONS environment variable */ + private static final String JAVA_OPTIONS = "_JAVA_OPTIONS"; + + /* Exit code for JVM, zero - for success, non-zero for failure */ + private static final int JVM_SUCCESS = 0; + private static final int JVM_FAIL_WITH_EXIT_CODE_1 = 1; + + /* Current working directory */ + private static final String CURRENT_DIR = System.getProperty("user.dir"); + + /* Source directory */ + private static final String SOURCE_DIR = System.getProperty("test.src", "."); + + /* VM Options which are passed to the JVM */ + private static final List VMParams = new ArrayList<>(); + /* Argument passed to the PrintPropertyAndOptions.main */ + private static final Set appParams = new LinkedHashSet<>(); + + private static OutputAnalyzer output; + + private static final String PRINT_PROPERTY_FORMAT = "Property %s=%s"; + private static final String PRINT_VM_OPTION_FORMAT = "Virtual Machine option %s=%s"; + + /* + * Get absoulte path to file from folder with sources + */ + private static String getAbsolutePathFromSource(String fileName) { + return SOURCE_DIR + File.separator + fileName; + } + + /* + * Make file non-readable by modifying its permissions. + * If file supports "posix" attributes, then modify it. + * Otherwise check for "acl" attributes. + */ + private static void makeFileNonReadable(String file) throws IOException { + Path filePath = Paths.get(file); + Set supportedAttr = filePath.getFileSystem().supportedFileAttributeViews(); + + if (supportedAttr.contains("posix")) { + Files.setPosixFilePermissions(filePath, PosixFilePermissions.fromString("-w--w----")); + } else if (supportedAttr.contains("acl")) { + UserPrincipal fileOwner = Files.getOwner(filePath); + + AclFileAttributeView view = Files.getFileAttributeView(filePath, AclFileAttributeView.class); + + AclEntry entry = AclEntry.newBuilder() + .setType(AclEntryType.DENY) + .setPrincipal(fileOwner) + .setPermissions(AclEntryPermission.READ_DATA) + .build(); + + List acl = view.getAcl(); + acl.add(0, entry); + view.setAcl(acl); + } + } + + private static void copyFromSource(String fileName) throws IOException { + Files.copy(Paths.get(getAbsolutePathFromSource(fileName)), + Paths.get(fileName), StandardCopyOption.REPLACE_EXISTING); + } + + private static void createOptionFiles() throws IOException { + FileWriter fw = new FileWriter(VM_OPTION_FILE_WITH_VM_OPTION_FILE); + + /* Create VM option file with following parameters "-XX:VMOptionFile= */ + fw.write("-XX:VMOptionsFile=" + getAbsolutePathFromSource(VM_OPTION_FILE_1)); + fw.close(); + + /* Create VM option file with following parameters "-XX:MinHeapFreeRatio=12 -XX:VMOptionFile= */ + fw = new FileWriter(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE); + fw.write("-XX:MinHeapFreeRatio=12 -XX:VMOptionsFile=" + (new File(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE)).getCanonicalPath()); + fw.close(); + + /* Create VM option file with long property */ + fw = new FileWriter(VM_OPTION_FILE_WITH_LONG_PROPERTY); + fw.write("-D" + LONG_PROPERTY_NAME + "=" + LONG_PROPERTY_VALUE); + fw.close(); + + /* Create big VM option file */ + fw = new FileWriter(VM_OPTION_FILE_BIG); + fw.write("-XX:MinHeapFreeRatio=17\n"); + for (int i = 0; i < REPEAT_COUNT; i++) { + if (i == REPEAT_COUNT / 2) { + fw.write("-XX:+PrintVMOptions "); + } + fw.write("-Dmy.property=value" + (i + 1) + "\n"); + } + fw.write("-XX:MaxHeapFreeRatio=85\n"); + fw.close(); + + /* Copy valid VM option file and change its permission to make it not accessible */ + Files.copy(Paths.get(getAbsolutePathFromSource(VM_OPTION_FILE_1)), + Paths.get(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS), + StandardCopyOption.REPLACE_EXISTING); + + makeFileNonReadable(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS); + + /* Copy valid VM option file to perform test with relative path */ + copyFromSource(VM_OPTION_FILE_2); + + /* Copy flags file to the current working folder */ + copyFromSource(FLAGS_FILE); + + /* Create a new empty file */ + new File(VM_OPTION_FILE_EMPTY).createNewFile(); + } + + /* + * Add parameters to the VM Parameters list + */ + private static void addVMParam(String... params) { + VMParams.addAll(Arrays.asList(params)); + } + + /* + * Add VM option name to the application arguments list + */ + private static void addVMOptionsToCheck(String... params) { + for (String param : params) { + appParams.add("vmoption=" + param); + } + } + + /* + * Add property to the VM Params list and to the application arguments list + */ + private static void addProperty(String propertyName, String propertyValue) { + addVMParam("-D" + propertyName + "=" + propertyValue); + } + + /* + * Add "-XX:VMOptionsfile" parameter to the VM Params list + */ + private static void addVMOptionsFile(String fileName) { + addVMParam("-XX:VMOptionsFile=" + fileName); + } + + private static void outputShouldContain(String expectedString) { + output.shouldContain(expectedString); + } + + private static void outputShouldNotContain(String expectedString) { + output.shouldNotContain(expectedString); + } + + private static ProcessBuilder createProcessBuilder() throws Exception { + ProcessBuilder pb; + List runJava = new ArrayList<>(); + + runJava.addAll(VMParams); + runJava.add(PrintPropertyAndOptions.class.getName()); + runJava.addAll(appParams); + + pb = ProcessTools.createJavaProcessBuilder(runJava.toArray(new String[0])); + + VMParams.clear(); + appParams.clear(); + + return pb; + } + + private static void runJavaCheckExitValue(ProcessBuilder pb, int expectedExitValue) throws Exception { + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(expectedExitValue); + } + + private static void runJavaCheckExitValue(int expectedExitValue) throws Exception { + runJavaCheckExitValue(createProcessBuilder(), expectedExitValue); + } + + /* + * Update environment variable in passed ProcessBuilder object to the passed value + */ + private static void updateEnvironment(ProcessBuilder pb, String name, String value) { + pb.environment().put(name, value); + } + + /* + * Check property value by examining output + */ + private static void checkProperty(String property, String expectedValue) { + outputShouldContain(String.format(PRINT_PROPERTY_FORMAT, property, expectedValue)); + } + + /* + * Check VM Option value by examining output + */ + private static void checkVMOption(String vmOption, String expectedValue) { + outputShouldContain(String.format(PRINT_VM_OPTION_FORMAT, vmOption, expectedValue)); + } + + private static void testVMOptions() throws Exception { + /* Check that empty VM Option file is accepted without errors */ + addVMOptionsFile(VM_OPTION_FILE_EMPTY); + + runJavaCheckExitValue(JVM_SUCCESS); + + /* Check that VM Option file with tabs and spaces is accepted without errors */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_TABS_AND_SPACES)); + + runJavaCheckExitValue(JVM_SUCCESS); + + /* Check that parameters are gotten from first VM Option file. Pass absolute path to the VM Option file */ + addVMParam("-showversion"); + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1)); + addVMOptionsToCheck("SurvivorRatio", "MinHeapFreeRatio"); + + runJavaCheckExitValue(JVM_SUCCESS); + outputShouldContain("interpreted mode"); + checkProperty("optfile_1", "option_file_1"); + checkVMOption("SurvivorRatio", "16"); + checkVMOption("MinHeapFreeRatio", "22"); + + /* + * Check that parameters are gotten from second VM Option file which also contains flags file. + * Flags file and option file contains NewRatio, but since options from VM Option file + * are processed later NewRatio should be set to value from VM Option file + * Pass relative path to the VM Option file in form "vmoptionfile" + */ + addVMOptionsFile(VM_OPTION_FILE_2); + addVMOptionsToCheck("UseGCOverheadLimit", "NewRatio", "MinHeapFreeRatio", "MaxFDLimit", "AlwaysPreTouch"); + + runJavaCheckExitValue(JVM_SUCCESS); + checkProperty("javax.net.ssl.keyStorePassword", "someVALUE123+"); + checkVMOption("UseGCOverheadLimit", "true"); + checkVMOption("NewRatio", "4"); + checkVMOption("MinHeapFreeRatio", "3"); + checkVMOption("MaxFDLimit", "true"); + checkVMOption("AlwaysPreTouch", "false"); + + /* Check that parameters are gotten from third VM Option file which contains a mix of the options */ + addVMParam("-showversion"); + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_3)); + addVMOptionsToCheck("UseGCOverheadLimit", "NewRatio"); + + runJavaCheckExitValue(JVM_SUCCESS); + outputShouldContain("interpreted mode"); + checkProperty("other.secret.data", "qwerty"); + checkProperty("property", "second"); + checkVMOption("UseGCOverheadLimit", "false"); + checkVMOption("NewRatio", "16"); + + /* Check that quotes are processed normally in VM Option file */ + addVMParam("-showversion"); + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_QUOTE)); + addVMOptionsToCheck("ErrorFile"); + + runJavaCheckExitValue(JVM_SUCCESS); + + outputShouldContain("interpreted mode"); + checkProperty("my.quote.single", "Property in single quote. Here a double qoute\" Add some slashes \\/"); + checkProperty("my.quote.double", "Double qoute. Include single '."); + checkProperty("javax.net.ssl.trustStorePassword", "data @+NEW"); + checkVMOption("ErrorFile", "./my error file"); + + /* + * Verify that VM Option file accepts a file with 70 properties and with two options on separate + * lines and properties that use quotes a lot. + */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE)); + addVMOptionsToCheck("MinHeapFreeRatio", "MaxHeapFreeRatio"); + + runJavaCheckExitValue(JVM_SUCCESS); + + for (int i = 1; i <= NUM_OF_PROP_IN_FILE_LOT_OF_OPTIONS_QUOTE; i++) { + checkProperty(String.format("prop%02d", i), String.format("%02d", i)); + } + checkVMOption("MinHeapFreeRatio", "7"); + checkVMOption("MaxHeapFreeRatio", "96"); + + /* + * Verify that VM Option file accepts a file with very long property. + */ + addVMOptionsFile(VM_OPTION_FILE_WITH_LONG_PROPERTY); + + runJavaCheckExitValue(JVM_SUCCESS); + + checkProperty(LONG_PROPERTY_NAME.replaceAll("'", ""), LONG_PROPERTY_VALUE); + + /* + * Verify that VM Option file accepts a big VM Option file + */ + addVMOptionsFile(VM_OPTION_FILE_BIG); + addVMOptionsToCheck("MinHeapFreeRatio"); + addVMOptionsToCheck("MaxHeapFreeRatio"); + + runJavaCheckExitValue(JVM_SUCCESS); + + outputShouldContain("VM option '+PrintVMOptions'"); + checkProperty("my.property", "value" + REPEAT_COUNT); + checkVMOption("MinHeapFreeRatio", "17"); + checkVMOption("MaxHeapFreeRatio", "85"); + } + + private static ProcessBuilder prepareTestCase(int testCase) throws Exception { + ProcessBuilder pb; + + Asserts.assertTrue(0 < testCase && testCase < 6, "testCase should be from 1 to 5"); + + addVMParam("-showversion"); + addVMOptionsToCheck("MinHeapFreeRatio", "SurvivorRatio", "NewRatio"); + + if (testCase < 5) { + addVMParam("-XX:Flags=flags_file", "-XX:-PrintVMOptions"); + addProperty("shared.property", "command_line_before"); + addProperty("clb", "unique_command_line_before"); + addVMParam("-XX:MinHeapFreeRatio=7"); + } + + if (testCase < 4) { + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1)); + } + + if (testCase < 3) { + addVMParam("-XX:MinHeapFreeRatio=9", "-XX:-PrintVMOptions"); + addProperty("shared.property", "command_line_after"); + addProperty("cla", "unique_command_line_after"); + } + + /* Create ProcessBuilder after all setup is done to update environment variables */ + pb = createProcessBuilder(); + + if (testCase < 2) { + updateEnvironment(pb, JAVA_OPTIONS, "-Dshared.property=somevalue -Djo=unique_java_options " + + "-XX:MinHeapFreeRatio=18 -Dshared.property=java_options -XX:MinHeapFreeRatio=11 -XX:+PrintVMOptions"); + } + + if (testCase < 6) { + updateEnvironment(pb, JAVA_TOOL_OPTIONS, "-Dshared.property=qwerty -Djto=unique_java_tool_options " + + "-XX:MinHeapFreeRatio=15 -Dshared.property=java_tool_options -XX:MinHeapFreeRatio=6 -XX:+PrintVMOptions"); + } + + return pb; + } + + private static void testVMOptionsLastArgumentsWins() throws Exception { + ProcessBuilder pb; + + /* + * "shared.property" property and "MinHeapFreeRatio" XX VM Option are defined + * in flags file, JAVA_TOOL_OPTIONS and _JAVA_OPTIONS environment variables, + * on command line before VM Option file, on command line after VM Option file + * and also in VM Option file. Verify that last argument wins. Also check + * unique properties and VM Options. + * Here is the order of options processing and last argument wins: + * 1) Flags file + * 2) JAVA_TOOL_OPTIONS environment variables + * 3) Pseudo command line from launcher + * 4) _JAVA_OPTIONS + * In every category arguments processed from left to right and from up to down + * and the last processed arguments wins, i.e. if argument is defined several + * times the value of argument will be equal to the last processed argument. + * + * "shared.property" property and "MinHeapFreeRatio" should be equal to the + * value from _JAVA_OPTIONS environment variable + */ + pb = prepareTestCase(1); + + runJavaCheckExitValue(pb, JVM_SUCCESS); + + outputShouldContain("interpreted mode"); + outputShouldContain("VM option '+PrintVMOptions'"); + checkProperty("shared.property", "java_options"); + checkVMOption("MinHeapFreeRatio", "11"); + /* Each category defines its own properties */ + checkProperty("jto", "unique_java_tool_options"); + checkProperty("jo", "unique_java_options"); + checkProperty("clb", "unique_command_line_before"); + checkProperty("optfile_1", "option_file_1"); + checkProperty("cla", "unique_command_line_after"); + /* SurvivorRatio defined only in VM Option file */ + checkVMOption("SurvivorRatio", "16"); + /* NewRatio defined only in flags file */ + checkVMOption("NewRatio", "5"); + + /* + * The same as previous but without _JAVA_OPTIONS environment variable. + * "shared.property" property and "MinHeapFreeRatio" should be equal to the + * value from pseudo command line after VM Option file + */ + pb = prepareTestCase(2); + + runJavaCheckExitValue(pb, JVM_SUCCESS); + + outputShouldContain("interpreted mode"); + outputShouldNotContain("VM option '+PrintVMOptions'"); + checkProperty("shared.property", "command_line_after"); + checkVMOption("MinHeapFreeRatio", "9"); + + /* + * The same as previous but without arguments in pseudo command line after + * VM Option file. + * "shared.property" property and "MinHeapFreeRatio" should be equal to the + * value from VM Option file. + */ + pb = prepareTestCase(3); + + runJavaCheckExitValue(pb, JVM_SUCCESS); + + outputShouldContain("interpreted mode"); + outputShouldContain("VM option '+PrintVMOptions'"); + checkProperty("shared.property", "vmoptfile"); + checkVMOption("MinHeapFreeRatio", "22"); + + /* + * The same as previous but without arguments in VM Option file. + * "shared.property" property and "MinHeapFreeRatio" should be equal to the + * value from pseudo command line. + */ + pb = prepareTestCase(4); + + runJavaCheckExitValue(pb, JVM_SUCCESS); + + outputShouldNotContain("VM option '+PrintVMOptions'"); + checkProperty("shared.property", "command_line_before"); + checkVMOption("MinHeapFreeRatio", "7"); + + /* + * The same as previous but without arguments from pseudo command line. + * "shared.property" property and "MinHeapFreeRatio" should be equal to the + * value from JAVA_TOOL_OPTIONS environment variable. + */ + pb = prepareTestCase(5); + + runJavaCheckExitValue(pb, JVM_SUCCESS); + + outputShouldContain("VM option '+PrintVMOptions'"); + checkProperty("shared.property", "java_tool_options"); + checkVMOption("MinHeapFreeRatio", "6"); + } + + private static void testVMOptionsInvalid() throws Exception { + ProcessBuilder pb; + + /* Pass directory instead of file */ + addVMOptionsFile(CURRENT_DIR); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + + /* Pass not existing file */ + addVMOptionsFile(getAbsolutePathFromSource(NOT_EXISTING_FILE)); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Could not open options file"); + + /* Pass VM option file with bad option */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_WITH_BAD_OPTION)); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Unrecognized VM option"); + + /* Pass VM option file with same VM option file option in it */ + addVMOptionsFile(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("The VM Options file can only be specified once and only on the command line."); + + /* Pass VM option file with VM option file option in it */ + addVMOptionsFile(VM_OPTION_FILE_WITH_VM_OPTION_FILE); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("The VM Options file can only be specified once and only on the command line."); + + /* Pass VM option file which is not accessible (without read permissions) */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS)); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Could not open options file"); + + /* Pass two VM option files */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1)); + addVMOptionsFile(VM_OPTION_FILE_2); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("The VM Options file can only be specified once and only on the command line."); + + /* Pass empty option file i.e. pass "-XX:VMOptionsFile=" */ + addVMOptionsFile(""); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Could not open options file"); + + /* Pass VM option file with unmatched single quote */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_UNMATCHED_QUOTE_1)); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Unmatched quote in"); + + /* Pass VM option file with unmatched double quote in X option */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_UNMATCHED_QUOTE_2)); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Unmatched quote in"); + + /* Pass VM Option file in _JAVA_OPTIONS environment variable */ + pb = createProcessBuilder(); + + updateEnvironment(pb, JAVA_OPTIONS, "-XX:VMOptionsFile=" + getAbsolutePathFromSource(VM_OPTION_FILE_1)); + + runJavaCheckExitValue(pb, JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("VM options file is only supported on the command line"); + + /* Pass VM Option file in JAVA_TOOL_OPTIONS environment variable */ + pb = createProcessBuilder(); + + updateEnvironment(pb, JAVA_TOOL_OPTIONS, "-XX:VMOptionsFile=" + getAbsolutePathFromSource(VM_OPTION_FILE_1)); + + runJavaCheckExitValue(pb, JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("VM options file is only supported on the command line"); + } + + public static void main(String[] args) throws Exception { + /* + * Preparation before actual testing - create two VM Option files + * which contains VM Option file in it and copy other files to the + * current working folder + */ + createOptionFiles(); + + testVMOptions(); /* Test VM Option file general functionality */ + testVMOptionsLastArgumentsWins(); /* Verify that last argument wins */ + testVMOptionsInvalid(); /* Test invalid VM Option file functionality */ + + } + + public static class PrintPropertyAndOptions { + + public static void main(String[] arguments) { + String vmOption; + Properties properties = System.getProperties(); + + for (String propertyName : properties.stringPropertyNames()) { + System.out.println(String.format(PRINT_PROPERTY_FORMAT, propertyName, System.getProperty(propertyName, "NOT DEFINED"))); + } + + for (String arg : arguments) { + if (arg.startsWith("vmoption=")) { + vmOption = arg.substring(9); + System.out.println(String.format(PRINT_VM_OPTION_FORMAT, vmOption, new DynamicVMOption(vmOption).getValue())); + } + } + } + } +} diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/flags_file b/hotspot/test/runtime/CommandLine/VMOptionsFile/flags_file new file mode 100644 index 00000000000..9c40fb240c2 --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/flags_file @@ -0,0 +1,5 @@ ++MaxFDLimit +-AlwaysPreTouch +MinHeapFreeRatio=3 +MaxHeapFreeRatio=89 +NewRatio=5 diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/optionFILE_2 b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionFILE_2 new file mode 100644 index 00000000000..f01e2b0dbfc --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionFILE_2 @@ -0,0 +1,4 @@ +-XX:+UseGCOverheadLimit +-XX:Flags=flags_file +-Djavax.net.ssl.keyStorePassword=someVALUE123+ +-XX:NewRatio=4 diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_1 b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_1 new file mode 100644 index 00000000000..c191be09bd8 --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_1 @@ -0,0 +1 @@ +-Dshared.property=othervalue -XX:MinHeapFreeRatio=13 -Doptfile_1=option_file_1 -Xint -XX:SurvivorRatio=16 -Xminf0.22 -Dshared.property=vmoptfile -XX:+PrintVMOptions diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_3 b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_3 new file mode 100644 index 00000000000..7249d32d71b --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_3 @@ -0,0 +1,8 @@ +-Xcomp -Dproperty=first + + -Xint +-XX:+UseGCOverheadLimit + + -XX:NewRatio=4 -XX:-UseGCOverheadLimit -Dproperty=second + +-Dother.secret.data=qwerty -XX:NewRatio=16 diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_bad_option b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_bad_option new file mode 100644 index 00000000000..3276d88cb54 --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_bad_option @@ -0,0 +1 @@ +-Dmy.property=user1 -XX:bad_option -Xint diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_lot_of_options_quote b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_lot_of_options_quote new file mode 100644 index 00000000000..362217849aa --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_lot_of_options_quote @@ -0,0 +1,72 @@ +-Dprop01='01' +-Dprop02='02' +-Dprop03='03' +-Dprop04='04' +-Dprop05='05' +-D"pr"op06='06' +-Dprop07='07' +-Dprop08='08' +-Dprop09="09" +-Dprop"10=10" +-Dprop11='11' +'-Dprop12=12' +-Dprop13='13' +-Dprop14='14' +-Dprop15='15' +-Dprop16='16' +-Dprop17='17' +-Dprop18='18' +-Dprop19='19' +-Dprop20='20' +-Dprop21='21' +-Dprop22='22' +-Dprop23='23' +-Dpr'o'p24='24' +-Dprop25='25' +-Dprop26='26' +-Dprop27='27' +-Dprop28='28' +-XX:MinHeapFreeRatio=7 +-D"prop29=29" +-Dprop30='30' +-Dprop31='31' +-Dprop32="32" +-Dprop33='33' +-Dprop34='34' +-Dprop35='35' +'-Dpr'op36='36' +-Dprop37='37' +-Dprop38='38' +-Dprop39='39' +-Dprop40='40' +-Dprop41='41' +-Dprop42='42' +-Dprop43='43' +-Dprop44='44' +-Dprop45='45' +-D"prop46="'46' +-Dprop47='47' +-Dprop48='48' +-Dprop49='49' -XX:MaxHeapFreeRatio=96 +"-"Dprop50='50' +-Dprop51='51' +-Dprop52='52' +-Dprop53='53' +-Dprop54='54' +-Dprop55='55' +-Dprop56='56' +-Dprop57='57' +-"D"prop58='58' +-Dprop59='59' +'-Dprop60=''60' +-Dprop61='61' +-Dprop62='62' +-Dprop63='63' +-Dprop64=64 +-Dprop65=65 +-Dprop66=66 +-Dprop67=67 +-Dprop68=68 +-Dprop69=69 +-Dprop70=70 + diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_only_tabsandspaces b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_only_tabsandspaces new file mode 100644 index 00000000000..281e728f358 --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_only_tabsandspaces @@ -0,0 +1,4 @@ + + + + diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_quote b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_quote new file mode 100644 index 00000000000..e0fd450ca41 --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_quote @@ -0,0 +1 @@ +'-Dmy.quote.single'='Property in single quote. Here a double qoute" Add some slashes \/' -D"my.quote.double"="Double qoute. Include single '." -'Xi'n"t" -X"X:ErrorFile"=./my' error file' -Djavax.net.ssl.trustStorePassword='data @+NEW' diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_1 b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_1 new file mode 100644 index 00000000000..16c1245402d --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_1 @@ -0,0 +1 @@ +-Dmy.quote.single='Unmatched single quote with embedded double " quote diff --git a/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_2 b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_2 new file mode 100644 index 00000000000..a787fc3fb86 --- /dev/null +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_2 @@ -0,0 +1 @@ +-"Xloggc:Unmatched quote in X option diff --git a/hotspot/test/runtime/ErrorHandling/ErrorHandler.java b/hotspot/test/runtime/ErrorHandling/ErrorHandler.java new file mode 100644 index 00000000000..deabd01755f --- /dev/null +++ b/hotspot/test/runtime/ErrorHandling/ErrorHandler.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6888954 + * @bug 8015884 + * @summary Exercise HotSpot error handling code by invoking java with + * -XX:ErrorHandlerTest option to cause an error report. Check the results. + * @library /testlibrary + * @run driver ErrorHandler + */ + +import jdk.test.lib.*; + +public class ErrorHandler { + + public static OutputAnalyzer runTest(int testcase) throws Exception { + return new OutputAnalyzer( + ProcessTools.createJavaProcessBuilder( + "-XX:-TransmitErrorReport", "-XX:-CreateCoredumpOnCrash", "-XX:ErrorHandlerTest=" + testcase) + .start()); + } + + public static void main(String[] args) throws Exception { + // Test is only applicable for debug builds + if (!Platform.isDebugBuild()) { + return; + } + // Keep this in sync with hotspot/src/share/vm/utilities/debug.cpp + int i = 1; + String[] strings = { + "assert(str == NULL) failed: expected null", + "assert(num == 1023 && *str == 'X') failed: num=", + "guarantee(str == NULL) failed: expected null", + "guarantee(num == 1023 && *str == 'X') failed: num=", + "fatal error: expected null", + "fatal error: num=", + "fatal error: this message should be truncated during formatting", + "ChunkPool::allocate", + "Error: ShouldNotCall()", + "Error: ShouldNotReachHere()", + "Error: Unimplemented()" + }; + + String[] patterns = { + "(SIGILL|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).* at pc=", + "(SIGBUS|SIGSEGV|SIGILL|EXCEPTION_ACCESS_VIOLATION).* at pc=" + }; + + for (String s : strings) { + runTest(i++).shouldContain(s); + } + + for (String p : patterns) { + runTest(i++).shouldMatch(p); + } + } +} diff --git a/hotspot/test/runtime/classFileParserBug/InitInInterface.java b/hotspot/test/runtime/classFileParserBug/InitInInterface.java new file mode 100644 index 00000000000..4010b97b0dc --- /dev/null +++ b/hotspot/test/runtime/classFileParserBug/InitInInterface.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8139069 + * @summary Check that any method named in an interface causes ClassFormatError + * @compile nonvoidinit.jasm voidinit.jasm + * @run main InitInInterface + */ + +// Test that an method is not allowed in interfaces. +public class InitInInterface { + public static void main(String args[]) throws Throwable { + + System.out.println("Regression test for bug 8130183"); + try { + Class newClass = Class.forName("nonvoidinit"); + throw new RuntimeException( + "ClassFormatError not thrown for non-void in an interface"); + } catch (java.lang.ClassFormatError e) { + if (!e.getMessage().contains("Interface cannot have a method named ")) { + throw new RuntimeException("Unexpected exception nonvoidint: " + e.getMessage()); + } + } + try { + Class newClass = Class.forName("voidinit"); + throw new RuntimeException( + "ClassFormatError not thrown for void in an interface"); + } catch (java.lang.ClassFormatError e) { + if (!e.getMessage().contains("Interface cannot have a method named ")) { + throw new RuntimeException("Unexpected exception voidint: " + e.getMessage()); + } + } + } +} diff --git a/hotspot/test/runtime/classFileParserBug/nonvoidinit.jasm b/hotspot/test/runtime/classFileParserBug/nonvoidinit.jasm new file mode 100644 index 00000000000..c60a985711c --- /dev/null +++ b/hotspot/test/runtime/classFileParserBug/nonvoidinit.jasm @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// Interface containing non-void method. +public interface nonvoidinit version 50:0 +{ + + public abstract Method "":"()I"; + +} // end Class nonvoidinit diff --git a/hotspot/test/runtime/classFileParserBug/voidinit.jasm b/hotspot/test/runtime/classFileParserBug/voidinit.jasm new file mode 100644 index 00000000000..195a50d2865 --- /dev/null +++ b/hotspot/test/runtime/classFileParserBug/voidinit.jasm @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// Interface containing void method. +public interface voidinit version 50:0 +{ + + public abstract Method "":"()V"; + +} // end Class voidinit diff --git a/hotspot/test/serviceability/dcmd/gc/FinalizationRunner.java b/hotspot/test/serviceability/dcmd/gc/FinalizationRunner.java new file mode 100644 index 00000000000..be73b12e36c --- /dev/null +++ b/hotspot/test/serviceability/dcmd/gc/FinalizationRunner.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.concurrent.CountDownLatch; + +import jdk.test.lib.dcmd.CommandExecutor; +import jdk.test.lib.dcmd.JMXExecutor; + +public class FinalizationRunner { + public static final String FAILED = "Failed"; + public static final String PASSED = "Passed"; + + static volatile boolean wasFinalized = false; + private static final CountDownLatch finRunLatch = new CountDownLatch(1); + private static final CountDownLatch finBlockLatch = new CountDownLatch(1); + + static class MyObject { + @Override + protected void finalize() { + if (Thread.currentThread().getName().equals("Finalizer")) { + try { + System.out.println("inside the regular finalizer thread; blocking"); + // 'regular' finalizer thread is ready to be effectively blocked - + // we can continue with the GC.run_finalization test + finRunLatch.countDown(); + // prevent the 'regular' finalizer from finalizing this instance + // until the GC.run_finalization has had its chance to do so + finBlockLatch.await(); + } catch (InterruptedException e) { + } + } else { + if (Thread.currentThread().getName().equals("Secondary finalizer")) { + System.out.println("finalizing the test instance"); + // finalizing on behalf of GC.run_finalization - + // unblock the 'regular' finalizer and the test main method + wasFinalized = true; + } else { + fail("Unexpected finalizer thread name: " + + Thread.currentThread().getName()); + } + finBlockLatch.countDown(); + } + } + } + + // this instance will be used to provoke the regular finalization + // so the finalizer thread can be blocked for the duration of + // GC.run_finalization test + public static MyObject o1; + + // this instance will be used to perform the GC.run_finalization test + public static MyObject o2; + + private static void run(CommandExecutor executor) { + o2 = new MyObject(); + o2 = null; + System.out.println("running GC.run_finalization"); + System.gc(); + executor.execute("GC.run_finalization"); + + System.out.println("Waiting for finalization"); + + try { + finBlockLatch.await(); + if (wasFinalized) { + System.out.println(PASSED + ": Object was finalized"); + } else { + fail("Object was not finalized"); + } + } catch (InterruptedException e) { + fail("Interrupted while waiting for finalization", e); + } + } + + public static void main(String ... args) { + System.out.println("\n=== FinalizationRunner"); + try { + blockFinalizerThread(); + + Runtime.getRuntime().addShutdownHook(new Thread(()->{ + run(new JMXExecutor()); + })); + } catch (InterruptedException e) { + fail("Interrupted while trying to block the finalizer thread", e); + } + } + + private static void blockFinalizerThread() throws InterruptedException { + System.out.println("trying to block the finalizer thread"); + o1 = new MyObject(); + o1 = null; + System.gc(); + finRunLatch.await(); + } + + private static void fail(String msg, Exception e) { + fail(msg); + e.printStackTrace(System.err); + } + + private static void fail(String msg) { + System.err.println(FAILED + ": " + msg); + } +} diff --git a/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java index bc34351974c..dcc2450757c 100644 --- a/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java +++ b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java @@ -21,13 +21,11 @@ * questions. */ -import java.util.concurrent.Phaser; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.ArrayList; +import java.util.List; -import jdk.test.lib.dcmd.CommandExecutor; -import jdk.test.lib.dcmd.JMXExecutor; -import jdk.test.lib.Utils; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; /* * @test @@ -39,71 +37,21 @@ import jdk.test.lib.Utils; * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* * @build jdk.test.lib.dcmd.* - * @run main/othervm RunFinalizationTest + * @build RunFinalizationTest FinalizationRunner + * @run main RunFinalizationTest */ public class RunFinalizationTest { - private static final long TIMEOUT = Utils.adjustTimeout(15000); // 15s - private static final Phaser ph = new Phaser(3); - static volatile boolean wasFinalized = false; - static volatile boolean wasInitialized = false; + private final static String TEST_APP_NAME = "FinalizationRunner"; - static class MyObject { - public MyObject() { - /* Make sure object allocation/deallocation is not optimized out */ - wasInitialized = true; - } + public static void main(String ... args) throws Exception { + List javaArgs = new ArrayList<>(); + javaArgs.add("-cp"); + javaArgs.add(System.getProperty("test.class.path")); + javaArgs.add(TEST_APP_NAME); + ProcessBuilder testAppPb = ProcessTools.createJavaProcessBuilder(javaArgs.toArray(new String[javaArgs.size()])); - protected void finalize() { - if (!Thread.currentThread().getName().equals("Finalizer")) { - wasFinalized = true; - ph.arrive(); - } else { - ph.arriveAndAwaitAdvance(); - } - } - } - - public static MyObject o; - - private static void run(CommandExecutor executor) { - o = new MyObject(); - o = null; - System.gc(); - executor.execute("GC.run_finalization"); - - System.out.println("Waiting for signal from finalizer"); - - long targetTime = System.currentTimeMillis() + TIMEOUT; - while (System.currentTimeMillis() < targetTime) { - try { - ph.awaitAdvanceInterruptibly(ph.arrive(), 200, TimeUnit.MILLISECONDS); - System.out.println("Received signal"); - break; - } catch (InterruptedException e) { - fail("Test error: Interrupted while waiting for signal from finalizer", e); - } catch (TimeoutException e) { - System.out.println("Haven't received signal in 200ms. Retrying ..."); - } - } - - if (!wasFinalized) { - fail("Test failure: Object was not finalized"); - } - } - - public static void main(String ... args) { - MyObject o = new MyObject(); - o = null; - Runtime.getRuntime().addShutdownHook(new Thread(()->{ - run(new JMXExecutor()); - })); - } - - private static void fail(String msg, Exception e) { - throw new Error(msg, e); - } - - private static void fail(String msg) { - throw new Error(msg); + OutputAnalyzer out = ProcessTools.executeProcess(testAppPb); + out.stderrShouldNotMatch("^" + FinalizationRunner.FAILED + ".*") + .stdoutShouldMatch("^" + FinalizationRunner.PASSED + ".*"); } } diff --git a/hotspot/test/serviceability/logging/TestBasicLogOutput.java b/hotspot/test/serviceability/logging/TestBasicLogOutput.java new file mode 100644 index 00000000000..c74a258f278 --- /dev/null +++ b/hotspot/test/serviceability/logging/TestBasicLogOutput.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestBasicLogOutput + * @summary Ensure logging can be enabled and successfully prints to stdout. + * @library /testlibrary + */ + +import jdk.test.lib.ProcessTools; +import jdk.test.lib.OutputAnalyzer; + +public class TestBasicLogOutput { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:all=trace", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldMatch("\\[logging *\\]"); // expected tag(s) + output.shouldContain("Log configuration fully initialized."); // expected message + output.shouldHaveExitValue(0); + } +} + diff --git a/hotspot/test/serviceability/sa/DeadlockDetectionTest.java b/hotspot/test/serviceability/sa/DeadlockDetectionTest.java new file mode 100644 index 00000000000..637acbd9f27 --- /dev/null +++ b/hotspot/test/serviceability/sa/DeadlockDetectionTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + + +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.apps.LingeredAppWithDeadlock; + +import jdk.test.lib.Utils; +import jdk.test.lib.Platform; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +/* + * @test + * @summary Test deadlock detection + * @library /../../test/lib/share/classes + * @library /testlibrary + * @modules java.management + * @build jdk.test.lib.* + * @build jdk.test.lib.apps.* + * @build DeadlockDetectionTest + * @run main DeadlockDetectionTest + */ + +public class DeadlockDetectionTest { + + private static LingeredAppWithDeadlock theApp = null; + private static ProcessBuilder processBuilder = new ProcessBuilder(); + + private static OutputAnalyzer jstack(String... toolArgs) throws Exception { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb"); + launcher.addToolArg("jstack"); + if (toolArgs != null) { + for (String toolArg : toolArgs) { + launcher.addToolArg(toolArg); + } + } + + processBuilder.command(launcher.getCommand()); + System.out.println(processBuilder.command().stream().collect(Collectors.joining(" "))); + OutputAnalyzer output = ProcessTools.executeProcess(processBuilder); + System.out.println(output.getOutput()); + + return output; + } + + public static void main(String[] args) throws Exception { + System.out.println("Starting DeadlockDetectionTest"); + + if (!Platform.shouldSAAttach()) { + // Silently skip the test if we don't have enough permissions to attach + // Not all conditions checked by function is relevant to SA but it's worth + // to check + System.err.println("Error! Insufficient permissions to attach."); + return; + } + + + if (!LingeredApp.isLastModifiedWorking()) { + // Exact behaviour of the test depends on operating system and the test nature, + // so just print the warning and continue + System.err.println("Warning! Last modified time doesn't work."); + } + + try { + List vmArgs = new ArrayList(); + vmArgs.add("-XX:+UsePerfData"); + vmArgs.addAll(Utils.getVmOptions()); + + theApp = new LingeredAppWithDeadlock(); + LingeredApp.startApp(vmArgs, theApp); + OutputAnalyzer output = jstack("--pid", Long.toString(theApp.getPid())); + System.out.println(output.getOutput()); + + if (output.getExitValue() == 3) { + System.out.println("Test can't run for some reason. Skipping"); + } + else { + output.shouldHaveExitValue(0); + output.shouldContain("Found a total of 1 deadlock."); + } + + } finally { + LingeredApp.stopApp(theApp); + } + } +} diff --git a/hotspot/test/test_env.sh b/hotspot/test/test_env.sh index 660776e2221..23d556e1c6c 100644 --- a/hotspot/test/test_env.sh +++ b/hotspot/test/test_env.sh @@ -111,7 +111,8 @@ if [ $? != 0 ]; then exit 1 fi -${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xinternalversion > vm_version.out 2>&1 +${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xinternalversion | sed -e 's/[(][^)]*[)]//g' -e 's/ by "[^"]*"//g' > vm_version.out 2>&1 +echo "INT_VERSION=`cat vm_version.out 2>&1`" VM_TYPE="unknown" grep "Server" vm_version.out > ${NULL} diff --git a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java index 1a5a034869a..f05a02a61b8 100644 --- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java +++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java @@ -24,7 +24,7 @@ package sun.hotspot.tools.ctw; import sun.hotspot.WhiteBox; -import sun.misc.SharedSecrets; +import jdk.internal.misc.SharedSecrets; import sun.reflect.ConstantPool; import java.lang.reflect.Executable; diff --git a/hotspot/test/testlibrary/jdk/test/lib/FileInstaller.java b/hotspot/test/testlibrary/jdk/test/lib/FileInstaller.java new file mode 100644 index 00000000000..c5f92527258 --- /dev/null +++ b/hotspot/test/testlibrary/jdk/test/lib/FileInstaller.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; + +/** + * Copy a resource: file or directory recursively, using relative path(src and dst) + * which are applied to test source directory(src) and current directory(dst) + */ +public class FileInstaller { + /** + * @param args source and destination + * @throws IOException if an I/O error occurs + */ + public static void main(String[] args) throws IOException { + if (args.length != 2) { + throw new IllegalArgumentException("Unexpected number of arguments for file copy"); + } + Path src = Paths.get(Utils.TEST_SRC, args[0]); + Path dst = Paths.get(args[1]); + if (src.toFile().exists()) { + if (src.toFile().isDirectory()) { + Files.walkFileTree(src, new CopyFileVisitor(src, dst)); + } else { + Path dstDir = dst.getParent(); + if (!dstDir.toFile().exists()) { + Files.createDirectories(dstDir); + } + Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING); + } + } else { + throw new IOException("Can't find source " + src); + } + } + + private static class CopyFileVisitor extends SimpleFileVisitor { + private final Path copyFrom; + private final Path copyTo; + + public CopyFileVisitor(Path copyFrom, Path copyTo) { + this.copyFrom = copyFrom; + this.copyTo = copyTo; + } + + @Override + public FileVisitResult preVisitDirectory(Path file, + BasicFileAttributes attrs) throws IOException { + Path relativePath = file.relativize(copyFrom); + Path destination = copyTo.resolve(relativePath); + if (!destination.toFile().exists()) { + Files.createDirectories(destination); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + if (!file.toFile().isFile()) { + return FileVisitResult.CONTINUE; + } + Path relativePath = copyFrom.relativize(file); + Path destination = copyTo.resolve(relativePath); + Files.copy(file, destination, StandardCopyOption.COPY_ATTRIBUTES); + return FileVisitResult.CONTINUE; + } + } +} diff --git a/hotspot/test/testlibrary/jdk/test/lib/Pair.java b/hotspot/test/testlibrary/jdk/test/lib/Pair.java new file mode 100644 index 00000000000..3e2a3c01ae5 --- /dev/null +++ b/hotspot/test/testlibrary/jdk/test/lib/Pair.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib; + +import java.util.Objects; + +/** + * Pair - a two element tuple + * + * @param first type + * @param second type + */ +public class Pair { + public final F first; + public final S second; + + public Pair(F first, S second) { + this.first = first; + this.second = second; + } + + @Override + public String toString() { + return "(" + first + ":" + second + ")"; + } + + @Override + public boolean equals(Object other) { + if (other instanceof Pair) { + Pair otherPair = (Pair) other; + return Objects.equals(first, otherPair.first) && + Objects.equals(second, otherPair.second); + } + return false; + } + + @Override + public int hashCode() { + if (first == null) { + return (second == null) ? 0 : second.hashCode(); + } else if (second == null) { + return first.hashCode(); + } else { + return first.hashCode() * 17 + second.hashCode(); + } + } +} diff --git a/hotspot/test/testlibrary/jdk/test/lib/Triple.java b/hotspot/test/testlibrary/jdk/test/lib/Triple.java new file mode 100644 index 00000000000..d459aa03af5 --- /dev/null +++ b/hotspot/test/testlibrary/jdk/test/lib/Triple.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib; + +import java.util.Objects; + +/** + * Triple - a three element tuple + * + * @param first element type + * @param second element type + * @param third element type + */ +public class Triple { + private final Pair> container; + + /** + * Constructor + * + * @param first first element of the triple + * @param second second element of the triple + * @param third third element of the triple + */ + public Triple(F first, S second, T third) { + container = new Pair<>(first, new Pair<>(second, third)); + } + + /** + * Gets first element of the triple + */ + public F getFirst() { + return container.first; + } + + /** + * Gets second element of the triple + */ + public S getSecond() { + return container.second.first; + } + + /** + * Gets third element of the triple + */ + public T getThird() { + return container.second.second; + } + + @Override + public int hashCode() { + return container.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Triple) { + Triple objTriple = (Triple) obj; + return Objects.equals(container.first, objTriple.container.first) + && Objects.equals(container.second, + objTriple.container.second); + } + return false; + } + + @Override + public String toString() { + return "(" + getFirst() + " : " + getSecond() + " : " + getThird() + ")"; + } +} diff --git a/hotspot/test/testlibrary/jdk/test/lib/Utils.java b/hotspot/test/testlibrary/jdk/test/lib/Utils.java index a15967bb77b..0518cdd0655 100644 --- a/hotspot/test/testlibrary/jdk/test/lib/Utils.java +++ b/hotspot/test/testlibrary/jdk/test/lib/Utils.java @@ -23,25 +23,31 @@ package jdk.test.lib; +import java.io.File; import static jdk.test.lib.Asserts.assertTrue; import java.io.IOException; import java.lang.reflect.Field; import java.net.InetAddress; +import java.net.MalformedURLException; import java.net.ServerSocket; +import java.net.URL; +import java.net.URLClassLoader; import java.net.UnknownHostException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.function.BooleanSupplier; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import sun.misc.Unsafe; /** @@ -49,6 +55,11 @@ import sun.misc.Unsafe; */ public final class Utils { + /** + * Returns the value of 'test.class.path' system property. + */ + public static final String TEST_CLASS_PATH = System.getProperty("test.class.path", "."); + /** * Returns the sequence used by operating system to separate lines. */ @@ -64,6 +75,11 @@ public final class Utils { */ public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); + /** + * Returns the value of 'test.src' system property. + */ + public static final String TEST_SRC = System.getProperty("test.src", "").trim(); + private static Unsafe unsafe = null; /** @@ -373,6 +389,28 @@ public final class Utils { return RANDOM_GENERATOR; } + /** + * Returns random element of non empty collection + * + * @param a type of collection element + * @param collection collection of elements + * @return random element of collection + * @throws IllegalArgumentException if collection is empty + */ + public static T getRandomElement(Collection collection) + throws IllegalArgumentException { + if (collection.isEmpty()) { + throw new IllegalArgumentException("Empty collection"); + } + Random random = getRandomInstance(); + int elementIndex = 1 + random.nextInt(collection.size() - 1); + Iterator iterator = collection.iterator(); + while (--elementIndex != 0) { + iterator.next(); + } + return iterator.next(); + } + /** * Wait for condition to be true * @@ -429,6 +467,42 @@ public final class Utils { return Math.round(tOut * Utils.TIMEOUT_FACTOR); } + /** + * Ensures a requested class is loaded + * @param aClass class to load + */ + public static void ensureClassIsLoaded(Class aClass) { + if (aClass == null) { + throw new Error("Requested null class"); + } + try { + Class.forName(aClass.getName(), /* initialize = */ true, + ClassLoader.getSystemClassLoader()); + } catch (ClassNotFoundException e) { + throw new Error("Class not found", e); + } + } + /** + * @param parent a class loader to be the parent for the returned one + * @return an UrlClassLoader with urls made of the 'test.class.path' jtreg + * property and with the given parent + */ + public static URLClassLoader getTestClassPathURLClassLoader(ClassLoader parent) { + URL[] urls = Arrays.stream(TEST_CLASS_PATH.split(File.pathSeparator)) + .map(Paths::get) + .map(Path::toUri) + .map(x -> { + try { + return x.toURL(); + } catch (MalformedURLException ex) { + throw new Error("Test issue. JTREG property" + + " 'test.class.path'" + + " is not defined correctly", ex); + } + }).toArray(URL[]::new); + return new URLClassLoader(urls, parent); + } + /** * Runs runnable and checks that it throws expected exception. If exceptionException is null it means * that we expect no exception to be thrown. @@ -436,20 +510,72 @@ public final class Utils { * @param expectedException expected exception */ public static void runAndCheckException(Runnable runnable, Class expectedException) { + runAndCheckException(runnable, t -> { + if (t == null) { + if (expectedException != null) { + throw new AssertionError("Didn't get expected exception " + expectedException.getSimpleName()); + } + } else { + String message = "Got unexpected exception " + t.getClass().getSimpleName(); + if (expectedException == null) { + throw new AssertionError(message, t); + } else if (!expectedException.isAssignableFrom(t.getClass())) { + message += " instead of " + expectedException.getSimpleName(); + throw new AssertionError(message, t); + } + } + }); + } + + /** + * Runs runnable and makes some checks to ensure that it throws expected exception. + * @param runnable what we run + * @param checkException a consumer which checks that we got expected exception and raises a new exception otherwise + */ + public static void runAndCheckException(Runnable runnable, Consumer checkException) { try { runnable.run(); - if (expectedException != null) { - throw new AssertionError("Didn't get expected exception " + expectedException.getSimpleName()); - } + checkException.accept(null); } catch (Throwable t) { - if (expectedException == null) { - throw new AssertionError("Got unexpected exception ", t); - } - if (!expectedException.isAssignableFrom(t.getClass())) { - throw new AssertionError(String.format("Got unexpected exception %s instead of %s", - t.getClass().getSimpleName(), expectedException.getSimpleName()), t); - } + checkException.accept(t); } } + /** + * Converts to VM type signature + * + * @param type Java type to convert + * @return string representation of VM type + */ + public static String toJVMTypeSignature(Class type) { + if (type.isPrimitive()) { + if (type == boolean.class) { + return "Z"; + } else if (type == byte.class) { + return "B"; + } else if (type == char.class) { + return "C"; + } else if (type == double.class) { + return "D"; + } else if (type == float.class) { + return "F"; + } else if (type == int.class) { + return "I"; + } else if (type == long.class) { + return "J"; + } else if (type == short.class) { + return "S"; + } else if (type == void.class) { + return "V"; + } else { + throw new Error("Unsupported type: " + type); + } + } + String result = type.getName().replaceAll("\\.", "/"); + if (!type.isArray()) { + return "L" + result + ";"; + } + return result; + } } + diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java index 2bb93a1ddd0..f3d42bd6c80 100644 --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java @@ -36,9 +36,7 @@ public class DoubleTest { private static final String FLAG_NAME = "CompileThresholdScaling"; - private static final Double[] TESTS = {0d, -0d, -1d, 1d, - Double.MAX_VALUE, Double.MIN_VALUE, Double.NaN, - Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}; + private static final Double[] TESTS = {0d, -0d, 1d, Double.MAX_VALUE}; public static void main(String[] args) throws Exception { VmFlagTest.runTest(FLAG_NAME, TESTS, diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java index ab49784c94e..901d0dd3472 100644 --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java @@ -29,7 +29,7 @@ * @build IntxTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI IntxTest + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-ProfileInterpreter IntxTest * @summary testing of WB::set/getIntxVMFlag() * @author igor.ignatyev@oracle.com */ @@ -37,8 +37,7 @@ public class IntxTest { private static final String FLAG_NAME = "OnStackReplacePercentage"; private static final String FLAG_DEBUG_NAME = "InlineFrequencyCount"; - private static final Long[] TESTS = {0L, 100L, -1L, - (long) Integer.MAX_VALUE, (long) Integer.MIN_VALUE}; + private static final Long[] TESTS = {0L, 100L, (long) Integer.MAX_VALUE}; public static void main(String[] args) throws Exception { VmFlagTest.runTest(FLAG_NAME, TESTS, diff --git a/jdk/.hgtags b/jdk/.hgtags index 4609832ca7f..99f308f0fe3 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -330,3 +330,4 @@ d11f25ce3c545823f53bb978d454a4d2901abac3 jdk9-b83 fe40b31c0e526d357cf5b62044fea006e43b53a5 jdk9-b85 e8a66c0b05d786a282a7ff1d7eb4989afa30c891 jdk9-b86 110fc90bdfa0fe59606c047c2301ed75d2bad6cf jdk9-b87 +6e50b992bef4def597a5033e696e5b1d4fe5b294 jdk9-b88 diff --git a/jdk/make/data/characterdata/CharacterData00.java.template b/jdk/make/data/characterdata/CharacterData00.java.template index 42473074cb0..6183fb5eaad 100644 --- a/jdk/make/data/characterdata/CharacterData00.java.template +++ b/jdk/make/data/characterdata/CharacterData00.java.template @@ -136,101 +136,179 @@ class CharacterData00 extends CharacterData { if ((val & $$maskLowerCase) != 0) { if ((val & $$maskCaseOffset) == $$maskCaseOffset) { switch(ch) { - // map the offset overflow chars - case 0x0130 : mapChar = 0x0069; break; - case 0x2126 : mapChar = 0x03C9; break; - case 0x212A : mapChar = 0x006B; break; - case 0x212B : mapChar = 0x00E5; break; - // map the titlecase chars with both a 1:M uppercase map - // and a lowercase map - case 0x1F88 : mapChar = 0x1F80; break; - case 0x1F89 : mapChar = 0x1F81; break; - case 0x1F8A : mapChar = 0x1F82; break; - case 0x1F8B : mapChar = 0x1F83; break; - case 0x1F8C : mapChar = 0x1F84; break; - case 0x1F8D : mapChar = 0x1F85; break; - case 0x1F8E : mapChar = 0x1F86; break; - case 0x1F8F : mapChar = 0x1F87; break; - case 0x1F98 : mapChar = 0x1F90; break; - case 0x1F99 : mapChar = 0x1F91; break; - case 0x1F9A : mapChar = 0x1F92; break; - case 0x1F9B : mapChar = 0x1F93; break; - case 0x1F9C : mapChar = 0x1F94; break; - case 0x1F9D : mapChar = 0x1F95; break; - case 0x1F9E : mapChar = 0x1F96; break; - case 0x1F9F : mapChar = 0x1F97; break; - case 0x1FA8 : mapChar = 0x1FA0; break; - case 0x1FA9 : mapChar = 0x1FA1; break; - case 0x1FAA : mapChar = 0x1FA2; break; - case 0x1FAB : mapChar = 0x1FA3; break; - case 0x1FAC : mapChar = 0x1FA4; break; - case 0x1FAD : mapChar = 0x1FA5; break; - case 0x1FAE : mapChar = 0x1FA6; break; - case 0x1FAF : mapChar = 0x1FA7; break; - case 0x1FBC : mapChar = 0x1FB3; break; - case 0x1FCC : mapChar = 0x1FC3; break; - case 0x1FFC : mapChar = 0x1FF3; break; - - case 0x023A : mapChar = 0x2C65; break; - case 0x023E : mapChar = 0x2C66; break; - case 0x10A0 : mapChar = 0x2D00; break; - case 0x10A1 : mapChar = 0x2D01; break; - case 0x10A2 : mapChar = 0x2D02; break; - case 0x10A3 : mapChar = 0x2D03; break; - case 0x10A4 : mapChar = 0x2D04; break; - case 0x10A5 : mapChar = 0x2D05; break; - case 0x10A6 : mapChar = 0x2D06; break; - case 0x10A7 : mapChar = 0x2D07; break; - case 0x10A8 : mapChar = 0x2D08; break; - case 0x10A9 : mapChar = 0x2D09; break; - case 0x10AA : mapChar = 0x2D0A; break; - case 0x10AB : mapChar = 0x2D0B; break; - case 0x10AC : mapChar = 0x2D0C; break; - case 0x10AD : mapChar = 0x2D0D; break; - case 0x10AE : mapChar = 0x2D0E; break; - case 0x10AF : mapChar = 0x2D0F; break; - case 0x10B0 : mapChar = 0x2D10; break; - case 0x10B1 : mapChar = 0x2D11; break; - case 0x10B2 : mapChar = 0x2D12; break; - case 0x10B3 : mapChar = 0x2D13; break; - case 0x10B4 : mapChar = 0x2D14; break; - case 0x10B5 : mapChar = 0x2D15; break; - case 0x10B6 : mapChar = 0x2D16; break; - case 0x10B7 : mapChar = 0x2D17; break; - case 0x10B8 : mapChar = 0x2D18; break; - case 0x10B9 : mapChar = 0x2D19; break; - case 0x10BA : mapChar = 0x2D1A; break; - case 0x10BB : mapChar = 0x2D1B; break; - case 0x10BC : mapChar = 0x2D1C; break; - case 0x10BD : mapChar = 0x2D1D; break; - case 0x10BE : mapChar = 0x2D1E; break; - case 0x10BF : mapChar = 0x2D1F; break; - case 0x10C0 : mapChar = 0x2D20; break; - case 0x10C1 : mapChar = 0x2D21; break; - case 0x10C2 : mapChar = 0x2D22; break; - case 0x10C3 : mapChar = 0x2D23; break; - case 0x10C4 : mapChar = 0x2D24; break; - case 0x10C5 : mapChar = 0x2D25; break; - case 0x10C7 : mapChar = 0x2D27; break; - case 0x10CD : mapChar = 0x2D2D; break; - case 0x1E9E : mapChar = 0x00DF; break; - case 0x2C62 : mapChar = 0x026B; break; - case 0x2C63 : mapChar = 0x1D7D; break; - case 0x2C64 : mapChar = 0x027D; break; - case 0x2C6D : mapChar = 0x0251; break; - case 0x2C6E : mapChar = 0x0271; break; - case 0x2C6F : mapChar = 0x0250; break; - case 0x2C70 : mapChar = 0x0252; break; - case 0x2C7E : mapChar = 0x023F; break; - case 0x2C7F : mapChar = 0x0240; break; - case 0xA77D : mapChar = 0x1D79; break; - case 0xA78D : mapChar = 0x0265; break; - case 0xA7AA : mapChar = 0x0266; break; - case 0xA7AB : mapChar = 0x025C; break; - case 0xA7AC : mapChar = 0x0261; break; - case 0xA7AD : mapChar = 0x026C; break; - case 0xA7B0 : mapChar = 0x029E; break; - case 0xA7B1 : mapChar = 0x0287; break; + case 0x0130: mapChar = 0x0069; break; + case 0x023A: mapChar = 0x2C65; break; + case 0x023E: mapChar = 0x2C66; break; + case 0x10A0: mapChar = 0x2D00; break; + case 0x10A1: mapChar = 0x2D01; break; + case 0x10A2: mapChar = 0x2D02; break; + case 0x10A3: mapChar = 0x2D03; break; + case 0x10A4: mapChar = 0x2D04; break; + case 0x10A5: mapChar = 0x2D05; break; + case 0x10A6: mapChar = 0x2D06; break; + case 0x10A7: mapChar = 0x2D07; break; + case 0x10A8: mapChar = 0x2D08; break; + case 0x10A9: mapChar = 0x2D09; break; + case 0x10AA: mapChar = 0x2D0A; break; + case 0x10AB: mapChar = 0x2D0B; break; + case 0x10AC: mapChar = 0x2D0C; break; + case 0x10AD: mapChar = 0x2D0D; break; + case 0x10AE: mapChar = 0x2D0E; break; + case 0x10AF: mapChar = 0x2D0F; break; + case 0x10B0: mapChar = 0x2D10; break; + case 0x10B1: mapChar = 0x2D11; break; + case 0x10B2: mapChar = 0x2D12; break; + case 0x10B3: mapChar = 0x2D13; break; + case 0x10B4: mapChar = 0x2D14; break; + case 0x10B5: mapChar = 0x2D15; break; + case 0x10B6: mapChar = 0x2D16; break; + case 0x10B7: mapChar = 0x2D17; break; + case 0x10B8: mapChar = 0x2D18; break; + case 0x10B9: mapChar = 0x2D19; break; + case 0x10BA: mapChar = 0x2D1A; break; + case 0x10BB: mapChar = 0x2D1B; break; + case 0x10BC: mapChar = 0x2D1C; break; + case 0x10BD: mapChar = 0x2D1D; break; + case 0x10BE: mapChar = 0x2D1E; break; + case 0x10BF: mapChar = 0x2D1F; break; + case 0x10C0: mapChar = 0x2D20; break; + case 0x10C1: mapChar = 0x2D21; break; + case 0x10C2: mapChar = 0x2D22; break; + case 0x10C3: mapChar = 0x2D23; break; + case 0x10C4: mapChar = 0x2D24; break; + case 0x10C5: mapChar = 0x2D25; break; + case 0x10C7: mapChar = 0x2D27; break; + case 0x10CD: mapChar = 0x2D2D; break; + case 0x13A0: mapChar = 0xAB70; break; + case 0x13A1: mapChar = 0xAB71; break; + case 0x13A2: mapChar = 0xAB72; break; + case 0x13A3: mapChar = 0xAB73; break; + case 0x13A4: mapChar = 0xAB74; break; + case 0x13A5: mapChar = 0xAB75; break; + case 0x13A6: mapChar = 0xAB76; break; + case 0x13A7: mapChar = 0xAB77; break; + case 0x13A8: mapChar = 0xAB78; break; + case 0x13A9: mapChar = 0xAB79; break; + case 0x13AA: mapChar = 0xAB7A; break; + case 0x13AB: mapChar = 0xAB7B; break; + case 0x13AC: mapChar = 0xAB7C; break; + case 0x13AD: mapChar = 0xAB7D; break; + case 0x13AE: mapChar = 0xAB7E; break; + case 0x13AF: mapChar = 0xAB7F; break; + case 0x13B0: mapChar = 0xAB80; break; + case 0x13B1: mapChar = 0xAB81; break; + case 0x13B2: mapChar = 0xAB82; break; + case 0x13B3: mapChar = 0xAB83; break; + case 0x13B4: mapChar = 0xAB84; break; + case 0x13B5: mapChar = 0xAB85; break; + case 0x13B6: mapChar = 0xAB86; break; + case 0x13B7: mapChar = 0xAB87; break; + case 0x13B8: mapChar = 0xAB88; break; + case 0x13B9: mapChar = 0xAB89; break; + case 0x13BA: mapChar = 0xAB8A; break; + case 0x13BB: mapChar = 0xAB8B; break; + case 0x13BC: mapChar = 0xAB8C; break; + case 0x13BD: mapChar = 0xAB8D; break; + case 0x13BE: mapChar = 0xAB8E; break; + case 0x13BF: mapChar = 0xAB8F; break; + case 0x13C0: mapChar = 0xAB90; break; + case 0x13C1: mapChar = 0xAB91; break; + case 0x13C2: mapChar = 0xAB92; break; + case 0x13C3: mapChar = 0xAB93; break; + case 0x13C4: mapChar = 0xAB94; break; + case 0x13C5: mapChar = 0xAB95; break; + case 0x13C6: mapChar = 0xAB96; break; + case 0x13C7: mapChar = 0xAB97; break; + case 0x13C8: mapChar = 0xAB98; break; + case 0x13C9: mapChar = 0xAB99; break; + case 0x13CA: mapChar = 0xAB9A; break; + case 0x13CB: mapChar = 0xAB9B; break; + case 0x13CC: mapChar = 0xAB9C; break; + case 0x13CD: mapChar = 0xAB9D; break; + case 0x13CE: mapChar = 0xAB9E; break; + case 0x13CF: mapChar = 0xAB9F; break; + case 0x13D0: mapChar = 0xABA0; break; + case 0x13D1: mapChar = 0xABA1; break; + case 0x13D2: mapChar = 0xABA2; break; + case 0x13D3: mapChar = 0xABA3; break; + case 0x13D4: mapChar = 0xABA4; break; + case 0x13D5: mapChar = 0xABA5; break; + case 0x13D6: mapChar = 0xABA6; break; + case 0x13D7: mapChar = 0xABA7; break; + case 0x13D8: mapChar = 0xABA8; break; + case 0x13D9: mapChar = 0xABA9; break; + case 0x13DA: mapChar = 0xABAA; break; + case 0x13DB: mapChar = 0xABAB; break; + case 0x13DC: mapChar = 0xABAC; break; + case 0x13DD: mapChar = 0xABAD; break; + case 0x13DE: mapChar = 0xABAE; break; + case 0x13DF: mapChar = 0xABAF; break; + case 0x13E0: mapChar = 0xABB0; break; + case 0x13E1: mapChar = 0xABB1; break; + case 0x13E2: mapChar = 0xABB2; break; + case 0x13E3: mapChar = 0xABB3; break; + case 0x13E4: mapChar = 0xABB4; break; + case 0x13E5: mapChar = 0xABB5; break; + case 0x13E6: mapChar = 0xABB6; break; + case 0x13E7: mapChar = 0xABB7; break; + case 0x13E8: mapChar = 0xABB8; break; + case 0x13E9: mapChar = 0xABB9; break; + case 0x13EA: mapChar = 0xABBA; break; + case 0x13EB: mapChar = 0xABBB; break; + case 0x13EC: mapChar = 0xABBC; break; + case 0x13ED: mapChar = 0xABBD; break; + case 0x13EE: mapChar = 0xABBE; break; + case 0x13EF: mapChar = 0xABBF; break; + case 0x1E9E: mapChar = 0x00DF; break; + case 0x1F88: mapChar = 0x1F80; break; + case 0x1F89: mapChar = 0x1F81; break; + case 0x1F8A: mapChar = 0x1F82; break; + case 0x1F8B: mapChar = 0x1F83; break; + case 0x1F8C: mapChar = 0x1F84; break; + case 0x1F8D: mapChar = 0x1F85; break; + case 0x1F8E: mapChar = 0x1F86; break; + case 0x1F8F: mapChar = 0x1F87; break; + case 0x1F98: mapChar = 0x1F90; break; + case 0x1F99: mapChar = 0x1F91; break; + case 0x1F9A: mapChar = 0x1F92; break; + case 0x1F9B: mapChar = 0x1F93; break; + case 0x1F9C: mapChar = 0x1F94; break; + case 0x1F9D: mapChar = 0x1F95; break; + case 0x1F9E: mapChar = 0x1F96; break; + case 0x1F9F: mapChar = 0x1F97; break; + case 0x1FA8: mapChar = 0x1FA0; break; + case 0x1FA9: mapChar = 0x1FA1; break; + case 0x1FAA: mapChar = 0x1FA2; break; + case 0x1FAB: mapChar = 0x1FA3; break; + case 0x1FAC: mapChar = 0x1FA4; break; + case 0x1FAD: mapChar = 0x1FA5; break; + case 0x1FAE: mapChar = 0x1FA6; break; + case 0x1FAF: mapChar = 0x1FA7; break; + case 0x1FBC: mapChar = 0x1FB3; break; + case 0x1FCC: mapChar = 0x1FC3; break; + case 0x1FFC: mapChar = 0x1FF3; break; + case 0x2126: mapChar = 0x03C9; break; + case 0x212A: mapChar = 0x006B; break; + case 0x212B: mapChar = 0x00E5; break; + case 0x2C62: mapChar = 0x026B; break; + case 0x2C63: mapChar = 0x1D7D; break; + case 0x2C64: mapChar = 0x027D; break; + case 0x2C6D: mapChar = 0x0251; break; + case 0x2C6E: mapChar = 0x0271; break; + case 0x2C6F: mapChar = 0x0250; break; + case 0x2C70: mapChar = 0x0252; break; + case 0x2C7E: mapChar = 0x023F; break; + case 0x2C7F: mapChar = 0x0240; break; + case 0xA77D: mapChar = 0x1D79; break; + case 0xA78D: mapChar = 0x0265; break; + case 0xA7AA: mapChar = 0x0266; break; + case 0xA7AB: mapChar = 0x025C; break; + case 0xA7AC: mapChar = 0x0261; break; + case 0xA7AD: mapChar = 0x026C; break; + case 0xA7B0: mapChar = 0x029E; break; + case 0xA7B1: mapChar = 0x0287; break; + case 0xA7B2: mapChar = 0x029D; break; + case 0xA7B3: mapChar = 0xAB53; break; // default mapChar is already set, so no // need to redo it here. // default : mapChar = ch; @@ -251,98 +329,176 @@ class CharacterData00 extends CharacterData { if ((val & $$maskUpperCase) != 0) { if ((val & $$maskCaseOffset) == $$maskCaseOffset) { switch(ch) { - // map chars with overflow offsets - case 0x00B5 : mapChar = 0x039C; break; - case 0x017F : mapChar = 0x0053; break; - case 0x1FBE : mapChar = 0x0399; break; - // map char that have both a 1:1 and 1:M map - case 0x1F80 : mapChar = 0x1F88; break; - case 0x1F81 : mapChar = 0x1F89; break; - case 0x1F82 : mapChar = 0x1F8A; break; - case 0x1F83 : mapChar = 0x1F8B; break; - case 0x1F84 : mapChar = 0x1F8C; break; - case 0x1F85 : mapChar = 0x1F8D; break; - case 0x1F86 : mapChar = 0x1F8E; break; - case 0x1F87 : mapChar = 0x1F8F; break; - case 0x1F90 : mapChar = 0x1F98; break; - case 0x1F91 : mapChar = 0x1F99; break; - case 0x1F92 : mapChar = 0x1F9A; break; - case 0x1F93 : mapChar = 0x1F9B; break; - case 0x1F94 : mapChar = 0x1F9C; break; - case 0x1F95 : mapChar = 0x1F9D; break; - case 0x1F96 : mapChar = 0x1F9E; break; - case 0x1F97 : mapChar = 0x1F9F; break; - case 0x1FA0 : mapChar = 0x1FA8; break; - case 0x1FA1 : mapChar = 0x1FA9; break; - case 0x1FA2 : mapChar = 0x1FAA; break; - case 0x1FA3 : mapChar = 0x1FAB; break; - case 0x1FA4 : mapChar = 0x1FAC; break; - case 0x1FA5 : mapChar = 0x1FAD; break; - case 0x1FA6 : mapChar = 0x1FAE; break; - case 0x1FA7 : mapChar = 0x1FAF; break; - case 0x1FB3 : mapChar = 0x1FBC; break; - case 0x1FC3 : mapChar = 0x1FCC; break; - case 0x1FF3 : mapChar = 0x1FFC; break; - - case 0x023F : mapChar = 0x2C7E; break; - case 0x0240 : mapChar = 0x2C7F; break; - case 0x0250 : mapChar = 0x2C6F; break; - case 0x0251 : mapChar = 0x2C6D; break; - case 0x0252 : mapChar = 0x2C70; break; - case 0x025C : mapChar = 0xA7AB; break; - case 0x0261 : mapChar = 0xA7AC; break; - case 0x0265 : mapChar = 0xA78D; break; - case 0x0266 : mapChar = 0xA7AA; break; - case 0x026B : mapChar = 0x2C62; break; - case 0x026C : mapChar = 0xA7AD; break; - case 0x0271 : mapChar = 0x2C6E; break; - case 0x0287 : mapChar = 0xA7B1; break; - case 0x029E : mapChar = 0xA7B0; break; - case 0x027D : mapChar = 0x2C64; break; - case 0x1D79 : mapChar = 0xA77D; break; - case 0x1D7D : mapChar = 0x2C63; break; - case 0x2C65 : mapChar = 0x023A; break; - case 0x2C66 : mapChar = 0x023E; break; - case 0x2D00 : mapChar = 0x10A0; break; - case 0x2D01 : mapChar = 0x10A1; break; - case 0x2D02 : mapChar = 0x10A2; break; - case 0x2D03 : mapChar = 0x10A3; break; - case 0x2D04 : mapChar = 0x10A4; break; - case 0x2D05 : mapChar = 0x10A5; break; - case 0x2D06 : mapChar = 0x10A6; break; - case 0x2D07 : mapChar = 0x10A7; break; - case 0x2D08 : mapChar = 0x10A8; break; - case 0x2D09 : mapChar = 0x10A9; break; - case 0x2D0A : mapChar = 0x10AA; break; - case 0x2D0B : mapChar = 0x10AB; break; - case 0x2D0C : mapChar = 0x10AC; break; - case 0x2D0D : mapChar = 0x10AD; break; - case 0x2D0E : mapChar = 0x10AE; break; - case 0x2D0F : mapChar = 0x10AF; break; - case 0x2D10 : mapChar = 0x10B0; break; - case 0x2D11 : mapChar = 0x10B1; break; - case 0x2D12 : mapChar = 0x10B2; break; - case 0x2D13 : mapChar = 0x10B3; break; - case 0x2D14 : mapChar = 0x10B4; break; - case 0x2D15 : mapChar = 0x10B5; break; - case 0x2D16 : mapChar = 0x10B6; break; - case 0x2D17 : mapChar = 0x10B7; break; - case 0x2D18 : mapChar = 0x10B8; break; - case 0x2D19 : mapChar = 0x10B9; break; - case 0x2D1A : mapChar = 0x10BA; break; - case 0x2D1B : mapChar = 0x10BB; break; - case 0x2D1C : mapChar = 0x10BC; break; - case 0x2D1D : mapChar = 0x10BD; break; - case 0x2D1E : mapChar = 0x10BE; break; - case 0x2D1F : mapChar = 0x10BF; break; - case 0x2D20 : mapChar = 0x10C0; break; - case 0x2D21 : mapChar = 0x10C1; break; - case 0x2D22 : mapChar = 0x10C2; break; - case 0x2D23 : mapChar = 0x10C3; break; - case 0x2D24 : mapChar = 0x10C4; break; - case 0x2D25 : mapChar = 0x10C5; break; - case 0x2D27 : mapChar = 0x10C7; break; - case 0x2D2D : mapChar = 0x10CD; break; + case 0x017F: mapChar = 0x0053; break; + case 0x023F: mapChar = 0x2C7E; break; + case 0x0240: mapChar = 0x2C7F; break; + case 0x0250: mapChar = 0x2C6F; break; + case 0x0251: mapChar = 0x2C6D; break; + case 0x0252: mapChar = 0x2C70; break; + case 0x025C: mapChar = 0xA7AB; break; + case 0x0261: mapChar = 0xA7AC; break; + case 0x0265: mapChar = 0xA78D; break; + case 0x0266: mapChar = 0xA7AA; break; + case 0x026B: mapChar = 0x2C62; break; + case 0x026C: mapChar = 0xA7AD; break; + case 0x0271: mapChar = 0x2C6E; break; + case 0x027D: mapChar = 0x2C64; break; + case 0x0287: mapChar = 0xA7B1; break; + case 0x029D: mapChar = 0xA7B2; break; + case 0x029E: mapChar = 0xA7B0; break; + case 0x1D79: mapChar = 0xA77D; break; + case 0x1D7D: mapChar = 0x2C63; break; + case 0x1F80: mapChar = 0x1F88; break; + case 0x1F81: mapChar = 0x1F89; break; + case 0x1F82: mapChar = 0x1F8A; break; + case 0x1F83: mapChar = 0x1F8B; break; + case 0x1F84: mapChar = 0x1F8C; break; + case 0x1F85: mapChar = 0x1F8D; break; + case 0x1F86: mapChar = 0x1F8E; break; + case 0x1F87: mapChar = 0x1F8F; break; + case 0x1F90: mapChar = 0x1F98; break; + case 0x1F91: mapChar = 0x1F99; break; + case 0x1F92: mapChar = 0x1F9A; break; + case 0x1F93: mapChar = 0x1F9B; break; + case 0x1F94: mapChar = 0x1F9C; break; + case 0x1F95: mapChar = 0x1F9D; break; + case 0x1F96: mapChar = 0x1F9E; break; + case 0x1F97: mapChar = 0x1F9F; break; + case 0x1FA0: mapChar = 0x1FA8; break; + case 0x1FA1: mapChar = 0x1FA9; break; + case 0x1FA2: mapChar = 0x1FAA; break; + case 0x1FA3: mapChar = 0x1FAB; break; + case 0x1FA4: mapChar = 0x1FAC; break; + case 0x1FA5: mapChar = 0x1FAD; break; + case 0x1FA6: mapChar = 0x1FAE; break; + case 0x1FA7: mapChar = 0x1FAF; break; + case 0x1FB3: mapChar = 0x1FBC; break; + case 0x1FBE: mapChar = 0x0399; break; + case 0x1FC3: mapChar = 0x1FCC; break; + case 0x1FF3: mapChar = 0x1FFC; break; + case 0x2C65: mapChar = 0x023A; break; + case 0x2C66: mapChar = 0x023E; break; + case 0x2D00: mapChar = 0x10A0; break; + case 0x2D01: mapChar = 0x10A1; break; + case 0x2D02: mapChar = 0x10A2; break; + case 0x2D03: mapChar = 0x10A3; break; + case 0x2D04: mapChar = 0x10A4; break; + case 0x2D05: mapChar = 0x10A5; break; + case 0x2D06: mapChar = 0x10A6; break; + case 0x2D07: mapChar = 0x10A7; break; + case 0x2D08: mapChar = 0x10A8; break; + case 0x2D09: mapChar = 0x10A9; break; + case 0x2D0A: mapChar = 0x10AA; break; + case 0x2D0B: mapChar = 0x10AB; break; + case 0x2D0C: mapChar = 0x10AC; break; + case 0x2D0D: mapChar = 0x10AD; break; + case 0x2D0E: mapChar = 0x10AE; break; + case 0x2D0F: mapChar = 0x10AF; break; + case 0x2D10: mapChar = 0x10B0; break; + case 0x2D11: mapChar = 0x10B1; break; + case 0x2D12: mapChar = 0x10B2; break; + case 0x2D13: mapChar = 0x10B3; break; + case 0x2D14: mapChar = 0x10B4; break; + case 0x2D15: mapChar = 0x10B5; break; + case 0x2D16: mapChar = 0x10B6; break; + case 0x2D17: mapChar = 0x10B7; break; + case 0x2D18: mapChar = 0x10B8; break; + case 0x2D19: mapChar = 0x10B9; break; + case 0x2D1A: mapChar = 0x10BA; break; + case 0x2D1B: mapChar = 0x10BB; break; + case 0x2D1C: mapChar = 0x10BC; break; + case 0x2D1D: mapChar = 0x10BD; break; + case 0x2D1E: mapChar = 0x10BE; break; + case 0x2D1F: mapChar = 0x10BF; break; + case 0x2D20: mapChar = 0x10C0; break; + case 0x2D21: mapChar = 0x10C1; break; + case 0x2D22: mapChar = 0x10C2; break; + case 0x2D23: mapChar = 0x10C3; break; + case 0x2D24: mapChar = 0x10C4; break; + case 0x2D25: mapChar = 0x10C5; break; + case 0x2D27: mapChar = 0x10C7; break; + case 0x2D2D: mapChar = 0x10CD; break; + case 0xAB53: mapChar = 0xA7B3; break; + case 0xAB70: mapChar = 0x13A0; break; + case 0xAB71: mapChar = 0x13A1; break; + case 0xAB72: mapChar = 0x13A2; break; + case 0xAB73: mapChar = 0x13A3; break; + case 0xAB74: mapChar = 0x13A4; break; + case 0xAB75: mapChar = 0x13A5; break; + case 0xAB76: mapChar = 0x13A6; break; + case 0xAB77: mapChar = 0x13A7; break; + case 0xAB78: mapChar = 0x13A8; break; + case 0xAB79: mapChar = 0x13A9; break; + case 0xAB7A: mapChar = 0x13AA; break; + case 0xAB7B: mapChar = 0x13AB; break; + case 0xAB7C: mapChar = 0x13AC; break; + case 0xAB7D: mapChar = 0x13AD; break; + case 0xAB7E: mapChar = 0x13AE; break; + case 0xAB7F: mapChar = 0x13AF; break; + case 0xAB80: mapChar = 0x13B0; break; + case 0xAB81: mapChar = 0x13B1; break; + case 0xAB82: mapChar = 0x13B2; break; + case 0xAB83: mapChar = 0x13B3; break; + case 0xAB84: mapChar = 0x13B4; break; + case 0xAB85: mapChar = 0x13B5; break; + case 0xAB86: mapChar = 0x13B6; break; + case 0xAB87: mapChar = 0x13B7; break; + case 0xAB88: mapChar = 0x13B8; break; + case 0xAB89: mapChar = 0x13B9; break; + case 0xAB8A: mapChar = 0x13BA; break; + case 0xAB8B: mapChar = 0x13BB; break; + case 0xAB8C: mapChar = 0x13BC; break; + case 0xAB8D: mapChar = 0x13BD; break; + case 0xAB8E: mapChar = 0x13BE; break; + case 0xAB8F: mapChar = 0x13BF; break; + case 0xAB90: mapChar = 0x13C0; break; + case 0xAB91: mapChar = 0x13C1; break; + case 0xAB92: mapChar = 0x13C2; break; + case 0xAB93: mapChar = 0x13C3; break; + case 0xAB94: mapChar = 0x13C4; break; + case 0xAB95: mapChar = 0x13C5; break; + case 0xAB96: mapChar = 0x13C6; break; + case 0xAB97: mapChar = 0x13C7; break; + case 0xAB98: mapChar = 0x13C8; break; + case 0xAB99: mapChar = 0x13C9; break; + case 0xAB9A: mapChar = 0x13CA; break; + case 0xAB9B: mapChar = 0x13CB; break; + case 0xAB9C: mapChar = 0x13CC; break; + case 0xAB9D: mapChar = 0x13CD; break; + case 0xAB9E: mapChar = 0x13CE; break; + case 0xAB9F: mapChar = 0x13CF; break; + case 0xABA0: mapChar = 0x13D0; break; + case 0xABA1: mapChar = 0x13D1; break; + case 0xABA2: mapChar = 0x13D2; break; + case 0xABA3: mapChar = 0x13D3; break; + case 0xABA4: mapChar = 0x13D4; break; + case 0xABA5: mapChar = 0x13D5; break; + case 0xABA6: mapChar = 0x13D6; break; + case 0xABA7: mapChar = 0x13D7; break; + case 0xABA8: mapChar = 0x13D8; break; + case 0xABA9: mapChar = 0x13D9; break; + case 0xABAA: mapChar = 0x13DA; break; + case 0xABAB: mapChar = 0x13DB; break; + case 0xABAC: mapChar = 0x13DC; break; + case 0xABAD: mapChar = 0x13DD; break; + case 0xABAE: mapChar = 0x13DE; break; + case 0xABAF: mapChar = 0x13DF; break; + case 0xABB0: mapChar = 0x13E0; break; + case 0xABB1: mapChar = 0x13E1; break; + case 0xABB2: mapChar = 0x13E2; break; + case 0xABB3: mapChar = 0x13E3; break; + case 0xABB4: mapChar = 0x13E4; break; + case 0xABB5: mapChar = 0x13E5; break; + case 0xABB6: mapChar = 0x13E6; break; + case 0xABB7: mapChar = 0x13E7; break; + case 0xABB8: mapChar = 0x13E8; break; + case 0xABB9: mapChar = 0x13E9; break; + case 0xABBA: mapChar = 0x13EA; break; + case 0xABBB: mapChar = 0x13EB; break; + case 0xABBC: mapChar = 0x13EC; break; + case 0xABBD: mapChar = 0x13ED; break; + case 0xABBE: mapChar = 0x13EE; break; + case 0xABBF: mapChar = 0x13EF; break; // ch must have a 1:M case mapping, but we // can't handle it here. Return ch. // since mapChar is already set, no need @@ -420,6 +576,8 @@ class CharacterData00 extends CharacterData { switch (ch) { case 0x0BF1: retval = 100; break; // TAMIL NUMBER ONE HUNDRED case 0x0BF2: retval = 1000; break; // TAMIL NUMBER ONE THOUSAND + case 0x0D71: retval = 100; break; // MALAYALAM NUMBER ONE HUNDRED + case 0x0D72: retval = 1000; break; // MALAYALAM NUMBER ONE THOUSAND case 0x1375: retval = 40; break; // ETHIOPIC NUMBER FORTY case 0x1376: retval = 50; break; // ETHIOPIC NUMBER FIFTY case 0x1377: retval = 60; break; // ETHIOPIC NUMBER SIXTY @@ -440,14 +598,15 @@ class CharacterData00 extends CharacterData { case 0x2180: retval = 1000; break; // ROMAN NUMERAL ONE THOUSAND C D case 0x2181: retval = 5000; break; // ROMAN NUMERAL FIVE THOUSAND case 0x2182: retval = 10000; break; // ROMAN NUMERAL TEN THOUSAND - - case 0x324B: retval = 40; break; - case 0x324C: retval = 50; break; - case 0x324D: retval = 60; break; - case 0x324E: retval = 70; break; - case 0x324F: retval = 80; break; - case 0x325C: retval = 32; break; - + case 0x2186: retval = 50; break; // ROMAN NUMERAL FIFTY EARLY FORM + case 0x2187: retval = 50000; break; // ROMAN NUMERAL FIFTY THOUSAND + case 0x2188: retval = 100000; break; // ROMAN NUMERAL ONE HUNDRED THOUSAND + case 0x324B: retval = 40; break; // CIRCLED NUMBER FORTY ON BLACK SQUARE + case 0x324C: retval = 50; break; // CIRCLED NUMBER FIFTY ON BLACK SQUARE + case 0x324D: retval = 60; break; // CIRCLED NUMBER SIXTY ON BLACK SQUARE + case 0x324E: retval = 70; break; // CIRCLED NUMBER SEVENTY ON BLACK SQUARE + case 0x324F: retval = 80; break; // CIRCLED NUMBER EIGHTY ON BLACK SQUARE + case 0x325C: retval = 32; break; // CIRCLED NUMBER THIRTY TWO case 0x325D: retval = 33; break; // CIRCLED NUMBER THIRTY THREE case 0x325E: retval = 34; break; // CIRCLED NUMBER THIRTY FOUR case 0x325F: retval = 35; break; // CIRCLED NUMBER THIRTY FIVE @@ -466,13 +625,6 @@ class CharacterData00 extends CharacterData { case 0x32BD: retval = 48; break; // CIRCLED NUMBER FORTY EIGHT case 0x32BE: retval = 49; break; // CIRCLED NUMBER FORTY NINE case 0x32BF: retval = 50; break; // CIRCLED NUMBER FIFTY - - case 0x0D71: retval = 100; break; // MALAYALAM NUMBER ONE HUNDRED - case 0x0D72: retval = 1000; break; // MALAYALAM NUMBER ONE THOUSAND - case 0x2186: retval = 50; break; // ROMAN NUMERAL FIFTY EARLY FORM - case 0x2187: retval = 50000; break; // ROMAN NUMERAL FIFTY THOUSAND - case 0x2188: retval = 100000; break; // ROMAN NUMERAL ONE HUNDRED THOUSAND - default: retval = -2; break; } break; @@ -553,70 +705,149 @@ class CharacterData00 extends CharacterData { } else { switch(ch) { - // map overflow characters - case 0x00B5 : mapChar = 0x039C; break; - case 0x017F : mapChar = 0x0053; break; - case 0x1FBE : mapChar = 0x0399; break; - - case 0x023F : mapChar = 0x2C7E; break; - case 0x0240 : mapChar = 0x2C7F; break; - case 0x0250 : mapChar = 0x2C6F; break; - case 0x0251 : mapChar = 0x2C6D; break; - case 0x0252 : mapChar = 0x2C70; break; - case 0x025C : mapChar = 0xA7AB; break; - case 0x0261 : mapChar = 0xA7AC; break; - case 0x0265 : mapChar = 0xA78D; break; - case 0x0266 : mapChar = 0xA7AA; break; - case 0x026B : mapChar = 0x2C62; break; - case 0x026C : mapChar = 0xA7AD; break; - case 0x0271 : mapChar = 0x2C6E; break; - case 0x027D : mapChar = 0x2C64; break; - case 0x0287 : mapChar = 0xA7B1; break; - case 0x029E : mapChar = 0xA7B0; break; - case 0x1D79 : mapChar = 0xA77D; break; - case 0x1D7D : mapChar = 0x2C63; break; - case 0x2C65 : mapChar = 0x023A; break; - case 0x2C66 : mapChar = 0x023E; break; - case 0x2D00 : mapChar = 0x10A0; break; - case 0x2D01 : mapChar = 0x10A1; break; - case 0x2D02 : mapChar = 0x10A2; break; - case 0x2D03 : mapChar = 0x10A3; break; - case 0x2D04 : mapChar = 0x10A4; break; - case 0x2D05 : mapChar = 0x10A5; break; - case 0x2D06 : mapChar = 0x10A6; break; - case 0x2D07 : mapChar = 0x10A7; break; - case 0x2D08 : mapChar = 0x10A8; break; - case 0x2D09 : mapChar = 0x10A9; break; - case 0x2D0A : mapChar = 0x10AA; break; - case 0x2D0B : mapChar = 0x10AB; break; - case 0x2D0C : mapChar = 0x10AC; break; - case 0x2D0D : mapChar = 0x10AD; break; - case 0x2D0E : mapChar = 0x10AE; break; - case 0x2D0F : mapChar = 0x10AF; break; - case 0x2D10 : mapChar = 0x10B0; break; - case 0x2D11 : mapChar = 0x10B1; break; - case 0x2D12 : mapChar = 0x10B2; break; - case 0x2D13 : mapChar = 0x10B3; break; - case 0x2D14 : mapChar = 0x10B4; break; - case 0x2D15 : mapChar = 0x10B5; break; - case 0x2D16 : mapChar = 0x10B6; break; - case 0x2D17 : mapChar = 0x10B7; break; - case 0x2D18 : mapChar = 0x10B8; break; - case 0x2D19 : mapChar = 0x10B9; break; - case 0x2D1A : mapChar = 0x10BA; break; - case 0x2D1B : mapChar = 0x10BB; break; - case 0x2D1C : mapChar = 0x10BC; break; - case 0x2D1D : mapChar = 0x10BD; break; - case 0x2D1E : mapChar = 0x10BE; break; - case 0x2D1F : mapChar = 0x10BF; break; - case 0x2D20 : mapChar = 0x10C0; break; - case 0x2D21 : mapChar = 0x10C1; break; - case 0x2D22 : mapChar = 0x10C2; break; - case 0x2D23 : mapChar = 0x10C3; break; - case 0x2D24 : mapChar = 0x10C4; break; - case 0x2D25 : mapChar = 0x10C5; break; - case 0x2D27 : mapChar = 0x10C7; break; - case 0x2D2D : mapChar = 0x10CD; break; + case 0x017F: mapChar = 0x0053; break; + case 0x023F: mapChar = 0x2C7E; break; + case 0x0240: mapChar = 0x2C7F; break; + case 0x0250: mapChar = 0x2C6F; break; + case 0x0251: mapChar = 0x2C6D; break; + case 0x0252: mapChar = 0x2C70; break; + case 0x025C: mapChar = 0xA7AB; break; + case 0x0261: mapChar = 0xA7AC; break; + case 0x0265: mapChar = 0xA78D; break; + case 0x0266: mapChar = 0xA7AA; break; + case 0x026B: mapChar = 0x2C62; break; + case 0x026C: mapChar = 0xA7AD; break; + case 0x0271: mapChar = 0x2C6E; break; + case 0x027D: mapChar = 0x2C64; break; + case 0x0287: mapChar = 0xA7B1; break; + case 0x029D: mapChar = 0xA7B2; break; + case 0x029E: mapChar = 0xA7B0; break; + case 0x1D79: mapChar = 0xA77D; break; + case 0x1D7D: mapChar = 0x2C63; break; + case 0x1FBE: mapChar = 0x0399; break; + case 0x2C65: mapChar = 0x023A; break; + case 0x2C66: mapChar = 0x023E; break; + case 0x2D00: mapChar = 0x10A0; break; + case 0x2D01: mapChar = 0x10A1; break; + case 0x2D02: mapChar = 0x10A2; break; + case 0x2D03: mapChar = 0x10A3; break; + case 0x2D04: mapChar = 0x10A4; break; + case 0x2D05: mapChar = 0x10A5; break; + case 0x2D06: mapChar = 0x10A6; break; + case 0x2D07: mapChar = 0x10A7; break; + case 0x2D08: mapChar = 0x10A8; break; + case 0x2D09: mapChar = 0x10A9; break; + case 0x2D0A: mapChar = 0x10AA; break; + case 0x2D0B: mapChar = 0x10AB; break; + case 0x2D0C: mapChar = 0x10AC; break; + case 0x2D0D: mapChar = 0x10AD; break; + case 0x2D0E: mapChar = 0x10AE; break; + case 0x2D0F: mapChar = 0x10AF; break; + case 0x2D10: mapChar = 0x10B0; break; + case 0x2D11: mapChar = 0x10B1; break; + case 0x2D12: mapChar = 0x10B2; break; + case 0x2D13: mapChar = 0x10B3; break; + case 0x2D14: mapChar = 0x10B4; break; + case 0x2D15: mapChar = 0x10B5; break; + case 0x2D16: mapChar = 0x10B6; break; + case 0x2D17: mapChar = 0x10B7; break; + case 0x2D18: mapChar = 0x10B8; break; + case 0x2D19: mapChar = 0x10B9; break; + case 0x2D1A: mapChar = 0x10BA; break; + case 0x2D1B: mapChar = 0x10BB; break; + case 0x2D1C: mapChar = 0x10BC; break; + case 0x2D1D: mapChar = 0x10BD; break; + case 0x2D1E: mapChar = 0x10BE; break; + case 0x2D1F: mapChar = 0x10BF; break; + case 0x2D20: mapChar = 0x10C0; break; + case 0x2D21: mapChar = 0x10C1; break; + case 0x2D22: mapChar = 0x10C2; break; + case 0x2D23: mapChar = 0x10C3; break; + case 0x2D24: mapChar = 0x10C4; break; + case 0x2D25: mapChar = 0x10C5; break; + case 0x2D27: mapChar = 0x10C7; break; + case 0x2D2D: mapChar = 0x10CD; break; + case 0xAB53: mapChar = 0xA7B3; break; + case 0xAB70: mapChar = 0x13A0; break; + case 0xAB71: mapChar = 0x13A1; break; + case 0xAB72: mapChar = 0x13A2; break; + case 0xAB73: mapChar = 0x13A3; break; + case 0xAB74: mapChar = 0x13A4; break; + case 0xAB75: mapChar = 0x13A5; break; + case 0xAB76: mapChar = 0x13A6; break; + case 0xAB77: mapChar = 0x13A7; break; + case 0xAB78: mapChar = 0x13A8; break; + case 0xAB79: mapChar = 0x13A9; break; + case 0xAB7A: mapChar = 0x13AA; break; + case 0xAB7B: mapChar = 0x13AB; break; + case 0xAB7C: mapChar = 0x13AC; break; + case 0xAB7D: mapChar = 0x13AD; break; + case 0xAB7E: mapChar = 0x13AE; break; + case 0xAB7F: mapChar = 0x13AF; break; + case 0xAB80: mapChar = 0x13B0; break; + case 0xAB81: mapChar = 0x13B1; break; + case 0xAB82: mapChar = 0x13B2; break; + case 0xAB83: mapChar = 0x13B3; break; + case 0xAB84: mapChar = 0x13B4; break; + case 0xAB85: mapChar = 0x13B5; break; + case 0xAB86: mapChar = 0x13B6; break; + case 0xAB87: mapChar = 0x13B7; break; + case 0xAB88: mapChar = 0x13B8; break; + case 0xAB89: mapChar = 0x13B9; break; + case 0xAB8A: mapChar = 0x13BA; break; + case 0xAB8B: mapChar = 0x13BB; break; + case 0xAB8C: mapChar = 0x13BC; break; + case 0xAB8D: mapChar = 0x13BD; break; + case 0xAB8E: mapChar = 0x13BE; break; + case 0xAB8F: mapChar = 0x13BF; break; + case 0xAB90: mapChar = 0x13C0; break; + case 0xAB91: mapChar = 0x13C1; break; + case 0xAB92: mapChar = 0x13C2; break; + case 0xAB93: mapChar = 0x13C3; break; + case 0xAB94: mapChar = 0x13C4; break; + case 0xAB95: mapChar = 0x13C5; break; + case 0xAB96: mapChar = 0x13C6; break; + case 0xAB97: mapChar = 0x13C7; break; + case 0xAB98: mapChar = 0x13C8; break; + case 0xAB99: mapChar = 0x13C9; break; + case 0xAB9A: mapChar = 0x13CA; break; + case 0xAB9B: mapChar = 0x13CB; break; + case 0xAB9C: mapChar = 0x13CC; break; + case 0xAB9D: mapChar = 0x13CD; break; + case 0xAB9E: mapChar = 0x13CE; break; + case 0xAB9F: mapChar = 0x13CF; break; + case 0xABA0: mapChar = 0x13D0; break; + case 0xABA1: mapChar = 0x13D1; break; + case 0xABA2: mapChar = 0x13D2; break; + case 0xABA3: mapChar = 0x13D3; break; + case 0xABA4: mapChar = 0x13D4; break; + case 0xABA5: mapChar = 0x13D5; break; + case 0xABA6: mapChar = 0x13D6; break; + case 0xABA7: mapChar = 0x13D7; break; + case 0xABA8: mapChar = 0x13D8; break; + case 0xABA9: mapChar = 0x13D9; break; + case 0xABAA: mapChar = 0x13DA; break; + case 0xABAB: mapChar = 0x13DB; break; + case 0xABAC: mapChar = 0x13DC; break; + case 0xABAD: mapChar = 0x13DD; break; + case 0xABAE: mapChar = 0x13DE; break; + case 0xABAF: mapChar = 0x13DF; break; + case 0xABB0: mapChar = 0x13E0; break; + case 0xABB1: mapChar = 0x13E1; break; + case 0xABB2: mapChar = 0x13E2; break; + case 0xABB3: mapChar = 0x13E3; break; + case 0xABB4: mapChar = 0x13E4; break; + case 0xABB5: mapChar = 0x13E5; break; + case 0xABB6: mapChar = 0x13E6; break; + case 0xABB7: mapChar = 0x13E7; break; + case 0xABB8: mapChar = 0x13E8; break; + case 0xABB9: mapChar = 0x13E9; break; + case 0xABBA: mapChar = 0x13EA; break; + case 0xABBB: mapChar = 0x13EB; break; + case 0xABBC: mapChar = 0x13EC; break; + case 0xABBD: mapChar = 0x13ED; break; + case 0xABBE: mapChar = 0x13EE; break; + case 0xABBF: mapChar = 0x13EF; break; default : mapChar = Character.ERROR; break; } } diff --git a/jdk/make/data/characterdata/CharacterData01.java.template b/jdk/make/data/characterdata/CharacterData01.java.template index 78bf83874d9..8441de74815 100644 --- a/jdk/make/data/characterdata/CharacterData01.java.template +++ b/jdk/make/data/characterdata/CharacterData01.java.template @@ -243,36 +243,35 @@ class CharacterData01 extends CharacterData { case 0x10131: retval = 70000; break; // AEGEAN NUMBER SEVENTY THOUSAND case 0x10132: retval = 80000; break; // AEGEAN NUMBER EIGHTY THOUSAND case 0x10133: retval = 90000; break; // AEGEAN NUMBER NINETY THOUSAND - case 0x10323: retval = 50; break; // OLD ITALIC NUMERAL FIFTY - case 0x10144: retval = 50; break; // ACROPHONIC ATTIC FIFTY - case 0x10145: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED - case 0x10146: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND - case 0x10147: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND - case 0x1014A: retval = 50; break; // ACROPHONIC ATTIC FIFTY TALENTS - case 0x1014B: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED TALENTS - case 0x1014C: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED TALENTS - case 0x1014D: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND TALENTS - case 0x1014E: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND TALENTS - case 0x10151: retval = 50; break; // ACROPHONIC ATTIC FIFTY STATERS - case 0x10152: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED STATERS - case 0x10153: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED STATERS - case 0x10154: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND STATERS - case 0x10155: retval = 10000; break; // ACROPHONIC ATTIC TEN THOUSAND STATERS - case 0x10156: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND STATERS - case 0x10166: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY - case 0x10167: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM - case 0x10168: retval = 50; break; // ACROPHONIC HERMIONIAN FIFTY - case 0x10169: retval = 50; break; // ACROPHONIC THESPIAN FIFTY - case 0x1016A: retval = 100; break; // ACROPHONIC THESPIAN ONE HUNDRED - case 0x1016B: retval = 300; break; // ACROPHONIC THESPIAN THREE HUNDRED - case 0x1016C: retval = 500; break; // ACROPHONIC EPIDAUREAN FIVE HUNDRED - case 0x1016D: retval = 500; break; // ACROPHONIC TROEZENIAN FIVE HUNDRED - case 0x1016E: retval = 500; break; // ACROPHONIC THESPIAN FIVE HUNDRED - case 0x1016F: retval = 500; break; // ACROPHONIC CARYSTIAN FIVE HUNDRED - case 0x10170: retval = 500; break; // ACROPHONIC NAXIAN FIVE HUNDRED - case 0x10171: retval = 1000; break; // ACROPHONIC THESPIAN ONE THOUSAND - case 0x10172: retval = 5000; break; // ACROPHONIC THESPIAN FIVE THOUSAND - case 0x10174: retval = 50; break; // ACROPHONIC STRATIAN FIFTY MNAS + case 0x10144: retval = 50; break; // GREEK ACROPHONIC ATTIC FIFTY + case 0x10145: retval = 500; break; // GREEK ACROPHONIC ATTIC FIVE HUNDRED + case 0x10146: retval = 5000; break; // GREEK ACROPHONIC ATTIC FIVE THOUSAND + case 0x10147: retval = 50000; break; // GREEK ACROPHONIC ATTIC FIFTY THOUSAND + case 0x1014A: retval = 50; break; // GREEK ACROPHONIC ATTIC FIFTY TALENTS + case 0x1014B: retval = 100; break; // GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS + case 0x1014C: retval = 500; break; // GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS + case 0x1014D: retval = 1000; break; // GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS + case 0x1014E: retval = 5000; break; // GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS + case 0x10151: retval = 50; break; // GREEK ACROPHONIC ATTIC FIFTY STATERS + case 0x10152: retval = 100; break; // GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS + case 0x10153: retval = 500; break; // GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS + case 0x10154: retval = 1000; break; // GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS + case 0x10155: retval = 10000; break; // GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS + case 0x10156: retval = 50000; break; // GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS + case 0x10166: retval = 50; break; // GREEK ACROPHONIC TROEZENIAN FIFTY + case 0x10167: retval = 50; break; // GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM + case 0x10168: retval = 50; break; // GREEK ACROPHONIC HERMIONIAN FIFTY + case 0x10169: retval = 50; break; // GREEK ACROPHONIC THESPIAN FIFTY + case 0x1016A: retval = 100; break; // GREEK ACROPHONIC THESPIAN ONE HUNDRED + case 0x1016B: retval = 300; break; // GREEK ACROPHONIC THESPIAN THREE HUNDRED + case 0x1016C: retval = 500; break; // GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED + case 0x1016D: retval = 500; break; // GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED + case 0x1016E: retval = 500; break; // GREEK ACROPHONIC THESPIAN FIVE HUNDRED + case 0x1016F: retval = 500; break; // GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED + case 0x10170: retval = 500; break; // GREEK ACROPHONIC NAXIAN FIVE HUNDRED + case 0x10171: retval = 1000; break; // GREEK ACROPHONIC THESPIAN ONE THOUSAND + case 0x10172: retval = 5000; break; // GREEK ACROPHONIC THESPIAN FIVE THOUSAND + case 0x10174: retval = 50; break; // GREEK ACROPHONIC STRATIAN FIFTY MNAS case 0x102ED: retval = 40; break; // COPTIC EPACT NUMBER FORTY case 0x102EE: retval = 50; break; // COPTIC EPACT NUMBER FIFTY case 0x102EF: retval = 60; break; // COPTIC EPACT NUMBER SIXTY @@ -288,6 +287,7 @@ class CharacterData01 extends CharacterData { case 0x102F9: retval = 700; break; // COPTIC EPACT NUMBER SEVEN HUNDRED case 0x102FA: retval = 800; break; // COPTIC EPACT NUMBER EIGHT HUNDRED case 0x102FB: retval = 900; break; // COPTIC EPACT NUMBER NINE HUNDRED + case 0x10323: retval = 50; break; // OLD ITALIC NUMERAL FIFTY case 0x10341: retval = 90; break; // GOTHIC LETTER NINETY case 0x1034A: retval = 900; break; // GOTHIC LETTER NINE HUNDRED case 0x103D5: retval = 100; break; // OLD PERSIAN NUMBER HUNDRED @@ -295,7 +295,48 @@ class CharacterData01 extends CharacterData { case 0x1085E: retval = 1000; break; // IMPERIAL ARAMAIC NUMBER ONE THOUSAND case 0x1085F: retval = 10000; break; // IMPERIAL ARAMAIC NUMBER TEN THOUSAND case 0x108AF: retval = 100; break; // NABATAEAN NUMBER ONE HUNDRED + case 0x108FF: retval = 100; break; // HATRAN NUMBER ONE HUNDRED case 0x10919: retval = 100; break; // PHOENICIAN NUMBER ONE HUNDRED + case 0x109CC: retval = 40; break; // MEROITIC CURSIVE NUMBER FORTY + case 0x109CD: retval = 50; break; // MEROITIC CURSIVE NUMBER FIFTY + case 0x109CE: retval = 60; break; // MEROITIC CURSIVE NUMBER SIXTY + case 0x109CF: retval = 70; break; // MEROITIC CURSIVE NUMBER SEVENTY + case 0x109D2: retval = 100; break; // MEROITIC CURSIVE NUMBER ONE HUNDRED + case 0x109D3: retval = 200; break; // MEROITIC CURSIVE NUMBER TWO HUNDRED + case 0x109D4: retval = 300; break; // MEROITIC CURSIVE NUMBER THREE HUNDRED + case 0x109D5: retval = 400; break; // MEROITIC CURSIVE NUMBER FOUR HUNDRED + case 0x109D6: retval = 500; break; // MEROITIC CURSIVE NUMBER FIVE HUNDRED + case 0x109D7: retval = 600; break; // MEROITIC CURSIVE NUMBER SIX HUNDRED + case 0x109D8: retval = 700; break; // MEROITIC CURSIVE NUMBER SEVEN HUNDRED + case 0x109D9: retval = 800; break; // MEROITIC CURSIVE NUMBER EIGHT HUNDRED + case 0x109DA: retval = 900; break; // MEROITIC CURSIVE NUMBER NINE HUNDRED + case 0x109DB: retval = 1000; break; // MEROITIC CURSIVE NUMBER ONE THOUSAND + case 0x109DC: retval = 2000; break; // MEROITIC CURSIVE NUMBER TWO THOUSAND + case 0x109DD: retval = 3000; break; // MEROITIC CURSIVE NUMBER THREE THOUSAND + case 0x109DE: retval = 4000; break; // MEROITIC CURSIVE NUMBER FOUR THOUSAND + case 0x109DF: retval = 5000; break; // MEROITIC CURSIVE NUMBER FIVE THOUSAND + case 0x109E0: retval = 6000; break; // MEROITIC CURSIVE NUMBER SIX THOUSAND + case 0x109E1: retval = 7000; break; // MEROITIC CURSIVE NUMBER SEVEN THOUSAND + case 0x109E2: retval = 8000; break; // MEROITIC CURSIVE NUMBER EIGHT THOUSAND + case 0x109E3: retval = 9000; break; // MEROITIC CURSIVE NUMBER NINE THOUSAND + case 0x109E4: retval = 10000; break; // MEROITIC CURSIVE NUMBER TEN THOUSAND + case 0x109E5: retval = 20000; break; // MEROITIC CURSIVE NUMBER TWENTY THOUSAND + case 0x109E6: retval = 30000; break; // MEROITIC CURSIVE NUMBER THIRTY THOUSAND + case 0x109E7: retval = 40000; break; // MEROITIC CURSIVE NUMBER FORTY THOUSAND + case 0x109E8: retval = 50000; break; // MEROITIC CURSIVE NUMBER FIFTY THOUSAND + case 0x109E9: retval = 60000; break; // MEROITIC CURSIVE NUMBER SIXTY THOUSAND + case 0x109EA: retval = 70000; break; // MEROITIC CURSIVE NUMBER SEVENTY THOUSAND + case 0x109EB: retval = 80000; break; // MEROITIC CURSIVE NUMBER EIGHTY THOUSAND + case 0x109EC: retval = 90000; break; // MEROITIC CURSIVE NUMBER NINETY THOUSAND + case 0x109ED: retval = 100000; break; // MEROITIC CURSIVE NUMBER ONE HUNDRED THOUSAND + case 0x109EE: retval = 200000; break; // MEROITIC CURSIVE NUMBER TWO HUNDRED THOUSAND + case 0x109EF: retval = 300000; break; // MEROITIC CURSIVE NUMBER THREE HUNDRED THOUSAND + case 0x109F0: retval = 400000; break; // MEROITIC CURSIVE NUMBER FOUR HUNDRED THOUSAND + case 0x109F1: retval = 500000; break; // MEROITIC CURSIVE NUMBER FIVE HUNDRED THOUSAND + case 0x109F2: retval = 600000; break; // MEROITIC CURSIVE NUMBER SIX HUNDRED THOUSAND + case 0x109F3: retval = 700000; break; // MEROITIC CURSIVE NUMBER SEVEN HUNDRED THOUSAND + case 0x109F4: retval = 800000; break; // MEROITIC CURSIVE NUMBER EIGHT HUNDRED THOUSAND + case 0x109F5: retval = 900000; break; // MEROITIC CURSIVE NUMBER NINE HUNDRED THOUSAND case 0x10A46: retval = 100; break; // KHAROSHTHI NUMBER ONE HUNDRED case 0x10A47: retval = 1000; break; // KHAROSHTHI NUMBER ONE THOUSAND case 0x10A7E: retval = 50; break; // OLD SOUTH ARABIAN NUMBER FIFTY @@ -305,6 +346,9 @@ class CharacterData01 extends CharacterData { case 0x10B7E: retval = 100; break; // INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED case 0x10B7F: retval = 1000; break; // INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND case 0x10BAF: retval = 100; break; // PSALTER PAHLAVI NUMBER ONE HUNDRED + case 0x10CFD: retval = 50; break; // OLD HUNGARIAN NUMBER FIFTY + case 0x10CFE: retval = 100; break; // OLD HUNGARIAN NUMBER ONE HUNDRED + case 0x10CFF: retval = 1000; break; // OLD HUNGARIAN NUMBER ONE THOUSAND case 0x10E6C: retval = 40; break; // RUMI NUMBER FORTY case 0x10E6D: retval = 50; break; // RUMI NUMBER FIFTY case 0x10E6E: retval = 60; break; // RUMI NUMBER SIXTY diff --git a/jdk/make/data/unicodedata/PropList.txt b/jdk/make/data/unicodedata/PropList.txt index 82f650d5749..2eb2926e072 100644 --- a/jdk/make/data/unicodedata/PropList.txt +++ b/jdk/make/data/unicodedata/PropList.txt @@ -1,8 +1,8 @@ -# PropList-7.0.0.txt -# Date: 2014-02-19, 15:51:26 GMT [MD] +# PropList-8.0.0.txt +# Date: 2015-05-16, 17:50:38 GMT [MD] # # Unicode Character Database -# Copyright (c) 1991-2014 Unicode, Inc. +# Copyright (c) 1991-2015 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # For documentation, see http://www.unicode.org/reports/tr44/ @@ -189,18 +189,22 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA 11141..11143 ; Terminal_Punctuation # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK 111C5..111C6 ; Terminal_Punctuation # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA 111CD ; Terminal_Punctuation # Po SHARADA SUTRA MARK +111DE..111DF ; Terminal_Punctuation # Po [2] SHARADA SECTION MARK-1..SHARADA SECTION MARK-2 11238..1123C ; Terminal_Punctuation # Po [5] KHOJKI DANDA..KHOJKI DOUBLE SECTION MARK +112A9 ; Terminal_Punctuation # Po MULTANI SECTION MARK 115C2..115C5 ; Terminal_Punctuation # Po [4] SIDDHAM DANDA..SIDDHAM SEPARATOR BAR -115C9 ; Terminal_Punctuation # Po SIDDHAM END OF TEXT MARK +115C9..115D7 ; Terminal_Punctuation # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES 11641..11642 ; Terminal_Punctuation # Po [2] MODI DANDA..MODI DOUBLE DANDA +1173C..1173E ; Terminal_Punctuation # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI 12470..12474 ; Terminal_Punctuation # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON 16A6E..16A6F ; Terminal_Punctuation # Po [2] MRO DANDA..MRO DOUBLE DANDA 16AF5 ; Terminal_Punctuation # Po BASSA VAH FULL STOP 16B37..16B39 ; Terminal_Punctuation # Po [3] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN CIM CHEEM 16B44 ; Terminal_Punctuation # Po PAHAWH HMONG SIGN XAUS 1BC9F ; Terminal_Punctuation # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP +1DA87..1DA8A ; Terminal_Punctuation # Po [4] SIGNWRITING COMMA..SIGNWRITING COLON -# Total code points: 214 +# Total code points: 238 # ================================================ @@ -425,7 +429,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 081B..0823 ; Other_Alphabetic # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A 0825..0827 ; Other_Alphabetic # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082C ; Other_Alphabetic # Mn [4] SAMARITAN VOWEL SIGN LONG I..SAMARITAN VOWEL SIGN SUKUN -08E4..08E9 ; Other_Alphabetic # Mn [6] ARABIC CURLY FATHA..ARABIC CURLY KASRATAN +08E3..08E9 ; Other_Alphabetic # Mn [7] ARABIC TURNED DAMMA BELOW..ARABIC CURLY KASRATAN 08F0..0902 ; Other_Alphabetic # Mn [19] ARABIC OPEN FATHATAN..DEVANAGARI SIGN ANUSVARA 0903 ; Other_Alphabetic # Mc DEVANAGARI SIGN VISARGA 093A ; Other_Alphabetic # Mn DEVANAGARI VOWEL SIGN OE @@ -560,8 +564,6 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 1930..1931 ; Other_Alphabetic # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA 1932 ; Other_Alphabetic # Mn LIMBU SMALL LETTER ANUSVARA 1933..1938 ; Other_Alphabetic # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA -19B0..19C0 ; Other_Alphabetic # Mc [17] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE VOWEL SIGN IY -19C8..19C9 ; Other_Alphabetic # Mc [2] NEW TAI LUE TONE MARK-1..NEW TAI LUE TONE MARK-2 1A17..1A18 ; Other_Alphabetic # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U 1A19..1A1A ; Other_Alphabetic # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O 1A1B ; Other_Alphabetic # Mn BUGINESE VOWEL SIGN AE @@ -605,7 +607,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 24B6..24E9 ; Other_Alphabetic # So [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z 2DE0..2DFF ; Other_Alphabetic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS A674..A67B ; Other_Alphabetic # Mn [8] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC LETTER OMEGA -A69F ; Other_Alphabetic # Mn COMBINING CYRILLIC LETTER IOTIFIED E +A69E..A69F ; Other_Alphabetic # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E A823..A824 ; Other_Alphabetic # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I A825..A826 ; Other_Alphabetic # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E A827 ; Other_Alphabetic # Mc SYLOTI NAGRI VOWEL SIGN OO @@ -672,7 +674,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 112DF ; Other_Alphabetic # Mn KHUDAWADI SIGN ANUSVARA 112E0..112E2 ; Other_Alphabetic # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II 112E3..112E8 ; Other_Alphabetic # Mn [6] KHUDAWADI VOWEL SIGN U..KHUDAWADI VOWEL SIGN AU -11301 ; Other_Alphabetic # Mn GRANTHA SIGN CANDRABINDU +11300..11301 ; Other_Alphabetic # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU 11302..11303 ; Other_Alphabetic # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA 1133E..1133F ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I 11340 ; Other_Alphabetic # Mn GRANTHA VOWEL SIGN II @@ -693,6 +695,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 115B8..115BB ; Other_Alphabetic # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU 115BC..115BD ; Other_Alphabetic # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA 115BE ; Other_Alphabetic # Mc SIDDHAM SIGN VISARGA +115DC..115DD ; Other_Alphabetic # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU 11630..11632 ; Other_Alphabetic # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II 11633..1163A ; Other_Alphabetic # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI 1163B..1163C ; Other_Alphabetic # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU @@ -704,6 +707,11 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 116AD ; Other_Alphabetic # Mn TAKRI VOWEL SIGN AA 116AE..116AF ; Other_Alphabetic # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II 116B0..116B5 ; Other_Alphabetic # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU +1171D..1171F ; Other_Alphabetic # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +11720..11721 ; Other_Alphabetic # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA +11722..11725 ; Other_Alphabetic # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU +11726 ; Other_Alphabetic # Mc AHOM VOWEL SIGN E +11727..1172A ; Other_Alphabetic # Mn [4] AHOM VOWEL SIGN AW..AHOM VOWEL SIGN AM 16B30..16B36 ; Other_Alphabetic # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F51..16F7E ; Other_Alphabetic # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG 1BC9E ; Other_Alphabetic # Mn DUPLOYAN DOUBLE MARK @@ -720,15 +728,16 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 3021..3029 ; Ideographic # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE 3038..303A ; Ideographic # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY 3400..4DB5 ; Ideographic # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 -4E00..9FCC ; Ideographic # Lo [20941] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FCC +4E00..9FD5 ; Ideographic # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5 F900..FA6D ; Ideographic # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9 20000..2A6D6 ; Ideographic # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 2A700..2B734 ; Ideographic # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 2B740..2B81D ; Ideographic # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEA1 ; Ideographic # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 2F800..2FA1D ; Ideographic # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D -# Total code points: 75633 +# Total code points: 81404 # ================================================ @@ -773,7 +782,7 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 07EB..07F3 ; Diacritic # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE 07F4..07F5 ; Diacritic # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE 0818..0819 ; Diacritic # Mn [2] SAMARITAN MARK OCCLUSION..SAMARITAN MARK DAGESH -08E4..08FE ; Diacritic # Mn [27] ARABIC CURLY FATHA..ARABIC DAMMA WITH DOT +08E3..08FE ; Diacritic # Mn [28] ARABIC TURNED DAMMA BELOW..ARABIC DAMMA WITH DOT 093C ; Diacritic # Mn DEVANAGARI SIGN NUKTA 094D ; Diacritic # Mn DEVANAGARI SIGN VIRAMA 0951..0954 ; Diacritic # Mn [4] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI ACUTE ACCENT @@ -877,7 +886,7 @@ AB5C..AB5F ; Diacritic # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER ABEC ; Diacritic # Mc MEETEI MAYEK LUM IYEK ABED ; Diacritic # Mn MEETEI MAYEK APUN IYEK FB1E ; Diacritic # Mn HEBREW POINT JUDEO-SPANISH VARIKA -FE20..FE2D ; Diacritic # Mn [14] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON BELOW +FE20..FE2F ; Diacritic # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF FF3E ; Diacritic # Sk FULLWIDTH CIRCUMFLEX ACCENT FF40 ; Diacritic # Sk FULLWIDTH GRAVE ACCENT FF70 ; Diacritic # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK @@ -889,6 +898,7 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON 11133..11134 ; Diacritic # Mn [2] CHAKMA VIRAMA..CHAKMA MAAYYAA 11173 ; Diacritic # Mn MAHAJANI SIGN NUKTA 111C0 ; Diacritic # Mc SHARADA SIGN VIRAMA +111CA..111CC ; Diacritic # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK 11235 ; Diacritic # Mc KHOJKI SIGN VIRAMA 11236 ; Diacritic # Mn KHOJKI SIGN NUKTA 112E9..112EA ; Diacritic # Mn [2] KHUDAWADI SIGN NUKTA..KHUDAWADI SIGN VIRAMA @@ -901,6 +911,7 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON 1163F ; Diacritic # Mn MODI SIGN VIRAMA 116B6 ; Diacritic # Mc TAKRI SIGN VIRAMA 116B7 ; Diacritic # Mn TAKRI SIGN NUKTA +1172B ; Diacritic # Mn AHOM SIGN KILLER 16AF0..16AF4 ; Diacritic # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16F8F..16F92 ; Diacritic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16F93..16F9F ; Diacritic # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 @@ -911,7 +922,7 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON 1D1AA..1D1AD ; Diacritic # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO 1E8D0..1E8D6 ; Diacritic # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS -# Total code points: 766 +# Total code points: 773 # ================================================ @@ -1053,7 +1064,7 @@ FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND # ================================================ 3400..4DB5 ; Unified_Ideograph # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 -4E00..9FCC ; Unified_Ideograph # Lo [20941] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FCC +4E00..9FD5 ; Unified_Ideograph # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5 FA0E..FA0F ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA0E..CJK COMPATIBILITY IDEOGRAPH-FA0F FA11 ; Unified_Ideograph # Lo CJK COMPATIBILITY IDEOGRAPH-FA11 FA13..FA14 ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA13..CJK COMPATIBILITY IDEOGRAPH-FA14 @@ -1064,8 +1075,9 @@ FA27..FA29 ; Unified_Ideograph # Lo [3] CJK COMPATIBILITY IDEOGRAPH-FA27..C 20000..2A6D6 ; Unified_Ideograph # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 2A700..2B734 ; Unified_Ideograph # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 2B740..2B81D ; Unified_Ideograph # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEA1 ; Unified_Ideograph # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 -# Total code points: 74617 +# Total code points: 80388 # ================================================ @@ -1094,9 +1106,9 @@ E01F0..E0FFF ; Other_Default_Ignorable_Code_Point # Cn [3600] . 2329 ; Deprecated # Ps LEFT-POINTING ANGLE BRACKET 232A ; Deprecated # Pe RIGHT-POINTING ANGLE BRACKET E0001 ; Deprecated # Cf LANGUAGE TAG -E0020..E007F ; Deprecated # Cf [96] TAG SPACE..CANCEL TAG +E007F ; Deprecated # Cf CANCEL TAG -# Total code points: 111 +# Total code points: 16 # ================================================ @@ -1138,11 +1150,13 @@ E0020..E007F ; Deprecated # Cf [96] TAG SPACE..CANCEL TAG 0E40..0E44 ; Logical_Order_Exception # Lo [5] THAI CHARACTER SARA E..THAI CHARACTER SARA AI MAIMALAI 0EC0..0EC4 ; Logical_Order_Exception # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI +19B5..19B7 ; Logical_Order_Exception # Lo [3] NEW TAI LUE VOWEL SIGN E..NEW TAI LUE VOWEL SIGN O +19BA ; Logical_Order_Exception # Lo NEW TAI LUE VOWEL SIGN AY AAB5..AAB6 ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O AAB9 ; Logical_Order_Exception # Lo TAI VIET VOWEL UEA AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET VOWEL AY -# Total code points: 15 +# Total code points: 19 # ================================================ @@ -1213,18 +1227,22 @@ FF61 ; STerm # Po HALFWIDTH IDEOGRAPHIC FULL STOP 11141..11143 ; STerm # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK 111C5..111C6 ; STerm # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA 111CD ; STerm # Po SHARADA SUTRA MARK +111DE..111DF ; STerm # Po [2] SHARADA SECTION MARK-1..SHARADA SECTION MARK-2 11238..11239 ; STerm # Po [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA 1123B..1123C ; STerm # Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK +112A9 ; STerm # Po MULTANI SECTION MARK 115C2..115C3 ; STerm # Po [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA -115C9 ; STerm # Po SIDDHAM END OF TEXT MARK +115C9..115D7 ; STerm # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES 11641..11642 ; STerm # Po [2] MODI DANDA..MODI DOUBLE DANDA +1173C..1173E ; STerm # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI 16A6E..16A6F ; STerm # Po [2] MRO DANDA..MRO DOUBLE DANDA 16AF5 ; STerm # Po BASSA VAH FULL STOP 16B37..16B38 ; STerm # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB 16B44 ; STerm # Po PAHAWH HMONG SIGN XAUS 1BC9F ; STerm # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP +1DA88 ; STerm # Po SIGNWRITING FULL STOP -# Total code points: 99 +# Total code points: 120 # ================================================ @@ -1432,7 +1450,9 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 2BBD..2BC8 ; Pattern_Syntax # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED 2BC9 ; Pattern_Syntax # Cn 2BCA..2BD1 ; Pattern_Syntax # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN -2BD2..2BFF ; Pattern_Syntax # Cn [46] .. +2BD2..2BEB ; Pattern_Syntax # Cn [26] .. +2BEC..2BEF ; Pattern_Syntax # So [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS +2BF0..2BFF ; Pattern_Syntax # Cn [16] .. 2E00..2E01 ; Pattern_Syntax # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER 2E02 ; Pattern_Syntax # Pi LEFT SUBSTITUTION BRACKET 2E03 ; Pattern_Syntax # Pf RIGHT SUBSTITUTION BRACKET diff --git a/jdk/make/data/unicodedata/Scripts.txt b/jdk/make/data/unicodedata/Scripts.txt index 0b69438a571..7e42740407c 100644 --- a/jdk/make/data/unicodedata/Scripts.txt +++ b/jdk/make/data/unicodedata/Scripts.txt @@ -1,10 +1,16 @@ -# Scripts-7.0.0.txt -# Date: 2014-05-15, 00:11:35 GMT [MD] +# Scripts-8.0.0.txt +# Date: 2015-03-11, 22:29:42 GMT [MD] # # Unicode Character Database -# Copyright (c) 1991-2014 Unicode, Inc. +# Copyright (c) 1991-2015 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # For documentation, see http://www.unicode.org/reports/tr44/ +# For more information, see: +# UAX #24, Unicode Script Property: http://www.unicode.org/reports/tr24/ +# Especially the sections: +# http://www.unicode.org/reports/tr24/#Assignment_Script_Values +# http://www.unicode.org/reports/tr24/#Assignment_ScriptX_Values +# # ================================================ @@ -89,7 +95,6 @@ 061C ; Common # Cf ARABIC LETTER MARK 061F ; Common # Po ARABIC QUESTION MARK 0640 ; Common # Lm ARABIC TATWEEL -0660..0669 ; Common # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE 06DD ; Common # Cf ARABIC END OF AYAH 0964..0965 ; Common # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA 0E3F ; Common # Sc THAI CURRENCY SYMBOL BAHT @@ -148,7 +153,7 @@ 208A..208C ; Common # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN 208D ; Common # Ps SUBSCRIPT LEFT PARENTHESIS 208E ; Common # Pe SUBSCRIPT RIGHT PARENTHESIS -20A0..20BD ; Common # Sc [30] EURO-CURRENCY SIGN..RUBLE SIGN +20A0..20BE ; Common # Sc [31] EURO-CURRENCY SIGN..LARI SIGN 2100..2101 ; Common # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT 2102 ; Common # L& DOUBLE-STRUCK CAPITAL C 2103..2106 ; Common # So [4] DEGREE CELSIUS..CADA UNA @@ -182,6 +187,7 @@ 214F ; Common # So SYMBOL FOR SAMARITAN SOURCE 2150..215F ; Common # No [16] VULGAR FRACTION ONE SEVENTH..FRACTION NUMERATOR ONE 2189 ; Common # No VULGAR FRACTION ZERO THIRDS +218A..218B ; Common # So [2] TURNED DIGIT TWO..TURNED DIGIT THREE 2190..2194 ; Common # Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW 2195..2199 ; Common # So [5] UP DOWN ARROW..SOUTH WEST ARROW 219A..219B ; Common # Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE @@ -304,6 +310,7 @@ 2B98..2BB9 ; Common # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX 2BBD..2BC8 ; Common # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED 2BCA..2BD1 ; Common # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN +2BEC..2BEF ; Common # So [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS 2E00..2E01 ; Common # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER 2E02 ; Common # Pi LEFT SUBSTITUTION BRACKET 2E03 ; Common # Pf RIGHT SUBSTITUTION BRACKET @@ -512,7 +519,7 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1D173..1D17A ; Common # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE 1D183..1D184 ; Common # So [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN 1D18C..1D1A9 ; Common # So [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH -1D1AE..1D1DD ; Common # So [48] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL PES SUBPUNCTIS +1D1AE..1D1E8 ; Common # So [59] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL KIEVAN FLAT SIGN 1D300..1D356 ; Common # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING 1D360..1D371 ; Common # No [18] COUNTING ROD UNIT DIGIT ONE..COUNTING ROD TENS DIGIT NINE 1D400..1D454 ; Common # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G @@ -571,16 +578,11 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1F210..1F23A ; Common # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 1F240..1F248 ; Common # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 1F250..1F251 ; Common # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT -1F300..1F32C ; Common # So [45] CYCLONE..WIND BLOWING FACE -1F330..1F37D ; Common # So [78] CHESTNUT..FORK AND KNIFE WITH PLATE -1F380..1F3CE ; Common # So [79] RIBBON..RACING CAR -1F3D4..1F3F7 ; Common # So [36] SNOW CAPPED MOUNTAIN..LABEL -1F400..1F4FE ; Common # So [255] RAT..PORTABLE STEREO -1F500..1F54A ; Common # So [75] TWISTED RIGHTWARDS ARROWS..DOVE OF PEACE -1F550..1F579 ; Common # So [42] CLOCK FACE ONE OCLOCK..JOYSTICK +1F300..1F3FA ; Common # So [251] CYCLONE..AMPHORA +1F3FB..1F3FF ; Common # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 +1F400..1F579 ; Common # So [378] RAT..JOYSTICK 1F57B..1F5A3 ; Common # So [41] LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX -1F5A5..1F642 ; Common # So [158] DESKTOP COMPUTER..SLIGHTLY SMILING FACE -1F645..1F6CF ; Common # So [139] FACE WITH NO GOOD GESTURE..BED +1F5A5..1F6D0 ; Common # So [300] DESKTOP COMPUTER..PLACE OF WORSHIP 1F6E0..1F6EC ; Common # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING 1F6F0..1F6F3 ; Common # So [4] SATELLITE..PASSENGER SHIP 1F700..1F773 ; Common # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE @@ -590,10 +592,13 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1F850..1F859 ; Common # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW 1F860..1F887 ; Common # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW 1F890..1F8AD ; Common # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS +1F910..1F918 ; Common # So [9] ZIPPER-MOUTH FACE..SIGN OF THE HORNS +1F980..1F984 ; Common # So [5] CRAB..UNICORN FACE +1F9C0 ; Common # So CHEESE WEDGE E0001 ; Common # Cf LANGUAGE TAG E0020..E007F ; Common # Cf [96] TAG SPACE..CANCEL TAG -# Total code points: 7129 +# Total code points: 7179 # ================================================ @@ -635,20 +640,21 @@ A722..A76F ; Latin # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN A770 ; Latin # Lm MODIFIER LETTER US A771..A787 ; Latin # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T A78B..A78E ; Latin # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT +A78F ; Latin # Lo LATIN LETTER SINOLOGICAL DOT A790..A7AD ; Latin # L& [30] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER L WITH BELT -A7B0..A7B1 ; Latin # L& [2] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER TURNED T +A7B0..A7B7 ; Latin # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA A7F7 ; Latin # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; Latin # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE A7FA ; Latin # L& LATIN LETTER SMALL CAPITAL TURNED M A7FB..A7FF ; Latin # Lo [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M AB30..AB5A ; Latin # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG AB5C..AB5F ; Latin # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK -AB64 ; Latin # L& LATIN SMALL LETTER INVERTED ALPHA +AB60..AB64 ; Latin # L& [5] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER INVERTED ALPHA FB00..FB06 ; Latin # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST FF21..FF3A ; Latin # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z -# Total code points: 1338 +# Total code points: 1349 # ================================================ @@ -731,9 +737,10 @@ A67E ; Cyrillic # Po CYRILLIC KAVYKA A67F ; Cyrillic # Lm CYRILLIC PAYEROK A680..A69B ; Cyrillic # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O A69C..A69D ; Cyrillic # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN -A69F ; Cyrillic # Mn COMBINING CYRILLIC LETTER IOTIFIED E +A69E..A69F ; Cyrillic # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E +FE2E..FE2F ; Cyrillic # Mn [2] COMBINING CYRILLIC TITLO LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF -# Total code points: 431 +# Total code points: 434 # ================================================ @@ -788,6 +795,7 @@ FB46..FB4F ; Hebrew # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATU 0620..063F ; Arabic # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE 0641..064A ; Arabic # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH 0656..065F ; Arabic # Mn [10] ARABIC SUBSCRIPT ALEF..ARABIC WAVY HAMZA BELOW +0660..0669 ; Arabic # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE 066A..066D ; Arabic # Po [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR 066E..066F ; Arabic # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF 0671..06D3 ; Arabic # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE @@ -806,8 +814,8 @@ FB46..FB4F ; Hebrew # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATU 06FD..06FE ; Arabic # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN 06FF ; Arabic # Lo ARABIC LETTER HEH WITH INVERTED V 0750..077F ; Arabic # Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE -08A0..08B2 ; Arabic # Lo [19] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER ZAIN WITH INVERTED V ABOVE -08E4..08FF ; Arabic # Mn [28] ARABIC CURLY FATHA..ARABIC MARK SIDEWAYS NOON GHUNNA +08A0..08B4 ; Arabic # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW +08E3..08FF ; Arabic # Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA FB50..FBB1 ; Arabic # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM FBB2..FBC1 ; Arabic # Sk [16] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW FBD3..FD3D ; Arabic # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM @@ -854,7 +862,7 @@ FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LA 1EEAB..1EEBB ; Arabic # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1EEF0..1EEF1 ; Arabic # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL -# Total code points: 1244 +# Total code points: 1257 # ================================================ @@ -902,8 +910,10 @@ A8E0..A8F1 ; Devanagari # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING A8F2..A8F7 ; Devanagari # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA A8F8..A8FA ; Devanagari # Po [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE +A8FC ; Devanagari # Po DEVANAGARI SIGN SIDDHAM +A8FD ; Devanagari # Lo DEVANAGARI JAIN OM -# Total code points: 152 +# Total code points: 154 # ================================================ @@ -987,8 +997,9 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 0AE6..0AEF ; Gujarati # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE 0AF0 ; Gujarati # Po GUJARATI ABBREVIATION SIGN 0AF1 ; Gujarati # Sc GUJARATI RUPEE SIGN +0AF9 ; Gujarati # Lo GUJARATI LETTER ZHA -# Total code points: 84 +# Total code points: 85 # ================================================ @@ -1064,14 +1075,14 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 0C46..0C48 ; Telugu # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI 0C4A..0C4D ; Telugu # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA 0C55..0C56 ; Telugu # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK -0C58..0C59 ; Telugu # Lo [2] TELUGU LETTER TSA..TELUGU LETTER DZA +0C58..0C5A ; Telugu # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA 0C60..0C61 ; Telugu # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL 0C62..0C63 ; Telugu # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL 0C66..0C6F ; Telugu # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE 0C78..0C7E ; Telugu # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR 0C7F ; Telugu # So TELUGU SIGN TUUMU -# Total code points: 95 +# Total code points: 96 # ================================================ @@ -1115,14 +1126,14 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 0D4D ; Malayalam # Mn MALAYALAM SIGN VIRAMA 0D4E ; Malayalam # Lo MALAYALAM LETTER DOT REPH 0D57 ; Malayalam # Mc MALAYALAM AU LENGTH MARK -0D60..0D61 ; Malayalam # Lo [2] MALAYALAM LETTER VOCALIC RR..MALAYALAM LETTER VOCALIC LL +0D5F..0D61 ; Malayalam # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL 0D62..0D63 ; Malayalam # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL 0D66..0D6F ; Malayalam # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE 0D70..0D75 ; Malayalam # No [6] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS 0D79 ; Malayalam # So MALAYALAM DATE MARK 0D7A..0D7F ; Malayalam # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K -# Total code points: 99 +# Total code points: 100 # ================================================ @@ -1358,9 +1369,11 @@ AB28..AB2E ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO # ================================================ -13A0..13F4 ; Cherokee # Lo [85] CHEROKEE LETTER A..CHEROKEE LETTER YV +13A0..13F5 ; Cherokee # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV +13F8..13FD ; Cherokee # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV +AB70..ABBF ; Cherokee # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA -# Total code points: 85 +# Total code points: 172 # ================================================ @@ -1472,15 +1485,16 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK 3038..303A ; Han # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY 303B ; Han # Lm VERTICAL IDEOGRAPHIC ITERATION MARK 3400..4DB5 ; Han # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 -4E00..9FCC ; Han # Lo [20941] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FCC +4E00..9FD5 ; Han # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5 F900..FA6D ; Han # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D FA70..FAD9 ; Han # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9 20000..2A6D6 ; Han # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 2A700..2B734 ; Han # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 2B740..2B81D ; Han # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEA1 ; Han # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 2F800..2FA1D ; Han # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D -# Total code points: 75963 +# Total code points: 81734 # ================================================ @@ -1680,9 +1694,7 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2 # ================================================ 1980..19AB ; New_Tai_Lue # Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA -19B0..19C0 ; New_Tai_Lue # Mc [17] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE VOWEL SIGN IY -19C1..19C7 ; New_Tai_Lue # Lo [7] NEW TAI LUE LETTER FINAL V..NEW TAI LUE LETTER FINAL B -19C8..19C9 ; New_Tai_Lue # Mc [2] NEW TAI LUE TONE MARK-1..NEW TAI LUE TONE MARK-2 +19B0..19C9 ; New_Tai_Lue # Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2 19D0..19D9 ; New_Tai_Lue # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE 19DA ; New_Tai_Lue # No NEW TAI LUE THAM DIGIT ONE 19DE..19DF ; New_Tai_Lue # So [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV @@ -1770,11 +1782,12 @@ A828..A82B ; Syloti_Nagri # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI # ================================================ -12000..12398 ; Cuneiform # Lo [921] CUNEIFORM SIGN A..CUNEIFORM SIGN UM TIMES ME +12000..12399 ; Cuneiform # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E ; Cuneiform # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM 12470..12474 ; Cuneiform # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON +12480..12543 ; Cuneiform # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU -# Total code points: 1037 +# Total code points: 1234 # ================================================ @@ -2151,9 +2164,12 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI # ================================================ 109A0..109B7 ; Meroitic_Cursive # Lo [24] MEROITIC CURSIVE LETTER A..MEROITIC CURSIVE LETTER DA +109BC..109BD ; Meroitic_Cursive # No [2] MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF 109BE..109BF ; Meroitic_Cursive # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN +109C0..109CF ; Meroitic_Cursive # No [16] MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY +109D2..109FF ; Meroitic_Cursive # No [46] MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS -# Total code points: 26 +# Total code points: 90 # ================================================ @@ -2180,12 +2196,16 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI 111B6..111BE ; Sharada # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O 111BF..111C0 ; Sharada # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA 111C1..111C4 ; Sharada # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM -111C5..111C8 ; Sharada # Po [4] SHARADA DANDA..SHARADA SEPARATOR +111C5..111C9 ; Sharada # Po [5] SHARADA DANDA..SHARADA SANDHI MARK +111CA..111CC ; Sharada # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK 111CD ; Sharada # Po SHARADA SUTRA MARK 111D0..111D9 ; Sharada # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE 111DA ; Sharada # Lo SHARADA EKAM +111DB ; Sharada # Po SHARADA SIGN SIDDHAM +111DC ; Sharada # Lo SHARADA HEADSTROKE +111DD..111DF ; Sharada # Po [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2 -# Total code points: 85 +# Total code points: 94 # ================================================ @@ -2243,7 +2263,7 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI # ================================================ -11301 ; Grantha # Mn GRANTHA SIGN CANDRABINDU +11300..11301 ; Grantha # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU 11302..11303 ; Grantha # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA 11305..1130C ; Grantha # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L 1130F..11310 ; Grantha # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI @@ -2258,13 +2278,14 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI 11341..11344 ; Grantha # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR 11347..11348 ; Grantha # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI 1134B..1134D ; Grantha # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA +11350 ; Grantha # Lo GRANTHA OM 11357 ; Grantha # Mc GRANTHA AU LENGTH MARK 1135D..11361 ; Grantha # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL 11362..11363 ; Grantha # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C ; Grantha # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Grantha # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA -# Total code points: 83 +# Total code points: 85 # ================================================ @@ -2407,9 +2428,11 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI 115BC..115BD ; Siddham # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA 115BE ; Siddham # Mc SIDDHAM SIGN VISARGA 115BF..115C0 ; Siddham # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA -115C1..115C9 ; Siddham # Po [9] SIDDHAM SIGN SIDDHAM..SIDDHAM END OF TEXT MARK +115C1..115D7 ; Siddham # Po [23] SIDDHAM SIGN SIDDHAM..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES +115D8..115DB ; Siddham # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U +115DC..115DD ; Siddham # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU -# Total code points: 72 +# Total code points: 92 # ================================================ @@ -2448,4 +2471,69 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI # Total code points: 84 +# ================================================ + +11700..11719 ; Ahom # Lo [26] AHOM LETTER KA..AHOM LETTER JHA +1171D..1171F ; Ahom # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +11720..11721 ; Ahom # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA +11722..11725 ; Ahom # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU +11726 ; Ahom # Mc AHOM VOWEL SIGN E +11727..1172B ; Ahom # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER +11730..11739 ; Ahom # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE +1173A..1173B ; Ahom # No [2] AHOM NUMBER TEN..AHOM NUMBER TWENTY +1173C..1173E ; Ahom # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI +1173F ; Ahom # So AHOM SYMBOL VI + +# Total code points: 57 + +# ================================================ + +14400..14646 ; Anatolian_Hieroglyphs # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 + +# Total code points: 583 + +# ================================================ + +108E0..108F2 ; Hatran # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH +108F4..108F5 ; Hatran # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW +108FB..108FF ; Hatran # No [5] HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED + +# Total code points: 26 + +# ================================================ + +11280..11286 ; Multani # Lo [7] MULTANI LETTER A..MULTANI LETTER GA +11288 ; Multani # Lo MULTANI LETTER GHA +1128A..1128D ; Multani # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA +1128F..1129D ; Multani # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA +1129F..112A8 ; Multani # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA +112A9 ; Multani # Po MULTANI SECTION MARK + +# Total code points: 38 + +# ================================================ + +10C80..10CB2 ; Old_Hungarian # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10CC0..10CF2 ; Old_Hungarian # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10CFA..10CFF ; Old_Hungarian # No [6] OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND + +# Total code points: 108 + +# ================================================ + +1D800..1D9FF ; SignWriting # So [512] SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD +1DA00..1DA36 ; SignWriting # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN +1DA37..1DA3A ; SignWriting # So [4] SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE +1DA3B..1DA6C ; SignWriting # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT +1DA6D..1DA74 ; SignWriting # So [8] SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING +1DA75 ; SignWriting # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS +1DA76..1DA83 ; SignWriting # So [14] SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH +1DA84 ; SignWriting # Mn SIGNWRITING LOCATION HEAD NECK +1DA85..1DA86 ; SignWriting # So [2] SIGNWRITING LOCATION TORSO..SIGNWRITING LOCATION LIMBS DIGITS +1DA87..1DA8B ; SignWriting # Po [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS +1DA9B..1DA9F ; SignWriting # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 +1DAA1..1DAAF ; SignWriting # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 + +# Total code points: 672 + # EOF diff --git a/jdk/make/data/unicodedata/SpecialCasing.txt b/jdk/make/data/unicodedata/SpecialCasing.txt index 43645bd2d10..8de6462f18c 100644 --- a/jdk/make/data/unicodedata/SpecialCasing.txt +++ b/jdk/make/data/unicodedata/SpecialCasing.txt @@ -1,5 +1,5 @@ -# SpecialCasing-7.0.0.txt -# Date: 2014-03-18, 07:18:02 GMT [MD] +# SpecialCasing-8.0.0.txt +# Date: 2014-12-16, 23:08:04 GMT [MD] # # Unicode Character Database # Copyright (c) 1991-2014 Unicode, Inc. diff --git a/jdk/make/data/unicodedata/UnicodeData.txt b/jdk/make/data/unicodedata/UnicodeData.txt index 31c8a7eaa04..aa0e914f843 100644 --- a/jdk/make/data/unicodedata/UnicodeData.txt +++ b/jdk/make/data/unicodedata/UnicodeData.txt @@ -667,7 +667,7 @@ 029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;; 029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;; 029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;; -029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;;; +029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;A7B2;;A7B2 029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;A7B0;;A7B0 029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;; 02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;; @@ -2091,6 +2091,9 @@ 08B0;ARABIC LETTER GAF WITH INVERTED STROKE;Lo;0;AL;;;;;N;;;;; 08B1;ARABIC LETTER STRAIGHT WAW;Lo;0;AL;;;;;N;;;;; 08B2;ARABIC LETTER ZAIN WITH INVERTED V ABOVE;Lo;0;AL;;;;;N;;;;; +08B3;ARABIC LETTER AIN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +08B4;ARABIC LETTER KAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +08E3;ARABIC TURNED DAMMA BELOW;Mn;220;NSM;;;;;N;;;;; 08E4;ARABIC CURLY FATHA;Mn;230;NSM;;;;;N;;;;; 08E5;ARABIC CURLY DAMMA;Mn;230;NSM;;;;;N;;;;; 08E6;ARABIC CURLY KASRA;Mn;220;NSM;;;;;N;;;;; @@ -2503,6 +2506,7 @@ 0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0AF0;GUJARATI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; +0AF9;GUJARATI LETTER ZHA;Lo;0;L;;;;;N;;;;; 0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2738,6 +2742,7 @@ 0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;; 0C58;TELUGU LETTER TSA;Lo;0;L;;;;;N;;;;; 0C59;TELUGU LETTER DZA;Lo;0;L;;;;;N;;;;; +0C5A;TELUGU LETTER RRRA;Lo;0;L;;;;;N;;;;; 0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; 0C62;TELUGU VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; @@ -2919,6 +2924,7 @@ 0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0D4E;MALAYALAM LETTER DOT REPH;Lo;0;L;;;;;N;;;;; 0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0D5F;MALAYALAM LETTER ARCHAIC II;Lo;0;L;;;;;N;;;;; 0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; 0D62;MALAYALAM VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; @@ -4289,91 +4295,98 @@ 1397;ETHIOPIC TONAL MARK HIDET;So;0;ON;;;;;N;;;;; 1398;ETHIOPIC TONAL MARK DERET-HIDET;So;0;ON;;;;;N;;;;; 1399;ETHIOPIC TONAL MARK KURT;So;0;ON;;;;;N;;;;; -13A0;CHEROKEE LETTER A;Lo;0;L;;;;;N;;;;; -13A1;CHEROKEE LETTER E;Lo;0;L;;;;;N;;;;; -13A2;CHEROKEE LETTER I;Lo;0;L;;;;;N;;;;; -13A3;CHEROKEE LETTER O;Lo;0;L;;;;;N;;;;; -13A4;CHEROKEE LETTER U;Lo;0;L;;;;;N;;;;; -13A5;CHEROKEE LETTER V;Lo;0;L;;;;;N;;;;; -13A6;CHEROKEE LETTER GA;Lo;0;L;;;;;N;;;;; -13A7;CHEROKEE LETTER KA;Lo;0;L;;;;;N;;;;; -13A8;CHEROKEE LETTER GE;Lo;0;L;;;;;N;;;;; -13A9;CHEROKEE LETTER GI;Lo;0;L;;;;;N;;;;; -13AA;CHEROKEE LETTER GO;Lo;0;L;;;;;N;;;;; -13AB;CHEROKEE LETTER GU;Lo;0;L;;;;;N;;;;; -13AC;CHEROKEE LETTER GV;Lo;0;L;;;;;N;;;;; -13AD;CHEROKEE LETTER HA;Lo;0;L;;;;;N;;;;; -13AE;CHEROKEE LETTER HE;Lo;0;L;;;;;N;;;;; -13AF;CHEROKEE LETTER HI;Lo;0;L;;;;;N;;;;; -13B0;CHEROKEE LETTER HO;Lo;0;L;;;;;N;;;;; -13B1;CHEROKEE LETTER HU;Lo;0;L;;;;;N;;;;; -13B2;CHEROKEE LETTER HV;Lo;0;L;;;;;N;;;;; -13B3;CHEROKEE LETTER LA;Lo;0;L;;;;;N;;;;; -13B4;CHEROKEE LETTER LE;Lo;0;L;;;;;N;;;;; -13B5;CHEROKEE LETTER LI;Lo;0;L;;;;;N;;;;; -13B6;CHEROKEE LETTER LO;Lo;0;L;;;;;N;;;;; -13B7;CHEROKEE LETTER LU;Lo;0;L;;;;;N;;;;; -13B8;CHEROKEE LETTER LV;Lo;0;L;;;;;N;;;;; -13B9;CHEROKEE LETTER MA;Lo;0;L;;;;;N;;;;; -13BA;CHEROKEE LETTER ME;Lo;0;L;;;;;N;;;;; -13BB;CHEROKEE LETTER MI;Lo;0;L;;;;;N;;;;; -13BC;CHEROKEE LETTER MO;Lo;0;L;;;;;N;;;;; -13BD;CHEROKEE LETTER MU;Lo;0;L;;;;;N;;;;; -13BE;CHEROKEE LETTER NA;Lo;0;L;;;;;N;;;;; -13BF;CHEROKEE LETTER HNA;Lo;0;L;;;;;N;;;;; -13C0;CHEROKEE LETTER NAH;Lo;0;L;;;;;N;;;;; -13C1;CHEROKEE LETTER NE;Lo;0;L;;;;;N;;;;; -13C2;CHEROKEE LETTER NI;Lo;0;L;;;;;N;;;;; -13C3;CHEROKEE LETTER NO;Lo;0;L;;;;;N;;;;; -13C4;CHEROKEE LETTER NU;Lo;0;L;;;;;N;;;;; -13C5;CHEROKEE LETTER NV;Lo;0;L;;;;;N;;;;; -13C6;CHEROKEE LETTER QUA;Lo;0;L;;;;;N;;;;; -13C7;CHEROKEE LETTER QUE;Lo;0;L;;;;;N;;;;; -13C8;CHEROKEE LETTER QUI;Lo;0;L;;;;;N;;;;; -13C9;CHEROKEE LETTER QUO;Lo;0;L;;;;;N;;;;; -13CA;CHEROKEE LETTER QUU;Lo;0;L;;;;;N;;;;; -13CB;CHEROKEE LETTER QUV;Lo;0;L;;;;;N;;;;; -13CC;CHEROKEE LETTER SA;Lo;0;L;;;;;N;;;;; -13CD;CHEROKEE LETTER S;Lo;0;L;;;;;N;;;;; -13CE;CHEROKEE LETTER SE;Lo;0;L;;;;;N;;;;; -13CF;CHEROKEE LETTER SI;Lo;0;L;;;;;N;;;;; -13D0;CHEROKEE LETTER SO;Lo;0;L;;;;;N;;;;; -13D1;CHEROKEE LETTER SU;Lo;0;L;;;;;N;;;;; -13D2;CHEROKEE LETTER SV;Lo;0;L;;;;;N;;;;; -13D3;CHEROKEE LETTER DA;Lo;0;L;;;;;N;;;;; -13D4;CHEROKEE LETTER TA;Lo;0;L;;;;;N;;;;; -13D5;CHEROKEE LETTER DE;Lo;0;L;;;;;N;;;;; -13D6;CHEROKEE LETTER TE;Lo;0;L;;;;;N;;;;; -13D7;CHEROKEE LETTER DI;Lo;0;L;;;;;N;;;;; -13D8;CHEROKEE LETTER TI;Lo;0;L;;;;;N;;;;; -13D9;CHEROKEE LETTER DO;Lo;0;L;;;;;N;;;;; -13DA;CHEROKEE LETTER DU;Lo;0;L;;;;;N;;;;; -13DB;CHEROKEE LETTER DV;Lo;0;L;;;;;N;;;;; -13DC;CHEROKEE LETTER DLA;Lo;0;L;;;;;N;;;;; -13DD;CHEROKEE LETTER TLA;Lo;0;L;;;;;N;;;;; -13DE;CHEROKEE LETTER TLE;Lo;0;L;;;;;N;;;;; -13DF;CHEROKEE LETTER TLI;Lo;0;L;;;;;N;;;;; -13E0;CHEROKEE LETTER TLO;Lo;0;L;;;;;N;;;;; -13E1;CHEROKEE LETTER TLU;Lo;0;L;;;;;N;;;;; -13E2;CHEROKEE LETTER TLV;Lo;0;L;;;;;N;;;;; -13E3;CHEROKEE LETTER TSA;Lo;0;L;;;;;N;;;;; -13E4;CHEROKEE LETTER TSE;Lo;0;L;;;;;N;;;;; -13E5;CHEROKEE LETTER TSI;Lo;0;L;;;;;N;;;;; -13E6;CHEROKEE LETTER TSO;Lo;0;L;;;;;N;;;;; -13E7;CHEROKEE LETTER TSU;Lo;0;L;;;;;N;;;;; -13E8;CHEROKEE LETTER TSV;Lo;0;L;;;;;N;;;;; -13E9;CHEROKEE LETTER WA;Lo;0;L;;;;;N;;;;; -13EA;CHEROKEE LETTER WE;Lo;0;L;;;;;N;;;;; -13EB;CHEROKEE LETTER WI;Lo;0;L;;;;;N;;;;; -13EC;CHEROKEE LETTER WO;Lo;0;L;;;;;N;;;;; -13ED;CHEROKEE LETTER WU;Lo;0;L;;;;;N;;;;; -13EE;CHEROKEE LETTER WV;Lo;0;L;;;;;N;;;;; -13EF;CHEROKEE LETTER YA;Lo;0;L;;;;;N;;;;; -13F0;CHEROKEE LETTER YE;Lo;0;L;;;;;N;;;;; -13F1;CHEROKEE LETTER YI;Lo;0;L;;;;;N;;;;; -13F2;CHEROKEE LETTER YO;Lo;0;L;;;;;N;;;;; -13F3;CHEROKEE LETTER YU;Lo;0;L;;;;;N;;;;; -13F4;CHEROKEE LETTER YV;Lo;0;L;;;;;N;;;;; +13A0;CHEROKEE LETTER A;Lu;0;L;;;;;N;;;;AB70; +13A1;CHEROKEE LETTER E;Lu;0;L;;;;;N;;;;AB71; +13A2;CHEROKEE LETTER I;Lu;0;L;;;;;N;;;;AB72; +13A3;CHEROKEE LETTER O;Lu;0;L;;;;;N;;;;AB73; +13A4;CHEROKEE LETTER U;Lu;0;L;;;;;N;;;;AB74; +13A5;CHEROKEE LETTER V;Lu;0;L;;;;;N;;;;AB75; +13A6;CHEROKEE LETTER GA;Lu;0;L;;;;;N;;;;AB76; +13A7;CHEROKEE LETTER KA;Lu;0;L;;;;;N;;;;AB77; +13A8;CHEROKEE LETTER GE;Lu;0;L;;;;;N;;;;AB78; +13A9;CHEROKEE LETTER GI;Lu;0;L;;;;;N;;;;AB79; +13AA;CHEROKEE LETTER GO;Lu;0;L;;;;;N;;;;AB7A; +13AB;CHEROKEE LETTER GU;Lu;0;L;;;;;N;;;;AB7B; +13AC;CHEROKEE LETTER GV;Lu;0;L;;;;;N;;;;AB7C; +13AD;CHEROKEE LETTER HA;Lu;0;L;;;;;N;;;;AB7D; +13AE;CHEROKEE LETTER HE;Lu;0;L;;;;;N;;;;AB7E; +13AF;CHEROKEE LETTER HI;Lu;0;L;;;;;N;;;;AB7F; +13B0;CHEROKEE LETTER HO;Lu;0;L;;;;;N;;;;AB80; +13B1;CHEROKEE LETTER HU;Lu;0;L;;;;;N;;;;AB81; +13B2;CHEROKEE LETTER HV;Lu;0;L;;;;;N;;;;AB82; +13B3;CHEROKEE LETTER LA;Lu;0;L;;;;;N;;;;AB83; +13B4;CHEROKEE LETTER LE;Lu;0;L;;;;;N;;;;AB84; +13B5;CHEROKEE LETTER LI;Lu;0;L;;;;;N;;;;AB85; +13B6;CHEROKEE LETTER LO;Lu;0;L;;;;;N;;;;AB86; +13B7;CHEROKEE LETTER LU;Lu;0;L;;;;;N;;;;AB87; +13B8;CHEROKEE LETTER LV;Lu;0;L;;;;;N;;;;AB88; +13B9;CHEROKEE LETTER MA;Lu;0;L;;;;;N;;;;AB89; +13BA;CHEROKEE LETTER ME;Lu;0;L;;;;;N;;;;AB8A; +13BB;CHEROKEE LETTER MI;Lu;0;L;;;;;N;;;;AB8B; +13BC;CHEROKEE LETTER MO;Lu;0;L;;;;;N;;;;AB8C; +13BD;CHEROKEE LETTER MU;Lu;0;L;;;;;N;;;;AB8D; +13BE;CHEROKEE LETTER NA;Lu;0;L;;;;;N;;;;AB8E; +13BF;CHEROKEE LETTER HNA;Lu;0;L;;;;;N;;;;AB8F; +13C0;CHEROKEE LETTER NAH;Lu;0;L;;;;;N;;;;AB90; +13C1;CHEROKEE LETTER NE;Lu;0;L;;;;;N;;;;AB91; +13C2;CHEROKEE LETTER NI;Lu;0;L;;;;;N;;;;AB92; +13C3;CHEROKEE LETTER NO;Lu;0;L;;;;;N;;;;AB93; +13C4;CHEROKEE LETTER NU;Lu;0;L;;;;;N;;;;AB94; +13C5;CHEROKEE LETTER NV;Lu;0;L;;;;;N;;;;AB95; +13C6;CHEROKEE LETTER QUA;Lu;0;L;;;;;N;;;;AB96; +13C7;CHEROKEE LETTER QUE;Lu;0;L;;;;;N;;;;AB97; +13C8;CHEROKEE LETTER QUI;Lu;0;L;;;;;N;;;;AB98; +13C9;CHEROKEE LETTER QUO;Lu;0;L;;;;;N;;;;AB99; +13CA;CHEROKEE LETTER QUU;Lu;0;L;;;;;N;;;;AB9A; +13CB;CHEROKEE LETTER QUV;Lu;0;L;;;;;N;;;;AB9B; +13CC;CHEROKEE LETTER SA;Lu;0;L;;;;;N;;;;AB9C; +13CD;CHEROKEE LETTER S;Lu;0;L;;;;;N;;;;AB9D; +13CE;CHEROKEE LETTER SE;Lu;0;L;;;;;N;;;;AB9E; +13CF;CHEROKEE LETTER SI;Lu;0;L;;;;;N;;;;AB9F; +13D0;CHEROKEE LETTER SO;Lu;0;L;;;;;N;;;;ABA0; +13D1;CHEROKEE LETTER SU;Lu;0;L;;;;;N;;;;ABA1; +13D2;CHEROKEE LETTER SV;Lu;0;L;;;;;N;;;;ABA2; +13D3;CHEROKEE LETTER DA;Lu;0;L;;;;;N;;;;ABA3; +13D4;CHEROKEE LETTER TA;Lu;0;L;;;;;N;;;;ABA4; +13D5;CHEROKEE LETTER DE;Lu;0;L;;;;;N;;;;ABA5; +13D6;CHEROKEE LETTER TE;Lu;0;L;;;;;N;;;;ABA6; +13D7;CHEROKEE LETTER DI;Lu;0;L;;;;;N;;;;ABA7; +13D8;CHEROKEE LETTER TI;Lu;0;L;;;;;N;;;;ABA8; +13D9;CHEROKEE LETTER DO;Lu;0;L;;;;;N;;;;ABA9; +13DA;CHEROKEE LETTER DU;Lu;0;L;;;;;N;;;;ABAA; +13DB;CHEROKEE LETTER DV;Lu;0;L;;;;;N;;;;ABAB; +13DC;CHEROKEE LETTER DLA;Lu;0;L;;;;;N;;;;ABAC; +13DD;CHEROKEE LETTER TLA;Lu;0;L;;;;;N;;;;ABAD; +13DE;CHEROKEE LETTER TLE;Lu;0;L;;;;;N;;;;ABAE; +13DF;CHEROKEE LETTER TLI;Lu;0;L;;;;;N;;;;ABAF; +13E0;CHEROKEE LETTER TLO;Lu;0;L;;;;;N;;;;ABB0; +13E1;CHEROKEE LETTER TLU;Lu;0;L;;;;;N;;;;ABB1; +13E2;CHEROKEE LETTER TLV;Lu;0;L;;;;;N;;;;ABB2; +13E3;CHEROKEE LETTER TSA;Lu;0;L;;;;;N;;;;ABB3; +13E4;CHEROKEE LETTER TSE;Lu;0;L;;;;;N;;;;ABB4; +13E5;CHEROKEE LETTER TSI;Lu;0;L;;;;;N;;;;ABB5; +13E6;CHEROKEE LETTER TSO;Lu;0;L;;;;;N;;;;ABB6; +13E7;CHEROKEE LETTER TSU;Lu;0;L;;;;;N;;;;ABB7; +13E8;CHEROKEE LETTER TSV;Lu;0;L;;;;;N;;;;ABB8; +13E9;CHEROKEE LETTER WA;Lu;0;L;;;;;N;;;;ABB9; +13EA;CHEROKEE LETTER WE;Lu;0;L;;;;;N;;;;ABBA; +13EB;CHEROKEE LETTER WI;Lu;0;L;;;;;N;;;;ABBB; +13EC;CHEROKEE LETTER WO;Lu;0;L;;;;;N;;;;ABBC; +13ED;CHEROKEE LETTER WU;Lu;0;L;;;;;N;;;;ABBD; +13EE;CHEROKEE LETTER WV;Lu;0;L;;;;;N;;;;ABBE; +13EF;CHEROKEE LETTER YA;Lu;0;L;;;;;N;;;;ABBF; +13F0;CHEROKEE LETTER YE;Lu;0;L;;;;;N;;;;13F8; +13F1;CHEROKEE LETTER YI;Lu;0;L;;;;;N;;;;13F9; +13F2;CHEROKEE LETTER YO;Lu;0;L;;;;;N;;;;13FA; +13F3;CHEROKEE LETTER YU;Lu;0;L;;;;;N;;;;13FB; +13F4;CHEROKEE LETTER YV;Lu;0;L;;;;;N;;;;13FC; +13F5;CHEROKEE LETTER MV;Lu;0;L;;;;;N;;;;13FD; +13F8;CHEROKEE SMALL LETTER YE;Ll;0;L;;;;;N;;;13F0;;13F0 +13F9;CHEROKEE SMALL LETTER YI;Ll;0;L;;;;;N;;;13F1;;13F1 +13FA;CHEROKEE SMALL LETTER YO;Ll;0;L;;;;;N;;;13F2;;13F2 +13FB;CHEROKEE SMALL LETTER YU;Ll;0;L;;;;;N;;;13F3;;13F3 +13FC;CHEROKEE SMALL LETTER YV;Ll;0;L;;;;;N;;;13F4;;13F4 +13FD;CHEROKEE SMALL LETTER MV;Ll;0;L;;;;;N;;;13F5;;13F5 1400;CANADIAN SYLLABICS HYPHEN;Pd;0;ON;;;;;N;;;;; 1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;; 1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;; @@ -5700,23 +5713,23 @@ 19A9;NEW TAI LUE LETTER LOW XVA;Lo;0;L;;;;;N;;;;; 19AA;NEW TAI LUE LETTER HIGH SUA;Lo;0;L;;;;;N;;;;; 19AB;NEW TAI LUE LETTER LOW SUA;Lo;0;L;;;;;N;;;;; -19B0;NEW TAI LUE VOWEL SIGN VOWEL SHORTENER;Mc;0;L;;;;;N;;;;; -19B1;NEW TAI LUE VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -19B2;NEW TAI LUE VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -19B3;NEW TAI LUE VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -19B4;NEW TAI LUE VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; -19B5;NEW TAI LUE VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -19B6;NEW TAI LUE VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; -19B7;NEW TAI LUE VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -19B8;NEW TAI LUE VOWEL SIGN OA;Mc;0;L;;;;;N;;;;; -19B9;NEW TAI LUE VOWEL SIGN UE;Mc;0;L;;;;;N;;;;; -19BA;NEW TAI LUE VOWEL SIGN AY;Mc;0;L;;;;;N;;;;; -19BB;NEW TAI LUE VOWEL SIGN AAY;Mc;0;L;;;;;N;;;;; -19BC;NEW TAI LUE VOWEL SIGN UY;Mc;0;L;;;;;N;;;;; -19BD;NEW TAI LUE VOWEL SIGN OY;Mc;0;L;;;;;N;;;;; -19BE;NEW TAI LUE VOWEL SIGN OAY;Mc;0;L;;;;;N;;;;; -19BF;NEW TAI LUE VOWEL SIGN UEY;Mc;0;L;;;;;N;;;;; -19C0;NEW TAI LUE VOWEL SIGN IY;Mc;0;L;;;;;N;;;;; +19B0;NEW TAI LUE VOWEL SIGN VOWEL SHORTENER;Lo;0;L;;;;;N;;;;; +19B1;NEW TAI LUE VOWEL SIGN AA;Lo;0;L;;;;;N;;;;; +19B2;NEW TAI LUE VOWEL SIGN II;Lo;0;L;;;;;N;;;;; +19B3;NEW TAI LUE VOWEL SIGN U;Lo;0;L;;;;;N;;;;; +19B4;NEW TAI LUE VOWEL SIGN UU;Lo;0;L;;;;;N;;;;; +19B5;NEW TAI LUE VOWEL SIGN E;Lo;0;L;;;;;N;;;;; +19B6;NEW TAI LUE VOWEL SIGN AE;Lo;0;L;;;;;N;;;;; +19B7;NEW TAI LUE VOWEL SIGN O;Lo;0;L;;;;;N;;;;; +19B8;NEW TAI LUE VOWEL SIGN OA;Lo;0;L;;;;;N;;;;; +19B9;NEW TAI LUE VOWEL SIGN UE;Lo;0;L;;;;;N;;;;; +19BA;NEW TAI LUE VOWEL SIGN AY;Lo;0;L;;;;;N;;;;; +19BB;NEW TAI LUE VOWEL SIGN AAY;Lo;0;L;;;;;N;;;;; +19BC;NEW TAI LUE VOWEL SIGN UY;Lo;0;L;;;;;N;;;;; +19BD;NEW TAI LUE VOWEL SIGN OY;Lo;0;L;;;;;N;;;;; +19BE;NEW TAI LUE VOWEL SIGN OAY;Lo;0;L;;;;;N;;;;; +19BF;NEW TAI LUE VOWEL SIGN UEY;Lo;0;L;;;;;N;;;;; +19C0;NEW TAI LUE VOWEL SIGN IY;Lo;0;L;;;;;N;;;;; 19C1;NEW TAI LUE LETTER FINAL V;Lo;0;L;;;;;N;;;;; 19C2;NEW TAI LUE LETTER FINAL NG;Lo;0;L;;;;;N;;;;; 19C3;NEW TAI LUE LETTER FINAL N;Lo;0;L;;;;;N;;;;; @@ -5724,8 +5737,8 @@ 19C5;NEW TAI LUE LETTER FINAL K;Lo;0;L;;;;;N;;;;; 19C6;NEW TAI LUE LETTER FINAL D;Lo;0;L;;;;;N;;;;; 19C7;NEW TAI LUE LETTER FINAL B;Lo;0;L;;;;;N;;;;; -19C8;NEW TAI LUE TONE MARK-1;Mc;0;L;;;;;N;;;;; -19C9;NEW TAI LUE TONE MARK-2;Mc;0;L;;;;;N;;;;; +19C8;NEW TAI LUE TONE MARK-1;Lo;0;L;;;;;N;;;;; +19C9;NEW TAI LUE TONE MARK-2;Lo;0;L;;;;;N;;;;; 19D0;NEW TAI LUE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 19D1;NEW TAI LUE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 19D2;NEW TAI LUE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -7277,6 +7290,7 @@ 20BB;NORDIC MARK SIGN;Sc;0;ET;;;;;N;;;;; 20BC;MANAT SIGN;Sc;0;ET;;;;;N;;;;; 20BD;RUBLE SIGN;Sc;0;ET;;;;;N;;;;; +20BE;LARI SIGN;Sc;0;ET;;;;;N;;;;; 20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; 20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; 20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; @@ -7448,6 +7462,8 @@ 2187;ROMAN NUMERAL FIFTY THOUSAND;Nl;0;L;;;;50000;N;;;;; 2188;ROMAN NUMERAL ONE HUNDRED THOUSAND;Nl;0;L;;;;100000;N;;;;; 2189;VULGAR FRACTION ZERO THIRDS;No;0;ON; 0030 2044 0033;;;0;N;;;;; +218A;TURNED DIGIT TWO;So;0;ON;;;;;N;;;;; +218B;TURNED DIGIT THREE;So;0;ON;;;;;N;;;;; 2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;; 2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;; 2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;; @@ -10015,6 +10031,10 @@ 2BCF;ROTATED WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;; 2BD0;SQUARE POSITION INDICATOR;So;0;ON;;;;;N;;;;; 2BD1;UNCERTAINTY SIGN;So;0;ON;;;;;N;;;;; +2BEC;LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; +2BED;UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; +2BEE;RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; +2BEF;DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; 2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30; 2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31; 2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32; @@ -11942,7 +11962,7 @@ 4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;; 4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;; 4E00;;Lo;0;L;;;;;N;;;;; -9FCC;;Lo;0;L;;;;;N;;;;; +9FD5;;Lo;0;L;;;;;N;;;;; A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; @@ -13605,6 +13625,7 @@ A69A;CYRILLIC CAPITAL LETTER CROSSED O;Lu;0;L;;;;;N;;;;A69B; A69B;CYRILLIC SMALL LETTER CROSSED O;Ll;0;L;;;;;N;;;A69A;;A69A A69C;MODIFIER LETTER CYRILLIC HARD SIGN;Lm;0;L; 044A;;;;N;;;;; A69D;MODIFIER LETTER CYRILLIC SOFT SIGN;Lm;0;L; 044C;;;;N;;;;; +A69E;COMBINING CYRILLIC LETTER EF;Mn;230;NSM;;;;;N;;;;; A69F;COMBINING CYRILLIC LETTER IOTIFIED E;Mn;230;NSM;;;;;N;;;;; A6A0;BAMUM LETTER A;Lo;0;L;;;;;N;;;;; A6A1;BAMUM LETTER KA;Lo;0;L;;;;;N;;;;; @@ -13837,6 +13858,7 @@ A78B;LATIN CAPITAL LETTER SALTILLO;Lu;0;L;;;;;N;;;;A78C; A78C;LATIN SMALL LETTER SALTILLO;Ll;0;L;;;;;N;;;A78B;;A78B A78D;LATIN CAPITAL LETTER TURNED H;Lu;0;L;;;;;N;;;;0265; A78E;LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT;Ll;0;L;;;;;N;;;;; +A78F;LATIN LETTER SINOLOGICAL DOT;Lo;0;L;;;;;N;;;;; A790;LATIN CAPITAL LETTER N WITH DESCENDER;Lu;0;L;;;;;N;;;;A791; A791;LATIN SMALL LETTER N WITH DESCENDER;Ll;0;L;;;;;N;;;A790;;A790 A792;LATIN CAPITAL LETTER C WITH BAR;Lu;0;L;;;;;N;;;;A793; @@ -13869,6 +13891,12 @@ A7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261; A7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C; A7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E; A7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287; +A7B2;LATIN CAPITAL LETTER J WITH CROSSED-TAIL;Lu;0;L;;;;;N;;;;029D; +A7B3;LATIN CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;AB53; +A7B4;LATIN CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;A7B5; +A7B5;LATIN SMALL LETTER BETA;Ll;0;L;;;;;N;;;A7B4;;A7B4 +A7B6;LATIN CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;A7B7; +A7B7;LATIN SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;A7B6;;A7B6 A7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;; A7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L; 0126;;;;N;;;;; A7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L; 0153;;;;N;;;;; @@ -14097,6 +14125,8 @@ A8F8;DEVANAGARI SIGN PUSHPIKA;Po;0;L;;;;;N;;;;; A8F9;DEVANAGARI GAP FILLER;Po;0;L;;;;;N;;;;; A8FA;DEVANAGARI CARET;Po;0;L;;;;;N;;;;; A8FB;DEVANAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;; +A8FC;DEVANAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;; +A8FD;DEVANAGARI JAIN OM;Lo;0;L;;;;;N;;;;; A900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; A901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; A902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -14610,7 +14640,7 @@ AB4F;LATIN SMALL LETTER U BAR WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;; AB50;LATIN SMALL LETTER UI;Ll;0;L;;;;;N;;;;; AB51;LATIN SMALL LETTER TURNED UI;Ll;0;L;;;;;N;;;;; AB52;LATIN SMALL LETTER U WITH LEFT HOOK;Ll;0;L;;;;;N;;;;; -AB53;LATIN SMALL LETTER CHI;Ll;0;L;;;;;N;;;;; +AB53;LATIN SMALL LETTER CHI;Ll;0;L;;;;;N;;;A7B3;;A7B3 AB54;LATIN SMALL LETTER CHI WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;; AB55;LATIN SMALL LETTER CHI WITH LOW LEFT SERIF;Ll;0;L;;;;;N;;;;; AB56;LATIN SMALL LETTER X WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;; @@ -14623,8 +14653,92 @@ AB5C;MODIFIER LETTER SMALL HENG;Lm;0;L; A727;;;;N;;;;; AB5D;MODIFIER LETTER SMALL L WITH INVERTED LAZY S;Lm;0;L; AB37;;;;N;;;;; AB5E;MODIFIER LETTER SMALL L WITH MIDDLE TILDE;Lm;0;L; 026B;;;;N;;;;; AB5F;MODIFIER LETTER SMALL U WITH LEFT HOOK;Lm;0;L; AB52;;;;N;;;;; +AB60;LATIN SMALL LETTER SAKHA YAT;Ll;0;L;;;;;N;;;;; +AB61;LATIN SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;;; +AB62;LATIN SMALL LETTER OPEN OE;Ll;0;L;;;;;N;;;;; +AB63;LATIN SMALL LETTER UO;Ll;0;L;;;;;N;;;;; AB64;LATIN SMALL LETTER INVERTED ALPHA;Ll;0;L;;;;;N;;;;; AB65;GREEK LETTER SMALL CAPITAL OMEGA;Ll;0;L;;;;;N;;;;; +AB70;CHEROKEE SMALL LETTER A;Ll;0;L;;;;;N;;;13A0;;13A0 +AB71;CHEROKEE SMALL LETTER E;Ll;0;L;;;;;N;;;13A1;;13A1 +AB72;CHEROKEE SMALL LETTER I;Ll;0;L;;;;;N;;;13A2;;13A2 +AB73;CHEROKEE SMALL LETTER O;Ll;0;L;;;;;N;;;13A3;;13A3 +AB74;CHEROKEE SMALL LETTER U;Ll;0;L;;;;;N;;;13A4;;13A4 +AB75;CHEROKEE SMALL LETTER V;Ll;0;L;;;;;N;;;13A5;;13A5 +AB76;CHEROKEE SMALL LETTER GA;Ll;0;L;;;;;N;;;13A6;;13A6 +AB77;CHEROKEE SMALL LETTER KA;Ll;0;L;;;;;N;;;13A7;;13A7 +AB78;CHEROKEE SMALL LETTER GE;Ll;0;L;;;;;N;;;13A8;;13A8 +AB79;CHEROKEE SMALL LETTER GI;Ll;0;L;;;;;N;;;13A9;;13A9 +AB7A;CHEROKEE SMALL LETTER GO;Ll;0;L;;;;;N;;;13AA;;13AA +AB7B;CHEROKEE SMALL LETTER GU;Ll;0;L;;;;;N;;;13AB;;13AB +AB7C;CHEROKEE SMALL LETTER GV;Ll;0;L;;;;;N;;;13AC;;13AC +AB7D;CHEROKEE SMALL LETTER HA;Ll;0;L;;;;;N;;;13AD;;13AD +AB7E;CHEROKEE SMALL LETTER HE;Ll;0;L;;;;;N;;;13AE;;13AE +AB7F;CHEROKEE SMALL LETTER HI;Ll;0;L;;;;;N;;;13AF;;13AF +AB80;CHEROKEE SMALL LETTER HO;Ll;0;L;;;;;N;;;13B0;;13B0 +AB81;CHEROKEE SMALL LETTER HU;Ll;0;L;;;;;N;;;13B1;;13B1 +AB82;CHEROKEE SMALL LETTER HV;Ll;0;L;;;;;N;;;13B2;;13B2 +AB83;CHEROKEE SMALL LETTER LA;Ll;0;L;;;;;N;;;13B3;;13B3 +AB84;CHEROKEE SMALL LETTER LE;Ll;0;L;;;;;N;;;13B4;;13B4 +AB85;CHEROKEE SMALL LETTER LI;Ll;0;L;;;;;N;;;13B5;;13B5 +AB86;CHEROKEE SMALL LETTER LO;Ll;0;L;;;;;N;;;13B6;;13B6 +AB87;CHEROKEE SMALL LETTER LU;Ll;0;L;;;;;N;;;13B7;;13B7 +AB88;CHEROKEE SMALL LETTER LV;Ll;0;L;;;;;N;;;13B8;;13B8 +AB89;CHEROKEE SMALL LETTER MA;Ll;0;L;;;;;N;;;13B9;;13B9 +AB8A;CHEROKEE SMALL LETTER ME;Ll;0;L;;;;;N;;;13BA;;13BA +AB8B;CHEROKEE SMALL LETTER MI;Ll;0;L;;;;;N;;;13BB;;13BB +AB8C;CHEROKEE SMALL LETTER MO;Ll;0;L;;;;;N;;;13BC;;13BC +AB8D;CHEROKEE SMALL LETTER MU;Ll;0;L;;;;;N;;;13BD;;13BD +AB8E;CHEROKEE SMALL LETTER NA;Ll;0;L;;;;;N;;;13BE;;13BE +AB8F;CHEROKEE SMALL LETTER HNA;Ll;0;L;;;;;N;;;13BF;;13BF +AB90;CHEROKEE SMALL LETTER NAH;Ll;0;L;;;;;N;;;13C0;;13C0 +AB91;CHEROKEE SMALL LETTER NE;Ll;0;L;;;;;N;;;13C1;;13C1 +AB92;CHEROKEE SMALL LETTER NI;Ll;0;L;;;;;N;;;13C2;;13C2 +AB93;CHEROKEE SMALL LETTER NO;Ll;0;L;;;;;N;;;13C3;;13C3 +AB94;CHEROKEE SMALL LETTER NU;Ll;0;L;;;;;N;;;13C4;;13C4 +AB95;CHEROKEE SMALL LETTER NV;Ll;0;L;;;;;N;;;13C5;;13C5 +AB96;CHEROKEE SMALL LETTER QUA;Ll;0;L;;;;;N;;;13C6;;13C6 +AB97;CHEROKEE SMALL LETTER QUE;Ll;0;L;;;;;N;;;13C7;;13C7 +AB98;CHEROKEE SMALL LETTER QUI;Ll;0;L;;;;;N;;;13C8;;13C8 +AB99;CHEROKEE SMALL LETTER QUO;Ll;0;L;;;;;N;;;13C9;;13C9 +AB9A;CHEROKEE SMALL LETTER QUU;Ll;0;L;;;;;N;;;13CA;;13CA +AB9B;CHEROKEE SMALL LETTER QUV;Ll;0;L;;;;;N;;;13CB;;13CB +AB9C;CHEROKEE SMALL LETTER SA;Ll;0;L;;;;;N;;;13CC;;13CC +AB9D;CHEROKEE SMALL LETTER S;Ll;0;L;;;;;N;;;13CD;;13CD +AB9E;CHEROKEE SMALL LETTER SE;Ll;0;L;;;;;N;;;13CE;;13CE +AB9F;CHEROKEE SMALL LETTER SI;Ll;0;L;;;;;N;;;13CF;;13CF +ABA0;CHEROKEE SMALL LETTER SO;Ll;0;L;;;;;N;;;13D0;;13D0 +ABA1;CHEROKEE SMALL LETTER SU;Ll;0;L;;;;;N;;;13D1;;13D1 +ABA2;CHEROKEE SMALL LETTER SV;Ll;0;L;;;;;N;;;13D2;;13D2 +ABA3;CHEROKEE SMALL LETTER DA;Ll;0;L;;;;;N;;;13D3;;13D3 +ABA4;CHEROKEE SMALL LETTER TA;Ll;0;L;;;;;N;;;13D4;;13D4 +ABA5;CHEROKEE SMALL LETTER DE;Ll;0;L;;;;;N;;;13D5;;13D5 +ABA6;CHEROKEE SMALL LETTER TE;Ll;0;L;;;;;N;;;13D6;;13D6 +ABA7;CHEROKEE SMALL LETTER DI;Ll;0;L;;;;;N;;;13D7;;13D7 +ABA8;CHEROKEE SMALL LETTER TI;Ll;0;L;;;;;N;;;13D8;;13D8 +ABA9;CHEROKEE SMALL LETTER DO;Ll;0;L;;;;;N;;;13D9;;13D9 +ABAA;CHEROKEE SMALL LETTER DU;Ll;0;L;;;;;N;;;13DA;;13DA +ABAB;CHEROKEE SMALL LETTER DV;Ll;0;L;;;;;N;;;13DB;;13DB +ABAC;CHEROKEE SMALL LETTER DLA;Ll;0;L;;;;;N;;;13DC;;13DC +ABAD;CHEROKEE SMALL LETTER TLA;Ll;0;L;;;;;N;;;13DD;;13DD +ABAE;CHEROKEE SMALL LETTER TLE;Ll;0;L;;;;;N;;;13DE;;13DE +ABAF;CHEROKEE SMALL LETTER TLI;Ll;0;L;;;;;N;;;13DF;;13DF +ABB0;CHEROKEE SMALL LETTER TLO;Ll;0;L;;;;;N;;;13E0;;13E0 +ABB1;CHEROKEE SMALL LETTER TLU;Ll;0;L;;;;;N;;;13E1;;13E1 +ABB2;CHEROKEE SMALL LETTER TLV;Ll;0;L;;;;;N;;;13E2;;13E2 +ABB3;CHEROKEE SMALL LETTER TSA;Ll;0;L;;;;;N;;;13E3;;13E3 +ABB4;CHEROKEE SMALL LETTER TSE;Ll;0;L;;;;;N;;;13E4;;13E4 +ABB5;CHEROKEE SMALL LETTER TSI;Ll;0;L;;;;;N;;;13E5;;13E5 +ABB6;CHEROKEE SMALL LETTER TSO;Ll;0;L;;;;;N;;;13E6;;13E6 +ABB7;CHEROKEE SMALL LETTER TSU;Ll;0;L;;;;;N;;;13E7;;13E7 +ABB8;CHEROKEE SMALL LETTER TSV;Ll;0;L;;;;;N;;;13E8;;13E8 +ABB9;CHEROKEE SMALL LETTER WA;Ll;0;L;;;;;N;;;13E9;;13E9 +ABBA;CHEROKEE SMALL LETTER WE;Ll;0;L;;;;;N;;;13EA;;13EA +ABBB;CHEROKEE SMALL LETTER WI;Ll;0;L;;;;;N;;;13EB;;13EB +ABBC;CHEROKEE SMALL LETTER WO;Ll;0;L;;;;;N;;;13EC;;13EC +ABBD;CHEROKEE SMALL LETTER WU;Ll;0;L;;;;;N;;;13ED;;13ED +ABBE;CHEROKEE SMALL LETTER WV;Ll;0;L;;;;;N;;;13EE;;13EE +ABBF;CHEROKEE SMALL LETTER YA;Ll;0;L;;;;;N;;;13EF;;13EF ABC0;MEETEI MAYEK LETTER KOK;Lo;0;L;;;;;N;;;;; ABC1;MEETEI MAYEK LETTER SAM;Lo;0;L;;;;;N;;;;; ABC2;MEETEI MAYEK LETTER LAI;Lo;0;L;;;;;N;;;;; @@ -15944,6 +16058,8 @@ FE2A;COMBINING TILDE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; FE2B;COMBINING MACRON LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;; FE2C;COMBINING MACRON RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; FE2D;COMBINING CONJOINING MACRON BELOW;Mn;220;NSM;;;;;N;;;;; +FE2E;COMBINING CYRILLIC TITLO LEFT HALF;Mn;230;NSM;;;;;N;;;;; +FE2F;COMBINING CYRILLIC TITLO RIGHT HALF;Mn;230;NSM;;;;;N;;;;; FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON; 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;; FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON; 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;; FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON; 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;; @@ -17830,6 +17946,32 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 108AD;NABATAEAN NUMBER TEN;No;0;R;;;;10;N;;;;; 108AE;NABATAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; 108AF;NABATAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +108E0;HATRAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; +108E1;HATRAN LETTER BETH;Lo;0;R;;;;;N;;;;; +108E2;HATRAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +108E3;HATRAN LETTER DALETH-RESH;Lo;0;R;;;;;N;;;;; +108E4;HATRAN LETTER HE;Lo;0;R;;;;;N;;;;; +108E5;HATRAN LETTER WAW;Lo;0;R;;;;;N;;;;; +108E6;HATRAN LETTER ZAYN;Lo;0;R;;;;;N;;;;; +108E7;HATRAN LETTER HETH;Lo;0;R;;;;;N;;;;; +108E8;HATRAN LETTER TETH;Lo;0;R;;;;;N;;;;; +108E9;HATRAN LETTER YODH;Lo;0;R;;;;;N;;;;; +108EA;HATRAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +108EB;HATRAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +108EC;HATRAN LETTER MEM;Lo;0;R;;;;;N;;;;; +108ED;HATRAN LETTER NUN;Lo;0;R;;;;;N;;;;; +108EE;HATRAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +108EF;HATRAN LETTER AYN;Lo;0;R;;;;;N;;;;; +108F0;HATRAN LETTER PE;Lo;0;R;;;;;N;;;;; +108F1;HATRAN LETTER SADHE;Lo;0;R;;;;;N;;;;; +108F2;HATRAN LETTER QOPH;Lo;0;R;;;;;N;;;;; +108F4;HATRAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +108F5;HATRAN LETTER TAW;Lo;0;R;;;;;N;;;;; +108FB;HATRAN NUMBER ONE;No;0;R;;;;1;N;;;;; +108FC;HATRAN NUMBER FIVE;No;0;R;;;;5;N;;;;; +108FD;HATRAN NUMBER TEN;No;0;R;;;;10;N;;;;; +108FE;HATRAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +108FF;HATRAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; 10900;PHOENICIAN LETTER ALF;Lo;0;R;;;;;N;;;;; 10901;PHOENICIAN LETTER BET;Lo;0;R;;;;;N;;;;; 10902;PHOENICIAN LETTER GAML;Lo;0;R;;;;;N;;;;; @@ -17942,8 +18084,72 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 109B5;MEROITIC CURSIVE LETTER TE;Lo;0;R;;;;;N;;;;; 109B6;MEROITIC CURSIVE LETTER TO;Lo;0;R;;;;;N;;;;; 109B7;MEROITIC CURSIVE LETTER DA;Lo;0;R;;;;;N;;;;; +109BC;MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS;No;0;R;;;;11/12;N;;;;; +109BD;MEROITIC CURSIVE FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;; 109BE;MEROITIC CURSIVE LOGOGRAM RMT;Lo;0;R;;;;;N;;;;; 109BF;MEROITIC CURSIVE LOGOGRAM IMN;Lo;0;R;;;;;N;;;;; +109C0;MEROITIC CURSIVE NUMBER ONE;No;0;R;;;;1;N;;;;; +109C1;MEROITIC CURSIVE NUMBER TWO;No;0;R;;;;2;N;;;;; +109C2;MEROITIC CURSIVE NUMBER THREE;No;0;R;;;;3;N;;;;; +109C3;MEROITIC CURSIVE NUMBER FOUR;No;0;R;;;;4;N;;;;; +109C4;MEROITIC CURSIVE NUMBER FIVE;No;0;R;;;;5;N;;;;; +109C5;MEROITIC CURSIVE NUMBER SIX;No;0;R;;;;6;N;;;;; +109C6;MEROITIC CURSIVE NUMBER SEVEN;No;0;R;;;;7;N;;;;; +109C7;MEROITIC CURSIVE NUMBER EIGHT;No;0;R;;;;8;N;;;;; +109C8;MEROITIC CURSIVE NUMBER NINE;No;0;R;;;;9;N;;;;; +109C9;MEROITIC CURSIVE NUMBER TEN;No;0;R;;;;10;N;;;;; +109CA;MEROITIC CURSIVE NUMBER TWENTY;No;0;R;;;;20;N;;;;; +109CB;MEROITIC CURSIVE NUMBER THIRTY;No;0;R;;;;30;N;;;;; +109CC;MEROITIC CURSIVE NUMBER FORTY;No;0;R;;;;40;N;;;;; +109CD;MEROITIC CURSIVE NUMBER FIFTY;No;0;R;;;;50;N;;;;; +109CE;MEROITIC CURSIVE NUMBER SIXTY;No;0;R;;;;60;N;;;;; +109CF;MEROITIC CURSIVE NUMBER SEVENTY;No;0;R;;;;70;N;;;;; +109D2;MEROITIC CURSIVE NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +109D3;MEROITIC CURSIVE NUMBER TWO HUNDRED;No;0;R;;;;200;N;;;;; +109D4;MEROITIC CURSIVE NUMBER THREE HUNDRED;No;0;R;;;;300;N;;;;; +109D5;MEROITIC CURSIVE NUMBER FOUR HUNDRED;No;0;R;;;;400;N;;;;; +109D6;MEROITIC CURSIVE NUMBER FIVE HUNDRED;No;0;R;;;;500;N;;;;; +109D7;MEROITIC CURSIVE NUMBER SIX HUNDRED;No;0;R;;;;600;N;;;;; +109D8;MEROITIC CURSIVE NUMBER SEVEN HUNDRED;No;0;R;;;;700;N;;;;; +109D9;MEROITIC CURSIVE NUMBER EIGHT HUNDRED;No;0;R;;;;800;N;;;;; +109DA;MEROITIC CURSIVE NUMBER NINE HUNDRED;No;0;R;;;;900;N;;;;; +109DB;MEROITIC CURSIVE NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +109DC;MEROITIC CURSIVE NUMBER TWO THOUSAND;No;0;R;;;;2000;N;;;;; +109DD;MEROITIC CURSIVE NUMBER THREE THOUSAND;No;0;R;;;;3000;N;;;;; +109DE;MEROITIC CURSIVE NUMBER FOUR THOUSAND;No;0;R;;;;4000;N;;;;; +109DF;MEROITIC CURSIVE NUMBER FIVE THOUSAND;No;0;R;;;;5000;N;;;;; +109E0;MEROITIC CURSIVE NUMBER SIX THOUSAND;No;0;R;;;;6000;N;;;;; +109E1;MEROITIC CURSIVE NUMBER SEVEN THOUSAND;No;0;R;;;;7000;N;;;;; +109E2;MEROITIC CURSIVE NUMBER EIGHT THOUSAND;No;0;R;;;;8000;N;;;;; +109E3;MEROITIC CURSIVE NUMBER NINE THOUSAND;No;0;R;;;;9000;N;;;;; +109E4;MEROITIC CURSIVE NUMBER TEN THOUSAND;No;0;R;;;;10000;N;;;;; +109E5;MEROITIC CURSIVE NUMBER TWENTY THOUSAND;No;0;R;;;;20000;N;;;;; +109E6;MEROITIC CURSIVE NUMBER THIRTY THOUSAND;No;0;R;;;;30000;N;;;;; +109E7;MEROITIC CURSIVE NUMBER FORTY THOUSAND;No;0;R;;;;40000;N;;;;; +109E8;MEROITIC CURSIVE NUMBER FIFTY THOUSAND;No;0;R;;;;50000;N;;;;; +109E9;MEROITIC CURSIVE NUMBER SIXTY THOUSAND;No;0;R;;;;60000;N;;;;; +109EA;MEROITIC CURSIVE NUMBER SEVENTY THOUSAND;No;0;R;;;;70000;N;;;;; +109EB;MEROITIC CURSIVE NUMBER EIGHTY THOUSAND;No;0;R;;;;80000;N;;;;; +109EC;MEROITIC CURSIVE NUMBER NINETY THOUSAND;No;0;R;;;;90000;N;;;;; +109ED;MEROITIC CURSIVE NUMBER ONE HUNDRED THOUSAND;No;0;R;;;;100000;N;;;;; +109EE;MEROITIC CURSIVE NUMBER TWO HUNDRED THOUSAND;No;0;R;;;;200000;N;;;;; +109EF;MEROITIC CURSIVE NUMBER THREE HUNDRED THOUSAND;No;0;R;;;;300000;N;;;;; +109F0;MEROITIC CURSIVE NUMBER FOUR HUNDRED THOUSAND;No;0;R;;;;400000;N;;;;; +109F1;MEROITIC CURSIVE NUMBER FIVE HUNDRED THOUSAND;No;0;R;;;;500000;N;;;;; +109F2;MEROITIC CURSIVE NUMBER SIX HUNDRED THOUSAND;No;0;R;;;;600000;N;;;;; +109F3;MEROITIC CURSIVE NUMBER SEVEN HUNDRED THOUSAND;No;0;R;;;;700000;N;;;;; +109F4;MEROITIC CURSIVE NUMBER EIGHT HUNDRED THOUSAND;No;0;R;;;;800000;N;;;;; +109F5;MEROITIC CURSIVE NUMBER NINE HUNDRED THOUSAND;No;0;R;;;;900000;N;;;;; +109F6;MEROITIC CURSIVE FRACTION ONE TWELFTH;No;0;R;;;;1/12;N;;;;; +109F7;MEROITIC CURSIVE FRACTION TWO TWELFTHS;No;0;R;;;;2/12;N;;;;; +109F8;MEROITIC CURSIVE FRACTION THREE TWELFTHS;No;0;R;;;;3/12;N;;;;; +109F9;MEROITIC CURSIVE FRACTION FOUR TWELFTHS;No;0;R;;;;4/12;N;;;;; +109FA;MEROITIC CURSIVE FRACTION FIVE TWELFTHS;No;0;R;;;;5/12;N;;;;; +109FB;MEROITIC CURSIVE FRACTION SIX TWELFTHS;No;0;R;;;;6/12;N;;;;; +109FC;MEROITIC CURSIVE FRACTION SEVEN TWELFTHS;No;0;R;;;;7/12;N;;;;; +109FD;MEROITIC CURSIVE FRACTION EIGHT TWELFTHS;No;0;R;;;;8/12;N;;;;; +109FE;MEROITIC CURSIVE FRACTION NINE TWELFTHS;No;0;R;;;;9/12;N;;;;; +109FF;MEROITIC CURSIVE FRACTION TEN TWELFTHS;No;0;R;;;;10/12;N;;;;; 10A00;KHAROSHTHI LETTER A;Lo;0;R;;;;;N;;;;; 10A01;KHAROSHTHI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 10A02;KHAROSHTHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; @@ -18344,6 +18550,114 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10C46;OLD TURKIC LETTER YENISEI AET;Lo;0;R;;;;;N;;;;; 10C47;OLD TURKIC LETTER ORKHON OT;Lo;0;R;;;;;N;;;;; 10C48;OLD TURKIC LETTER ORKHON BASH;Lo;0;R;;;;;N;;;;; +10C80;OLD HUNGARIAN CAPITAL LETTER A;Lu;0;R;;;;;N;;;;10CC0; +10C81;OLD HUNGARIAN CAPITAL LETTER AA;Lu;0;R;;;;;N;;;;10CC1; +10C82;OLD HUNGARIAN CAPITAL LETTER EB;Lu;0;R;;;;;N;;;;10CC2; +10C83;OLD HUNGARIAN CAPITAL LETTER AMB;Lu;0;R;;;;;N;;;;10CC3; +10C84;OLD HUNGARIAN CAPITAL LETTER EC;Lu;0;R;;;;;N;;;;10CC4; +10C85;OLD HUNGARIAN CAPITAL LETTER ENC;Lu;0;R;;;;;N;;;;10CC5; +10C86;OLD HUNGARIAN CAPITAL LETTER ECS;Lu;0;R;;;;;N;;;;10CC6; +10C87;OLD HUNGARIAN CAPITAL LETTER ED;Lu;0;R;;;;;N;;;;10CC7; +10C88;OLD HUNGARIAN CAPITAL LETTER AND;Lu;0;R;;;;;N;;;;10CC8; +10C89;OLD HUNGARIAN CAPITAL LETTER E;Lu;0;R;;;;;N;;;;10CC9; +10C8A;OLD HUNGARIAN CAPITAL LETTER CLOSE E;Lu;0;R;;;;;N;;;;10CCA; +10C8B;OLD HUNGARIAN CAPITAL LETTER EE;Lu;0;R;;;;;N;;;;10CCB; +10C8C;OLD HUNGARIAN CAPITAL LETTER EF;Lu;0;R;;;;;N;;;;10CCC; +10C8D;OLD HUNGARIAN CAPITAL LETTER EG;Lu;0;R;;;;;N;;;;10CCD; +10C8E;OLD HUNGARIAN CAPITAL LETTER EGY;Lu;0;R;;;;;N;;;;10CCE; +10C8F;OLD HUNGARIAN CAPITAL LETTER EH;Lu;0;R;;;;;N;;;;10CCF; +10C90;OLD HUNGARIAN CAPITAL LETTER I;Lu;0;R;;;;;N;;;;10CD0; +10C91;OLD HUNGARIAN CAPITAL LETTER II;Lu;0;R;;;;;N;;;;10CD1; +10C92;OLD HUNGARIAN CAPITAL LETTER EJ;Lu;0;R;;;;;N;;;;10CD2; +10C93;OLD HUNGARIAN CAPITAL LETTER EK;Lu;0;R;;;;;N;;;;10CD3; +10C94;OLD HUNGARIAN CAPITAL LETTER AK;Lu;0;R;;;;;N;;;;10CD4; +10C95;OLD HUNGARIAN CAPITAL LETTER UNK;Lu;0;R;;;;;N;;;;10CD5; +10C96;OLD HUNGARIAN CAPITAL LETTER EL;Lu;0;R;;;;;N;;;;10CD6; +10C97;OLD HUNGARIAN CAPITAL LETTER ELY;Lu;0;R;;;;;N;;;;10CD7; +10C98;OLD HUNGARIAN CAPITAL LETTER EM;Lu;0;R;;;;;N;;;;10CD8; +10C99;OLD HUNGARIAN CAPITAL LETTER EN;Lu;0;R;;;;;N;;;;10CD9; +10C9A;OLD HUNGARIAN CAPITAL LETTER ENY;Lu;0;R;;;;;N;;;;10CDA; +10C9B;OLD HUNGARIAN CAPITAL LETTER O;Lu;0;R;;;;;N;;;;10CDB; +10C9C;OLD HUNGARIAN CAPITAL LETTER OO;Lu;0;R;;;;;N;;;;10CDC; +10C9D;OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE;Lu;0;R;;;;;N;;;;10CDD; +10C9E;OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE;Lu;0;R;;;;;N;;;;10CDE; +10C9F;OLD HUNGARIAN CAPITAL LETTER OEE;Lu;0;R;;;;;N;;;;10CDF; +10CA0;OLD HUNGARIAN CAPITAL LETTER EP;Lu;0;R;;;;;N;;;;10CE0; +10CA1;OLD HUNGARIAN CAPITAL LETTER EMP;Lu;0;R;;;;;N;;;;10CE1; +10CA2;OLD HUNGARIAN CAPITAL LETTER ER;Lu;0;R;;;;;N;;;;10CE2; +10CA3;OLD HUNGARIAN CAPITAL LETTER SHORT ER;Lu;0;R;;;;;N;;;;10CE3; +10CA4;OLD HUNGARIAN CAPITAL LETTER ES;Lu;0;R;;;;;N;;;;10CE4; +10CA5;OLD HUNGARIAN CAPITAL LETTER ESZ;Lu;0;R;;;;;N;;;;10CE5; +10CA6;OLD HUNGARIAN CAPITAL LETTER ET;Lu;0;R;;;;;N;;;;10CE6; +10CA7;OLD HUNGARIAN CAPITAL LETTER ENT;Lu;0;R;;;;;N;;;;10CE7; +10CA8;OLD HUNGARIAN CAPITAL LETTER ETY;Lu;0;R;;;;;N;;;;10CE8; +10CA9;OLD HUNGARIAN CAPITAL LETTER ECH;Lu;0;R;;;;;N;;;;10CE9; +10CAA;OLD HUNGARIAN CAPITAL LETTER U;Lu;0;R;;;;;N;;;;10CEA; +10CAB;OLD HUNGARIAN CAPITAL LETTER UU;Lu;0;R;;;;;N;;;;10CEB; +10CAC;OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE;Lu;0;R;;;;;N;;;;10CEC; +10CAD;OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE;Lu;0;R;;;;;N;;;;10CED; +10CAE;OLD HUNGARIAN CAPITAL LETTER EV;Lu;0;R;;;;;N;;;;10CEE; +10CAF;OLD HUNGARIAN CAPITAL LETTER EZ;Lu;0;R;;;;;N;;;;10CEF; +10CB0;OLD HUNGARIAN CAPITAL LETTER EZS;Lu;0;R;;;;;N;;;;10CF0; +10CB1;OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN;Lu;0;R;;;;;N;;;;10CF1; +10CB2;OLD HUNGARIAN CAPITAL LETTER US;Lu;0;R;;;;;N;;;;10CF2; +10CC0;OLD HUNGARIAN SMALL LETTER A;Ll;0;R;;;;;N;;;10C80;;10C80 +10CC1;OLD HUNGARIAN SMALL LETTER AA;Ll;0;R;;;;;N;;;10C81;;10C81 +10CC2;OLD HUNGARIAN SMALL LETTER EB;Ll;0;R;;;;;N;;;10C82;;10C82 +10CC3;OLD HUNGARIAN SMALL LETTER AMB;Ll;0;R;;;;;N;;;10C83;;10C83 +10CC4;OLD HUNGARIAN SMALL LETTER EC;Ll;0;R;;;;;N;;;10C84;;10C84 +10CC5;OLD HUNGARIAN SMALL LETTER ENC;Ll;0;R;;;;;N;;;10C85;;10C85 +10CC6;OLD HUNGARIAN SMALL LETTER ECS;Ll;0;R;;;;;N;;;10C86;;10C86 +10CC7;OLD HUNGARIAN SMALL LETTER ED;Ll;0;R;;;;;N;;;10C87;;10C87 +10CC8;OLD HUNGARIAN SMALL LETTER AND;Ll;0;R;;;;;N;;;10C88;;10C88 +10CC9;OLD HUNGARIAN SMALL LETTER E;Ll;0;R;;;;;N;;;10C89;;10C89 +10CCA;OLD HUNGARIAN SMALL LETTER CLOSE E;Ll;0;R;;;;;N;;;10C8A;;10C8A +10CCB;OLD HUNGARIAN SMALL LETTER EE;Ll;0;R;;;;;N;;;10C8B;;10C8B +10CCC;OLD HUNGARIAN SMALL LETTER EF;Ll;0;R;;;;;N;;;10C8C;;10C8C +10CCD;OLD HUNGARIAN SMALL LETTER EG;Ll;0;R;;;;;N;;;10C8D;;10C8D +10CCE;OLD HUNGARIAN SMALL LETTER EGY;Ll;0;R;;;;;N;;;10C8E;;10C8E +10CCF;OLD HUNGARIAN SMALL LETTER EH;Ll;0;R;;;;;N;;;10C8F;;10C8F +10CD0;OLD HUNGARIAN SMALL LETTER I;Ll;0;R;;;;;N;;;10C90;;10C90 +10CD1;OLD HUNGARIAN SMALL LETTER II;Ll;0;R;;;;;N;;;10C91;;10C91 +10CD2;OLD HUNGARIAN SMALL LETTER EJ;Ll;0;R;;;;;N;;;10C92;;10C92 +10CD3;OLD HUNGARIAN SMALL LETTER EK;Ll;0;R;;;;;N;;;10C93;;10C93 +10CD4;OLD HUNGARIAN SMALL LETTER AK;Ll;0;R;;;;;N;;;10C94;;10C94 +10CD5;OLD HUNGARIAN SMALL LETTER UNK;Ll;0;R;;;;;N;;;10C95;;10C95 +10CD6;OLD HUNGARIAN SMALL LETTER EL;Ll;0;R;;;;;N;;;10C96;;10C96 +10CD7;OLD HUNGARIAN SMALL LETTER ELY;Ll;0;R;;;;;N;;;10C97;;10C97 +10CD8;OLD HUNGARIAN SMALL LETTER EM;Ll;0;R;;;;;N;;;10C98;;10C98 +10CD9;OLD HUNGARIAN SMALL LETTER EN;Ll;0;R;;;;;N;;;10C99;;10C99 +10CDA;OLD HUNGARIAN SMALL LETTER ENY;Ll;0;R;;;;;N;;;10C9A;;10C9A +10CDB;OLD HUNGARIAN SMALL LETTER O;Ll;0;R;;;;;N;;;10C9B;;10C9B +10CDC;OLD HUNGARIAN SMALL LETTER OO;Ll;0;R;;;;;N;;;10C9C;;10C9C +10CDD;OLD HUNGARIAN SMALL LETTER NIKOLSBURG OE;Ll;0;R;;;;;N;;;10C9D;;10C9D +10CDE;OLD HUNGARIAN SMALL LETTER RUDIMENTA OE;Ll;0;R;;;;;N;;;10C9E;;10C9E +10CDF;OLD HUNGARIAN SMALL LETTER OEE;Ll;0;R;;;;;N;;;10C9F;;10C9F +10CE0;OLD HUNGARIAN SMALL LETTER EP;Ll;0;R;;;;;N;;;10CA0;;10CA0 +10CE1;OLD HUNGARIAN SMALL LETTER EMP;Ll;0;R;;;;;N;;;10CA1;;10CA1 +10CE2;OLD HUNGARIAN SMALL LETTER ER;Ll;0;R;;;;;N;;;10CA2;;10CA2 +10CE3;OLD HUNGARIAN SMALL LETTER SHORT ER;Ll;0;R;;;;;N;;;10CA3;;10CA3 +10CE4;OLD HUNGARIAN SMALL LETTER ES;Ll;0;R;;;;;N;;;10CA4;;10CA4 +10CE5;OLD HUNGARIAN SMALL LETTER ESZ;Ll;0;R;;;;;N;;;10CA5;;10CA5 +10CE6;OLD HUNGARIAN SMALL LETTER ET;Ll;0;R;;;;;N;;;10CA6;;10CA6 +10CE7;OLD HUNGARIAN SMALL LETTER ENT;Ll;0;R;;;;;N;;;10CA7;;10CA7 +10CE8;OLD HUNGARIAN SMALL LETTER ETY;Ll;0;R;;;;;N;;;10CA8;;10CA8 +10CE9;OLD HUNGARIAN SMALL LETTER ECH;Ll;0;R;;;;;N;;;10CA9;;10CA9 +10CEA;OLD HUNGARIAN SMALL LETTER U;Ll;0;R;;;;;N;;;10CAA;;10CAA +10CEB;OLD HUNGARIAN SMALL LETTER UU;Ll;0;R;;;;;N;;;10CAB;;10CAB +10CEC;OLD HUNGARIAN SMALL LETTER NIKOLSBURG UE;Ll;0;R;;;;;N;;;10CAC;;10CAC +10CED;OLD HUNGARIAN SMALL LETTER RUDIMENTA UE;Ll;0;R;;;;;N;;;10CAD;;10CAD +10CEE;OLD HUNGARIAN SMALL LETTER EV;Ll;0;R;;;;;N;;;10CAE;;10CAE +10CEF;OLD HUNGARIAN SMALL LETTER EZ;Ll;0;R;;;;;N;;;10CAF;;10CAF +10CF0;OLD HUNGARIAN SMALL LETTER EZS;Ll;0;R;;;;;N;;;10CB0;;10CB0 +10CF1;OLD HUNGARIAN SMALL LETTER ENT-SHAPED SIGN;Ll;0;R;;;;;N;;;10CB1;;10CB1 +10CF2;OLD HUNGARIAN SMALL LETTER US;Ll;0;R;;;;;N;;;10CB2;;10CB2 +10CFA;OLD HUNGARIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10CFB;OLD HUNGARIAN NUMBER FIVE;No;0;R;;;;5;N;;;;; +10CFC;OLD HUNGARIAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10CFD;OLD HUNGARIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;; +10CFE;OLD HUNGARIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10CFF;OLD HUNGARIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; 10E60;RUMI DIGIT ONE;No;0;AN;;;1;1;N;;;;; 10E61;RUMI DIGIT TWO;No;0;AN;;;2;2;N;;;;; 10E62;RUMI DIGIT THREE;No;0;AN;;;3;3;N;;;;; @@ -18764,6 +19078,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 111C6;SHARADA DOUBLE DANDA;Po;0;L;;;;;N;;;;; 111C7;SHARADA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 111C8;SHARADA SEPARATOR;Po;0;L;;;;;N;;;;; +111C9;SHARADA SANDHI MARK;Po;0;L;;;;;N;;;;; +111CA;SHARADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +111CB;SHARADA VOWEL MODIFIER MARK;Mn;0;NSM;;;;;N;;;;; +111CC;SHARADA EXTRA SHORT VOWEL MARK;Mn;0;NSM;;;;;N;;;;; 111CD;SHARADA SUTRA MARK;Po;0;L;;;;;N;;;;; 111D0;SHARADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 111D1;SHARADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; @@ -18776,6 +19094,11 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 111D8;SHARADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 111D9;SHARADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 111DA;SHARADA EKAM;Lo;0;L;;;;;N;;;;; +111DB;SHARADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;; +111DC;SHARADA HEADSTROKE;Lo;0;L;;;;;N;;;;; +111DD;SHARADA CONTINUATION SIGN;Po;0;L;;;;;N;;;;; +111DE;SHARADA SECTION MARK-1;Po;0;L;;;;;N;;;;; +111DF;SHARADA SECTION MARK-2;Po;0;L;;;;;N;;;;; 111E1;SINHALA ARCHAIC DIGIT ONE;No;0;L;;;;1;N;;;;; 111E2;SINHALA ARCHAIC DIGIT TWO;No;0;L;;;;2;N;;;;; 111E3;SINHALA ARCHAIC DIGIT THREE;No;0;L;;;;3;N;;;;; @@ -18857,6 +19180,44 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1123B;KHOJKI SECTION MARK;Po;0;L;;;;;N;;;;; 1123C;KHOJKI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; 1123D;KHOJKI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +11280;MULTANI LETTER A;Lo;0;L;;;;;N;;;;; +11281;MULTANI LETTER I;Lo;0;L;;;;;N;;;;; +11282;MULTANI LETTER U;Lo;0;L;;;;;N;;;;; +11283;MULTANI LETTER E;Lo;0;L;;;;;N;;;;; +11284;MULTANI LETTER KA;Lo;0;L;;;;;N;;;;; +11285;MULTANI LETTER KHA;Lo;0;L;;;;;N;;;;; +11286;MULTANI LETTER GA;Lo;0;L;;;;;N;;;;; +11288;MULTANI LETTER GHA;Lo;0;L;;;;;N;;;;; +1128A;MULTANI LETTER CA;Lo;0;L;;;;;N;;;;; +1128B;MULTANI LETTER CHA;Lo;0;L;;;;;N;;;;; +1128C;MULTANI LETTER JA;Lo;0;L;;;;;N;;;;; +1128D;MULTANI LETTER JJA;Lo;0;L;;;;;N;;;;; +1128F;MULTANI LETTER NYA;Lo;0;L;;;;;N;;;;; +11290;MULTANI LETTER TTA;Lo;0;L;;;;;N;;;;; +11291;MULTANI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11292;MULTANI LETTER DDA;Lo;0;L;;;;;N;;;;; +11293;MULTANI LETTER DDDA;Lo;0;L;;;;;N;;;;; +11294;MULTANI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11295;MULTANI LETTER NNA;Lo;0;L;;;;;N;;;;; +11296;MULTANI LETTER TA;Lo;0;L;;;;;N;;;;; +11297;MULTANI LETTER THA;Lo;0;L;;;;;N;;;;; +11298;MULTANI LETTER DA;Lo;0;L;;;;;N;;;;; +11299;MULTANI LETTER DHA;Lo;0;L;;;;;N;;;;; +1129A;MULTANI LETTER NA;Lo;0;L;;;;;N;;;;; +1129B;MULTANI LETTER PA;Lo;0;L;;;;;N;;;;; +1129C;MULTANI LETTER PHA;Lo;0;L;;;;;N;;;;; +1129D;MULTANI LETTER BA;Lo;0;L;;;;;N;;;;; +1129F;MULTANI LETTER BHA;Lo;0;L;;;;;N;;;;; +112A0;MULTANI LETTER MA;Lo;0;L;;;;;N;;;;; +112A1;MULTANI LETTER YA;Lo;0;L;;;;;N;;;;; +112A2;MULTANI LETTER RA;Lo;0;L;;;;;N;;;;; +112A3;MULTANI LETTER LA;Lo;0;L;;;;;N;;;;; +112A4;MULTANI LETTER VA;Lo;0;L;;;;;N;;;;; +112A5;MULTANI LETTER SA;Lo;0;L;;;;;N;;;;; +112A6;MULTANI LETTER HA;Lo;0;L;;;;;N;;;;; +112A7;MULTANI LETTER RRA;Lo;0;L;;;;;N;;;;; +112A8;MULTANI LETTER RHA;Lo;0;L;;;;;N;;;;; +112A9;MULTANI SECTION MARK;Po;0;L;;;;;N;;;;; 112B0;KHUDAWADI LETTER A;Lo;0;L;;;;;N;;;;; 112B1;KHUDAWADI LETTER AA;Lo;0;L;;;;;N;;;;; 112B2;KHUDAWADI LETTER I;Lo;0;L;;;;;N;;;;; @@ -18926,6 +19287,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 112F7;KHUDAWADI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 112F8;KHUDAWADI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 112F9;KHUDAWADI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11300;GRANTHA SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;; 11301;GRANTHA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 11302;GRANTHA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 11303;GRANTHA SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -18989,6 +19351,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1134B;GRANTHA VOWEL SIGN OO;Mc;0;L;11347 1133E;;;;N;;;;; 1134C;GRANTHA VOWEL SIGN AU;Mc;0;L;11347 11357;;;;N;;;;; 1134D;GRANTHA SIGN VIRAMA;Mc;9;L;;;;;N;;;;; +11350;GRANTHA OM;Lo;0;L;;;;;N;;;;; 11357;GRANTHA AU LENGTH MARK;Mc;0;L;;;;;N;;;;; 1135D;GRANTHA SIGN PLUTA;Lo;0;L;;;;;N;;;;; 1135E;GRANTHA LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; @@ -19163,6 +19526,26 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 115C7;SIDDHAM REPETITION MARK-2;Po;0;L;;;;;N;;;;; 115C8;SIDDHAM REPETITION MARK-3;Po;0;L;;;;;N;;;;; 115C9;SIDDHAM END OF TEXT MARK;Po;0;L;;;;;N;;;;; +115CA;SIDDHAM SECTION MARK WITH TRIDENT AND U-SHAPED ORNAMENTS;Po;0;L;;;;;N;;;;; +115CB;SIDDHAM SECTION MARK WITH TRIDENT AND DOTTED CRESCENTS;Po;0;L;;;;;N;;;;; +115CC;SIDDHAM SECTION MARK WITH RAYS AND DOTTED CRESCENTS;Po;0;L;;;;;N;;;;; +115CD;SIDDHAM SECTION MARK WITH RAYS AND DOTTED DOUBLE CRESCENTS;Po;0;L;;;;;N;;;;; +115CE;SIDDHAM SECTION MARK WITH RAYS AND DOTTED TRIPLE CRESCENTS;Po;0;L;;;;;N;;;;; +115CF;SIDDHAM SECTION MARK DOUBLE RING;Po;0;L;;;;;N;;;;; +115D0;SIDDHAM SECTION MARK DOUBLE RING WITH RAYS;Po;0;L;;;;;N;;;;; +115D1;SIDDHAM SECTION MARK WITH DOUBLE CRESCENTS;Po;0;L;;;;;N;;;;; +115D2;SIDDHAM SECTION MARK WITH TRIPLE CRESCENTS;Po;0;L;;;;;N;;;;; +115D3;SIDDHAM SECTION MARK WITH QUADRUPLE CRESCENTS;Po;0;L;;;;;N;;;;; +115D4;SIDDHAM SECTION MARK WITH SEPTUPLE CRESCENTS;Po;0;L;;;;;N;;;;; +115D5;SIDDHAM SECTION MARK WITH CIRCLES AND RAYS;Po;0;L;;;;;N;;;;; +115D6;SIDDHAM SECTION MARK WITH CIRCLES AND TWO ENCLOSURES;Po;0;L;;;;;N;;;;; +115D7;SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES;Po;0;L;;;;;N;;;;; +115D8;SIDDHAM LETTER THREE-CIRCLE ALTERNATE I;Lo;0;L;;;;;N;;;;; +115D9;SIDDHAM LETTER TWO-CIRCLE ALTERNATE I;Lo;0;L;;;;;N;;;;; +115DA;SIDDHAM LETTER TWO-CIRCLE ALTERNATE II;Lo;0;L;;;;;N;;;;; +115DB;SIDDHAM LETTER ALTERNATE U;Lo;0;L;;;;;N;;;;; +115DC;SIDDHAM VOWEL SIGN ALTERNATE U;Mn;0;NSM;;;;;N;;;;; +115DD;SIDDHAM VOWEL SIGN ALTERNATE UU;Mn;0;NSM;;;;;N;;;;; 11600;MODI LETTER A;Lo;0;L;;;;;N;;;;; 11601;MODI LETTER AA;Lo;0;L;;;;;N;;;;; 11602;MODI LETTER I;Lo;0;L;;;;;N;;;;; @@ -19308,6 +19691,63 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 116C7;TAKRI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 116C8;TAKRI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 116C9;TAKRI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11700;AHOM LETTER KA;Lo;0;L;;;;;N;;;;; +11701;AHOM LETTER KHA;Lo;0;L;;;;;N;;;;; +11702;AHOM LETTER NGA;Lo;0;L;;;;;N;;;;; +11703;AHOM LETTER NA;Lo;0;L;;;;;N;;;;; +11704;AHOM LETTER TA;Lo;0;L;;;;;N;;;;; +11705;AHOM LETTER ALTERNATE TA;Lo;0;L;;;;;N;;;;; +11706;AHOM LETTER PA;Lo;0;L;;;;;N;;;;; +11707;AHOM LETTER PHA;Lo;0;L;;;;;N;;;;; +11708;AHOM LETTER BA;Lo;0;L;;;;;N;;;;; +11709;AHOM LETTER MA;Lo;0;L;;;;;N;;;;; +1170A;AHOM LETTER JA;Lo;0;L;;;;;N;;;;; +1170B;AHOM LETTER CHA;Lo;0;L;;;;;N;;;;; +1170C;AHOM LETTER THA;Lo;0;L;;;;;N;;;;; +1170D;AHOM LETTER RA;Lo;0;L;;;;;N;;;;; +1170E;AHOM LETTER LA;Lo;0;L;;;;;N;;;;; +1170F;AHOM LETTER SA;Lo;0;L;;;;;N;;;;; +11710;AHOM LETTER NYA;Lo;0;L;;;;;N;;;;; +11711;AHOM LETTER HA;Lo;0;L;;;;;N;;;;; +11712;AHOM LETTER A;Lo;0;L;;;;;N;;;;; +11713;AHOM LETTER DA;Lo;0;L;;;;;N;;;;; +11714;AHOM LETTER DHA;Lo;0;L;;;;;N;;;;; +11715;AHOM LETTER GA;Lo;0;L;;;;;N;;;;; +11716;AHOM LETTER ALTERNATE GA;Lo;0;L;;;;;N;;;;; +11717;AHOM LETTER GHA;Lo;0;L;;;;;N;;;;; +11718;AHOM LETTER BHA;Lo;0;L;;;;;N;;;;; +11719;AHOM LETTER JHA;Lo;0;L;;;;;N;;;;; +1171D;AHOM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;; +1171E;AHOM CONSONANT SIGN MEDIAL RA;Mn;0;NSM;;;;;N;;;;; +1171F;AHOM CONSONANT SIGN MEDIAL LIGATING RA;Mn;0;NSM;;;;;N;;;;; +11720;AHOM VOWEL SIGN A;Mc;0;L;;;;;N;;;;; +11721;AHOM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11722;AHOM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11723;AHOM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11724;AHOM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11725;AHOM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11726;AHOM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +11727;AHOM VOWEL SIGN AW;Mn;0;NSM;;;;;N;;;;; +11728;AHOM VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11729;AHOM VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +1172A;AHOM VOWEL SIGN AM;Mn;0;NSM;;;;;N;;;;; +1172B;AHOM SIGN KILLER;Mn;9;NSM;;;;;N;;;;; +11730;AHOM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11731;AHOM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11732;AHOM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11733;AHOM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11734;AHOM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11735;AHOM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11736;AHOM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11737;AHOM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11738;AHOM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11739;AHOM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1173A;AHOM NUMBER TEN;No;0;L;;;;10;N;;;;; +1173B;AHOM NUMBER TWENTY;No;0;L;;;;20;N;;;;; +1173C;AHOM SIGN SMALL SECTION;Po;0;L;;;;;N;;;;; +1173D;AHOM SIGN SECTION;Po;0;L;;;;;N;;;;; +1173E;AHOM SIGN RULAI;Po;0;L;;;;;N;;;;; +1173F;AHOM SYMBOL VI;So;0;L;;;;;N;;;;; 118A0;WARANG CITI CAPITAL LETTER NGAA;Lu;0;L;;;;;N;;;;118C0; 118A1;WARANG CITI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;118C1; 118A2;WARANG CITI CAPITAL LETTER WI;Lu;0;L;;;;;N;;;;118C2; @@ -20370,6 +20810,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 12396;CUNEIFORM SIGN SAG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; 12397;CUNEIFORM SIGN TI2;Lo;0;L;;;;;N;;;;; 12398;CUNEIFORM SIGN UM TIMES ME;Lo;0;L;;;;;N;;;;; +12399;CUNEIFORM SIGN U U;Lo;0;L;;;;;N;;;;; 12400;CUNEIFORM NUMERIC SIGN TWO ASH;Nl;0;L;;;;2;N;;;;; 12401;CUNEIFORM NUMERIC SIGN THREE ASH;Nl;0;L;;;;3;N;;;;; 12402;CUNEIFORM NUMERIC SIGN FOUR ASH;Nl;0;L;;;;4;N;;;;; @@ -20486,6 +20927,202 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 12472;CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON;Po;0;L;;;;;N;;;;; 12473;CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON;Po;0;L;;;;;N;;;;; 12474;CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON;Po;0;L;;;;;N;;;;; +12480;CUNEIFORM SIGN AB TIMES NUN TENU;Lo;0;L;;;;;N;;;;; +12481;CUNEIFORM SIGN AB TIMES SHU2;Lo;0;L;;;;;N;;;;; +12482;CUNEIFORM SIGN AD TIMES ESH2;Lo;0;L;;;;;N;;;;; +12483;CUNEIFORM SIGN BAD TIMES DISH TENU;Lo;0;L;;;;;N;;;;; +12484;CUNEIFORM SIGN BAHAR2 TIMES AB2;Lo;0;L;;;;;N;;;;; +12485;CUNEIFORM SIGN BAHAR2 TIMES NI;Lo;0;L;;;;;N;;;;; +12486;CUNEIFORM SIGN BAHAR2 TIMES ZA;Lo;0;L;;;;;N;;;;; +12487;CUNEIFORM SIGN BU OVER BU TIMES NA2;Lo;0;L;;;;;N;;;;; +12488;CUNEIFORM SIGN DA TIMES TAK4;Lo;0;L;;;;;N;;;;; +12489;CUNEIFORM SIGN DAG TIMES KUR;Lo;0;L;;;;;N;;;;; +1248A;CUNEIFORM SIGN DIM TIMES IGI;Lo;0;L;;;;;N;;;;; +1248B;CUNEIFORM SIGN DIM TIMES U U U;Lo;0;L;;;;;N;;;;; +1248C;CUNEIFORM SIGN DIM2 TIMES UD;Lo;0;L;;;;;N;;;;; +1248D;CUNEIFORM SIGN DUG TIMES ANSHE;Lo;0;L;;;;;N;;;;; +1248E;CUNEIFORM SIGN DUG TIMES ASH;Lo;0;L;;;;;N;;;;; +1248F;CUNEIFORM SIGN DUG TIMES ASH AT LEFT;Lo;0;L;;;;;N;;;;; +12490;CUNEIFORM SIGN DUG TIMES DIN;Lo;0;L;;;;;N;;;;; +12491;CUNEIFORM SIGN DUG TIMES DUN;Lo;0;L;;;;;N;;;;; +12492;CUNEIFORM SIGN DUG TIMES ERIN2;Lo;0;L;;;;;N;;;;; +12493;CUNEIFORM SIGN DUG TIMES GA;Lo;0;L;;;;;N;;;;; +12494;CUNEIFORM SIGN DUG TIMES GI;Lo;0;L;;;;;N;;;;; +12495;CUNEIFORM SIGN DUG TIMES GIR2 GUNU;Lo;0;L;;;;;N;;;;; +12496;CUNEIFORM SIGN DUG TIMES GISH;Lo;0;L;;;;;N;;;;; +12497;CUNEIFORM SIGN DUG TIMES HA;Lo;0;L;;;;;N;;;;; +12498;CUNEIFORM SIGN DUG TIMES HI;Lo;0;L;;;;;N;;;;; +12499;CUNEIFORM SIGN DUG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +1249A;CUNEIFORM SIGN DUG TIMES KASKAL;Lo;0;L;;;;;N;;;;; +1249B;CUNEIFORM SIGN DUG TIMES KUR;Lo;0;L;;;;;N;;;;; +1249C;CUNEIFORM SIGN DUG TIMES KUSHU2;Lo;0;L;;;;;N;;;;; +1249D;CUNEIFORM SIGN DUG TIMES KUSHU2 PLUS KASKAL;Lo;0;L;;;;;N;;;;; +1249E;CUNEIFORM SIGN DUG TIMES LAK-020;Lo;0;L;;;;;N;;;;; +1249F;CUNEIFORM SIGN DUG TIMES LAM;Lo;0;L;;;;;N;;;;; +124A0;CUNEIFORM SIGN DUG TIMES LAM TIMES KUR;Lo;0;L;;;;;N;;;;; +124A1;CUNEIFORM SIGN DUG TIMES LUH PLUS GISH;Lo;0;L;;;;;N;;;;; +124A2;CUNEIFORM SIGN DUG TIMES MASH;Lo;0;L;;;;;N;;;;; +124A3;CUNEIFORM SIGN DUG TIMES MES;Lo;0;L;;;;;N;;;;; +124A4;CUNEIFORM SIGN DUG TIMES MI;Lo;0;L;;;;;N;;;;; +124A5;CUNEIFORM SIGN DUG TIMES NI;Lo;0;L;;;;;N;;;;; +124A6;CUNEIFORM SIGN DUG TIMES PI;Lo;0;L;;;;;N;;;;; +124A7;CUNEIFORM SIGN DUG TIMES SHE;Lo;0;L;;;;;N;;;;; +124A8;CUNEIFORM SIGN DUG TIMES SI GUNU;Lo;0;L;;;;;N;;;;; +124A9;CUNEIFORM SIGN E2 TIMES KUR;Lo;0;L;;;;;N;;;;; +124AA;CUNEIFORM SIGN E2 TIMES PAP;Lo;0;L;;;;;N;;;;; +124AB;CUNEIFORM SIGN ERIN2 X;Lo;0;L;;;;;N;;;;; +124AC;CUNEIFORM SIGN ESH2 CROSSING ESH2;Lo;0;L;;;;;N;;;;; +124AD;CUNEIFORM SIGN EZEN SHESHIG TIMES ASH;Lo;0;L;;;;;N;;;;; +124AE;CUNEIFORM SIGN EZEN SHESHIG TIMES HI;Lo;0;L;;;;;N;;;;; +124AF;CUNEIFORM SIGN EZEN SHESHIG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +124B0;CUNEIFORM SIGN EZEN SHESHIG TIMES LA;Lo;0;L;;;;;N;;;;; +124B1;CUNEIFORM SIGN EZEN SHESHIG TIMES LAL;Lo;0;L;;;;;N;;;;; +124B2;CUNEIFORM SIGN EZEN SHESHIG TIMES ME;Lo;0;L;;;;;N;;;;; +124B3;CUNEIFORM SIGN EZEN SHESHIG TIMES MES;Lo;0;L;;;;;N;;;;; +124B4;CUNEIFORM SIGN EZEN SHESHIG TIMES SU;Lo;0;L;;;;;N;;;;; +124B5;CUNEIFORM SIGN EZEN TIMES SU;Lo;0;L;;;;;N;;;;; +124B6;CUNEIFORM SIGN GA2 TIMES BAHAR2;Lo;0;L;;;;;N;;;;; +124B7;CUNEIFORM SIGN GA2 TIMES DIM GUNU;Lo;0;L;;;;;N;;;;; +124B8;CUNEIFORM SIGN GA2 TIMES DUG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +124B9;CUNEIFORM SIGN GA2 TIMES DUG TIMES KASKAL;Lo;0;L;;;;;N;;;;; +124BA;CUNEIFORM SIGN GA2 TIMES EREN;Lo;0;L;;;;;N;;;;; +124BB;CUNEIFORM SIGN GA2 TIMES GA;Lo;0;L;;;;;N;;;;; +124BC;CUNEIFORM SIGN GA2 TIMES GAR PLUS DI;Lo;0;L;;;;;N;;;;; +124BD;CUNEIFORM SIGN GA2 TIMES GAR PLUS NE;Lo;0;L;;;;;N;;;;; +124BE;CUNEIFORM SIGN GA2 TIMES HA PLUS A;Lo;0;L;;;;;N;;;;; +124BF;CUNEIFORM SIGN GA2 TIMES KUSHU2 PLUS KASKAL;Lo;0;L;;;;;N;;;;; +124C0;CUNEIFORM SIGN GA2 TIMES LAM;Lo;0;L;;;;;N;;;;; +124C1;CUNEIFORM SIGN GA2 TIMES LAM TIMES KUR;Lo;0;L;;;;;N;;;;; +124C2;CUNEIFORM SIGN GA2 TIMES LUH;Lo;0;L;;;;;N;;;;; +124C3;CUNEIFORM SIGN GA2 TIMES MUSH;Lo;0;L;;;;;N;;;;; +124C4;CUNEIFORM SIGN GA2 TIMES NE;Lo;0;L;;;;;N;;;;; +124C5;CUNEIFORM SIGN GA2 TIMES NE PLUS E2;Lo;0;L;;;;;N;;;;; +124C6;CUNEIFORM SIGN GA2 TIMES NE PLUS GI;Lo;0;L;;;;;N;;;;; +124C7;CUNEIFORM SIGN GA2 TIMES SHIM;Lo;0;L;;;;;N;;;;; +124C8;CUNEIFORM SIGN GA2 TIMES ZIZ2;Lo;0;L;;;;;N;;;;; +124C9;CUNEIFORM SIGN GABA ROTATED NINETY DEGREES;Lo;0;L;;;;;N;;;;; +124CA;CUNEIFORM SIGN GESHTIN TIMES U;Lo;0;L;;;;;N;;;;; +124CB;CUNEIFORM SIGN GISH TIMES GISH CROSSING GISH;Lo;0;L;;;;;N;;;;; +124CC;CUNEIFORM SIGN GU2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +124CD;CUNEIFORM SIGN GUD PLUS GISH TIMES TAK4;Lo;0;L;;;;;N;;;;; +124CE;CUNEIFORM SIGN HA TENU GUNU;Lo;0;L;;;;;N;;;;; +124CF;CUNEIFORM SIGN HI TIMES ASH OVER HI TIMES ASH;Lo;0;L;;;;;N;;;;; +124D0;CUNEIFORM SIGN KA TIMES BU;Lo;0;L;;;;;N;;;;; +124D1;CUNEIFORM SIGN KA TIMES KA;Lo;0;L;;;;;N;;;;; +124D2;CUNEIFORM SIGN KA TIMES U U U;Lo;0;L;;;;;N;;;;; +124D3;CUNEIFORM SIGN KA TIMES UR;Lo;0;L;;;;;N;;;;; +124D4;CUNEIFORM SIGN LAGAB TIMES ZU OVER ZU;Lo;0;L;;;;;N;;;;; +124D5;CUNEIFORM SIGN LAK-003;Lo;0;L;;;;;N;;;;; +124D6;CUNEIFORM SIGN LAK-021;Lo;0;L;;;;;N;;;;; +124D7;CUNEIFORM SIGN LAK-025;Lo;0;L;;;;;N;;;;; +124D8;CUNEIFORM SIGN LAK-030;Lo;0;L;;;;;N;;;;; +124D9;CUNEIFORM SIGN LAK-050;Lo;0;L;;;;;N;;;;; +124DA;CUNEIFORM SIGN LAK-051;Lo;0;L;;;;;N;;;;; +124DB;CUNEIFORM SIGN LAK-062;Lo;0;L;;;;;N;;;;; +124DC;CUNEIFORM SIGN LAK-079 OVER LAK-079 GUNU;Lo;0;L;;;;;N;;;;; +124DD;CUNEIFORM SIGN LAK-080;Lo;0;L;;;;;N;;;;; +124DE;CUNEIFORM SIGN LAK-081 OVER LAK-081;Lo;0;L;;;;;N;;;;; +124DF;CUNEIFORM SIGN LAK-092;Lo;0;L;;;;;N;;;;; +124E0;CUNEIFORM SIGN LAK-130;Lo;0;L;;;;;N;;;;; +124E1;CUNEIFORM SIGN LAK-142;Lo;0;L;;;;;N;;;;; +124E2;CUNEIFORM SIGN LAK-210;Lo;0;L;;;;;N;;;;; +124E3;CUNEIFORM SIGN LAK-219;Lo;0;L;;;;;N;;;;; +124E4;CUNEIFORM SIGN LAK-220;Lo;0;L;;;;;N;;;;; +124E5;CUNEIFORM SIGN LAK-225;Lo;0;L;;;;;N;;;;; +124E6;CUNEIFORM SIGN LAK-228;Lo;0;L;;;;;N;;;;; +124E7;CUNEIFORM SIGN LAK-238;Lo;0;L;;;;;N;;;;; +124E8;CUNEIFORM SIGN LAK-265;Lo;0;L;;;;;N;;;;; +124E9;CUNEIFORM SIGN LAK-266;Lo;0;L;;;;;N;;;;; +124EA;CUNEIFORM SIGN LAK-343;Lo;0;L;;;;;N;;;;; +124EB;CUNEIFORM SIGN LAK-347;Lo;0;L;;;;;N;;;;; +124EC;CUNEIFORM SIGN LAK-348;Lo;0;L;;;;;N;;;;; +124ED;CUNEIFORM SIGN LAK-383;Lo;0;L;;;;;N;;;;; +124EE;CUNEIFORM SIGN LAK-384;Lo;0;L;;;;;N;;;;; +124EF;CUNEIFORM SIGN LAK-390;Lo;0;L;;;;;N;;;;; +124F0;CUNEIFORM SIGN LAK-441;Lo;0;L;;;;;N;;;;; +124F1;CUNEIFORM SIGN LAK-449;Lo;0;L;;;;;N;;;;; +124F2;CUNEIFORM SIGN LAK-449 TIMES GU;Lo;0;L;;;;;N;;;;; +124F3;CUNEIFORM SIGN LAK-449 TIMES IGI;Lo;0;L;;;;;N;;;;; +124F4;CUNEIFORM SIGN LAK-449 TIMES PAP PLUS LU3;Lo;0;L;;;;;N;;;;; +124F5;CUNEIFORM SIGN LAK-449 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;; +124F6;CUNEIFORM SIGN LAK-449 TIMES U2 PLUS BA;Lo;0;L;;;;;N;;;;; +124F7;CUNEIFORM SIGN LAK-450;Lo;0;L;;;;;N;;;;; +124F8;CUNEIFORM SIGN LAK-457;Lo;0;L;;;;;N;;;;; +124F9;CUNEIFORM SIGN LAK-470;Lo;0;L;;;;;N;;;;; +124FA;CUNEIFORM SIGN LAK-483;Lo;0;L;;;;;N;;;;; +124FB;CUNEIFORM SIGN LAK-490;Lo;0;L;;;;;N;;;;; +124FC;CUNEIFORM SIGN LAK-492;Lo;0;L;;;;;N;;;;; +124FD;CUNEIFORM SIGN LAK-493;Lo;0;L;;;;;N;;;;; +124FE;CUNEIFORM SIGN LAK-495;Lo;0;L;;;;;N;;;;; +124FF;CUNEIFORM SIGN LAK-550;Lo;0;L;;;;;N;;;;; +12500;CUNEIFORM SIGN LAK-608;Lo;0;L;;;;;N;;;;; +12501;CUNEIFORM SIGN LAK-617;Lo;0;L;;;;;N;;;;; +12502;CUNEIFORM SIGN LAK-617 TIMES ASH;Lo;0;L;;;;;N;;;;; +12503;CUNEIFORM SIGN LAK-617 TIMES BAD;Lo;0;L;;;;;N;;;;; +12504;CUNEIFORM SIGN LAK-617 TIMES DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;; +12505;CUNEIFORM SIGN LAK-617 TIMES KU3;Lo;0;L;;;;;N;;;;; +12506;CUNEIFORM SIGN LAK-617 TIMES LA;Lo;0;L;;;;;N;;;;; +12507;CUNEIFORM SIGN LAK-617 TIMES TAR;Lo;0;L;;;;;N;;;;; +12508;CUNEIFORM SIGN LAK-617 TIMES TE;Lo;0;L;;;;;N;;;;; +12509;CUNEIFORM SIGN LAK-617 TIMES U2;Lo;0;L;;;;;N;;;;; +1250A;CUNEIFORM SIGN LAK-617 TIMES UD;Lo;0;L;;;;;N;;;;; +1250B;CUNEIFORM SIGN LAK-617 TIMES URUDA;Lo;0;L;;;;;N;;;;; +1250C;CUNEIFORM SIGN LAK-636;Lo;0;L;;;;;N;;;;; +1250D;CUNEIFORM SIGN LAK-648;Lo;0;L;;;;;N;;;;; +1250E;CUNEIFORM SIGN LAK-648 TIMES DUB;Lo;0;L;;;;;N;;;;; +1250F;CUNEIFORM SIGN LAK-648 TIMES GA;Lo;0;L;;;;;N;;;;; +12510;CUNEIFORM SIGN LAK-648 TIMES IGI;Lo;0;L;;;;;N;;;;; +12511;CUNEIFORM SIGN LAK-648 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; +12512;CUNEIFORM SIGN LAK-648 TIMES NI;Lo;0;L;;;;;N;;;;; +12513;CUNEIFORM SIGN LAK-648 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;; +12514;CUNEIFORM SIGN LAK-648 TIMES SHESH PLUS KI;Lo;0;L;;;;;N;;;;; +12515;CUNEIFORM SIGN LAK-648 TIMES UD;Lo;0;L;;;;;N;;;;; +12516;CUNEIFORM SIGN LAK-648 TIMES URUDA;Lo;0;L;;;;;N;;;;; +12517;CUNEIFORM SIGN LAK-724;Lo;0;L;;;;;N;;;;; +12518;CUNEIFORM SIGN LAK-749;Lo;0;L;;;;;N;;;;; +12519;CUNEIFORM SIGN LU2 GUNU TIMES ASH;Lo;0;L;;;;;N;;;;; +1251A;CUNEIFORM SIGN LU2 TIMES DISH;Lo;0;L;;;;;N;;;;; +1251B;CUNEIFORM SIGN LU2 TIMES HAL;Lo;0;L;;;;;N;;;;; +1251C;CUNEIFORM SIGN LU2 TIMES PAP;Lo;0;L;;;;;N;;;;; +1251D;CUNEIFORM SIGN LU2 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;; +1251E;CUNEIFORM SIGN LU2 TIMES TAK4;Lo;0;L;;;;;N;;;;; +1251F;CUNEIFORM SIGN MI PLUS ZA7;Lo;0;L;;;;;N;;;;; +12520;CUNEIFORM SIGN MUSH OVER MUSH TIMES GA;Lo;0;L;;;;;N;;;;; +12521;CUNEIFORM SIGN MUSH OVER MUSH TIMES KAK;Lo;0;L;;;;;N;;;;; +12522;CUNEIFORM SIGN NINDA2 TIMES DIM GUNU;Lo;0;L;;;;;N;;;;; +12523;CUNEIFORM SIGN NINDA2 TIMES GISH;Lo;0;L;;;;;N;;;;; +12524;CUNEIFORM SIGN NINDA2 TIMES GUL;Lo;0;L;;;;;N;;;;; +12525;CUNEIFORM SIGN NINDA2 TIMES HI;Lo;0;L;;;;;N;;;;; +12526;CUNEIFORM SIGN NINDA2 TIMES KESH2;Lo;0;L;;;;;N;;;;; +12527;CUNEIFORM SIGN NINDA2 TIMES LAK-050;Lo;0;L;;;;;N;;;;; +12528;CUNEIFORM SIGN NINDA2 TIMES MASH;Lo;0;L;;;;;N;;;;; +12529;CUNEIFORM SIGN NINDA2 TIMES PAP PLUS PAP;Lo;0;L;;;;;N;;;;; +1252A;CUNEIFORM SIGN NINDA2 TIMES U;Lo;0;L;;;;;N;;;;; +1252B;CUNEIFORM SIGN NINDA2 TIMES U PLUS U;Lo;0;L;;;;;N;;;;; +1252C;CUNEIFORM SIGN NINDA2 TIMES URUDA;Lo;0;L;;;;;N;;;;; +1252D;CUNEIFORM SIGN SAG GUNU TIMES HA;Lo;0;L;;;;;N;;;;; +1252E;CUNEIFORM SIGN SAG TIMES EN;Lo;0;L;;;;;N;;;;; +1252F;CUNEIFORM SIGN SAG TIMES SHE AT LEFT;Lo;0;L;;;;;N;;;;; +12530;CUNEIFORM SIGN SAG TIMES TAK4;Lo;0;L;;;;;N;;;;; +12531;CUNEIFORM SIGN SHA6 TENU;Lo;0;L;;;;;N;;;;; +12532;CUNEIFORM SIGN SHE OVER SHE;Lo;0;L;;;;;N;;;;; +12533;CUNEIFORM SIGN SHE PLUS HUB2;Lo;0;L;;;;;N;;;;; +12534;CUNEIFORM SIGN SHE PLUS NAM2;Lo;0;L;;;;;N;;;;; +12535;CUNEIFORM SIGN SHE PLUS SAR;Lo;0;L;;;;;N;;;;; +12536;CUNEIFORM SIGN SHU2 PLUS DUG TIMES NI;Lo;0;L;;;;;N;;;;; +12537;CUNEIFORM SIGN SHU2 PLUS E2 TIMES AN;Lo;0;L;;;;;N;;;;; +12538;CUNEIFORM SIGN SI TIMES TAK4;Lo;0;L;;;;;N;;;;; +12539;CUNEIFORM SIGN TAK4 PLUS SAG;Lo;0;L;;;;;N;;;;; +1253A;CUNEIFORM SIGN TUM TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; +1253B;CUNEIFORM SIGN TUM TIMES THREE DISH;Lo;0;L;;;;;N;;;;; +1253C;CUNEIFORM SIGN UR2 INVERTED;Lo;0;L;;;;;N;;;;; +1253D;CUNEIFORM SIGN UR2 TIMES UD;Lo;0;L;;;;;N;;;;; +1253E;CUNEIFORM SIGN URU TIMES DARA3;Lo;0;L;;;;;N;;;;; +1253F;CUNEIFORM SIGN URU TIMES LAK-668;Lo;0;L;;;;;N;;;;; +12540;CUNEIFORM SIGN URU TIMES LU3;Lo;0;L;;;;;N;;;;; +12541;CUNEIFORM SIGN ZA7;Lo;0;L;;;;;N;;;;; +12542;CUNEIFORM SIGN ZU OVER ZU PLUS SAR;Lo;0;L;;;;;N;;;;; +12543;CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU;Lo;0;L;;;;;N;;;;; 13000;EGYPTIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;; 13001;EGYPTIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;; 13002;EGYPTIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;; @@ -21557,6 +22194,589 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1342C;EGYPTIAN HIEROGLYPH AA030;Lo;0;L;;;;;N;;;;; 1342D;EGYPTIAN HIEROGLYPH AA031;Lo;0;L;;;;;N;;;;; 1342E;EGYPTIAN HIEROGLYPH AA032;Lo;0;L;;;;;N;;;;; +14400;ANATOLIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;; +14401;ANATOLIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;; +14402;ANATOLIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;; +14403;ANATOLIAN HIEROGLYPH A004;Lo;0;L;;;;;N;;;;; +14404;ANATOLIAN HIEROGLYPH A005;Lo;0;L;;;;;N;;;;; +14405;ANATOLIAN HIEROGLYPH A006;Lo;0;L;;;;;N;;;;; +14406;ANATOLIAN HIEROGLYPH A007;Lo;0;L;;;;;N;;;;; +14407;ANATOLIAN HIEROGLYPH A008;Lo;0;L;;;;;N;;;;; +14408;ANATOLIAN HIEROGLYPH A009;Lo;0;L;;;;;N;;;;; +14409;ANATOLIAN HIEROGLYPH A010;Lo;0;L;;;;;N;;;;; +1440A;ANATOLIAN HIEROGLYPH A010A;Lo;0;L;;;;;N;;;;; +1440B;ANATOLIAN HIEROGLYPH A011;Lo;0;L;;;;;N;;;;; +1440C;ANATOLIAN HIEROGLYPH A012;Lo;0;L;;;;;N;;;;; +1440D;ANATOLIAN HIEROGLYPH A013;Lo;0;L;;;;;N;;;;; +1440E;ANATOLIAN HIEROGLYPH A014;Lo;0;L;;;;;N;;;;; +1440F;ANATOLIAN HIEROGLYPH A015;Lo;0;L;;;;;N;;;;; +14410;ANATOLIAN HIEROGLYPH A016;Lo;0;L;;;;;N;;;;; +14411;ANATOLIAN HIEROGLYPH A017;Lo;0;L;;;;;N;;;;; +14412;ANATOLIAN HIEROGLYPH A018;Lo;0;L;;;;;N;;;;; +14413;ANATOLIAN HIEROGLYPH A019;Lo;0;L;;;;;N;;;;; +14414;ANATOLIAN HIEROGLYPH A020;Lo;0;L;;;;;N;;;;; +14415;ANATOLIAN HIEROGLYPH A021;Lo;0;L;;;;;N;;;;; +14416;ANATOLIAN HIEROGLYPH A022;Lo;0;L;;;;;N;;;;; +14417;ANATOLIAN HIEROGLYPH A023;Lo;0;L;;;;;N;;;;; +14418;ANATOLIAN HIEROGLYPH A024;Lo;0;L;;;;;N;;;;; +14419;ANATOLIAN HIEROGLYPH A025;Lo;0;L;;;;;N;;;;; +1441A;ANATOLIAN HIEROGLYPH A026;Lo;0;L;;;;;N;;;;; +1441B;ANATOLIAN HIEROGLYPH A026A;Lo;0;L;;;;;N;;;;; +1441C;ANATOLIAN HIEROGLYPH A027;Lo;0;L;;;;;N;;;;; +1441D;ANATOLIAN HIEROGLYPH A028;Lo;0;L;;;;;N;;;;; +1441E;ANATOLIAN HIEROGLYPH A029;Lo;0;L;;;;;N;;;;; +1441F;ANATOLIAN HIEROGLYPH A030;Lo;0;L;;;;;N;;;;; +14420;ANATOLIAN HIEROGLYPH A031;Lo;0;L;;;;;N;;;;; +14421;ANATOLIAN HIEROGLYPH A032;Lo;0;L;;;;;N;;;;; +14422;ANATOLIAN HIEROGLYPH A033;Lo;0;L;;;;;N;;;;; +14423;ANATOLIAN HIEROGLYPH A034;Lo;0;L;;;;;N;;;;; +14424;ANATOLIAN HIEROGLYPH A035;Lo;0;L;;;;;N;;;;; +14425;ANATOLIAN HIEROGLYPH A036;Lo;0;L;;;;;N;;;;; +14426;ANATOLIAN HIEROGLYPH A037;Lo;0;L;;;;;N;;;;; +14427;ANATOLIAN HIEROGLYPH A038;Lo;0;L;;;;;N;;;;; +14428;ANATOLIAN HIEROGLYPH A039;Lo;0;L;;;;;N;;;;; +14429;ANATOLIAN HIEROGLYPH A039A;Lo;0;L;;;;;N;;;;; +1442A;ANATOLIAN HIEROGLYPH A040;Lo;0;L;;;;;N;;;;; +1442B;ANATOLIAN HIEROGLYPH A041;Lo;0;L;;;;;N;;;;; +1442C;ANATOLIAN HIEROGLYPH A041A;Lo;0;L;;;;;N;;;;; +1442D;ANATOLIAN HIEROGLYPH A042;Lo;0;L;;;;;N;;;;; +1442E;ANATOLIAN HIEROGLYPH A043;Lo;0;L;;;;;N;;;;; +1442F;ANATOLIAN HIEROGLYPH A044;Lo;0;L;;;;;N;;;;; +14430;ANATOLIAN HIEROGLYPH A045;Lo;0;L;;;;;N;;;;; +14431;ANATOLIAN HIEROGLYPH A045A;Lo;0;L;;;;;N;;;;; +14432;ANATOLIAN HIEROGLYPH A046;Lo;0;L;;;;;N;;;;; +14433;ANATOLIAN HIEROGLYPH A046A;Lo;0;L;;;;;N;;;;; +14434;ANATOLIAN HIEROGLYPH A046B;Lo;0;L;;;;;N;;;;; +14435;ANATOLIAN HIEROGLYPH A047;Lo;0;L;;;;;N;;;;; +14436;ANATOLIAN HIEROGLYPH A048;Lo;0;L;;;;;N;;;;; +14437;ANATOLIAN HIEROGLYPH A049;Lo;0;L;;;;;N;;;;; +14438;ANATOLIAN HIEROGLYPH A050;Lo;0;L;;;;;N;;;;; +14439;ANATOLIAN HIEROGLYPH A051;Lo;0;L;;;;;N;;;;; +1443A;ANATOLIAN HIEROGLYPH A052;Lo;0;L;;;;;N;;;;; +1443B;ANATOLIAN HIEROGLYPH A053;Lo;0;L;;;;;N;;;;; +1443C;ANATOLIAN HIEROGLYPH A054;Lo;0;L;;;;;N;;;;; +1443D;ANATOLIAN HIEROGLYPH A055;Lo;0;L;;;;;N;;;;; +1443E;ANATOLIAN HIEROGLYPH A056;Lo;0;L;;;;;N;;;;; +1443F;ANATOLIAN HIEROGLYPH A057;Lo;0;L;;;;;N;;;;; +14440;ANATOLIAN HIEROGLYPH A058;Lo;0;L;;;;;N;;;;; +14441;ANATOLIAN HIEROGLYPH A059;Lo;0;L;;;;;N;;;;; +14442;ANATOLIAN HIEROGLYPH A060;Lo;0;L;;;;;N;;;;; +14443;ANATOLIAN HIEROGLYPH A061;Lo;0;L;;;;;N;;;;; +14444;ANATOLIAN HIEROGLYPH A062;Lo;0;L;;;;;N;;;;; +14445;ANATOLIAN HIEROGLYPH A063;Lo;0;L;;;;;N;;;;; +14446;ANATOLIAN HIEROGLYPH A064;Lo;0;L;;;;;N;;;;; +14447;ANATOLIAN HIEROGLYPH A065;Lo;0;L;;;;;N;;;;; +14448;ANATOLIAN HIEROGLYPH A066;Lo;0;L;;;;;N;;;;; +14449;ANATOLIAN HIEROGLYPH A066A;Lo;0;L;;;;;N;;;;; +1444A;ANATOLIAN HIEROGLYPH A066B;Lo;0;L;;;;;N;;;;; +1444B;ANATOLIAN HIEROGLYPH A066C;Lo;0;L;;;;;N;;;;; +1444C;ANATOLIAN HIEROGLYPH A067;Lo;0;L;;;;;N;;;;; +1444D;ANATOLIAN HIEROGLYPH A068;Lo;0;L;;;;;N;;;;; +1444E;ANATOLIAN HIEROGLYPH A069;Lo;0;L;;;;;N;;;;; +1444F;ANATOLIAN HIEROGLYPH A070;Lo;0;L;;;;;N;;;;; +14450;ANATOLIAN HIEROGLYPH A071;Lo;0;L;;;;;N;;;;; +14451;ANATOLIAN HIEROGLYPH A072;Lo;0;L;;;;;N;;;;; +14452;ANATOLIAN HIEROGLYPH A073;Lo;0;L;;;;;N;;;;; +14453;ANATOLIAN HIEROGLYPH A074;Lo;0;L;;;;;N;;;;; +14454;ANATOLIAN HIEROGLYPH A075;Lo;0;L;;;;;N;;;;; +14455;ANATOLIAN HIEROGLYPH A076;Lo;0;L;;;;;N;;;;; +14456;ANATOLIAN HIEROGLYPH A077;Lo;0;L;;;;;N;;;;; +14457;ANATOLIAN HIEROGLYPH A078;Lo;0;L;;;;;N;;;;; +14458;ANATOLIAN HIEROGLYPH A079;Lo;0;L;;;;;N;;;;; +14459;ANATOLIAN HIEROGLYPH A080;Lo;0;L;;;;;N;;;;; +1445A;ANATOLIAN HIEROGLYPH A081;Lo;0;L;;;;;N;;;;; +1445B;ANATOLIAN HIEROGLYPH A082;Lo;0;L;;;;;N;;;;; +1445C;ANATOLIAN HIEROGLYPH A083;Lo;0;L;;;;;N;;;;; +1445D;ANATOLIAN HIEROGLYPH A084;Lo;0;L;;;;;N;;;;; +1445E;ANATOLIAN HIEROGLYPH A085;Lo;0;L;;;;;N;;;;; +1445F;ANATOLIAN HIEROGLYPH A086;Lo;0;L;;;;;N;;;;; +14460;ANATOLIAN HIEROGLYPH A087;Lo;0;L;;;;;N;;;;; +14461;ANATOLIAN HIEROGLYPH A088;Lo;0;L;;;;;N;;;;; +14462;ANATOLIAN HIEROGLYPH A089;Lo;0;L;;;;;N;;;;; +14463;ANATOLIAN HIEROGLYPH A090;Lo;0;L;;;;;N;;;;; +14464;ANATOLIAN HIEROGLYPH A091;Lo;0;L;;;;;N;;;;; +14465;ANATOLIAN HIEROGLYPH A092;Lo;0;L;;;;;N;;;;; +14466;ANATOLIAN HIEROGLYPH A093;Lo;0;L;;;;;N;;;;; +14467;ANATOLIAN HIEROGLYPH A094;Lo;0;L;;;;;N;;;;; +14468;ANATOLIAN HIEROGLYPH A095;Lo;0;L;;;;;N;;;;; +14469;ANATOLIAN HIEROGLYPH A096;Lo;0;L;;;;;N;;;;; +1446A;ANATOLIAN HIEROGLYPH A097;Lo;0;L;;;;;N;;;;; +1446B;ANATOLIAN HIEROGLYPH A097A;Lo;0;L;;;;;N;;;;; +1446C;ANATOLIAN HIEROGLYPH A098;Lo;0;L;;;;;N;;;;; +1446D;ANATOLIAN HIEROGLYPH A098A;Lo;0;L;;;;;N;;;;; +1446E;ANATOLIAN HIEROGLYPH A099;Lo;0;L;;;;;N;;;;; +1446F;ANATOLIAN HIEROGLYPH A100;Lo;0;L;;;;;N;;;;; +14470;ANATOLIAN HIEROGLYPH A100A;Lo;0;L;;;;;N;;;;; +14471;ANATOLIAN HIEROGLYPH A101;Lo;0;L;;;;;N;;;;; +14472;ANATOLIAN HIEROGLYPH A101A;Lo;0;L;;;;;N;;;;; +14473;ANATOLIAN HIEROGLYPH A102;Lo;0;L;;;;;N;;;;; +14474;ANATOLIAN HIEROGLYPH A102A;Lo;0;L;;;;;N;;;;; +14475;ANATOLIAN HIEROGLYPH A103;Lo;0;L;;;;;N;;;;; +14476;ANATOLIAN HIEROGLYPH A104;Lo;0;L;;;;;N;;;;; +14477;ANATOLIAN HIEROGLYPH A104A;Lo;0;L;;;;;N;;;;; +14478;ANATOLIAN HIEROGLYPH A104B;Lo;0;L;;;;;N;;;;; +14479;ANATOLIAN HIEROGLYPH A104C;Lo;0;L;;;;;N;;;;; +1447A;ANATOLIAN HIEROGLYPH A105;Lo;0;L;;;;;N;;;;; +1447B;ANATOLIAN HIEROGLYPH A105A;Lo;0;L;;;;;N;;;;; +1447C;ANATOLIAN HIEROGLYPH A105B;Lo;0;L;;;;;N;;;;; +1447D;ANATOLIAN HIEROGLYPH A106;Lo;0;L;;;;;N;;;;; +1447E;ANATOLIAN HIEROGLYPH A107;Lo;0;L;;;;;N;;;;; +1447F;ANATOLIAN HIEROGLYPH A107A;Lo;0;L;;;;;N;;;;; +14480;ANATOLIAN HIEROGLYPH A107B;Lo;0;L;;;;;N;;;;; +14481;ANATOLIAN HIEROGLYPH A107C;Lo;0;L;;;;;N;;;;; +14482;ANATOLIAN HIEROGLYPH A108;Lo;0;L;;;;;N;;;;; +14483;ANATOLIAN HIEROGLYPH A109;Lo;0;L;;;;;N;;;;; +14484;ANATOLIAN HIEROGLYPH A110;Lo;0;L;;;;;N;;;;; +14485;ANATOLIAN HIEROGLYPH A110A;Lo;0;L;;;;;N;;;;; +14486;ANATOLIAN HIEROGLYPH A110B;Lo;0;L;;;;;N;;;;; +14487;ANATOLIAN HIEROGLYPH A111;Lo;0;L;;;;;N;;;;; +14488;ANATOLIAN HIEROGLYPH A112;Lo;0;L;;;;;N;;;;; +14489;ANATOLIAN HIEROGLYPH A113;Lo;0;L;;;;;N;;;;; +1448A;ANATOLIAN HIEROGLYPH A114;Lo;0;L;;;;;N;;;;; +1448B;ANATOLIAN HIEROGLYPH A115;Lo;0;L;;;;;N;;;;; +1448C;ANATOLIAN HIEROGLYPH A115A;Lo;0;L;;;;;N;;;;; +1448D;ANATOLIAN HIEROGLYPH A116;Lo;0;L;;;;;N;;;;; +1448E;ANATOLIAN HIEROGLYPH A117;Lo;0;L;;;;;N;;;;; +1448F;ANATOLIAN HIEROGLYPH A118;Lo;0;L;;;;;N;;;;; +14490;ANATOLIAN HIEROGLYPH A119;Lo;0;L;;;;;N;;;;; +14491;ANATOLIAN HIEROGLYPH A120;Lo;0;L;;;;;N;;;;; +14492;ANATOLIAN HIEROGLYPH A121;Lo;0;L;;;;;N;;;;; +14493;ANATOLIAN HIEROGLYPH A122;Lo;0;L;;;;;N;;;;; +14494;ANATOLIAN HIEROGLYPH A123;Lo;0;L;;;;;N;;;;; +14495;ANATOLIAN HIEROGLYPH A124;Lo;0;L;;;;;N;;;;; +14496;ANATOLIAN HIEROGLYPH A125;Lo;0;L;;;;;N;;;;; +14497;ANATOLIAN HIEROGLYPH A125A;Lo;0;L;;;;;N;;;;; +14498;ANATOLIAN HIEROGLYPH A126;Lo;0;L;;;;;N;;;;; +14499;ANATOLIAN HIEROGLYPH A127;Lo;0;L;;;;;N;;;;; +1449A;ANATOLIAN HIEROGLYPH A128;Lo;0;L;;;;;N;;;;; +1449B;ANATOLIAN HIEROGLYPH A129;Lo;0;L;;;;;N;;;;; +1449C;ANATOLIAN HIEROGLYPH A130;Lo;0;L;;;;;N;;;;; +1449D;ANATOLIAN HIEROGLYPH A131;Lo;0;L;;;;;N;;;;; +1449E;ANATOLIAN HIEROGLYPH A132;Lo;0;L;;;;;N;;;;; +1449F;ANATOLIAN HIEROGLYPH A133;Lo;0;L;;;;;N;;;;; +144A0;ANATOLIAN HIEROGLYPH A134;Lo;0;L;;;;;N;;;;; +144A1;ANATOLIAN HIEROGLYPH A135;Lo;0;L;;;;;N;;;;; +144A2;ANATOLIAN HIEROGLYPH A135A;Lo;0;L;;;;;N;;;;; +144A3;ANATOLIAN HIEROGLYPH A136;Lo;0;L;;;;;N;;;;; +144A4;ANATOLIAN HIEROGLYPH A137;Lo;0;L;;;;;N;;;;; +144A5;ANATOLIAN HIEROGLYPH A138;Lo;0;L;;;;;N;;;;; +144A6;ANATOLIAN HIEROGLYPH A139;Lo;0;L;;;;;N;;;;; +144A7;ANATOLIAN HIEROGLYPH A140;Lo;0;L;;;;;N;;;;; +144A8;ANATOLIAN HIEROGLYPH A141;Lo;0;L;;;;;N;;;;; +144A9;ANATOLIAN HIEROGLYPH A142;Lo;0;L;;;;;N;;;;; +144AA;ANATOLIAN HIEROGLYPH A143;Lo;0;L;;;;;N;;;;; +144AB;ANATOLIAN HIEROGLYPH A144;Lo;0;L;;;;;N;;;;; +144AC;ANATOLIAN HIEROGLYPH A145;Lo;0;L;;;;;N;;;;; +144AD;ANATOLIAN HIEROGLYPH A146;Lo;0;L;;;;;N;;;;; +144AE;ANATOLIAN HIEROGLYPH A147;Lo;0;L;;;;;N;;;;; +144AF;ANATOLIAN HIEROGLYPH A148;Lo;0;L;;;;;N;;;;; +144B0;ANATOLIAN HIEROGLYPH A149;Lo;0;L;;;;;N;;;;; +144B1;ANATOLIAN HIEROGLYPH A150;Lo;0;L;;;;;N;;;;; +144B2;ANATOLIAN HIEROGLYPH A151;Lo;0;L;;;;;N;;;;; +144B3;ANATOLIAN HIEROGLYPH A152;Lo;0;L;;;;;N;;;;; +144B4;ANATOLIAN HIEROGLYPH A153;Lo;0;L;;;;;N;;;;; +144B5;ANATOLIAN HIEROGLYPH A154;Lo;0;L;;;;;N;;;;; +144B6;ANATOLIAN HIEROGLYPH A155;Lo;0;L;;;;;N;;;;; +144B7;ANATOLIAN HIEROGLYPH A156;Lo;0;L;;;;;N;;;;; +144B8;ANATOLIAN HIEROGLYPH A157;Lo;0;L;;;;;N;;;;; +144B9;ANATOLIAN HIEROGLYPH A158;Lo;0;L;;;;;N;;;;; +144BA;ANATOLIAN HIEROGLYPH A159;Lo;0;L;;;;;N;;;;; +144BB;ANATOLIAN HIEROGLYPH A160;Lo;0;L;;;;;N;;;;; +144BC;ANATOLIAN HIEROGLYPH A161;Lo;0;L;;;;;N;;;;; +144BD;ANATOLIAN HIEROGLYPH A162;Lo;0;L;;;;;N;;;;; +144BE;ANATOLIAN HIEROGLYPH A163;Lo;0;L;;;;;N;;;;; +144BF;ANATOLIAN HIEROGLYPH A164;Lo;0;L;;;;;N;;;;; +144C0;ANATOLIAN HIEROGLYPH A165;Lo;0;L;;;;;N;;;;; +144C1;ANATOLIAN HIEROGLYPH A166;Lo;0;L;;;;;N;;;;; +144C2;ANATOLIAN HIEROGLYPH A167;Lo;0;L;;;;;N;;;;; +144C3;ANATOLIAN HIEROGLYPH A168;Lo;0;L;;;;;N;;;;; +144C4;ANATOLIAN HIEROGLYPH A169;Lo;0;L;;;;;N;;;;; +144C5;ANATOLIAN HIEROGLYPH A170;Lo;0;L;;;;;N;;;;; +144C6;ANATOLIAN HIEROGLYPH A171;Lo;0;L;;;;;N;;;;; +144C7;ANATOLIAN HIEROGLYPH A172;Lo;0;L;;;;;N;;;;; +144C8;ANATOLIAN HIEROGLYPH A173;Lo;0;L;;;;;N;;;;; +144C9;ANATOLIAN HIEROGLYPH A174;Lo;0;L;;;;;N;;;;; +144CA;ANATOLIAN HIEROGLYPH A175;Lo;0;L;;;;;N;;;;; +144CB;ANATOLIAN HIEROGLYPH A176;Lo;0;L;;;;;N;;;;; +144CC;ANATOLIAN HIEROGLYPH A177;Lo;0;L;;;;;N;;;;; +144CD;ANATOLIAN HIEROGLYPH A178;Lo;0;L;;;;;N;;;;; +144CE;ANATOLIAN HIEROGLYPH A179;Lo;0;L;;;;;N;;;;; +144CF;ANATOLIAN HIEROGLYPH A180;Lo;0;L;;;;;N;;;;; +144D0;ANATOLIAN HIEROGLYPH A181;Lo;0;L;;;;;N;;;;; +144D1;ANATOLIAN HIEROGLYPH A182;Lo;0;L;;;;;N;;;;; +144D2;ANATOLIAN HIEROGLYPH A183;Lo;0;L;;;;;N;;;;; +144D3;ANATOLIAN HIEROGLYPH A184;Lo;0;L;;;;;N;;;;; +144D4;ANATOLIAN HIEROGLYPH A185;Lo;0;L;;;;;N;;;;; +144D5;ANATOLIAN HIEROGLYPH A186;Lo;0;L;;;;;N;;;;; +144D6;ANATOLIAN HIEROGLYPH A187;Lo;0;L;;;;;N;;;;; +144D7;ANATOLIAN HIEROGLYPH A188;Lo;0;L;;;;;N;;;;; +144D8;ANATOLIAN HIEROGLYPH A189;Lo;0;L;;;;;N;;;;; +144D9;ANATOLIAN HIEROGLYPH A190;Lo;0;L;;;;;N;;;;; +144DA;ANATOLIAN HIEROGLYPH A191;Lo;0;L;;;;;N;;;;; +144DB;ANATOLIAN HIEROGLYPH A192;Lo;0;L;;;;;N;;;;; +144DC;ANATOLIAN HIEROGLYPH A193;Lo;0;L;;;;;N;;;;; +144DD;ANATOLIAN HIEROGLYPH A194;Lo;0;L;;;;;N;;;;; +144DE;ANATOLIAN HIEROGLYPH A195;Lo;0;L;;;;;N;;;;; +144DF;ANATOLIAN HIEROGLYPH A196;Lo;0;L;;;;;N;;;;; +144E0;ANATOLIAN HIEROGLYPH A197;Lo;0;L;;;;;N;;;;; +144E1;ANATOLIAN HIEROGLYPH A198;Lo;0;L;;;;;N;;;;; +144E2;ANATOLIAN HIEROGLYPH A199;Lo;0;L;;;;;N;;;;; +144E3;ANATOLIAN HIEROGLYPH A200;Lo;0;L;;;;;N;;;;; +144E4;ANATOLIAN HIEROGLYPH A201;Lo;0;L;;;;;N;;;;; +144E5;ANATOLIAN HIEROGLYPH A202;Lo;0;L;;;;;N;;;;; +144E6;ANATOLIAN HIEROGLYPH A202A;Lo;0;L;;;;;N;;;;; +144E7;ANATOLIAN HIEROGLYPH A202B;Lo;0;L;;;;;N;;;;; +144E8;ANATOLIAN HIEROGLYPH A203;Lo;0;L;;;;;N;;;;; +144E9;ANATOLIAN HIEROGLYPH A204;Lo;0;L;;;;;N;;;;; +144EA;ANATOLIAN HIEROGLYPH A205;Lo;0;L;;;;;N;;;;; +144EB;ANATOLIAN HIEROGLYPH A206;Lo;0;L;;;;;N;;;;; +144EC;ANATOLIAN HIEROGLYPH A207;Lo;0;L;;;;;N;;;;; +144ED;ANATOLIAN HIEROGLYPH A207A;Lo;0;L;;;;;N;;;;; +144EE;ANATOLIAN HIEROGLYPH A208;Lo;0;L;;;;;N;;;;; +144EF;ANATOLIAN HIEROGLYPH A209;Lo;0;L;;;;;N;;;;; +144F0;ANATOLIAN HIEROGLYPH A209A;Lo;0;L;;;;;N;;;;; +144F1;ANATOLIAN HIEROGLYPH A210;Lo;0;L;;;;;N;;;;; +144F2;ANATOLIAN HIEROGLYPH A211;Lo;0;L;;;;;N;;;;; +144F3;ANATOLIAN HIEROGLYPH A212;Lo;0;L;;;;;N;;;;; +144F4;ANATOLIAN HIEROGLYPH A213;Lo;0;L;;;;;N;;;;; +144F5;ANATOLIAN HIEROGLYPH A214;Lo;0;L;;;;;N;;;;; +144F6;ANATOLIAN HIEROGLYPH A215;Lo;0;L;;;;;N;;;;; +144F7;ANATOLIAN HIEROGLYPH A215A;Lo;0;L;;;;;N;;;;; +144F8;ANATOLIAN HIEROGLYPH A216;Lo;0;L;;;;;N;;;;; +144F9;ANATOLIAN HIEROGLYPH A216A;Lo;0;L;;;;;N;;;;; +144FA;ANATOLIAN HIEROGLYPH A217;Lo;0;L;;;;;N;;;;; +144FB;ANATOLIAN HIEROGLYPH A218;Lo;0;L;;;;;N;;;;; +144FC;ANATOLIAN HIEROGLYPH A219;Lo;0;L;;;;;N;;;;; +144FD;ANATOLIAN HIEROGLYPH A220;Lo;0;L;;;;;N;;;;; +144FE;ANATOLIAN HIEROGLYPH A221;Lo;0;L;;;;;N;;;;; +144FF;ANATOLIAN HIEROGLYPH A222;Lo;0;L;;;;;N;;;;; +14500;ANATOLIAN HIEROGLYPH A223;Lo;0;L;;;;;N;;;;; +14501;ANATOLIAN HIEROGLYPH A224;Lo;0;L;;;;;N;;;;; +14502;ANATOLIAN HIEROGLYPH A225;Lo;0;L;;;;;N;;;;; +14503;ANATOLIAN HIEROGLYPH A226;Lo;0;L;;;;;N;;;;; +14504;ANATOLIAN HIEROGLYPH A227;Lo;0;L;;;;;N;;;;; +14505;ANATOLIAN HIEROGLYPH A227A;Lo;0;L;;;;;N;;;;; +14506;ANATOLIAN HIEROGLYPH A228;Lo;0;L;;;;;N;;;;; +14507;ANATOLIAN HIEROGLYPH A229;Lo;0;L;;;;;N;;;;; +14508;ANATOLIAN HIEROGLYPH A230;Lo;0;L;;;;;N;;;;; +14509;ANATOLIAN HIEROGLYPH A231;Lo;0;L;;;;;N;;;;; +1450A;ANATOLIAN HIEROGLYPH A232;Lo;0;L;;;;;N;;;;; +1450B;ANATOLIAN HIEROGLYPH A233;Lo;0;L;;;;;N;;;;; +1450C;ANATOLIAN HIEROGLYPH A234;Lo;0;L;;;;;N;;;;; +1450D;ANATOLIAN HIEROGLYPH A235;Lo;0;L;;;;;N;;;;; +1450E;ANATOLIAN HIEROGLYPH A236;Lo;0;L;;;;;N;;;;; +1450F;ANATOLIAN HIEROGLYPH A237;Lo;0;L;;;;;N;;;;; +14510;ANATOLIAN HIEROGLYPH A238;Lo;0;L;;;;;N;;;;; +14511;ANATOLIAN HIEROGLYPH A239;Lo;0;L;;;;;N;;;;; +14512;ANATOLIAN HIEROGLYPH A240;Lo;0;L;;;;;N;;;;; +14513;ANATOLIAN HIEROGLYPH A241;Lo;0;L;;;;;N;;;;; +14514;ANATOLIAN HIEROGLYPH A242;Lo;0;L;;;;;N;;;;; +14515;ANATOLIAN HIEROGLYPH A243;Lo;0;L;;;;;N;;;;; +14516;ANATOLIAN HIEROGLYPH A244;Lo;0;L;;;;;N;;;;; +14517;ANATOLIAN HIEROGLYPH A245;Lo;0;L;;;;;N;;;;; +14518;ANATOLIAN HIEROGLYPH A246;Lo;0;L;;;;;N;;;;; +14519;ANATOLIAN HIEROGLYPH A247;Lo;0;L;;;;;N;;;;; +1451A;ANATOLIAN HIEROGLYPH A248;Lo;0;L;;;;;N;;;;; +1451B;ANATOLIAN HIEROGLYPH A249;Lo;0;L;;;;;N;;;;; +1451C;ANATOLIAN HIEROGLYPH A250;Lo;0;L;;;;;N;;;;; +1451D;ANATOLIAN HIEROGLYPH A251;Lo;0;L;;;;;N;;;;; +1451E;ANATOLIAN HIEROGLYPH A252;Lo;0;L;;;;;N;;;;; +1451F;ANATOLIAN HIEROGLYPH A253;Lo;0;L;;;;;N;;;;; +14520;ANATOLIAN HIEROGLYPH A254;Lo;0;L;;;;;N;;;;; +14521;ANATOLIAN HIEROGLYPH A255;Lo;0;L;;;;;N;;;;; +14522;ANATOLIAN HIEROGLYPH A256;Lo;0;L;;;;;N;;;;; +14523;ANATOLIAN HIEROGLYPH A257;Lo;0;L;;;;;N;;;;; +14524;ANATOLIAN HIEROGLYPH A258;Lo;0;L;;;;;N;;;;; +14525;ANATOLIAN HIEROGLYPH A259;Lo;0;L;;;;;N;;;;; +14526;ANATOLIAN HIEROGLYPH A260;Lo;0;L;;;;;N;;;;; +14527;ANATOLIAN HIEROGLYPH A261;Lo;0;L;;;;;N;;;;; +14528;ANATOLIAN HIEROGLYPH A262;Lo;0;L;;;;;N;;;;; +14529;ANATOLIAN HIEROGLYPH A263;Lo;0;L;;;;;N;;;;; +1452A;ANATOLIAN HIEROGLYPH A264;Lo;0;L;;;;;N;;;;; +1452B;ANATOLIAN HIEROGLYPH A265;Lo;0;L;;;;;N;;;;; +1452C;ANATOLIAN HIEROGLYPH A266;Lo;0;L;;;;;N;;;;; +1452D;ANATOLIAN HIEROGLYPH A267;Lo;0;L;;;;;N;;;;; +1452E;ANATOLIAN HIEROGLYPH A267A;Lo;0;L;;;;;N;;;;; +1452F;ANATOLIAN HIEROGLYPH A268;Lo;0;L;;;;;N;;;;; +14530;ANATOLIAN HIEROGLYPH A269;Lo;0;L;;;;;N;;;;; +14531;ANATOLIAN HIEROGLYPH A270;Lo;0;L;;;;;N;;;;; +14532;ANATOLIAN HIEROGLYPH A271;Lo;0;L;;;;;N;;;;; +14533;ANATOLIAN HIEROGLYPH A272;Lo;0;L;;;;;N;;;;; +14534;ANATOLIAN HIEROGLYPH A273;Lo;0;L;;;;;N;;;;; +14535;ANATOLIAN HIEROGLYPH A274;Lo;0;L;;;;;N;;;;; +14536;ANATOLIAN HIEROGLYPH A275;Lo;0;L;;;;;N;;;;; +14537;ANATOLIAN HIEROGLYPH A276;Lo;0;L;;;;;N;;;;; +14538;ANATOLIAN HIEROGLYPH A277;Lo;0;L;;;;;N;;;;; +14539;ANATOLIAN HIEROGLYPH A278;Lo;0;L;;;;;N;;;;; +1453A;ANATOLIAN HIEROGLYPH A279;Lo;0;L;;;;;N;;;;; +1453B;ANATOLIAN HIEROGLYPH A280;Lo;0;L;;;;;N;;;;; +1453C;ANATOLIAN HIEROGLYPH A281;Lo;0;L;;;;;N;;;;; +1453D;ANATOLIAN HIEROGLYPH A282;Lo;0;L;;;;;N;;;;; +1453E;ANATOLIAN HIEROGLYPH A283;Lo;0;L;;;;;N;;;;; +1453F;ANATOLIAN HIEROGLYPH A284;Lo;0;L;;;;;N;;;;; +14540;ANATOLIAN HIEROGLYPH A285;Lo;0;L;;;;;N;;;;; +14541;ANATOLIAN HIEROGLYPH A286;Lo;0;L;;;;;N;;;;; +14542;ANATOLIAN HIEROGLYPH A287;Lo;0;L;;;;;N;;;;; +14543;ANATOLIAN HIEROGLYPH A288;Lo;0;L;;;;;N;;;;; +14544;ANATOLIAN HIEROGLYPH A289;Lo;0;L;;;;;N;;;;; +14545;ANATOLIAN HIEROGLYPH A289A;Lo;0;L;;;;;N;;;;; +14546;ANATOLIAN HIEROGLYPH A290;Lo;0;L;;;;;N;;;;; +14547;ANATOLIAN HIEROGLYPH A291;Lo;0;L;;;;;N;;;;; +14548;ANATOLIAN HIEROGLYPH A292;Lo;0;L;;;;;N;;;;; +14549;ANATOLIAN HIEROGLYPH A293;Lo;0;L;;;;;N;;;;; +1454A;ANATOLIAN HIEROGLYPH A294;Lo;0;L;;;;;N;;;;; +1454B;ANATOLIAN HIEROGLYPH A294A;Lo;0;L;;;;;N;;;;; +1454C;ANATOLIAN HIEROGLYPH A295;Lo;0;L;;;;;N;;;;; +1454D;ANATOLIAN HIEROGLYPH A296;Lo;0;L;;;;;N;;;;; +1454E;ANATOLIAN HIEROGLYPH A297;Lo;0;L;;;;;N;;;;; +1454F;ANATOLIAN HIEROGLYPH A298;Lo;0;L;;;;;N;;;;; +14550;ANATOLIAN HIEROGLYPH A299;Lo;0;L;;;;;N;;;;; +14551;ANATOLIAN HIEROGLYPH A299A;Lo;0;L;;;;;N;;;;; +14552;ANATOLIAN HIEROGLYPH A300;Lo;0;L;;;;;N;;;;; +14553;ANATOLIAN HIEROGLYPH A301;Lo;0;L;;;;;N;;;;; +14554;ANATOLIAN HIEROGLYPH A302;Lo;0;L;;;;;N;;;;; +14555;ANATOLIAN HIEROGLYPH A303;Lo;0;L;;;;;N;;;;; +14556;ANATOLIAN HIEROGLYPH A304;Lo;0;L;;;;;N;;;;; +14557;ANATOLIAN HIEROGLYPH A305;Lo;0;L;;;;;N;;;;; +14558;ANATOLIAN HIEROGLYPH A306;Lo;0;L;;;;;N;;;;; +14559;ANATOLIAN HIEROGLYPH A307;Lo;0;L;;;;;N;;;;; +1455A;ANATOLIAN HIEROGLYPH A308;Lo;0;L;;;;;N;;;;; +1455B;ANATOLIAN HIEROGLYPH A309;Lo;0;L;;;;;N;;;;; +1455C;ANATOLIAN HIEROGLYPH A309A;Lo;0;L;;;;;N;;;;; +1455D;ANATOLIAN HIEROGLYPH A310;Lo;0;L;;;;;N;;;;; +1455E;ANATOLIAN HIEROGLYPH A311;Lo;0;L;;;;;N;;;;; +1455F;ANATOLIAN HIEROGLYPH A312;Lo;0;L;;;;;N;;;;; +14560;ANATOLIAN HIEROGLYPH A313;Lo;0;L;;;;;N;;;;; +14561;ANATOLIAN HIEROGLYPH A314;Lo;0;L;;;;;N;;;;; +14562;ANATOLIAN HIEROGLYPH A315;Lo;0;L;;;;;N;;;;; +14563;ANATOLIAN HIEROGLYPH A316;Lo;0;L;;;;;N;;;;; +14564;ANATOLIAN HIEROGLYPH A317;Lo;0;L;;;;;N;;;;; +14565;ANATOLIAN HIEROGLYPH A318;Lo;0;L;;;;;N;;;;; +14566;ANATOLIAN HIEROGLYPH A319;Lo;0;L;;;;;N;;;;; +14567;ANATOLIAN HIEROGLYPH A320;Lo;0;L;;;;;N;;;;; +14568;ANATOLIAN HIEROGLYPH A321;Lo;0;L;;;;;N;;;;; +14569;ANATOLIAN HIEROGLYPH A322;Lo;0;L;;;;;N;;;;; +1456A;ANATOLIAN HIEROGLYPH A323;Lo;0;L;;;;;N;;;;; +1456B;ANATOLIAN HIEROGLYPH A324;Lo;0;L;;;;;N;;;;; +1456C;ANATOLIAN HIEROGLYPH A325;Lo;0;L;;;;;N;;;;; +1456D;ANATOLIAN HIEROGLYPH A326;Lo;0;L;;;;;N;;;;; +1456E;ANATOLIAN HIEROGLYPH A327;Lo;0;L;;;;;N;;;;; +1456F;ANATOLIAN HIEROGLYPH A328;Lo;0;L;;;;;N;;;;; +14570;ANATOLIAN HIEROGLYPH A329;Lo;0;L;;;;;N;;;;; +14571;ANATOLIAN HIEROGLYPH A329A;Lo;0;L;;;;;N;;;;; +14572;ANATOLIAN HIEROGLYPH A330;Lo;0;L;;;;;N;;;;; +14573;ANATOLIAN HIEROGLYPH A331;Lo;0;L;;;;;N;;;;; +14574;ANATOLIAN HIEROGLYPH A332A;Lo;0;L;;;;;N;;;;; +14575;ANATOLIAN HIEROGLYPH A332B;Lo;0;L;;;;;N;;;;; +14576;ANATOLIAN HIEROGLYPH A332C;Lo;0;L;;;;;N;;;;; +14577;ANATOLIAN HIEROGLYPH A333;Lo;0;L;;;;;N;;;;; +14578;ANATOLIAN HIEROGLYPH A334;Lo;0;L;;;;;N;;;;; +14579;ANATOLIAN HIEROGLYPH A335;Lo;0;L;;;;;N;;;;; +1457A;ANATOLIAN HIEROGLYPH A336;Lo;0;L;;;;;N;;;;; +1457B;ANATOLIAN HIEROGLYPH A336A;Lo;0;L;;;;;N;;;;; +1457C;ANATOLIAN HIEROGLYPH A336B;Lo;0;L;;;;;N;;;;; +1457D;ANATOLIAN HIEROGLYPH A336C;Lo;0;L;;;;;N;;;;; +1457E;ANATOLIAN HIEROGLYPH A337;Lo;0;L;;;;;N;;;;; +1457F;ANATOLIAN HIEROGLYPH A338;Lo;0;L;;;;;N;;;;; +14580;ANATOLIAN HIEROGLYPH A339;Lo;0;L;;;;;N;;;;; +14581;ANATOLIAN HIEROGLYPH A340;Lo;0;L;;;;;N;;;;; +14582;ANATOLIAN HIEROGLYPH A341;Lo;0;L;;;;;N;;;;; +14583;ANATOLIAN HIEROGLYPH A342;Lo;0;L;;;;;N;;;;; +14584;ANATOLIAN HIEROGLYPH A343;Lo;0;L;;;;;N;;;;; +14585;ANATOLIAN HIEROGLYPH A344;Lo;0;L;;;;;N;;;;; +14586;ANATOLIAN HIEROGLYPH A345;Lo;0;L;;;;;N;;;;; +14587;ANATOLIAN HIEROGLYPH A346;Lo;0;L;;;;;N;;;;; +14588;ANATOLIAN HIEROGLYPH A347;Lo;0;L;;;;;N;;;;; +14589;ANATOLIAN HIEROGLYPH A348;Lo;0;L;;;;;N;;;;; +1458A;ANATOLIAN HIEROGLYPH A349;Lo;0;L;;;;;N;;;;; +1458B;ANATOLIAN HIEROGLYPH A350;Lo;0;L;;;;;N;;;;; +1458C;ANATOLIAN HIEROGLYPH A351;Lo;0;L;;;;;N;;;;; +1458D;ANATOLIAN HIEROGLYPH A352;Lo;0;L;;;;;N;;;;; +1458E;ANATOLIAN HIEROGLYPH A353;Lo;0;L;;;;;N;;;;; +1458F;ANATOLIAN HIEROGLYPH A354;Lo;0;L;;;;;N;;;;; +14590;ANATOLIAN HIEROGLYPH A355;Lo;0;L;;;;;N;;;;; +14591;ANATOLIAN HIEROGLYPH A356;Lo;0;L;;;;;N;;;;; +14592;ANATOLIAN HIEROGLYPH A357;Lo;0;L;;;;;N;;;;; +14593;ANATOLIAN HIEROGLYPH A358;Lo;0;L;;;;;N;;;;; +14594;ANATOLIAN HIEROGLYPH A359;Lo;0;L;;;;;N;;;;; +14595;ANATOLIAN HIEROGLYPH A359A;Lo;0;L;;;;;N;;;;; +14596;ANATOLIAN HIEROGLYPH A360;Lo;0;L;;;;;N;;;;; +14597;ANATOLIAN HIEROGLYPH A361;Lo;0;L;;;;;N;;;;; +14598;ANATOLIAN HIEROGLYPH A362;Lo;0;L;;;;;N;;;;; +14599;ANATOLIAN HIEROGLYPH A363;Lo;0;L;;;;;N;;;;; +1459A;ANATOLIAN HIEROGLYPH A364;Lo;0;L;;;;;N;;;;; +1459B;ANATOLIAN HIEROGLYPH A364A;Lo;0;L;;;;;N;;;;; +1459C;ANATOLIAN HIEROGLYPH A365;Lo;0;L;;;;;N;;;;; +1459D;ANATOLIAN HIEROGLYPH A366;Lo;0;L;;;;;N;;;;; +1459E;ANATOLIAN HIEROGLYPH A367;Lo;0;L;;;;;N;;;;; +1459F;ANATOLIAN HIEROGLYPH A368;Lo;0;L;;;;;N;;;;; +145A0;ANATOLIAN HIEROGLYPH A368A;Lo;0;L;;;;;N;;;;; +145A1;ANATOLIAN HIEROGLYPH A369;Lo;0;L;;;;;N;;;;; +145A2;ANATOLIAN HIEROGLYPH A370;Lo;0;L;;;;;N;;;;; +145A3;ANATOLIAN HIEROGLYPH A371;Lo;0;L;;;;;N;;;;; +145A4;ANATOLIAN HIEROGLYPH A371A;Lo;0;L;;;;;N;;;;; +145A5;ANATOLIAN HIEROGLYPH A372;Lo;0;L;;;;;N;;;;; +145A6;ANATOLIAN HIEROGLYPH A373;Lo;0;L;;;;;N;;;;; +145A7;ANATOLIAN HIEROGLYPH A374;Lo;0;L;;;;;N;;;;; +145A8;ANATOLIAN HIEROGLYPH A375;Lo;0;L;;;;;N;;;;; +145A9;ANATOLIAN HIEROGLYPH A376;Lo;0;L;;;;;N;;;;; +145AA;ANATOLIAN HIEROGLYPH A377;Lo;0;L;;;;;N;;;;; +145AB;ANATOLIAN HIEROGLYPH A378;Lo;0;L;;;;;N;;;;; +145AC;ANATOLIAN HIEROGLYPH A379;Lo;0;L;;;;;N;;;;; +145AD;ANATOLIAN HIEROGLYPH A380;Lo;0;L;;;;;N;;;;; +145AE;ANATOLIAN HIEROGLYPH A381;Lo;0;L;;;;;N;;;;; +145AF;ANATOLIAN HIEROGLYPH A381A;Lo;0;L;;;;;N;;;;; +145B0;ANATOLIAN HIEROGLYPH A382;Lo;0;L;;;;;N;;;;; +145B1;ANATOLIAN HIEROGLYPH A383 RA OR RI;Lo;0;L;;;;;N;;;;; +145B2;ANATOLIAN HIEROGLYPH A383A;Lo;0;L;;;;;N;;;;; +145B3;ANATOLIAN HIEROGLYPH A384;Lo;0;L;;;;;N;;;;; +145B4;ANATOLIAN HIEROGLYPH A385;Lo;0;L;;;;;N;;;;; +145B5;ANATOLIAN HIEROGLYPH A386;Lo;0;L;;;;;N;;;;; +145B6;ANATOLIAN HIEROGLYPH A386A;Lo;0;L;;;;;N;;;;; +145B7;ANATOLIAN HIEROGLYPH A387;Lo;0;L;;;;;N;;;;; +145B8;ANATOLIAN HIEROGLYPH A388;Lo;0;L;;;;;N;;;;; +145B9;ANATOLIAN HIEROGLYPH A389;Lo;0;L;;;;;N;;;;; +145BA;ANATOLIAN HIEROGLYPH A390;Lo;0;L;;;;;N;;;;; +145BB;ANATOLIAN HIEROGLYPH A391;Lo;0;L;;;;;N;;;;; +145BC;ANATOLIAN HIEROGLYPH A392;Lo;0;L;;;;;N;;;;; +145BD;ANATOLIAN HIEROGLYPH A393 EIGHT;Lo;0;L;;;;;N;;;;; +145BE;ANATOLIAN HIEROGLYPH A394;Lo;0;L;;;;;N;;;;; +145BF;ANATOLIAN HIEROGLYPH A395;Lo;0;L;;;;;N;;;;; +145C0;ANATOLIAN HIEROGLYPH A396;Lo;0;L;;;;;N;;;;; +145C1;ANATOLIAN HIEROGLYPH A397;Lo;0;L;;;;;N;;;;; +145C2;ANATOLIAN HIEROGLYPH A398;Lo;0;L;;;;;N;;;;; +145C3;ANATOLIAN HIEROGLYPH A399;Lo;0;L;;;;;N;;;;; +145C4;ANATOLIAN HIEROGLYPH A400;Lo;0;L;;;;;N;;;;; +145C5;ANATOLIAN HIEROGLYPH A401;Lo;0;L;;;;;N;;;;; +145C6;ANATOLIAN HIEROGLYPH A402;Lo;0;L;;;;;N;;;;; +145C7;ANATOLIAN HIEROGLYPH A403;Lo;0;L;;;;;N;;;;; +145C8;ANATOLIAN HIEROGLYPH A404;Lo;0;L;;;;;N;;;;; +145C9;ANATOLIAN HIEROGLYPH A405;Lo;0;L;;;;;N;;;;; +145CA;ANATOLIAN HIEROGLYPH A406;Lo;0;L;;;;;N;;;;; +145CB;ANATOLIAN HIEROGLYPH A407;Lo;0;L;;;;;N;;;;; +145CC;ANATOLIAN HIEROGLYPH A408;Lo;0;L;;;;;N;;;;; +145CD;ANATOLIAN HIEROGLYPH A409;Lo;0;L;;;;;N;;;;; +145CE;ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARK;Lo;0;L;;;;;N;;;;; +145CF;ANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARK;Lo;0;L;;;;;N;;;;; +145D0;ANATOLIAN HIEROGLYPH A411;Lo;0;L;;;;;N;;;;; +145D1;ANATOLIAN HIEROGLYPH A412;Lo;0;L;;;;;N;;;;; +145D2;ANATOLIAN HIEROGLYPH A413;Lo;0;L;;;;;N;;;;; +145D3;ANATOLIAN HIEROGLYPH A414;Lo;0;L;;;;;N;;;;; +145D4;ANATOLIAN HIEROGLYPH A415;Lo;0;L;;;;;N;;;;; +145D5;ANATOLIAN HIEROGLYPH A416;Lo;0;L;;;;;N;;;;; +145D6;ANATOLIAN HIEROGLYPH A417;Lo;0;L;;;;;N;;;;; +145D7;ANATOLIAN HIEROGLYPH A418;Lo;0;L;;;;;N;;;;; +145D8;ANATOLIAN HIEROGLYPH A419;Lo;0;L;;;;;N;;;;; +145D9;ANATOLIAN HIEROGLYPH A420;Lo;0;L;;;;;N;;;;; +145DA;ANATOLIAN HIEROGLYPH A421;Lo;0;L;;;;;N;;;;; +145DB;ANATOLIAN HIEROGLYPH A422;Lo;0;L;;;;;N;;;;; +145DC;ANATOLIAN HIEROGLYPH A423;Lo;0;L;;;;;N;;;;; +145DD;ANATOLIAN HIEROGLYPH A424;Lo;0;L;;;;;N;;;;; +145DE;ANATOLIAN HIEROGLYPH A425;Lo;0;L;;;;;N;;;;; +145DF;ANATOLIAN HIEROGLYPH A426;Lo;0;L;;;;;N;;;;; +145E0;ANATOLIAN HIEROGLYPH A427;Lo;0;L;;;;;N;;;;; +145E1;ANATOLIAN HIEROGLYPH A428;Lo;0;L;;;;;N;;;;; +145E2;ANATOLIAN HIEROGLYPH A429;Lo;0;L;;;;;N;;;;; +145E3;ANATOLIAN HIEROGLYPH A430;Lo;0;L;;;;;N;;;;; +145E4;ANATOLIAN HIEROGLYPH A431;Lo;0;L;;;;;N;;;;; +145E5;ANATOLIAN HIEROGLYPH A432;Lo;0;L;;;;;N;;;;; +145E6;ANATOLIAN HIEROGLYPH A433;Lo;0;L;;;;;N;;;;; +145E7;ANATOLIAN HIEROGLYPH A434;Lo;0;L;;;;;N;;;;; +145E8;ANATOLIAN HIEROGLYPH A435;Lo;0;L;;;;;N;;;;; +145E9;ANATOLIAN HIEROGLYPH A436;Lo;0;L;;;;;N;;;;; +145EA;ANATOLIAN HIEROGLYPH A437;Lo;0;L;;;;;N;;;;; +145EB;ANATOLIAN HIEROGLYPH A438;Lo;0;L;;;;;N;;;;; +145EC;ANATOLIAN HIEROGLYPH A439;Lo;0;L;;;;;N;;;;; +145ED;ANATOLIAN HIEROGLYPH A440;Lo;0;L;;;;;N;;;;; +145EE;ANATOLIAN HIEROGLYPH A441;Lo;0;L;;;;;N;;;;; +145EF;ANATOLIAN HIEROGLYPH A442;Lo;0;L;;;;;N;;;;; +145F0;ANATOLIAN HIEROGLYPH A443;Lo;0;L;;;;;N;;;;; +145F1;ANATOLIAN HIEROGLYPH A444;Lo;0;L;;;;;N;;;;; +145F2;ANATOLIAN HIEROGLYPH A445;Lo;0;L;;;;;N;;;;; +145F3;ANATOLIAN HIEROGLYPH A446;Lo;0;L;;;;;N;;;;; +145F4;ANATOLIAN HIEROGLYPH A447;Lo;0;L;;;;;N;;;;; +145F5;ANATOLIAN HIEROGLYPH A448;Lo;0;L;;;;;N;;;;; +145F6;ANATOLIAN HIEROGLYPH A449;Lo;0;L;;;;;N;;;;; +145F7;ANATOLIAN HIEROGLYPH A450;Lo;0;L;;;;;N;;;;; +145F8;ANATOLIAN HIEROGLYPH A450A;Lo;0;L;;;;;N;;;;; +145F9;ANATOLIAN HIEROGLYPH A451;Lo;0;L;;;;;N;;;;; +145FA;ANATOLIAN HIEROGLYPH A452;Lo;0;L;;;;;N;;;;; +145FB;ANATOLIAN HIEROGLYPH A453;Lo;0;L;;;;;N;;;;; +145FC;ANATOLIAN HIEROGLYPH A454;Lo;0;L;;;;;N;;;;; +145FD;ANATOLIAN HIEROGLYPH A455;Lo;0;L;;;;;N;;;;; +145FE;ANATOLIAN HIEROGLYPH A456;Lo;0;L;;;;;N;;;;; +145FF;ANATOLIAN HIEROGLYPH A457;Lo;0;L;;;;;N;;;;; +14600;ANATOLIAN HIEROGLYPH A457A;Lo;0;L;;;;;N;;;;; +14601;ANATOLIAN HIEROGLYPH A458;Lo;0;L;;;;;N;;;;; +14602;ANATOLIAN HIEROGLYPH A459;Lo;0;L;;;;;N;;;;; +14603;ANATOLIAN HIEROGLYPH A460;Lo;0;L;;;;;N;;;;; +14604;ANATOLIAN HIEROGLYPH A461;Lo;0;L;;;;;N;;;;; +14605;ANATOLIAN HIEROGLYPH A462;Lo;0;L;;;;;N;;;;; +14606;ANATOLIAN HIEROGLYPH A463;Lo;0;L;;;;;N;;;;; +14607;ANATOLIAN HIEROGLYPH A464;Lo;0;L;;;;;N;;;;; +14608;ANATOLIAN HIEROGLYPH A465;Lo;0;L;;;;;N;;;;; +14609;ANATOLIAN HIEROGLYPH A466;Lo;0;L;;;;;N;;;;; +1460A;ANATOLIAN HIEROGLYPH A467;Lo;0;L;;;;;N;;;;; +1460B;ANATOLIAN HIEROGLYPH A468;Lo;0;L;;;;;N;;;;; +1460C;ANATOLIAN HIEROGLYPH A469;Lo;0;L;;;;;N;;;;; +1460D;ANATOLIAN HIEROGLYPH A470;Lo;0;L;;;;;N;;;;; +1460E;ANATOLIAN HIEROGLYPH A471;Lo;0;L;;;;;N;;;;; +1460F;ANATOLIAN HIEROGLYPH A472;Lo;0;L;;;;;N;;;;; +14610;ANATOLIAN HIEROGLYPH A473;Lo;0;L;;;;;N;;;;; +14611;ANATOLIAN HIEROGLYPH A474;Lo;0;L;;;;;N;;;;; +14612;ANATOLIAN HIEROGLYPH A475;Lo;0;L;;;;;N;;;;; +14613;ANATOLIAN HIEROGLYPH A476;Lo;0;L;;;;;N;;;;; +14614;ANATOLIAN HIEROGLYPH A477;Lo;0;L;;;;;N;;;;; +14615;ANATOLIAN HIEROGLYPH A478;Lo;0;L;;;;;N;;;;; +14616;ANATOLIAN HIEROGLYPH A479;Lo;0;L;;;;;N;;;;; +14617;ANATOLIAN HIEROGLYPH A480;Lo;0;L;;;;;N;;;;; +14618;ANATOLIAN HIEROGLYPH A481;Lo;0;L;;;;;N;;;;; +14619;ANATOLIAN HIEROGLYPH A482;Lo;0;L;;;;;N;;;;; +1461A;ANATOLIAN HIEROGLYPH A483;Lo;0;L;;;;;N;;;;; +1461B;ANATOLIAN HIEROGLYPH A484;Lo;0;L;;;;;N;;;;; +1461C;ANATOLIAN HIEROGLYPH A485;Lo;0;L;;;;;N;;;;; +1461D;ANATOLIAN HIEROGLYPH A486;Lo;0;L;;;;;N;;;;; +1461E;ANATOLIAN HIEROGLYPH A487;Lo;0;L;;;;;N;;;;; +1461F;ANATOLIAN HIEROGLYPH A488;Lo;0;L;;;;;N;;;;; +14620;ANATOLIAN HIEROGLYPH A489;Lo;0;L;;;;;N;;;;; +14621;ANATOLIAN HIEROGLYPH A490;Lo;0;L;;;;;N;;;;; +14622;ANATOLIAN HIEROGLYPH A491;Lo;0;L;;;;;N;;;;; +14623;ANATOLIAN HIEROGLYPH A492;Lo;0;L;;;;;N;;;;; +14624;ANATOLIAN HIEROGLYPH A493;Lo;0;L;;;;;N;;;;; +14625;ANATOLIAN HIEROGLYPH A494;Lo;0;L;;;;;N;;;;; +14626;ANATOLIAN HIEROGLYPH A495;Lo;0;L;;;;;N;;;;; +14627;ANATOLIAN HIEROGLYPH A496;Lo;0;L;;;;;N;;;;; +14628;ANATOLIAN HIEROGLYPH A497;Lo;0;L;;;;;N;;;;; +14629;ANATOLIAN HIEROGLYPH A501;Lo;0;L;;;;;N;;;;; +1462A;ANATOLIAN HIEROGLYPH A502;Lo;0;L;;;;;N;;;;; +1462B;ANATOLIAN HIEROGLYPH A503;Lo;0;L;;;;;N;;;;; +1462C;ANATOLIAN HIEROGLYPH A504;Lo;0;L;;;;;N;;;;; +1462D;ANATOLIAN HIEROGLYPH A505;Lo;0;L;;;;;N;;;;; +1462E;ANATOLIAN HIEROGLYPH A506;Lo;0;L;;;;;N;;;;; +1462F;ANATOLIAN HIEROGLYPH A507;Lo;0;L;;;;;N;;;;; +14630;ANATOLIAN HIEROGLYPH A508;Lo;0;L;;;;;N;;;;; +14631;ANATOLIAN HIEROGLYPH A509;Lo;0;L;;;;;N;;;;; +14632;ANATOLIAN HIEROGLYPH A510;Lo;0;L;;;;;N;;;;; +14633;ANATOLIAN HIEROGLYPH A511;Lo;0;L;;;;;N;;;;; +14634;ANATOLIAN HIEROGLYPH A512;Lo;0;L;;;;;N;;;;; +14635;ANATOLIAN HIEROGLYPH A513;Lo;0;L;;;;;N;;;;; +14636;ANATOLIAN HIEROGLYPH A514;Lo;0;L;;;;;N;;;;; +14637;ANATOLIAN HIEROGLYPH A515;Lo;0;L;;;;;N;;;;; +14638;ANATOLIAN HIEROGLYPH A516;Lo;0;L;;;;;N;;;;; +14639;ANATOLIAN HIEROGLYPH A517;Lo;0;L;;;;;N;;;;; +1463A;ANATOLIAN HIEROGLYPH A518;Lo;0;L;;;;;N;;;;; +1463B;ANATOLIAN HIEROGLYPH A519;Lo;0;L;;;;;N;;;;; +1463C;ANATOLIAN HIEROGLYPH A520;Lo;0;L;;;;;N;;;;; +1463D;ANATOLIAN HIEROGLYPH A521;Lo;0;L;;;;;N;;;;; +1463E;ANATOLIAN HIEROGLYPH A522;Lo;0;L;;;;;N;;;;; +1463F;ANATOLIAN HIEROGLYPH A523;Lo;0;L;;;;;N;;;;; +14640;ANATOLIAN HIEROGLYPH A524;Lo;0;L;;;;;N;;;;; +14641;ANATOLIAN HIEROGLYPH A525;Lo;0;L;;;;;N;;;;; +14642;ANATOLIAN HIEROGLYPH A526;Lo;0;L;;;;;N;;;;; +14643;ANATOLIAN HIEROGLYPH A527;Lo;0;L;;;;;N;;;;; +14644;ANATOLIAN HIEROGLYPH A528;Lo;0;L;;;;;N;;;;; +14645;ANATOLIAN HIEROGLYPH A529;Lo;0;L;;;;;N;;;;; +14646;ANATOLIAN HIEROGLYPH A530;Lo;0;L;;;;;N;;;;; 16800;BAMUM LETTER PHASE-A NGKUE MFON;Lo;0;L;;;;;N;;;;; 16801;BAMUM LETTER PHASE-A GBIEE FON;Lo;0;L;;;;;N;;;;; 16802;BAMUM LETTER PHASE-A PON MFON PIPAEMGBIEE;Lo;0;L;;;;;N;;;;; @@ -23080,6 +24300,17 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;; 1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;; 1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;; +1D1DE;MUSICAL SYMBOL KIEVAN C CLEF;So;0;L;;;;;N;;;;; +1D1DF;MUSICAL SYMBOL KIEVAN END OF PIECE;So;0;L;;;;;N;;;;; +1D1E0;MUSICAL SYMBOL KIEVAN FINAL NOTE;So;0;L;;;;;N;;;;; +1D1E1;MUSICAL SYMBOL KIEVAN RECITATIVE MARK;So;0;L;;;;;N;;;;; +1D1E2;MUSICAL SYMBOL KIEVAN WHOLE NOTE;So;0;L;;;;;N;;;;; +1D1E3;MUSICAL SYMBOL KIEVAN HALF NOTE;So;0;L;;;;;N;;;;; +1D1E4;MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM DOWN;So;0;L;;;;;N;;;;; +1D1E5;MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM UP;So;0;L;;;;;N;;;;; +1D1E6;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM DOWN;So;0;L;;;;;N;;;;; +1D1E7;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM UP;So;0;L;;;;;N;;;;; +1D1E8;MUSICAL SYMBOL KIEVAN FLAT SIGN;So;0;L;;;;;N;;;;; 1D200;GREEK VOCAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;; 1D201;GREEK VOCAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;; 1D202;GREEK VOCAL NOTATION SYMBOL-3;So;0;ON;;;;;N;;;;; @@ -24251,6 +25482,678 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; 1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; 1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1D800;SIGNWRITING HAND-FIST INDEX;So;0;L;;;;;N;;;;; +1D801;SIGNWRITING HAND-CIRCLE INDEX;So;0;L;;;;;N;;;;; +1D802;SIGNWRITING HAND-CUP INDEX;So;0;L;;;;;N;;;;; +1D803;SIGNWRITING HAND-OVAL INDEX;So;0;L;;;;;N;;;;; +1D804;SIGNWRITING HAND-HINGE INDEX;So;0;L;;;;;N;;;;; +1D805;SIGNWRITING HAND-ANGLE INDEX;So;0;L;;;;;N;;;;; +1D806;SIGNWRITING HAND-FIST INDEX BENT;So;0;L;;;;;N;;;;; +1D807;SIGNWRITING HAND-CIRCLE INDEX BENT;So;0;L;;;;;N;;;;; +1D808;SIGNWRITING HAND-FIST THUMB UNDER INDEX BENT;So;0;L;;;;;N;;;;; +1D809;SIGNWRITING HAND-FIST INDEX RAISED KNUCKLE;So;0;L;;;;;N;;;;; +1D80A;SIGNWRITING HAND-FIST INDEX CUPPED;So;0;L;;;;;N;;;;; +1D80B;SIGNWRITING HAND-FIST INDEX HINGED;So;0;L;;;;;N;;;;; +1D80C;SIGNWRITING HAND-FIST INDEX HINGED LOW;So;0;L;;;;;N;;;;; +1D80D;SIGNWRITING HAND-CIRCLE INDEX HINGE;So;0;L;;;;;N;;;;; +1D80E;SIGNWRITING HAND-FIST INDEX MIDDLE;So;0;L;;;;;N;;;;; +1D80F;SIGNWRITING HAND-CIRCLE INDEX MIDDLE;So;0;L;;;;;N;;;;; +1D810;SIGNWRITING HAND-FIST INDEX MIDDLE BENT;So;0;L;;;;;N;;;;; +1D811;SIGNWRITING HAND-FIST INDEX MIDDLE RAISED KNUCKLES;So;0;L;;;;;N;;;;; +1D812;SIGNWRITING HAND-FIST INDEX MIDDLE HINGED;So;0;L;;;;;N;;;;; +1D813;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED;So;0;L;;;;;N;;;;; +1D814;SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP;So;0;L;;;;;N;;;;; +1D815;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED;So;0;L;;;;;N;;;;; +1D816;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED INDEX BENT;So;0;L;;;;;N;;;;; +1D817;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED MIDDLE BENT;So;0;L;;;;;N;;;;; +1D818;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED;So;0;L;;;;;N;;;;; +1D819;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED;So;0;L;;;;;N;;;;; +1D81A;SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED;So;0;L;;;;;N;;;;; +1D81B;SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSSED;So;0;L;;;;;N;;;;; +1D81C;SIGNWRITING HAND-FIST MIDDLE BENT OVER INDEX;So;0;L;;;;;N;;;;; +1D81D;SIGNWRITING HAND-FIST INDEX BENT OVER MIDDLE;So;0;L;;;;;N;;;;; +1D81E;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB;So;0;L;;;;;N;;;;; +1D81F;SIGNWRITING HAND-CIRCLE INDEX MIDDLE THUMB;So;0;L;;;;;N;;;;; +1D820;SIGNWRITING HAND-FIST INDEX MIDDLE STRAIGHT THUMB BENT;So;0;L;;;;;N;;;;; +1D821;SIGNWRITING HAND-FIST INDEX MIDDLE BENT THUMB STRAIGHT;So;0;L;;;;;N;;;;; +1D822;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB BENT;So;0;L;;;;;N;;;;; +1D823;SIGNWRITING HAND-FIST INDEX MIDDLE HINGED SPREAD THUMB SIDE;So;0;L;;;;;N;;;;; +1D824;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB SIDE;So;0;L;;;;;N;;;;; +1D825;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB CONJOINED;So;0;L;;;;;N;;;;; +1D826;SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP THUMB SIDE;So;0;L;;;;;N;;;;; +1D827;SIGNWRITING HAND-FIST INDEX MIDDLE UP SPREAD THUMB FORWARD;So;0;L;;;;;N;;;;; +1D828;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CUPPED;So;0;L;;;;;N;;;;; +1D829;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CIRCLED;So;0;L;;;;;N;;;;; +1D82A;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HOOKED;So;0;L;;;;;N;;;;; +1D82B;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HINGED;So;0;L;;;;;N;;;;; +1D82C;SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE STRAIGHT;So;0;L;;;;;N;;;;; +1D82D;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE;So;0;L;;;;;N;;;;; +1D82E;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE CONJOINED;So;0;L;;;;;N;;;;; +1D82F;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE BENT;So;0;L;;;;;N;;;;; +1D830;SIGNWRITING HAND-FIST MIDDLE THUMB HOOKED INDEX UP;So;0;L;;;;;N;;;;; +1D831;SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE UP;So;0;L;;;;;N;;;;; +1D832;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED THUMB SIDE;So;0;L;;;;;N;;;;; +1D833;SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED THUMB SIDE;So;0;L;;;;;N;;;;; +1D834;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB FORWARD;So;0;L;;;;;N;;;;; +1D835;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED THUMB FORWARD;So;0;L;;;;;N;;;;; +1D836;SIGNWRITING HAND-FIST MIDDLE THUMB CUPPED INDEX UP;So;0;L;;;;;N;;;;; +1D837;SIGNWRITING HAND-FIST INDEX THUMB CUPPED MIDDLE UP;So;0;L;;;;;N;;;;; +1D838;SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX UP;So;0;L;;;;;N;;;;; +1D839;SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX HINGED;So;0;L;;;;;N;;;;; +1D83A;SIGNWRITING HAND-FIST INDEX THUMB ANGLED OUT MIDDLE UP;So;0;L;;;;;N;;;;; +1D83B;SIGNWRITING HAND-FIST INDEX THUMB ANGLED IN MIDDLE UP;So;0;L;;;;;N;;;;; +1D83C;SIGNWRITING HAND-FIST INDEX THUMB CIRCLED MIDDLE UP;So;0;L;;;;;N;;;;; +1D83D;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CONJOINED HINGED;So;0;L;;;;;N;;;;; +1D83E;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED OUT;So;0;L;;;;;N;;;;; +1D83F;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED;So;0;L;;;;;N;;;;; +1D840;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX UP;So;0;L;;;;;N;;;;; +1D841;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX CROSSED;So;0;L;;;;;N;;;;; +1D842;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED INDEX UP;So;0;L;;;;;N;;;;; +1D843;SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE HINGED;So;0;L;;;;;N;;;;; +1D844;SIGNWRITING HAND-FLAT FOUR FINGERS;So;0;L;;;;;N;;;;; +1D845;SIGNWRITING HAND-FLAT FOUR FINGERS BENT;So;0;L;;;;;N;;;;; +1D846;SIGNWRITING HAND-FLAT FOUR FINGERS HINGED;So;0;L;;;;;N;;;;; +1D847;SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;; +1D848;SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED SPLIT;So;0;L;;;;;N;;;;; +1D849;SIGNWRITING HAND-CLAW FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;; +1D84A;SIGNWRITING HAND-FIST FOUR FINGERS CONJOINED BENT;So;0;L;;;;;N;;;;; +1D84B;SIGNWRITING HAND-HINGE FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;; +1D84C;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; +1D84D;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; +1D84E;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD FOUR BENT;So;0;L;;;;;N;;;;; +1D84F;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD FOUR BENT;So;0;L;;;;;N;;;;; +1D850;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD BENT;So;0;L;;;;;N;;;;; +1D851;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD BENT;So;0;L;;;;;N;;;;; +1D852;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD THUMB FORWARD;So;0;L;;;;;N;;;;; +1D853;SIGNWRITING HAND-CUP FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; +1D854;SIGNWRITING HAND-CUP FIVE FINGERS SPREAD OPEN;So;0;L;;;;;N;;;;; +1D855;SIGNWRITING HAND-HINGE FIVE FINGERS SPREAD OPEN;So;0;L;;;;;N;;;;; +1D856;SIGNWRITING HAND-OVAL FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; +1D857;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED;So;0;L;;;;;N;;;;; +1D858;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED THUMB SIDE;So;0;L;;;;;N;;;;; +1D859;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED NO THUMB;So;0;L;;;;;N;;;;; +1D85A;SIGNWRITING HAND-FLAT;So;0;L;;;;;N;;;;; +1D85B;SIGNWRITING HAND-FLAT BETWEEN PALM FACINGS;So;0;L;;;;;N;;;;; +1D85C;SIGNWRITING HAND-FLAT HEEL;So;0;L;;;;;N;;;;; +1D85D;SIGNWRITING HAND-FLAT THUMB SIDE;So;0;L;;;;;N;;;;; +1D85E;SIGNWRITING HAND-FLAT HEEL THUMB SIDE;So;0;L;;;;;N;;;;; +1D85F;SIGNWRITING HAND-FLAT THUMB BENT;So;0;L;;;;;N;;;;; +1D860;SIGNWRITING HAND-FLAT THUMB FORWARD;So;0;L;;;;;N;;;;; +1D861;SIGNWRITING HAND-FLAT SPLIT INDEX THUMB SIDE;So;0;L;;;;;N;;;;; +1D862;SIGNWRITING HAND-FLAT SPLIT CENTRE;So;0;L;;;;;N;;;;; +1D863;SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE;So;0;L;;;;;N;;;;; +1D864;SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE BENT;So;0;L;;;;;N;;;;; +1D865;SIGNWRITING HAND-FLAT SPLIT LITTLE;So;0;L;;;;;N;;;;; +1D866;SIGNWRITING HAND-CLAW;So;0;L;;;;;N;;;;; +1D867;SIGNWRITING HAND-CLAW THUMB SIDE;So;0;L;;;;;N;;;;; +1D868;SIGNWRITING HAND-CLAW NO THUMB;So;0;L;;;;;N;;;;; +1D869;SIGNWRITING HAND-CLAW THUMB FORWARD;So;0;L;;;;;N;;;;; +1D86A;SIGNWRITING HAND-HOOK CURLICUE;So;0;L;;;;;N;;;;; +1D86B;SIGNWRITING HAND-HOOK;So;0;L;;;;;N;;;;; +1D86C;SIGNWRITING HAND-CUP OPEN;So;0;L;;;;;N;;;;; +1D86D;SIGNWRITING HAND-CUP;So;0;L;;;;;N;;;;; +1D86E;SIGNWRITING HAND-CUP OPEN THUMB SIDE;So;0;L;;;;;N;;;;; +1D86F;SIGNWRITING HAND-CUP THUMB SIDE;So;0;L;;;;;N;;;;; +1D870;SIGNWRITING HAND-CUP OPEN NO THUMB;So;0;L;;;;;N;;;;; +1D871;SIGNWRITING HAND-CUP NO THUMB;So;0;L;;;;;N;;;;; +1D872;SIGNWRITING HAND-CUP OPEN THUMB FORWARD;So;0;L;;;;;N;;;;; +1D873;SIGNWRITING HAND-CUP THUMB FORWARD;So;0;L;;;;;N;;;;; +1D874;SIGNWRITING HAND-CURLICUE OPEN;So;0;L;;;;;N;;;;; +1D875;SIGNWRITING HAND-CURLICUE;So;0;L;;;;;N;;;;; +1D876;SIGNWRITING HAND-CIRCLE;So;0;L;;;;;N;;;;; +1D877;SIGNWRITING HAND-OVAL;So;0;L;;;;;N;;;;; +1D878;SIGNWRITING HAND-OVAL THUMB SIDE;So;0;L;;;;;N;;;;; +1D879;SIGNWRITING HAND-OVAL NO THUMB;So;0;L;;;;;N;;;;; +1D87A;SIGNWRITING HAND-OVAL THUMB FORWARD;So;0;L;;;;;N;;;;; +1D87B;SIGNWRITING HAND-HINGE OPEN;So;0;L;;;;;N;;;;; +1D87C;SIGNWRITING HAND-HINGE OPEN THUMB FORWARD;So;0;L;;;;;N;;;;; +1D87D;SIGNWRITING HAND-HINGE;So;0;L;;;;;N;;;;; +1D87E;SIGNWRITING HAND-HINGE SMALL;So;0;L;;;;;N;;;;; +1D87F;SIGNWRITING HAND-HINGE OPEN THUMB SIDE;So;0;L;;;;;N;;;;; +1D880;SIGNWRITING HAND-HINGE THUMB SIDE;So;0;L;;;;;N;;;;; +1D881;SIGNWRITING HAND-HINGE OPEN NO THUMB;So;0;L;;;;;N;;;;; +1D882;SIGNWRITING HAND-HINGE NO THUMB;So;0;L;;;;;N;;;;; +1D883;SIGNWRITING HAND-HINGE THUMB SIDE TOUCHING INDEX;So;0;L;;;;;N;;;;; +1D884;SIGNWRITING HAND-HINGE THUMB BETWEEN MIDDLE RING;So;0;L;;;;;N;;;;; +1D885;SIGNWRITING HAND-ANGLE;So;0;L;;;;;N;;;;; +1D886;SIGNWRITING HAND-FIST INDEX MIDDLE RING;So;0;L;;;;;N;;;;; +1D887;SIGNWRITING HAND-CIRCLE INDEX MIDDLE RING;So;0;L;;;;;N;;;;; +1D888;SIGNWRITING HAND-HINGE INDEX MIDDLE RING;So;0;L;;;;;N;;;;; +1D889;SIGNWRITING HAND-ANGLE INDEX MIDDLE RING;So;0;L;;;;;N;;;;; +1D88A;SIGNWRITING HAND-HINGE LITTLE;So;0;L;;;;;N;;;;; +1D88B;SIGNWRITING HAND-FIST INDEX MIDDLE RING BENT;So;0;L;;;;;N;;;;; +1D88C;SIGNWRITING HAND-FIST INDEX MIDDLE RING CONJOINED;So;0;L;;;;;N;;;;; +1D88D;SIGNWRITING HAND-HINGE INDEX MIDDLE RING CONJOINED;So;0;L;;;;;N;;;;; +1D88E;SIGNWRITING HAND-FIST LITTLE DOWN;So;0;L;;;;;N;;;;; +1D88F;SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE STRAIGHT;So;0;L;;;;;N;;;;; +1D890;SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE CURVED;So;0;L;;;;;N;;;;; +1D891;SIGNWRITING HAND-FIST LITTLE DOWN OTHERS CIRCLED;So;0;L;;;;;N;;;;; +1D892;SIGNWRITING HAND-FIST LITTLE UP;So;0;L;;;;;N;;;;; +1D893;SIGNWRITING HAND-FIST THUMB UNDER LITTLE UP;So;0;L;;;;;N;;;;; +1D894;SIGNWRITING HAND-CIRCLE LITTLE UP;So;0;L;;;;;N;;;;; +1D895;SIGNWRITING HAND-OVAL LITTLE UP;So;0;L;;;;;N;;;;; +1D896;SIGNWRITING HAND-ANGLE LITTLE UP;So;0;L;;;;;N;;;;; +1D897;SIGNWRITING HAND-FIST LITTLE RAISED KNUCKLE;So;0;L;;;;;N;;;;; +1D898;SIGNWRITING HAND-FIST LITTLE BENT;So;0;L;;;;;N;;;;; +1D899;SIGNWRITING HAND-FIST LITTLE TOUCHES THUMB;So;0;L;;;;;N;;;;; +1D89A;SIGNWRITING HAND-FIST LITTLE THUMB;So;0;L;;;;;N;;;;; +1D89B;SIGNWRITING HAND-HINGE LITTLE THUMB;So;0;L;;;;;N;;;;; +1D89C;SIGNWRITING HAND-FIST LITTLE INDEX THUMB;So;0;L;;;;;N;;;;; +1D89D;SIGNWRITING HAND-HINGE LITTLE INDEX THUMB;So;0;L;;;;;N;;;;; +1D89E;SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB OUT;So;0;L;;;;;N;;;;; +1D89F;SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB;So;0;L;;;;;N;;;;; +1D8A0;SIGNWRITING HAND-FIST LITTLE INDEX;So;0;L;;;;;N;;;;; +1D8A1;SIGNWRITING HAND-CIRCLE LITTLE INDEX;So;0;L;;;;;N;;;;; +1D8A2;SIGNWRITING HAND-HINGE LITTLE INDEX;So;0;L;;;;;N;;;;; +1D8A3;SIGNWRITING HAND-ANGLE LITTLE INDEX;So;0;L;;;;;N;;;;; +1D8A4;SIGNWRITING HAND-FIST INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; +1D8A5;SIGNWRITING HAND-CIRCLE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; +1D8A6;SIGNWRITING HAND-HINGE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; +1D8A7;SIGNWRITING HAND-HINGE RING;So;0;L;;;;;N;;;;; +1D8A8;SIGNWRITING HAND-ANGLE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; +1D8A9;SIGNWRITING HAND-FIST INDEX MIDDLE CROSS LITTLE;So;0;L;;;;;N;;;;; +1D8AA;SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSS LITTLE;So;0;L;;;;;N;;;;; +1D8AB;SIGNWRITING HAND-FIST RING DOWN;So;0;L;;;;;N;;;;; +1D8AC;SIGNWRITING HAND-HINGE RING DOWN INDEX THUMB HOOK MIDDLE;So;0;L;;;;;N;;;;; +1D8AD;SIGNWRITING HAND-ANGLE RING DOWN MIDDLE THUMB INDEX CROSS;So;0;L;;;;;N;;;;; +1D8AE;SIGNWRITING HAND-FIST RING UP;So;0;L;;;;;N;;;;; +1D8AF;SIGNWRITING HAND-FIST RING RAISED KNUCKLE;So;0;L;;;;;N;;;;; +1D8B0;SIGNWRITING HAND-FIST RING LITTLE;So;0;L;;;;;N;;;;; +1D8B1;SIGNWRITING HAND-CIRCLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8B2;SIGNWRITING HAND-OVAL RING LITTLE;So;0;L;;;;;N;;;;; +1D8B3;SIGNWRITING HAND-ANGLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8B4;SIGNWRITING HAND-FIST RING MIDDLE;So;0;L;;;;;N;;;;; +1D8B5;SIGNWRITING HAND-FIST RING MIDDLE CONJOINED;So;0;L;;;;;N;;;;; +1D8B6;SIGNWRITING HAND-FIST RING MIDDLE RAISED KNUCKLES;So;0;L;;;;;N;;;;; +1D8B7;SIGNWRITING HAND-FIST RING INDEX;So;0;L;;;;;N;;;;; +1D8B8;SIGNWRITING HAND-FIST RING THUMB;So;0;L;;;;;N;;;;; +1D8B9;SIGNWRITING HAND-HOOK RING THUMB;So;0;L;;;;;N;;;;; +1D8BA;SIGNWRITING HAND-FIST INDEX RING LITTLE;So;0;L;;;;;N;;;;; +1D8BB;SIGNWRITING HAND-CIRCLE INDEX RING LITTLE;So;0;L;;;;;N;;;;; +1D8BC;SIGNWRITING HAND-CURLICUE INDEX RING LITTLE ON;So;0;L;;;;;N;;;;; +1D8BD;SIGNWRITING HAND-HOOK INDEX RING LITTLE OUT;So;0;L;;;;;N;;;;; +1D8BE;SIGNWRITING HAND-HOOK INDEX RING LITTLE IN;So;0;L;;;;;N;;;;; +1D8BF;SIGNWRITING HAND-HOOK INDEX RING LITTLE UNDER;So;0;L;;;;;N;;;;; +1D8C0;SIGNWRITING HAND-CUP INDEX RING LITTLE;So;0;L;;;;;N;;;;; +1D8C1;SIGNWRITING HAND-HINGE INDEX RING LITTLE;So;0;L;;;;;N;;;;; +1D8C2;SIGNWRITING HAND-ANGLE INDEX RING LITTLE OUT;So;0;L;;;;;N;;;;; +1D8C3;SIGNWRITING HAND-ANGLE INDEX RING LITTLE;So;0;L;;;;;N;;;;; +1D8C4;SIGNWRITING HAND-FIST MIDDLE DOWN;So;0;L;;;;;N;;;;; +1D8C5;SIGNWRITING HAND-HINGE MIDDLE;So;0;L;;;;;N;;;;; +1D8C6;SIGNWRITING HAND-FIST MIDDLE UP;So;0;L;;;;;N;;;;; +1D8C7;SIGNWRITING HAND-CIRCLE MIDDLE UP;So;0;L;;;;;N;;;;; +1D8C8;SIGNWRITING HAND-FIST MIDDLE RAISED KNUCKLE;So;0;L;;;;;N;;;;; +1D8C9;SIGNWRITING HAND-FIST MIDDLE UP THUMB SIDE;So;0;L;;;;;N;;;;; +1D8CA;SIGNWRITING HAND-HOOK MIDDLE THUMB;So;0;L;;;;;N;;;;; +1D8CB;SIGNWRITING HAND-FIST MIDDLE THUMB LITTLE;So;0;L;;;;;N;;;;; +1D8CC;SIGNWRITING HAND-FIST MIDDLE LITTLE;So;0;L;;;;;N;;;;; +1D8CD;SIGNWRITING HAND-FIST MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8CE;SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8CF;SIGNWRITING HAND-CURLICUE MIDDLE RING LITTLE ON;So;0;L;;;;;N;;;;; +1D8D0;SIGNWRITING HAND-CUP MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8D1;SIGNWRITING HAND-HINGE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8D2;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE OUT;So;0;L;;;;;N;;;;; +1D8D3;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE IN;So;0;L;;;;;N;;;;; +1D8D4;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; +1D8D5;SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE BENT;So;0;L;;;;;N;;;;; +1D8D6;SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED;So;0;L;;;;;N;;;;; +1D8D7;SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED SIDE;So;0;L;;;;;N;;;;; +1D8D8;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED OUT;So;0;L;;;;;N;;;;; +1D8D9;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED IN;So;0;L;;;;;N;;;;; +1D8DA;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED;So;0;L;;;;;N;;;;; +1D8DB;SIGNWRITING HAND-HINGE INDEX HINGED;So;0;L;;;;;N;;;;; +1D8DC;SIGNWRITING HAND-FIST INDEX THUMB SIDE;So;0;L;;;;;N;;;;; +1D8DD;SIGNWRITING HAND-HINGE INDEX THUMB SIDE;So;0;L;;;;;N;;;;; +1D8DE;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB DIAGONAL;So;0;L;;;;;N;;;;; +1D8DF;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB CONJOINED;So;0;L;;;;;N;;;;; +1D8E0;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB BENT;So;0;L;;;;;N;;;;; +1D8E1;SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX BENT;So;0;L;;;;;N;;;;; +1D8E2;SIGNWRITING HAND-FIST INDEX THUMB SIDE BOTH BENT;So;0;L;;;;;N;;;;; +1D8E3;SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX HINGE;So;0;L;;;;;N;;;;; +1D8E4;SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX STRAIGHT;So;0;L;;;;;N;;;;; +1D8E5;SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX BENT;So;0;L;;;;;N;;;;; +1D8E6;SIGNWRITING HAND-FIST INDEX THUMB HOOK;So;0;L;;;;;N;;;;; +1D8E7;SIGNWRITING HAND-FIST INDEX THUMB CURLICUE;So;0;L;;;;;N;;;;; +1D8E8;SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB INSIDE;So;0;L;;;;;N;;;;; +1D8E9;SIGNWRITING HAND-CLAW INDEX THUMB CURVE THUMB INSIDE;So;0;L;;;;;N;;;;; +1D8EA;SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB UNDER;So;0;L;;;;;N;;;;; +1D8EB;SIGNWRITING HAND-FIST INDEX THUMB CIRCLE;So;0;L;;;;;N;;;;; +1D8EC;SIGNWRITING HAND-CUP INDEX THUMB;So;0;L;;;;;N;;;;; +1D8ED;SIGNWRITING HAND-CUP INDEX THUMB OPEN;So;0;L;;;;;N;;;;; +1D8EE;SIGNWRITING HAND-HINGE INDEX THUMB OPEN;So;0;L;;;;;N;;;;; +1D8EF;SIGNWRITING HAND-HINGE INDEX THUMB LARGE;So;0;L;;;;;N;;;;; +1D8F0;SIGNWRITING HAND-HINGE INDEX THUMB;So;0;L;;;;;N;;;;; +1D8F1;SIGNWRITING HAND-HINGE INDEX THUMB SMALL;So;0;L;;;;;N;;;;; +1D8F2;SIGNWRITING HAND-ANGLE INDEX THUMB OUT;So;0;L;;;;;N;;;;; +1D8F3;SIGNWRITING HAND-ANGLE INDEX THUMB IN;So;0;L;;;;;N;;;;; +1D8F4;SIGNWRITING HAND-ANGLE INDEX THUMB;So;0;L;;;;;N;;;;; +1D8F5;SIGNWRITING HAND-FIST THUMB;So;0;L;;;;;N;;;;; +1D8F6;SIGNWRITING HAND-FIST THUMB HEEL;So;0;L;;;;;N;;;;; +1D8F7;SIGNWRITING HAND-FIST THUMB SIDE DIAGONAL;So;0;L;;;;;N;;;;; +1D8F8;SIGNWRITING HAND-FIST THUMB SIDE CONJOINED;So;0;L;;;;;N;;;;; +1D8F9;SIGNWRITING HAND-FIST THUMB SIDE BENT;So;0;L;;;;;N;;;;; +1D8FA;SIGNWRITING HAND-FIST THUMB FORWARD;So;0;L;;;;;N;;;;; +1D8FB;SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE;So;0;L;;;;;N;;;;; +1D8FC;SIGNWRITING HAND-FIST THUMB BETWEEN MIDDLE RING;So;0;L;;;;;N;;;;; +1D8FD;SIGNWRITING HAND-FIST THUMB BETWEEN RING LITTLE;So;0;L;;;;;N;;;;; +1D8FE;SIGNWRITING HAND-FIST THUMB UNDER TWO FINGERS;So;0;L;;;;;N;;;;; +1D8FF;SIGNWRITING HAND-FIST THUMB OVER TWO FINGERS;So;0;L;;;;;N;;;;; +1D900;SIGNWRITING HAND-FIST THUMB UNDER THREE FINGERS;So;0;L;;;;;N;;;;; +1D901;SIGNWRITING HAND-FIST THUMB UNDER FOUR FINGERS;So;0;L;;;;;N;;;;; +1D902;SIGNWRITING HAND-FIST THUMB OVER FOUR RAISED KNUCKLES;So;0;L;;;;;N;;;;; +1D903;SIGNWRITING HAND-FIST;So;0;L;;;;;N;;;;; +1D904;SIGNWRITING HAND-FIST HEEL;So;0;L;;;;;N;;;;; +1D905;SIGNWRITING TOUCH SINGLE;So;0;L;;;;;N;;;;; +1D906;SIGNWRITING TOUCH MULTIPLE;So;0;L;;;;;N;;;;; +1D907;SIGNWRITING TOUCH BETWEEN;So;0;L;;;;;N;;;;; +1D908;SIGNWRITING GRASP SINGLE;So;0;L;;;;;N;;;;; +1D909;SIGNWRITING GRASP MULTIPLE;So;0;L;;;;;N;;;;; +1D90A;SIGNWRITING GRASP BETWEEN;So;0;L;;;;;N;;;;; +1D90B;SIGNWRITING STRIKE SINGLE;So;0;L;;;;;N;;;;; +1D90C;SIGNWRITING STRIKE MULTIPLE;So;0;L;;;;;N;;;;; +1D90D;SIGNWRITING STRIKE BETWEEN;So;0;L;;;;;N;;;;; +1D90E;SIGNWRITING BRUSH SINGLE;So;0;L;;;;;N;;;;; +1D90F;SIGNWRITING BRUSH MULTIPLE;So;0;L;;;;;N;;;;; +1D910;SIGNWRITING BRUSH BETWEEN;So;0;L;;;;;N;;;;; +1D911;SIGNWRITING RUB SINGLE;So;0;L;;;;;N;;;;; +1D912;SIGNWRITING RUB MULTIPLE;So;0;L;;;;;N;;;;; +1D913;SIGNWRITING RUB BETWEEN;So;0;L;;;;;N;;;;; +1D914;SIGNWRITING SURFACE SYMBOLS;So;0;L;;;;;N;;;;; +1D915;SIGNWRITING SURFACE BETWEEN;So;0;L;;;;;N;;;;; +1D916;SIGNWRITING SQUEEZE LARGE SINGLE;So;0;L;;;;;N;;;;; +1D917;SIGNWRITING SQUEEZE SMALL SINGLE;So;0;L;;;;;N;;;;; +1D918;SIGNWRITING SQUEEZE LARGE MULTIPLE;So;0;L;;;;;N;;;;; +1D919;SIGNWRITING SQUEEZE SMALL MULTIPLE;So;0;L;;;;;N;;;;; +1D91A;SIGNWRITING SQUEEZE SEQUENTIAL;So;0;L;;;;;N;;;;; +1D91B;SIGNWRITING FLICK LARGE SINGLE;So;0;L;;;;;N;;;;; +1D91C;SIGNWRITING FLICK SMALL SINGLE;So;0;L;;;;;N;;;;; +1D91D;SIGNWRITING FLICK LARGE MULTIPLE;So;0;L;;;;;N;;;;; +1D91E;SIGNWRITING FLICK SMALL MULTIPLE;So;0;L;;;;;N;;;;; +1D91F;SIGNWRITING FLICK SEQUENTIAL;So;0;L;;;;;N;;;;; +1D920;SIGNWRITING SQUEEZE FLICK ALTERNATING;So;0;L;;;;;N;;;;; +1D921;SIGNWRITING MOVEMENT-HINGE UP DOWN LARGE;So;0;L;;;;;N;;;;; +1D922;SIGNWRITING MOVEMENT-HINGE UP DOWN SMALL;So;0;L;;;;;N;;;;; +1D923;SIGNWRITING MOVEMENT-HINGE UP SEQUENTIAL;So;0;L;;;;;N;;;;; +1D924;SIGNWRITING MOVEMENT-HINGE DOWN SEQUENTIAL;So;0;L;;;;;N;;;;; +1D925;SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING LARGE;So;0;L;;;;;N;;;;; +1D926;SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING SMALL;So;0;L;;;;;N;;;;; +1D927;SIGNWRITING MOVEMENT-HINGE SIDE TO SIDE SCISSORS;So;0;L;;;;;N;;;;; +1D928;SIGNWRITING MOVEMENT-WALLPLANE FINGER CONTACT;So;0;L;;;;;N;;;;; +1D929;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CONTACT;So;0;L;;;;;N;;;;; +1D92A;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT SMALL;So;0;L;;;;;N;;;;; +1D92B;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT MEDIUM;So;0;L;;;;;N;;;;; +1D92C;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGE;So;0;L;;;;;N;;;;; +1D92D;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGEST;So;0;L;;;;;N;;;;; +1D92E;SIGNWRITING MOVEMENT-WALLPLANE SINGLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D92F;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE STRAIGHT;So;0;L;;;;;N;;;;; +1D930;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D931;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING;So;0;L;;;;;N;;;;; +1D932;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; +1D933;SIGNWRITING MOVEMENT-WALLPLANE CROSS;So;0;L;;;;;N;;;;; +1D934;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE STRAIGHT MOVEMENT;So;0;L;;;;;N;;;;; +1D935;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D936;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING;So;0;L;;;;;N;;;;; +1D937;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; +1D938;SIGNWRITING MOVEMENT-WALLPLANE BEND SMALL;So;0;L;;;;;N;;;;; +1D939;SIGNWRITING MOVEMENT-WALLPLANE BEND MEDIUM;So;0;L;;;;;N;;;;; +1D93A;SIGNWRITING MOVEMENT-WALLPLANE BEND LARGE;So;0;L;;;;;N;;;;; +1D93B;SIGNWRITING MOVEMENT-WALLPLANE CORNER SMALL;So;0;L;;;;;N;;;;; +1D93C;SIGNWRITING MOVEMENT-WALLPLANE CORNER MEDIUM;So;0;L;;;;;N;;;;; +1D93D;SIGNWRITING MOVEMENT-WALLPLANE CORNER LARGE;So;0;L;;;;;N;;;;; +1D93E;SIGNWRITING MOVEMENT-WALLPLANE CORNER ROTATION;So;0;L;;;;;N;;;;; +1D93F;SIGNWRITING MOVEMENT-WALLPLANE CHECK SMALL;So;0;L;;;;;N;;;;; +1D940;SIGNWRITING MOVEMENT-WALLPLANE CHECK MEDIUM;So;0;L;;;;;N;;;;; +1D941;SIGNWRITING MOVEMENT-WALLPLANE CHECK LARGE;So;0;L;;;;;N;;;;; +1D942;SIGNWRITING MOVEMENT-WALLPLANE BOX SMALL;So;0;L;;;;;N;;;;; +1D943;SIGNWRITING MOVEMENT-WALLPLANE BOX MEDIUM;So;0;L;;;;;N;;;;; +1D944;SIGNWRITING MOVEMENT-WALLPLANE BOX LARGE;So;0;L;;;;;N;;;;; +1D945;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG SMALL;So;0;L;;;;;N;;;;; +1D946;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG MEDIUM;So;0;L;;;;;N;;;;; +1D947;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG LARGE;So;0;L;;;;;N;;;;; +1D948;SIGNWRITING MOVEMENT-WALLPLANE PEAKS SMALL;So;0;L;;;;;N;;;;; +1D949;SIGNWRITING MOVEMENT-WALLPLANE PEAKS MEDIUM;So;0;L;;;;;N;;;;; +1D94A;SIGNWRITING MOVEMENT-WALLPLANE PEAKS LARGE;So;0;L;;;;;N;;;;; +1D94B;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;; +1D94C;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D94D;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE ALTERNATING;So;0;L;;;;;N;;;;; +1D94E;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;; +1D94F;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D950;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;; +1D951;SIGNWRITING TRAVEL-WALLPLANE SHAKING;So;0;L;;;;;N;;;;; +1D952;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL SINGLE;So;0;L;;;;;N;;;;; +1D953;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL DOUBLE;So;0;L;;;;;N;;;;; +1D954;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL TRIPLE;So;0;L;;;;;N;;;;; +1D955;SIGNWRITING MOVEMENT-DIAGONAL AWAY SMALL;So;0;L;;;;;N;;;;; +1D956;SIGNWRITING MOVEMENT-DIAGONAL AWAY MEDIUM;So;0;L;;;;;N;;;;; +1D957;SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGE;So;0;L;;;;;N;;;;; +1D958;SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGEST;So;0;L;;;;;N;;;;; +1D959;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS SMALL;So;0;L;;;;;N;;;;; +1D95A;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS MEDIUM;So;0;L;;;;;N;;;;; +1D95B;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGE;So;0;L;;;;;N;;;;; +1D95C;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGEST;So;0;L;;;;;N;;;;; +1D95D;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY SMALL;So;0;L;;;;;N;;;;; +1D95E;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY MEDIUM;So;0;L;;;;;N;;;;; +1D95F;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGE;So;0;L;;;;;N;;;;; +1D960;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGEST;So;0;L;;;;;N;;;;; +1D961;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS SMALL;So;0;L;;;;;N;;;;; +1D962;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS MEDIUM;So;0;L;;;;;N;;;;; +1D963;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGE;So;0;L;;;;;N;;;;; +1D964;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGEST;So;0;L;;;;;N;;;;; +1D965;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT SMALL;So;0;L;;;;;N;;;;; +1D966;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT MEDIUM;So;0;L;;;;;N;;;;; +1D967;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGE;So;0;L;;;;;N;;;;; +1D968;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGEST;So;0;L;;;;;N;;;;; +1D969;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D96A;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE STRAIGHT;So;0;L;;;;;N;;;;; +1D96B;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D96C;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING;So;0;L;;;;;N;;;;; +1D96D;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; +1D96E;SIGNWRITING MOVEMENT-FLOORPLANE CROSS;So;0;L;;;;;N;;;;; +1D96F;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE STRAIGHT MOVEMENT;So;0;L;;;;;N;;;;; +1D970;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE WRIST FLEX;So;0;L;;;;;N;;;;; +1D971;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING MOVEMENT;So;0;L;;;;;N;;;;; +1D972;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; +1D973;SIGNWRITING MOVEMENT-FLOORPLANE BEND;So;0;L;;;;;N;;;;; +1D974;SIGNWRITING MOVEMENT-FLOORPLANE CORNER SMALL;So;0;L;;;;;N;;;;; +1D975;SIGNWRITING MOVEMENT-FLOORPLANE CORNER MEDIUM;So;0;L;;;;;N;;;;; +1D976;SIGNWRITING MOVEMENT-FLOORPLANE CORNER LARGE;So;0;L;;;;;N;;;;; +1D977;SIGNWRITING MOVEMENT-FLOORPLANE CHECK;So;0;L;;;;;N;;;;; +1D978;SIGNWRITING MOVEMENT-FLOORPLANE BOX SMALL;So;0;L;;;;;N;;;;; +1D979;SIGNWRITING MOVEMENT-FLOORPLANE BOX MEDIUM;So;0;L;;;;;N;;;;; +1D97A;SIGNWRITING MOVEMENT-FLOORPLANE BOX LARGE;So;0;L;;;;;N;;;;; +1D97B;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG SMALL;So;0;L;;;;;N;;;;; +1D97C;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG MEDIUM;So;0;L;;;;;N;;;;; +1D97D;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG LARGE;So;0;L;;;;;N;;;;; +1D97E;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS SMALL;So;0;L;;;;;N;;;;; +1D97F;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS MEDIUM;So;0;L;;;;;N;;;;; +1D980;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS LARGE;So;0;L;;;;;N;;;;; +1D981;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;; +1D982;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D983;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;; +1D984;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;; +1D985;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D986;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE ALTERNATING;So;0;L;;;;;N;;;;; +1D987;SIGNWRITING TRAVEL-FLOORPLANE SHAKING;So;0;L;;;;;N;;;;; +1D988;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER SMALL;So;0;L;;;;;N;;;;; +1D989;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER MEDIUM;So;0;L;;;;;N;;;;; +1D98A;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGE;So;0;L;;;;;N;;;;; +1D98B;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGEST;So;0;L;;;;;N;;;;; +1D98C;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE SMALL;So;0;L;;;;;N;;;;; +1D98D;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE MEDIUM;So;0;L;;;;;N;;;;; +1D98E;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGE;So;0;L;;;;;N;;;;; +1D98F;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGEST;So;0;L;;;;;N;;;;; +1D990;SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE SMALL;So;0;L;;;;;N;;;;; +1D991;SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE MEDIUM;So;0;L;;;;;N;;;;; +1D992;SIGNWRITING MOVEMENT-WALLPLANE HUMP SMALL;So;0;L;;;;;N;;;;; +1D993;SIGNWRITING MOVEMENT-WALLPLANE HUMP MEDIUM;So;0;L;;;;;N;;;;; +1D994;SIGNWRITING MOVEMENT-WALLPLANE HUMP LARGE;So;0;L;;;;;N;;;;; +1D995;SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL;So;0;L;;;;;N;;;;; +1D996;SIGNWRITING MOVEMENT-WALLPLANE LOOP MEDIUM;So;0;L;;;;;N;;;;; +1D997;SIGNWRITING MOVEMENT-WALLPLANE LOOP LARGE;So;0;L;;;;;N;;;;; +1D998;SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D999;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE SMALL;So;0;L;;;;;N;;;;; +1D99A;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE MEDIUM;So;0;L;;;;;N;;;;; +1D99B;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE LARGE;So;0;L;;;;;N;;;;; +1D99C;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE SMALL;So;0;L;;;;;N;;;;; +1D99D;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE MEDIUM;So;0;L;;;;;N;;;;; +1D99E;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE LARGE;So;0;L;;;;;N;;;;; +1D99F;SIGNWRITING MOVEMENT-WALLPLANE CURVE THEN STRAIGHT;So;0;L;;;;;N;;;;; +1D9A0;SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS SMALL;So;0;L;;;;;N;;;;; +1D9A1;SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS MEDIUM;So;0;L;;;;;N;;;;; +1D9A2;SIGNWRITING ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;; +1D9A3;SIGNWRITING ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D9A4;SIGNWRITING ROTATION-WALLPLANE ALTERNATE;So;0;L;;;;;N;;;;; +1D9A5;SIGNWRITING MOVEMENT-WALLPLANE SHAKING;So;0;L;;;;;N;;;;; +1D9A6;SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9A7;SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9A8;SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9A9;SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9AA;SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9AB;SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9AC;SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING FRONT WALL;So;0;L;;;;;N;;;;; +1D9AD;SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING CHEST;So;0;L;;;;;N;;;;; +1D9AE;SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING CHEST;So;0;L;;;;;N;;;;; +1D9AF;SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING CHEST;So;0;L;;;;;N;;;;; +1D9B0;SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING CHEST;So;0;L;;;;;N;;;;; +1D9B1;SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING CHEST;So;0;L;;;;;N;;;;; +1D9B2;SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING CHEST;So;0;L;;;;;N;;;;; +1D9B3;SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING CHEST;So;0;L;;;;;N;;;;; +1D9B4;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH SMALL;So;0;L;;;;;N;;;;; +1D9B5;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH MEDIUM;So;0;L;;;;;N;;;;; +1D9B6;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH LARGE;So;0;L;;;;;N;;;;; +1D9B7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING SMALL;So;0;L;;;;;N;;;;; +1D9B8;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING LARGE;So;0;L;;;;;N;;;;; +1D9B9;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9BA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE DOUBLE;So;0;L;;;;;N;;;;; +1D9BB;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL TRIPLE;So;0;L;;;;;N;;;;; +1D9BC;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE TRIPLE;So;0;L;;;;;N;;;;; +1D9BD;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL SINGLE;So;0;L;;;;;N;;;;; +1D9BE;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE SINGLE;So;0;L;;;;;N;;;;; +1D9BF;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9C0;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE DOUBLE;So;0;L;;;;;N;;;;; +1D9C1;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING SMALL;So;0;L;;;;;N;;;;; +1D9C2;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING LARGE;So;0;L;;;;;N;;;;; +1D9C3;SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING CEILING;So;0;L;;;;;N;;;;; +1D9C4;SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING CEILING;So;0;L;;;;;N;;;;; +1D9C5;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING CEILING;So;0;L;;;;;N;;;;; +1D9C6;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR SMALL;So;0;L;;;;;N;;;;; +1D9C7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR LARGE;So;0;L;;;;;N;;;;; +1D9C8;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9C9;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR LARGE DOUBLE;So;0;L;;;;;N;;;;; +1D9CA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE SMALL TRIPLE;So;0;L;;;;;N;;;;; +1D9CB;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE LARGE TRIPLE;So;0;L;;;;;N;;;;; +1D9CC;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL SINGLE;So;0;L;;;;;N;;;;; +1D9CD;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE SINGLE;So;0;L;;;;;N;;;;; +1D9CE;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9CF;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE DOUBLE;So;0;L;;;;;N;;;;; +1D9D0;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR SMALL;So;0;L;;;;;N;;;;; +1D9D1;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR LARGE;So;0;L;;;;;N;;;;; +1D9D2;SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING FLOOR;So;0;L;;;;;N;;;;; +1D9D3;SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING FLOOR;So;0;L;;;;;N;;;;; +1D9D4;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING FLOOR;So;0;L;;;;;N;;;;; +1D9D5;SIGNWRITING MOVEMENT-FLOORPLANE CURVE SMALL;So;0;L;;;;;N;;;;; +1D9D6;SIGNWRITING MOVEMENT-FLOORPLANE CURVE MEDIUM;So;0;L;;;;;N;;;;; +1D9D7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGE;So;0;L;;;;;N;;;;; +1D9D8;SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGEST;So;0;L;;;;;N;;;;; +1D9D9;SIGNWRITING MOVEMENT-FLOORPLANE CURVE COMBINED;So;0;L;;;;;N;;;;; +1D9DA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP SMALL;So;0;L;;;;;N;;;;; +1D9DB;SIGNWRITING MOVEMENT-FLOORPLANE LOOP SMALL;So;0;L;;;;;N;;;;; +1D9DC;SIGNWRITING MOVEMENT-FLOORPLANE WAVE SNAKE;So;0;L;;;;;N;;;;; +1D9DD;SIGNWRITING MOVEMENT-FLOORPLANE WAVE SMALL;So;0;L;;;;;N;;;;; +1D9DE;SIGNWRITING MOVEMENT-FLOORPLANE WAVE LARGE;So;0;L;;;;;N;;;;; +1D9DF;SIGNWRITING ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;; +1D9E0;SIGNWRITING ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;; +1D9E1;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;; +1D9E2;SIGNWRITING MOVEMENT-FLOORPLANE SHAKING PARALLEL;So;0;L;;;;;N;;;;; +1D9E3;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL SINGLE;So;0;L;;;;;N;;;;; +1D9E4;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM SINGLE;So;0;L;;;;;N;;;;; +1D9E5;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9E6;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM DOUBLE;So;0;L;;;;;N;;;;; +1D9E7;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL SINGLE;So;0;L;;;;;N;;;;; +1D9E8;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM SINGLE;So;0;L;;;;;N;;;;; +1D9E9;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE SINGLE;So;0;L;;;;;N;;;;; +1D9EA;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL DOUBLE;So;0;L;;;;;N;;;;; +1D9EB;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM DOUBLE;So;0;L;;;;;N;;;;; +1D9EC;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE DOUBLE;So;0;L;;;;;N;;;;; +1D9ED;SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT SINGLE;So;0;L;;;;;N;;;;; +1D9EE;SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT DOUBLE;So;0;L;;;;;N;;;;; +1D9EF;SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL SINGLE;So;0;L;;;;;N;;;;; +1D9F0;SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL DOUBLE;So;0;L;;;;;N;;;;; +1D9F1;SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES SINGLE;So;0;L;;;;;N;;;;; +1D9F2;SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES DOUBLE;So;0;L;;;;;N;;;;; +1D9F3;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL SINGLE;So;0;L;;;;;N;;;;; +1D9F4;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL DOUBLE;So;0;L;;;;;N;;;;; +1D9F5;SIGNWRITING DYNAMIC ARROWHEAD SMALL;So;0;L;;;;;N;;;;; +1D9F6;SIGNWRITING DYNAMIC ARROWHEAD LARGE;So;0;L;;;;;N;;;;; +1D9F7;SIGNWRITING DYNAMIC FAST;So;0;L;;;;;N;;;;; +1D9F8;SIGNWRITING DYNAMIC SLOW;So;0;L;;;;;N;;;;; +1D9F9;SIGNWRITING DYNAMIC TENSE;So;0;L;;;;;N;;;;; +1D9FA;SIGNWRITING DYNAMIC RELAXED;So;0;L;;;;;N;;;;; +1D9FB;SIGNWRITING DYNAMIC SIMULTANEOUS;So;0;L;;;;;N;;;;; +1D9FC;SIGNWRITING DYNAMIC SIMULTANEOUS ALTERNATING;So;0;L;;;;;N;;;;; +1D9FD;SIGNWRITING DYNAMIC EVERY OTHER TIME;So;0;L;;;;;N;;;;; +1D9FE;SIGNWRITING DYNAMIC GRADUAL;So;0;L;;;;;N;;;;; +1D9FF;SIGNWRITING HEAD;So;0;L;;;;;N;;;;; +1DA00;SIGNWRITING HEAD RIM;Mn;0;NSM;;;;;N;;;;; +1DA01;SIGNWRITING HEAD MOVEMENT-WALLPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; +1DA02;SIGNWRITING HEAD MOVEMENT-WALLPLANE TILT;Mn;0;NSM;;;;;N;;;;; +1DA03;SIGNWRITING HEAD MOVEMENT-FLOORPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; +1DA04;SIGNWRITING HEAD MOVEMENT-WALLPLANE CURVE;Mn;0;NSM;;;;;N;;;;; +1DA05;SIGNWRITING HEAD MOVEMENT-FLOORPLANE CURVE;Mn;0;NSM;;;;;N;;;;; +1DA06;SIGNWRITING HEAD MOVEMENT CIRCLE;Mn;0;NSM;;;;;N;;;;; +1DA07;SIGNWRITING FACE DIRECTION POSITION NOSE FORWARD TILTING;Mn;0;NSM;;;;;N;;;;; +1DA08;SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN;Mn;0;NSM;;;;;N;;;;; +1DA09;SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN TILTING;Mn;0;NSM;;;;;N;;;;; +1DA0A;SIGNWRITING EYEBROWS STRAIGHT UP;Mn;0;NSM;;;;;N;;;;; +1DA0B;SIGNWRITING EYEBROWS STRAIGHT NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA0C;SIGNWRITING EYEBROWS STRAIGHT DOWN;Mn;0;NSM;;;;;N;;;;; +1DA0D;SIGNWRITING DREAMY EYEBROWS NEUTRAL DOWN;Mn;0;NSM;;;;;N;;;;; +1DA0E;SIGNWRITING DREAMY EYEBROWS DOWN NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA0F;SIGNWRITING DREAMY EYEBROWS UP NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA10;SIGNWRITING DREAMY EYEBROWS NEUTRAL UP;Mn;0;NSM;;;;;N;;;;; +1DA11;SIGNWRITING FOREHEAD NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA12;SIGNWRITING FOREHEAD CONTACT;Mn;0;NSM;;;;;N;;;;; +1DA13;SIGNWRITING FOREHEAD WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA14;SIGNWRITING EYES OPEN;Mn;0;NSM;;;;;N;;;;; +1DA15;SIGNWRITING EYES SQUEEZED;Mn;0;NSM;;;;;N;;;;; +1DA16;SIGNWRITING EYES CLOSED;Mn;0;NSM;;;;;N;;;;; +1DA17;SIGNWRITING EYE BLINK SINGLE;Mn;0;NSM;;;;;N;;;;; +1DA18;SIGNWRITING EYE BLINK MULTIPLE;Mn;0;NSM;;;;;N;;;;; +1DA19;SIGNWRITING EYES HALF OPEN;Mn;0;NSM;;;;;N;;;;; +1DA1A;SIGNWRITING EYES WIDE OPEN;Mn;0;NSM;;;;;N;;;;; +1DA1B;SIGNWRITING EYES HALF CLOSED;Mn;0;NSM;;;;;N;;;;; +1DA1C;SIGNWRITING EYES WIDENING MOVEMENT;Mn;0;NSM;;;;;N;;;;; +1DA1D;SIGNWRITING EYE WINK;Mn;0;NSM;;;;;N;;;;; +1DA1E;SIGNWRITING EYELASHES UP;Mn;0;NSM;;;;;N;;;;; +1DA1F;SIGNWRITING EYELASHES DOWN;Mn;0;NSM;;;;;N;;;;; +1DA20;SIGNWRITING EYELASHES FLUTTERING;Mn;0;NSM;;;;;N;;;;; +1DA21;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; +1DA22;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT DOUBLE;Mn;0;NSM;;;;;N;;;;; +1DA23;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT ALTERNATING;Mn;0;NSM;;;;;N;;;;; +1DA24;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; +1DA25;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT DOUBLE;Mn;0;NSM;;;;;N;;;;; +1DA26;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT ALTERNATING;Mn;0;NSM;;;;;N;;;;; +1DA27;SIGNWRITING EYEGAZE-WALLPLANE CURVED;Mn;0;NSM;;;;;N;;;;; +1DA28;SIGNWRITING EYEGAZE-FLOORPLANE CURVED;Mn;0;NSM;;;;;N;;;;; +1DA29;SIGNWRITING EYEGAZE-WALLPLANE CIRCLING;Mn;0;NSM;;;;;N;;;;; +1DA2A;SIGNWRITING CHEEKS PUFFED;Mn;0;NSM;;;;;N;;;;; +1DA2B;SIGNWRITING CHEEKS NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA2C;SIGNWRITING CHEEKS SUCKED;Mn;0;NSM;;;;;N;;;;; +1DA2D;SIGNWRITING TENSE CHEEKS HIGH;Mn;0;NSM;;;;;N;;;;; +1DA2E;SIGNWRITING TENSE CHEEKS MIDDLE;Mn;0;NSM;;;;;N;;;;; +1DA2F;SIGNWRITING TENSE CHEEKS LOW;Mn;0;NSM;;;;;N;;;;; +1DA30;SIGNWRITING EARS;Mn;0;NSM;;;;;N;;;;; +1DA31;SIGNWRITING NOSE NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA32;SIGNWRITING NOSE CONTACT;Mn;0;NSM;;;;;N;;;;; +1DA33;SIGNWRITING NOSE WRINKLES;Mn;0;NSM;;;;;N;;;;; +1DA34;SIGNWRITING NOSE WIGGLES;Mn;0;NSM;;;;;N;;;;; +1DA35;SIGNWRITING AIR BLOWING OUT;Mn;0;NSM;;;;;N;;;;; +1DA36;SIGNWRITING AIR SUCKING IN;Mn;0;NSM;;;;;N;;;;; +1DA37;SIGNWRITING AIR BLOW SMALL ROTATIONS;So;0;L;;;;;N;;;;; +1DA38;SIGNWRITING AIR SUCK SMALL ROTATIONS;So;0;L;;;;;N;;;;; +1DA39;SIGNWRITING BREATH INHALE;So;0;L;;;;;N;;;;; +1DA3A;SIGNWRITING BREATH EXHALE;So;0;L;;;;;N;;;;; +1DA3B;SIGNWRITING MOUTH CLOSED NEUTRAL;Mn;0;NSM;;;;;N;;;;; +1DA3C;SIGNWRITING MOUTH CLOSED FORWARD;Mn;0;NSM;;;;;N;;;;; +1DA3D;SIGNWRITING MOUTH CLOSED CONTACT;Mn;0;NSM;;;;;N;;;;; +1DA3E;SIGNWRITING MOUTH SMILE;Mn;0;NSM;;;;;N;;;;; +1DA3F;SIGNWRITING MOUTH SMILE WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA40;SIGNWRITING MOUTH SMILE OPEN;Mn;0;NSM;;;;;N;;;;; +1DA41;SIGNWRITING MOUTH FROWN;Mn;0;NSM;;;;;N;;;;; +1DA42;SIGNWRITING MOUTH FROWN WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA43;SIGNWRITING MOUTH FROWN OPEN;Mn;0;NSM;;;;;N;;;;; +1DA44;SIGNWRITING MOUTH OPEN CIRCLE;Mn;0;NSM;;;;;N;;;;; +1DA45;SIGNWRITING MOUTH OPEN FORWARD;Mn;0;NSM;;;;;N;;;;; +1DA46;SIGNWRITING MOUTH OPEN WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA47;SIGNWRITING MOUTH OPEN OVAL;Mn;0;NSM;;;;;N;;;;; +1DA48;SIGNWRITING MOUTH OPEN OVAL WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA49;SIGNWRITING MOUTH OPEN OVAL YAWN;Mn;0;NSM;;;;;N;;;;; +1DA4A;SIGNWRITING MOUTH OPEN RECTANGLE;Mn;0;NSM;;;;;N;;;;; +1DA4B;SIGNWRITING MOUTH OPEN RECTANGLE WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA4C;SIGNWRITING MOUTH OPEN RECTANGLE YAWN;Mn;0;NSM;;;;;N;;;;; +1DA4D;SIGNWRITING MOUTH KISS;Mn;0;NSM;;;;;N;;;;; +1DA4E;SIGNWRITING MOUTH KISS FORWARD;Mn;0;NSM;;;;;N;;;;; +1DA4F;SIGNWRITING MOUTH KISS WRINKLED;Mn;0;NSM;;;;;N;;;;; +1DA50;SIGNWRITING MOUTH TENSE;Mn;0;NSM;;;;;N;;;;; +1DA51;SIGNWRITING MOUTH TENSE FORWARD;Mn;0;NSM;;;;;N;;;;; +1DA52;SIGNWRITING MOUTH TENSE SUCKED;Mn;0;NSM;;;;;N;;;;; +1DA53;SIGNWRITING LIPS PRESSED TOGETHER;Mn;0;NSM;;;;;N;;;;; +1DA54;SIGNWRITING LIP LOWER OVER UPPER;Mn;0;NSM;;;;;N;;;;; +1DA55;SIGNWRITING LIP UPPER OVER LOWER;Mn;0;NSM;;;;;N;;;;; +1DA56;SIGNWRITING MOUTH CORNERS;Mn;0;NSM;;;;;N;;;;; +1DA57;SIGNWRITING MOUTH WRINKLES SINGLE;Mn;0;NSM;;;;;N;;;;; +1DA58;SIGNWRITING MOUTH WRINKLES DOUBLE;Mn;0;NSM;;;;;N;;;;; +1DA59;SIGNWRITING TONGUE STICKING OUT FAR;Mn;0;NSM;;;;;N;;;;; +1DA5A;SIGNWRITING TONGUE LICKING LIPS;Mn;0;NSM;;;;;N;;;;; +1DA5B;SIGNWRITING TONGUE TIP BETWEEN LIPS;Mn;0;NSM;;;;;N;;;;; +1DA5C;SIGNWRITING TONGUE TIP TOUCHING INSIDE MOUTH;Mn;0;NSM;;;;;N;;;;; +1DA5D;SIGNWRITING TONGUE INSIDE MOUTH RELAXED;Mn;0;NSM;;;;;N;;;;; +1DA5E;SIGNWRITING TONGUE MOVES AGAINST CHEEK;Mn;0;NSM;;;;;N;;;;; +1DA5F;SIGNWRITING TONGUE CENTRE STICKING OUT;Mn;0;NSM;;;;;N;;;;; +1DA60;SIGNWRITING TONGUE CENTRE INSIDE MOUTH;Mn;0;NSM;;;;;N;;;;; +1DA61;SIGNWRITING TEETH;Mn;0;NSM;;;;;N;;;;; +1DA62;SIGNWRITING TEETH MOVEMENT;Mn;0;NSM;;;;;N;;;;; +1DA63;SIGNWRITING TEETH ON TONGUE;Mn;0;NSM;;;;;N;;;;; +1DA64;SIGNWRITING TEETH ON TONGUE MOVEMENT;Mn;0;NSM;;;;;N;;;;; +1DA65;SIGNWRITING TEETH ON LIPS;Mn;0;NSM;;;;;N;;;;; +1DA66;SIGNWRITING TEETH ON LIPS MOVEMENT;Mn;0;NSM;;;;;N;;;;; +1DA67;SIGNWRITING TEETH BITE LIPS;Mn;0;NSM;;;;;N;;;;; +1DA68;SIGNWRITING MOVEMENT-WALLPLANE JAW;Mn;0;NSM;;;;;N;;;;; +1DA69;SIGNWRITING MOVEMENT-FLOORPLANE JAW;Mn;0;NSM;;;;;N;;;;; +1DA6A;SIGNWRITING NECK;Mn;0;NSM;;;;;N;;;;; +1DA6B;SIGNWRITING HAIR;Mn;0;NSM;;;;;N;;;;; +1DA6C;SIGNWRITING EXCITEMENT;Mn;0;NSM;;;;;N;;;;; +1DA6D;SIGNWRITING SHOULDER HIP SPINE;So;0;L;;;;;N;;;;; +1DA6E;SIGNWRITING SHOULDER HIP POSITIONS;So;0;L;;;;;N;;;;; +1DA6F;SIGNWRITING WALLPLANE SHOULDER HIP MOVE;So;0;L;;;;;N;;;;; +1DA70;SIGNWRITING FLOORPLANE SHOULDER HIP MOVE;So;0;L;;;;;N;;;;; +1DA71;SIGNWRITING SHOULDER TILTING FROM WAIST;So;0;L;;;;;N;;;;; +1DA72;SIGNWRITING TORSO-WALLPLANE STRAIGHT STRETCH;So;0;L;;;;;N;;;;; +1DA73;SIGNWRITING TORSO-WALLPLANE CURVED BEND;So;0;L;;;;;N;;;;; +1DA74;SIGNWRITING TORSO-FLOORPLANE TWISTING;So;0;L;;;;;N;;;;; +1DA75;SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS;Mn;0;NSM;;;;;N;;;;; +1DA76;SIGNWRITING LIMB COMBINATION;So;0;L;;;;;N;;;;; +1DA77;SIGNWRITING LIMB LENGTH-1;So;0;L;;;;;N;;;;; +1DA78;SIGNWRITING LIMB LENGTH-2;So;0;L;;;;;N;;;;; +1DA79;SIGNWRITING LIMB LENGTH-3;So;0;L;;;;;N;;;;; +1DA7A;SIGNWRITING LIMB LENGTH-4;So;0;L;;;;;N;;;;; +1DA7B;SIGNWRITING LIMB LENGTH-5;So;0;L;;;;;N;;;;; +1DA7C;SIGNWRITING LIMB LENGTH-6;So;0;L;;;;;N;;;;; +1DA7D;SIGNWRITING LIMB LENGTH-7;So;0;L;;;;;N;;;;; +1DA7E;SIGNWRITING FINGER;So;0;L;;;;;N;;;;; +1DA7F;SIGNWRITING LOCATION-WALLPLANE SPACE;So;0;L;;;;;N;;;;; +1DA80;SIGNWRITING LOCATION-FLOORPLANE SPACE;So;0;L;;;;;N;;;;; +1DA81;SIGNWRITING LOCATION HEIGHT;So;0;L;;;;;N;;;;; +1DA82;SIGNWRITING LOCATION WIDTH;So;0;L;;;;;N;;;;; +1DA83;SIGNWRITING LOCATION DEPTH;So;0;L;;;;;N;;;;; +1DA84;SIGNWRITING LOCATION HEAD NECK;Mn;0;NSM;;;;;N;;;;; +1DA85;SIGNWRITING LOCATION TORSO;So;0;L;;;;;N;;;;; +1DA86;SIGNWRITING LOCATION LIMBS DIGITS;So;0;L;;;;;N;;;;; +1DA87;SIGNWRITING COMMA;Po;0;L;;;;;N;;;;; +1DA88;SIGNWRITING FULL STOP;Po;0;L;;;;;N;;;;; +1DA89;SIGNWRITING SEMICOLON;Po;0;L;;;;;N;;;;; +1DA8A;SIGNWRITING COLON;Po;0;L;;;;;N;;;;; +1DA8B;SIGNWRITING PARENTHESIS;Po;0;L;;;;;N;;;;; +1DA9B;SIGNWRITING FILL MODIFIER-2;Mn;0;NSM;;;;;N;;;;; +1DA9C;SIGNWRITING FILL MODIFIER-3;Mn;0;NSM;;;;;N;;;;; +1DA9D;SIGNWRITING FILL MODIFIER-4;Mn;0;NSM;;;;;N;;;;; +1DA9E;SIGNWRITING FILL MODIFIER-5;Mn;0;NSM;;;;;N;;;;; +1DA9F;SIGNWRITING FILL MODIFIER-6;Mn;0;NSM;;;;;N;;;;; +1DAA1;SIGNWRITING ROTATION MODIFIER-2;Mn;0;NSM;;;;;N;;;;; +1DAA2;SIGNWRITING ROTATION MODIFIER-3;Mn;0;NSM;;;;;N;;;;; +1DAA3;SIGNWRITING ROTATION MODIFIER-4;Mn;0;NSM;;;;;N;;;;; +1DAA4;SIGNWRITING ROTATION MODIFIER-5;Mn;0;NSM;;;;;N;;;;; +1DAA5;SIGNWRITING ROTATION MODIFIER-6;Mn;0;NSM;;;;;N;;;;; +1DAA6;SIGNWRITING ROTATION MODIFIER-7;Mn;0;NSM;;;;;N;;;;; +1DAA7;SIGNWRITING ROTATION MODIFIER-8;Mn;0;NSM;;;;;N;;;;; +1DAA8;SIGNWRITING ROTATION MODIFIER-9;Mn;0;NSM;;;;;N;;;;; +1DAA9;SIGNWRITING ROTATION MODIFIER-10;Mn;0;NSM;;;;;N;;;;; +1DAAA;SIGNWRITING ROTATION MODIFIER-11;Mn;0;NSM;;;;;N;;;;; +1DAAB;SIGNWRITING ROTATION MODIFIER-12;Mn;0;NSM;;;;;N;;;;; +1DAAC;SIGNWRITING ROTATION MODIFIER-13;Mn;0;NSM;;;;;N;;;;; +1DAAD;SIGNWRITING ROTATION MODIFIER-14;Mn;0;NSM;;;;;N;;;;; +1DAAE;SIGNWRITING ROTATION MODIFIER-15;Mn;0;NSM;;;;;N;;;;; +1DAAF;SIGNWRITING ROTATION MODIFIER-16;Mn;0;NSM;;;;;N;;;;; 1E800;MENDE KIKAKUI SYLLABLE M001 KI;Lo;0;R;;;;;N;;;;; 1E801;MENDE KIKAKUI SYLLABLE M002 KA;Lo;0;R;;;;;N;;;;; 1E802;MENDE KIKAKUI SYLLABLE M003 KU;Lo;0;R;;;;;N;;;;; @@ -25108,6 +27011,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F32A;CLOUD WITH TORNADO;So;0;ON;;;;;N;;;;; 1F32B;FOG;So;0;ON;;;;;N;;;;; 1F32C;WIND BLOWING FACE;So;0;ON;;;;;N;;;;; +1F32D;HOT DOG;So;0;ON;;;;;N;;;;; +1F32E;TACO;So;0;ON;;;;;N;;;;; +1F32F;BURRITO;So;0;ON;;;;;N;;;;; 1F330;CHESTNUT;So;0;ON;;;;;N;;;;; 1F331;SEEDLING;So;0;ON;;;;;N;;;;; 1F332;EVERGREEN TREE;So;0;ON;;;;;N;;;;; @@ -25186,6 +27092,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F37B;CLINKING BEER MUGS;So;0;ON;;;;;N;;;;; 1F37C;BABY BOTTLE;So;0;ON;;;;;N;;;;; 1F37D;FORK AND KNIFE WITH PLATE;So;0;ON;;;;;N;;;;; +1F37E;BOTTLE WITH POPPING CORK;So;0;ON;;;;;N;;;;; +1F37F;POPCORN;So;0;ON;;;;;N;;;;; 1F380;RIBBON;So;0;ON;;;;;N;;;;; 1F381;WRAPPED PRESENT;So;0;ON;;;;;N;;;;; 1F382;BIRTHDAY CAKE;So;0;ON;;;;;N;;;;; @@ -25265,6 +27173,11 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F3CC;GOLFER;So;0;ON;;;;;N;;;;; 1F3CD;RACING MOTORCYCLE;So;0;ON;;;;;N;;;;; 1F3CE;RACING CAR;So;0;ON;;;;;N;;;;; +1F3CF;CRICKET BAT AND BALL;So;0;ON;;;;;N;;;;; +1F3D0;VOLLEYBALL;So;0;ON;;;;;N;;;;; +1F3D1;FIELD HOCKEY STICK AND BALL;So;0;ON;;;;;N;;;;; +1F3D2;ICE HOCKEY STICK AND PUCK;So;0;ON;;;;;N;;;;; +1F3D3;TABLE TENNIS PADDLE AND BALL;So;0;ON;;;;;N;;;;; 1F3D4;SNOW CAPPED MOUNTAIN;So;0;ON;;;;;N;;;;; 1F3D5;CAMPING;So;0;ON;;;;;N;;;;; 1F3D6;BEACH WITH UMBRELLA;So;0;ON;;;;;N;;;;; @@ -25301,6 +27214,14 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F3F5;ROSETTE;So;0;ON;;;;;N;;;;; 1F3F6;BLACK ROSETTE;So;0;ON;;;;;N;;;;; 1F3F7;LABEL;So;0;ON;;;;;N;;;;; +1F3F8;BADMINTON RACQUET AND SHUTTLECOCK;So;0;ON;;;;;N;;;;; +1F3F9;BOW AND ARROW;So;0;ON;;;;;N;;;;; +1F3FA;AMPHORA;So;0;ON;;;;;N;;;;; +1F3FB;EMOJI MODIFIER FITZPATRICK TYPE-1-2;Sk;0;ON;;;;;N;;;;; +1F3FC;EMOJI MODIFIER FITZPATRICK TYPE-3;Sk;0;ON;;;;;N;;;;; +1F3FD;EMOJI MODIFIER FITZPATRICK TYPE-4;Sk;0;ON;;;;;N;;;;; +1F3FE;EMOJI MODIFIER FITZPATRICK TYPE-5;Sk;0;ON;;;;;N;;;;; +1F3FF;EMOJI MODIFIER FITZPATRICK TYPE-6;Sk;0;ON;;;;;N;;;;; 1F400;RAT;So;0;ON;;;;;N;;;;; 1F401;MOUSE;So;0;ON;;;;;N;;;;; 1F402;OX;So;0;ON;;;;;N;;;;; @@ -25556,6 +27477,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F4FC;VIDEOCASSETTE;So;0;ON;;;;;N;;;;; 1F4FD;FILM PROJECTOR;So;0;ON;;;;;N;;;;; 1F4FE;PORTABLE STEREO;So;0;ON;;;;;N;;;;; +1F4FF;PRAYER BEADS;So;0;ON;;;;;N;;;;; 1F500;TWISTED RIGHTWARDS ARROWS;So;0;ON;;;;;N;;;;; 1F501;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; 1F502;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAY;So;0;ON;;;;;N;;;;; @@ -25631,6 +27553,11 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F548;CELTIC CROSS;So;0;ON;;;;;N;;;;; 1F549;OM SYMBOL;So;0;ON;;;;;N;;;;; 1F54A;DOVE OF PEACE;So;0;ON;;;;;N;;;;; +1F54B;KAABA;So;0;ON;;;;;N;;;;; +1F54C;MOSQUE;So;0;ON;;;;;N;;;;; +1F54D;SYNAGOGUE;So;0;ON;;;;;N;;;;; +1F54E;MENORAH WITH NINE BRANCHES;So;0;ON;;;;;N;;;;; +1F54F;BOWL OF HYGIEIA;So;0;ON;;;;;N;;;;; 1F550;CLOCK FACE ONE OCLOCK;So;0;ON;;;;;N;;;;; 1F551;CLOCK FACE TWO OCLOCK;So;0;ON;;;;;N;;;;; 1F552;CLOCK FACE THREE OCLOCK;So;0;ON;;;;;N;;;;; @@ -25872,6 +27799,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F640;WEARY CAT FACE;So;0;ON;;;;;N;;;;; 1F641;SLIGHTLY FROWNING FACE;So;0;ON;;;;;N;;;;; 1F642;SLIGHTLY SMILING FACE;So;0;ON;;;;;N;;;;; +1F643;UPSIDE-DOWN FACE;So;0;ON;;;;;N;;;;; +1F644;FACE WITH ROLLING EYES;So;0;ON;;;;;N;;;;; 1F645;FACE WITH NO GOOD GESTURE;So;0;ON;;;;;N;;;;; 1F646;FACE WITH OK GESTURE;So;0;ON;;;;;N;;;;; 1F647;PERSON BOWING DEEPLY;So;0;ON;;;;;N;;;;; @@ -26011,6 +27940,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F6CD;SHOPPING BAGS;So;0;ON;;;;;N;;;;; 1F6CE;BELLHOP BELL;So;0;ON;;;;;N;;;;; 1F6CF;BED;So;0;ON;;;;;N;;;;; +1F6D0;PLACE OF WORSHIP;So;0;ON;;;;;N;;;;; 1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;; 1F6E1;SHIELD;So;0;ON;;;;;N;;;;; 1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;; @@ -26377,12 +28307,29 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F8AB;RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; 1F8AC;WHITE ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;; 1F8AD;WHITE ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;; +1F910;ZIPPER-MOUTH FACE;So;0;ON;;;;;N;;;;; +1F911;MONEY-MOUTH FACE;So;0;ON;;;;;N;;;;; +1F912;FACE WITH THERMOMETER;So;0;ON;;;;;N;;;;; +1F913;NERD FACE;So;0;ON;;;;;N;;;;; +1F914;THINKING FACE;So;0;ON;;;;;N;;;;; +1F915;FACE WITH HEAD-BANDAGE;So;0;ON;;;;;N;;;;; +1F916;ROBOT FACE;So;0;ON;;;;;N;;;;; +1F917;HUGGING FACE;So;0;ON;;;;;N;;;;; +1F918;SIGN OF THE HORNS;So;0;ON;;;;;N;;;;; +1F980;CRAB;So;0;ON;;;;;N;;;;; +1F981;LION FACE;So;0;ON;;;;;N;;;;; +1F982;SCORPION;So;0;ON;;;;;N;;;;; +1F983;TURKEY;So;0;ON;;;;;N;;;;; +1F984;UNICORN FACE;So;0;ON;;;;;N;;;;; +1F9C0;CHEESE WEDGE;So;0;ON;;;;;N;;;;; 20000;;Lo;0;L;;;;;N;;;;; 2A6D6;;Lo;0;L;;;;;N;;;;; 2A700;;Lo;0;L;;;;;N;;;;; 2B734;;Lo;0;L;;;;;N;;;;; 2B740;;Lo;0;L;;;;;N;;;;; 2B81D;;Lo;0;L;;;;;N;;;;; +2B820;;Lo;0;L;;;;;N;;;;; +2CEA1;;Lo;0;L;;;;;N;;;;; 2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;; 2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;; 2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;; diff --git a/jdk/make/data/unicodedata/VERSION b/jdk/make/data/unicodedata/VERSION index 66ce77b7ead..ae9a76b9249 100644 --- a/jdk/make/data/unicodedata/VERSION +++ b/jdk/make/data/unicodedata/VERSION @@ -1 +1 @@ -7.0.0 +8.0.0 diff --git a/jdk/make/gendata/Gendata-java.base.gmk b/jdk/make/gendata/Gendata-java.base.gmk index c0ee693f730..d94ec3404c0 100644 --- a/jdk/make/gendata/Gendata-java.base.gmk +++ b/jdk/make/gendata/Gendata-java.base.gmk @@ -70,7 +70,7 @@ $(GENDATA_JAVA_SECURITY): $(BUILD_TOOLS) $(GENDATA_JAVA_SECURITY_SRC) $(RESTRICT $(ECHO) "Generating java.security" $(MKDIR) -p $(@D) $(TOOL_MAKEJAVASECURITY) $(GENDATA_JAVA_SECURITY_SRC) $@ $(OPENJDK_TARGET_OS) \ - $(RESTRICTED_PKGS_SRC) || exit 1 + $(OPENJDK_TARGET_CPU_ARCH) $(RESTRICTED_PKGS_SRC) || exit 1 TARGETS += $(GENDATA_JAVA_SECURITY) diff --git a/jdk/make/gensrc/GensrcSwing.gmk b/jdk/make/gensrc/GensrcSwing.gmk index 74b4f8a81dd..2f643d4abc2 100644 --- a/jdk/make/gensrc/GensrcSwing.gmk +++ b/jdk/make/gensrc/GensrcSwing.gmk @@ -41,71 +41,4 @@ $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/_the.generated_nimbus: $(NIMBUS_SKIN_FI GENSRC_SWING_NIMBUS := $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/_the.generated_nimbus -# -# Generate beaninfo java files -# - -BEANINFO_OUTPUTDIR := $(SUPPORT_OUTPUTDIR)/gensrc_no_docs/java.desktop -DOCLET_DATA_DIR := $(JDK_TOPDIR)/make/data/swingbeaninfo - -# javax.swing package -BEANS = AbstractButton Box JComponent JApplet JButton \ - JCheckBox JCheckBoxMenuItem JComboBox JColorChooser \ - JDesktopPane JDialog JEditorPane JFileChooser JFrame \ - JFormattedTextField JInternalFrame JLabel JLayeredPane \ - JList JMenu JMenuBar JMenuItem JOptionPane JPanel \ - JPasswordField JPopupMenu JProgressBar JRadioButton \ - JRadioButtonMenuItem JScrollBar JScrollPane JSeparator \ - JSlider JSplitPane JSpinner JTabbedPane JTable \ - JTextArea JTextField JTextPane JToggleButton JToolBar \ - JTree JWindow - -# javax.swing.text package -BEANS_TEXT = JTextComponent - -BEANS_SRC = $(BEANS:%=$(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/%.java) \ - $(BEANS_TEXT:%=$(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/text/%.java) - -# Dummy variable so far, in the old build system it was false by default -SWINGBEAN_DEBUG_FLAG = false -# GenDocletBeanInfo is compiled in Tools.gmk and picks up from $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes -# LocaleDataMetaInfo needs to be generated before running this to avoid confusing errors -# in the build log. -$(BEANINFO_OUTPUTDIR)/_the.generated_beaninfo: $(BEANS_SRC) \ - $(BEANINFO_OUTPUTDIR)/javax/swing/SwingBeanInfoBase.java \ - $(BEANINFO_OUTPUTDIR)/sun/swing/BeanInfoUtils.java $(BUILD_TOOLS_JDK) - $(ECHO) Generating beaninfo - $(MKDIR) -p $(BEANINFO_OUTPUTDIR)/javax/swing - $(JAVA) -Djava.awt.headless=true $(NEW_JAVADOC) \ - -sourcepath $(call PathList,\ - $(wildcard $(JDK_TOPDIR)/src/*/*/classes) \ - $(SUPPORT_OUTPUTDIR)/gensrc/java.base) \ - -doclet build.tools.swingbeaninfo.GenDocletBeanInfo \ - -x $(SWINGBEAN_DEBUG_FLAG) -d $(BEANINFO_OUTPUTDIR)/javax/swing \ - -t $(DOCLET_DATA_DIR)/SwingBeanInfo.template \ - -docletpath $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - -XDignore.symbol.file=true \ - -classpath $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes $(BEANS_SRC) $(LOG_INFO) - # Move the JTextComponent into its proper package directory. - $(MKDIR) -p $(BEANINFO_OUTPUTDIR)/javax/swing/text - $(MV) $(BEANINFO_OUTPUTDIR)/javax/swing/JTextComponentBeanInfo.java \ - $(BEANINFO_OUTPUTDIR)/javax/swing/text/JTextComponentBeanInfo.java - $(TOUCH) $@ - -# This file is the part of dt.jar -# For some reason it is under $(JDK_TOPDIR)/make/data/swingbeaninfo -# Should it be moved under $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing instead? -$(BEANINFO_OUTPUTDIR)/javax/swing/SwingBeanInfoBase.java: \ - $(DOCLET_DATA_DIR)/javax/swing/SwingBeanInfoBase.java - $(call install-file) - -# This file is the part of dt.jar -# For some reason it is under $(JDK_TOPDIR)/make/data/swingbeaninfo -# Should it be moved under $(JDK_TOPDIR)/src/java.desktop/share/classes/sun/swing instead? -$(BEANINFO_OUTPUTDIR)/sun/swing/BeanInfoUtils.java: \ - $(DOCLET_DATA_DIR)/sun/swing/BeanInfoUtils.java - $(call install-file) - -GENSRC_SWING_BEANINFO = $(BEANINFO_OUTPUTDIR)/_the.generated_beaninfo - -GENSRC_JAVA_DESKTOP += $(GENSRC_SWING_BEANINFO) $(GENSRC_SWING_NIMBUS) +GENSRC_JAVA_DESKTOP += $(GENSRC_SWING_NIMBUS) diff --git a/jdk/make/launcher/Launcher-jdk.jshell.gmk b/jdk/make/launcher/Launcher-jdk.jshell.gmk new file mode 100644 index 00000000000..ca1a69d0d67 --- /dev/null +++ b/jdk/make/launcher/Launcher-jdk.jshell.gmk @@ -0,0 +1,31 @@ +# +# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +include LauncherCommon.gmk + +$(eval $(call SetupLauncher,jshell, \ + -DEXPAND_CLASSPATH_WILDCARDS \ + -DNEVER_ACT_AS_SERVER_CLASS_MACHINE \ + -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "jdk.internal.jshell.tool.JShellTool"$(COMMA) }')) diff --git a/jdk/make/launcher/Launcher-jdk.pack200.gmk b/jdk/make/launcher/Launcher-jdk.pack200.gmk index 69830816a75..2dcbb684af5 100644 --- a/jdk/make/launcher/Launcher-jdk.pack200.gmk +++ b/jdk/make/launcher/Launcher-jdk.pack200.gmk @@ -40,7 +40,7 @@ UNPACKEXE_CFLAGS := -I$(JDK_TOPDIR)/src/jdk.pack200/share/native/common-unpack \ ifeq ($(USE_EXTERNAL_LIBZ), true) UNPACKEXE_CFLAGS += -DSYSTEM_ZLIB - UNPACKEXE_ZIPOBJS := -lz + UNPACKEXE_LIBS := -lz else UNPACKEXE_CFLAGS += -I$(JDK_TOPDIR)/src/java.base/share/native/libzip/zlib-1.2.8 UNPACKEXE_ZIPOBJS := $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zcrc32$(OBJ_SUFFIX) \ @@ -90,9 +90,9 @@ $(eval $(call SetupNativeCompilation,BUILD_UNPACKEXE, \ $(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \ $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)unpack$(SHARED_LIBRARY_SUFFIX)) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ - LDFLAGS_linux := -lc, \ + LDFLAGS_linux := , \ LDFLAGS_solaris := $(UNPACKEXE_LDFLAGS_solaris) -lc, \ - LDFLAGS_SUFFIX := $(LIBCXX), \ + LDFLAGS_SUFFIX := $(UNPACKEXE_LIBS) $(LIBCXX), \ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpackexe$(OUTPUT_SUBDIR), \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/$(MODULE), \ PROGRAM := unpack200, \ diff --git a/jdk/make/lib/Awt2dLibraries.gmk b/jdk/make/lib/Awt2dLibraries.gmk index 858ca275970..e4097b566ba 100644 --- a/jdk/make/lib/Awt2dLibraries.gmk +++ b/jdk/make/lib/Awt2dLibraries.gmk @@ -391,6 +391,8 @@ LIBLCMS_CPPFLAGS += -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \ -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \ $(LIBJAVA_HEADER_FLAGS) \ # +# The fast floor code loses precision. +LCMS_CFLAGS=-DCMS_DONT_USE_FAST_FLOOR ifeq ($(USE_EXTERNAL_LCMS), true) # If we're using an external library, we'll just need the wrapper part. @@ -498,10 +500,10 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJAVAJPEG, \ DISABLED_WARNINGS_clang := logical-op-parentheses, \ DISABLED_WARNINGS_microsoft := 4267, \ MAPFILE := $(BUILD_LIBJAVAJPEG_MAPFILE), \ - LDFLAGS := $(LDFLAGS_JDKLIB) $(LIBJPEG_LIBS) \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LDFLAGS_windows := $(WIN_JAVA_LIB) jvm.lib, \ - LDFLAGS_SUFFIX := $(LDFLAGS_JDKLIB_SUFFIX), \ + LDFLAGS_SUFFIX := $(LIBJPEG_LIBS) $(LDFLAGS_JDKLIB_SUFFIX), \ VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \ RC_FLAGS := $(RC_FLAGS) \ -D "JDK_FNAME=javajpeg.dll" \ diff --git a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 63c0fe2aa21..697e7172081 100644 --- a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -28,6 +28,7 @@ package build.tools.cldrconverter; import java.io.File; import java.io.IOException; import java.io.PrintWriter; +import java.util.Arrays; import java.util.Formatter; import java.util.HashSet; import java.util.HashMap; @@ -285,15 +286,16 @@ class ResourceBundleGenerator implements BundleGenerator { out.printf(" parentLocalesMap.put(Locale.forLanguageTag(\"%s\"),\n", parentTag); } - String[] childlen = toLocaleList(metaInfo.get(key), true).split(" "); + String[] children = toLocaleList(metaInfo.get(key), true).split(" "); + Arrays.sort(children); out.printf(" new String[] {\n" + " "); int count = 0; - for (int i = 0; i < childlen.length; i++) { - String child = childlen[i]; + for (int i = 0; i < children.length; i++) { + String child = children[i]; out.printf("\"%s\", ", child); count += child.length() + 4; - if (i != childlen.length - 1 && count > 64) { + if (i != children.length - 1 && count > 64) { out.printf("\n "); count = 0; } diff --git a/jdk/make/src/classes/build/tools/makejavasecurity/MakeJavaSecurity.java b/jdk/make/src/classes/build/tools/makejavasecurity/MakeJavaSecurity.java index d5c6e14c7b1..46f8ce9af9d 100644 --- a/jdk/make/src/classes/build/tools/makejavasecurity/MakeJavaSecurity.java +++ b/jdk/make/src/classes/build/tools/makejavasecurity/MakeJavaSecurity.java @@ -50,19 +50,21 @@ public class MakeJavaSecurity { public static void main(String[] args) throws Exception { - if (args.length < 3) { + if (args.length < 4) { System.err.println("Usage: java MakeJavaSecurity " + "[input java.security file name] " + "[output java.security file name] " + "[openjdk target os] " + + "[openjdk target cpu architecture]" + "[more restricted packages file name?]"); - System.exit(1); + + System.exit(1); } // more restricted packages List extraLines; - if (args.length == 4) { - extraLines = Files.readAllLines(Paths.get(args[3])); + if (args.length == 5) { + extraLines = Files.readAllLines(Paths.get(args[4])); } else { extraLines = Collections.emptyList(); } @@ -96,7 +98,11 @@ public class MakeJavaSecurity { mode = 0; iter.remove(); } else if (line.startsWith("#ifdef ")) { - mode = line.endsWith(args[2])?1:2; + if (line.indexOf('-') > 0) { + mode = line.endsWith(args[2]+"-"+args[3]) ? 1 : 2; + } else { + mode = line.endsWith(args[2]) ? 1 : 2; + } iter.remove(); } else if (line.startsWith("#ifndef ")) { mode = line.endsWith(args[2])?2:1; diff --git a/jdk/make/src/classes/build/tools/module/boot.modules b/jdk/make/src/classes/build/tools/module/boot.modules index 6830c6c8335..02de8910651 100644 --- a/jdk/make/src/classes/build/tools/module/boot.modules +++ b/jdk/make/src/classes/build/tools/module/boot.modules @@ -29,3 +29,4 @@ jdk.sctp jdk.security.auth jdk.security.jgss jdk.snmp +jdk.vm.ci diff --git a/jdk/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java b/jdk/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java index e4eb8da63cd..9fbf1f03776 100644 --- a/jdk/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java +++ b/jdk/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,13 +57,13 @@ import sun.util.spi.CalendarProvider; public class HostLocaleProviderAdapterImpl { // per supported locale instances - private static ConcurrentMap>> dateFormatPatternsMap = + private static final ConcurrentMap>> dateFormatPatternsMap = new ConcurrentHashMap<>(2); - private static ConcurrentMap>> numberFormatPatternsMap = + private static final ConcurrentMap>> numberFormatPatternsMap = new ConcurrentHashMap<>(2); - private static ConcurrentMap> dateFormatSymbolsMap = + private static final ConcurrentMap> dateFormatSymbolsMap = new ConcurrentHashMap<>(2); - private static ConcurrentMap> decimalFormatSymbolsMap = + private static final ConcurrentMap> decimalFormatSymbolsMap = new ConcurrentHashMap<>(2); // locale categories diff --git a/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java b/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java index 5c3c707768b..aa516a15d67 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java @@ -189,6 +189,9 @@ public class ObjectStreamClass implements Serializable { /** superclass descriptor appearing in stream */ private ObjectStreamClass superDesc; + /** true if, and only if, the object has been correctly initialized */ + private boolean initialized; + /** * Initializes native code. */ @@ -266,6 +269,7 @@ public class ObjectStreamClass implements Serializable { if (cl == null) { return null; } + requireInitialized(); if (System.getSecurityManager() != null) { Class caller = Reflection.getCallerClass(); if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) { @@ -533,6 +537,7 @@ public class ObjectStreamClass implements Serializable { name, "unmatched serializable field(s) declared"); } } + initialized = true; } /** @@ -550,6 +555,14 @@ public class ObjectStreamClass implements Serializable { ObjectStreamClass superDesc) throws InvalidClassException { + ObjectStreamClass osc = null; + if (cl != null) { + osc = lookup(cl, true); + if (!osc.isProxy) { + throw new InvalidClassException( + "cannot bind proxy descriptor to a non-proxy class"); + } + } this.cl = cl; this.resolveEx = resolveEx; this.superDesc = superDesc; @@ -557,21 +570,17 @@ public class ObjectStreamClass implements Serializable { serializable = true; suid = Long.valueOf(0); fields = NO_FIELDS; - - if (cl != null) { - localDesc = lookup(cl, true); - if (!localDesc.isProxy) { - throw new InvalidClassException( - "cannot bind proxy descriptor to a non-proxy class"); - } + if (osc != null) { + localDesc = osc; name = localDesc.name; externalizable = localDesc.externalizable; - cons = localDesc.cons; writeReplaceMethod = localDesc.writeReplaceMethod; readResolveMethod = localDesc.readResolveMethod; deserializeEx = localDesc.deserializeEx; + cons = localDesc.cons; } fieldRefl = getReflector(fields, localDesc); + initialized = true; } /** @@ -583,11 +592,57 @@ public class ObjectStreamClass implements Serializable { ObjectStreamClass superDesc) throws InvalidClassException { + long suid = Long.valueOf(model.getSerialVersionUID()); + ObjectStreamClass osc = null; + if (cl != null) { + osc = lookup(cl, true); + if (osc.isProxy) { + throw new InvalidClassException( + "cannot bind non-proxy descriptor to a proxy class"); + } + if (model.isEnum != osc.isEnum) { + throw new InvalidClassException(model.isEnum ? + "cannot bind enum descriptor to a non-enum class" : + "cannot bind non-enum descriptor to an enum class"); + } + + if (model.serializable == osc.serializable && + !cl.isArray() && + suid != osc.getSerialVersionUID()) { + throw new InvalidClassException(osc.name, + "local class incompatible: " + + "stream classdesc serialVersionUID = " + suid + + ", local class serialVersionUID = " + + osc.getSerialVersionUID()); + } + + if (!classNamesEqual(model.name, osc.name)) { + throw new InvalidClassException(osc.name, + "local class name incompatible with stream class " + + "name \"" + model.name + "\""); + } + + if (!model.isEnum) { + if ((model.serializable == osc.serializable) && + (model.externalizable != osc.externalizable)) { + throw new InvalidClassException(osc.name, + "Serializable incompatible with Externalizable"); + } + + if ((model.serializable != osc.serializable) || + (model.externalizable != osc.externalizable) || + !(model.serializable || model.externalizable)) { + deserializeEx = new ExceptionInfo( + osc.name, "class invalid for deserialization"); + } + } + } + this.cl = cl; this.resolveEx = resolveEx; this.superDesc = superDesc; name = model.name; - suid = Long.valueOf(model.getSerialVersionUID()); + this.suid = suid; isProxy = false; isEnum = model.isEnum; serializable = model.serializable; @@ -598,53 +653,8 @@ public class ObjectStreamClass implements Serializable { primDataSize = model.primDataSize; numObjFields = model.numObjFields; - if (cl != null) { - localDesc = lookup(cl, true); - if (localDesc.isProxy) { - throw new InvalidClassException( - "cannot bind non-proxy descriptor to a proxy class"); - } - if (isEnum != localDesc.isEnum) { - throw new InvalidClassException(isEnum ? - "cannot bind enum descriptor to a non-enum class" : - "cannot bind non-enum descriptor to an enum class"); - } - - if (serializable == localDesc.serializable && - !cl.isArray() && - suid.longValue() != localDesc.getSerialVersionUID()) - { - throw new InvalidClassException(localDesc.name, - "local class incompatible: " + - "stream classdesc serialVersionUID = " + suid + - ", local class serialVersionUID = " + - localDesc.getSerialVersionUID()); - } - - if (!classNamesEqual(name, localDesc.name)) { - throw new InvalidClassException(localDesc.name, - "local class name incompatible with stream class " + - "name \"" + name + "\""); - } - - if (!isEnum) { - if ((serializable == localDesc.serializable) && - (externalizable != localDesc.externalizable)) - { - throw new InvalidClassException(localDesc.name, - "Serializable incompatible with Externalizable"); - } - - if ((serializable != localDesc.serializable) || - (externalizable != localDesc.externalizable) || - !(serializable || externalizable)) - { - deserializeEx = new ExceptionInfo( - localDesc.name, "class invalid for deserialization"); - } - } - - cons = localDesc.cons; + if (osc != null) { + localDesc = osc; writeObjectMethod = localDesc.writeObjectMethod; readObjectMethod = localDesc.readObjectMethod; readObjectNoDataMethod = localDesc.readObjectNoDataMethod; @@ -653,10 +663,13 @@ public class ObjectStreamClass implements Serializable { if (deserializeEx == null) { deserializeEx = localDesc.deserializeEx; } + cons = localDesc.cons; } + fieldRefl = getReflector(fields, localDesc); // reassign to matched fields so as to reflect local unshared settings fields = fieldRefl.getFields(); + initialized = true; } /** @@ -758,12 +771,21 @@ public class ObjectStreamClass implements Serializable { return resolveEx; } + /** + * Throws InternalError if not initialized. + */ + private final void requireInitialized() { + if (!initialized) + throw new InternalError("Unexpected call when not initialized"); + } + /** * Throws an InvalidClassException if object instances referencing this * class descriptor should not be allowed to deserialize. This method does * not apply to deserialization of enum constants. */ void checkDeserialize() throws InvalidClassException { + requireInitialized(); if (deserializeEx != null) { throw deserializeEx.newInvalidClassException(); } @@ -775,6 +797,7 @@ public class ObjectStreamClass implements Serializable { * not apply to serialization of enum constants. */ void checkSerialize() throws InvalidClassException { + requireInitialized(); if (serializeEx != null) { throw serializeEx.newInvalidClassException(); } @@ -788,6 +811,7 @@ public class ObjectStreamClass implements Serializable { * does not apply to deserialization of enum constants. */ void checkDefaultSerialize() throws InvalidClassException { + requireInitialized(); if (defaultSerializeEx != null) { throw defaultSerializeEx.newInvalidClassException(); } @@ -799,6 +823,7 @@ public class ObjectStreamClass implements Serializable { * of the subclass descriptor's bound class. */ ObjectStreamClass getSuperDesc() { + requireInitialized(); return superDesc; } @@ -809,6 +834,7 @@ public class ObjectStreamClass implements Serializable { * associated with this descriptor. */ ObjectStreamClass getLocalDesc() { + requireInitialized(); return localDesc; } @@ -851,6 +877,7 @@ public class ObjectStreamClass implements Serializable { * otherwise. */ boolean isProxy() { + requireInitialized(); return isProxy; } @@ -859,6 +886,7 @@ public class ObjectStreamClass implements Serializable { * otherwise. */ boolean isEnum() { + requireInitialized(); return isEnum; } @@ -867,6 +895,7 @@ public class ObjectStreamClass implements Serializable { * otherwise. */ boolean isExternalizable() { + requireInitialized(); return externalizable; } @@ -875,6 +904,7 @@ public class ObjectStreamClass implements Serializable { * otherwise. */ boolean isSerializable() { + requireInitialized(); return serializable; } @@ -883,6 +913,7 @@ public class ObjectStreamClass implements Serializable { * has written its data in 1.2 (block data) format, false otherwise. */ boolean hasBlockExternalData() { + requireInitialized(); return hasBlockExternalData; } @@ -892,6 +923,7 @@ public class ObjectStreamClass implements Serializable { * writeObject() method, false otherwise. */ boolean hasWriteObjectData() { + requireInitialized(); return hasWriteObjectData; } @@ -903,6 +935,7 @@ public class ObjectStreamClass implements Serializable { * accessible no-arg constructor. Otherwise, returns false. */ boolean isInstantiable() { + requireInitialized(); return (cons != null); } @@ -912,6 +945,7 @@ public class ObjectStreamClass implements Serializable { * returns false. */ boolean hasWriteObjectMethod() { + requireInitialized(); return (writeObjectMethod != null); } @@ -921,6 +955,7 @@ public class ObjectStreamClass implements Serializable { * returns false. */ boolean hasReadObjectMethod() { + requireInitialized(); return (readObjectMethod != null); } @@ -930,6 +965,7 @@ public class ObjectStreamClass implements Serializable { * Otherwise, returns false. */ boolean hasReadObjectNoDataMethod() { + requireInitialized(); return (readObjectNoDataMethod != null); } @@ -938,6 +974,7 @@ public class ObjectStreamClass implements Serializable { * defines a conformant writeReplace method. Otherwise, returns false. */ boolean hasWriteReplaceMethod() { + requireInitialized(); return (writeReplaceMethod != null); } @@ -946,6 +983,7 @@ public class ObjectStreamClass implements Serializable { * defines a conformant readResolve method. Otherwise, returns false. */ boolean hasReadResolveMethod() { + requireInitialized(); return (readResolveMethod != null); } @@ -962,6 +1000,7 @@ public class ObjectStreamClass implements Serializable { throws InstantiationException, InvocationTargetException, UnsupportedOperationException { + requireInitialized(); if (cons != null) { try { return cons.newInstance(); @@ -983,6 +1022,7 @@ public class ObjectStreamClass implements Serializable { void invokeWriteObject(Object obj, ObjectOutputStream out) throws IOException, UnsupportedOperationException { + requireInitialized(); if (writeObjectMethod != null) { try { writeObjectMethod.invoke(obj, new Object[]{ out }); @@ -1012,6 +1052,7 @@ public class ObjectStreamClass implements Serializable { throws ClassNotFoundException, IOException, UnsupportedOperationException { + requireInitialized(); if (readObjectMethod != null) { try { readObjectMethod.invoke(obj, new Object[]{ in }); @@ -1042,6 +1083,7 @@ public class ObjectStreamClass implements Serializable { void invokeReadObjectNoData(Object obj) throws IOException, UnsupportedOperationException { + requireInitialized(); if (readObjectNoDataMethod != null) { try { readObjectNoDataMethod.invoke(obj, (Object[]) null); @@ -1070,6 +1112,7 @@ public class ObjectStreamClass implements Serializable { Object invokeWriteReplace(Object obj) throws IOException, UnsupportedOperationException { + requireInitialized(); if (writeReplaceMethod != null) { try { return writeReplaceMethod.invoke(obj, (Object[]) null); @@ -1099,6 +1142,7 @@ public class ObjectStreamClass implements Serializable { Object invokeReadResolve(Object obj) throws IOException, UnsupportedOperationException { + requireInitialized(); if (readResolveMethod != null) { try { return readResolveMethod.invoke(obj, (Object[]) null); diff --git a/jdk/src/java.base/share/classes/java/lang/Character.java b/jdk/src/java.base/share/classes/java/lang/Character.java index eb4ee65f760..ae3d1ef6bd8 100644 --- a/jdk/src/java.base/share/classes/java/lang/Character.java +++ b/jdk/src/java.base/share/classes/java/lang/Character.java @@ -42,7 +42,7 @@ import jdk.internal.HotSpotIntrinsicCandidate; * a character's category (lowercase letter, digit, etc.) and for converting * characters from uppercase to lowercase and vice versa. *

      - * Character information is based on the Unicode Standard, version 7.0.0. + * Character information is based on the Unicode Standard, version 8.0.0. *

      * The methods and data of class {@code Character} are defined by * the information in the UnicodeData file that is part of the @@ -2850,6 +2850,93 @@ class Character implements java.io.Serializable, Comparable { "SUPPLEMENTAL ARROWS-C", "SUPPLEMENTALARROWS-C"); + /** + * Constant for the "Cherokee Supplement" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock CHEROKEE_SUPPLEMENT = + new UnicodeBlock("CHEROKEE_SUPPLEMENT", + "CHEROKEE SUPPLEMENT", + "CHEROKEESUPPLEMENT"); + + /** + * Constant for the "Hatran" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock HATRAN = + new UnicodeBlock("HATRAN"); + + /** + * Constant for the "Old Hungarian" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock OLD_HUNGARIAN = + new UnicodeBlock("OLD_HUNGARIAN", + "OLD HUNGARIAN", + "OLDHUNGARIAN"); + + /** + * Constant for the "Multani" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock MULTANI = + new UnicodeBlock("MULTANI"); + + /** + * Constant for the "Ahom" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock AHOM = + new UnicodeBlock("AHOM"); + + /** + * Constant for the "Early Dynastic Cuneiform" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock EARLY_DYNASTIC_CUNEIFORM = + new UnicodeBlock("EARLY_DYNASTIC_CUNEIFORM", + "EARLY DYNASTIC CUNEIFORM", + "EARLYDYNASTICCUNEIFORM"); + + /** + * Constant for the "Anatolian Hieroglyphs" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock ANATOLIAN_HIEROGLYPHS = + new UnicodeBlock("ANATOLIAN_HIEROGLYPHS", + "ANATOLIAN HIEROGLYPHS", + "ANATOLIANHIEROGLYPHS"); + + /** + * Constant for the "Sutton SignWriting" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock SUTTON_SIGNWRITING = + new UnicodeBlock("SUTTON_SIGNWRITING", + "SUTTON SIGNWRITING", + "SUTTONSIGNWRITING"); + + /** + * Constant for the "Supplemental Symbols and Pictographs" Unicode + * character block. + * @since 1.9 + */ + public static final UnicodeBlock SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS = + new UnicodeBlock("SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS", + "SUPPLEMENTAL SYMBOLS AND PICTOGRAPHS", + "SUPPLEMENTALSYMBOLSANDPICTOGRAPHS"); + + /** + * Constant for the "CJK Unified Ideographs Extension E" Unicode + * character block. + * @since 1.9 + */ + public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E = + new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E", + "CJK UNIFIED IDEOGRAPHS EXTENSION E", + "CJKUNIFIEDIDEOGRAPHSEXTENSIONE"); + + private static final int blockStarts[] = { 0x0000, // 0000..007F; Basic Latin 0x0080, // 0080..00FF; Latin-1 Supplement @@ -2995,7 +3082,7 @@ class Character implements java.io.Serializable, Comparable { 0xAAE0, // AAE0..AAFF; Meetei Mayek Extensions 0xAB00, // AB00..AB2F; Ethiopic Extended-A 0xAB30, // AB30..AB6F; Latin Extended-E - 0xAB70, // unassigned + 0xAB70, // AB70..ABBF; Cherokee Supplement 0xABC0, // ABC0..ABFF; Meetei Mayek 0xAC00, // AC00..D7AF; Hangul Syllables 0xD7B0, // D7B0..D7FF; Hangul Jamo Extended-B @@ -3044,6 +3131,7 @@ class Character implements java.io.Serializable, Comparable { 0x10860, // 10860..1087F; Palmyrene 0x10880, // 10880..108AF; Nabataean 0x108B0, // unassigned + 0x108E0, // 108E0..108FF; Hatran 0x10900, // 10900..1091F; Phoenician 0x10920, // 10920..1093F; Lydian 0x10940, // unassigned @@ -3061,6 +3149,8 @@ class Character implements java.io.Serializable, Comparable { 0x10BB0, // unassigned 0x10C00, // 10C00..10C4F; Old Turkic 0x10C50, // unassigned + 0x10C80, // 10C80..10CFF; Old Hungarian + 0x10D00, // unassigned 0x10E60, // 10E60..10E7F; Rumi Numeral Symbols 0x10E80, // unassigned 0x11000, // 11000..1107F; Brahmi @@ -3072,6 +3162,7 @@ class Character implements java.io.Serializable, Comparable { 0x111E0, // 111E0..111FF; Sinhala Archaic Numbers 0x11200, // 11200..1124F; Khojki 0x11250, // unassigned + 0x11280, // 11280..112AF; Multani 0x112B0, // 112B0..112FF; Khudawadi 0x11300, // 11300..1137F; Grantha 0x11380, // unassigned @@ -3082,15 +3173,20 @@ class Character implements java.io.Serializable, Comparable { 0x11660, // unassigned 0x11680, // 11680..116CF; Takri 0x116D0, // unassigned + 0x11700, // 11700..1173F; Ahom + 0x11740, // unassigned 0x118A0, // 118A0..118FF; Warang Citi 0x11900, // unassigned 0x11AC0, // 11AC0..11AFF; Pau Cin Hau 0x11B00, // unassigned 0x12000, // 12000..123FF; Cuneiform 0x12400, // 12400..1247F; Cuneiform Numbers and Punctuation - 0x12480, // unassigned + 0x12480, // 12480..1254F; Early Dynastic Cuneiform + 0x12550, // unassigned 0x13000, // 13000..1342F; Egyptian Hieroglyphs 0x13430, // unassigned + 0x14400, // 14400..1467F; Anatolian Hieroglyphs + 0x14680, // unassigned 0x16800, // 16800..16A3F; Bamum Supplement 0x16A40, // 16A40..16A6F; Mro 0x16A70, // unassigned @@ -3112,7 +3208,8 @@ class Character implements java.io.Serializable, Comparable { 0x1D360, // 1D360..1D37F; Counting Rod Numerals 0x1D380, // unassigned 0x1D400, // 1D400..1D7FF; Mathematical Alphanumeric Symbols - 0x1D800, // unassigned + 0x1D800, // 1D800..1DAAF; Sutton SignWriting + 0x1DAB0, // unassigned 0x1E800, // 1E800..1E8DF; Mende Kikakui 0x1E8E0, // unassigned 0x1EE00, // 1EE00..1EEFF; Arabic Mathematical Alphabetic Symbols @@ -3122,19 +3219,21 @@ class Character implements java.io.Serializable, Comparable { 0x1F0A0, // 1F0A0..1F0FF; Playing Cards 0x1F100, // 1F100..1F1FF; Enclosed Alphanumeric Supplement 0x1F200, // 1F200..1F2FF; Enclosed Ideographic Supplement - 0x1F300, // 1F300..1F5FF; Miscellaneous Symbols And Pictographs + 0x1F300, // 1F300..1F5FF; Miscellaneous Symbols and Pictographs 0x1F600, // 1F600..1F64F; Emoticons 0x1F650, // 1F650..1F67F; Ornamental Dingbats - 0x1F680, // 1F680..1F6FF; Transport And Map Symbols + 0x1F680, // 1F680..1F6FF; Transport and Map Symbols 0x1F700, // 1F700..1F77F; Alchemical Symbols 0x1F780, // 1F780..1F7FF; Geometric Shapes Extended 0x1F800, // 1F800..1F8FF; Supplemental Arrows-C - 0x1F900, // unassigned + 0x1F900, // 1F900..1F9FF; Supplemental Symbols and Pictographs + 0x1FA00, // unassigned 0x20000, // 20000..2A6DF; CJK Unified Ideographs Extension B 0x2A6E0, // unassigned 0x2A700, // 2A700..2B73F; CJK Unified Ideographs Extension C 0x2B740, // 2B740..2B81F; CJK Unified Ideographs Extension D - 0x2B820, // unassigned + 0x2B820, // 2B820..2CEAF; CJK Unified Ideographs Extension E + 0x2CEB0, // unassigned 0x2F800, // 2F800..2FA1F; CJK Compatibility Ideographs Supplement 0x2FA20, // unassigned 0xE0000, // E0000..E007F; Tags @@ -3290,7 +3389,7 @@ class Character implements java.io.Serializable, Comparable { MEETEI_MAYEK_EXTENSIONS, ETHIOPIC_EXTENDED_A, LATIN_EXTENDED_E, - null, + CHEROKEE_SUPPLEMENT, MEETEI_MAYEK, HANGUL_SYLLABLES, HANGUL_JAMO_EXTENDED_B, @@ -3339,6 +3438,7 @@ class Character implements java.io.Serializable, Comparable { PALMYRENE, NABATAEAN, null, + HATRAN, PHOENICIAN, LYDIAN, null, @@ -3356,6 +3456,8 @@ class Character implements java.io.Serializable, Comparable { null, OLD_TURKIC, null, + OLD_HUNGARIAN, + null, RUMI_NUMERAL_SYMBOLS, null, BRAHMI, @@ -3367,6 +3469,7 @@ class Character implements java.io.Serializable, Comparable { SINHALA_ARCHAIC_NUMBERS, KHOJKI, null, + MULTANI, KHUDAWADI, GRANTHA, null, @@ -3377,15 +3480,20 @@ class Character implements java.io.Serializable, Comparable { null, TAKRI, null, + AHOM, + null, WARANG_CITI, null, PAU_CIN_HAU, null, CUNEIFORM, CUNEIFORM_NUMBERS_AND_PUNCTUATION, + EARLY_DYNASTIC_CUNEIFORM, null, EGYPTIAN_HIEROGLYPHS, null, + ANATOLIAN_HIEROGLYPHS, + null, BAMUM_SUPPLEMENT, MRO, null, @@ -3407,6 +3515,7 @@ class Character implements java.io.Serializable, Comparable { COUNTING_ROD_NUMERALS, null, MATHEMATICAL_ALPHANUMERIC_SYMBOLS, + SUTTON_SIGNWRITING, null, MENDE_KIKAKUI, null, @@ -3424,11 +3533,13 @@ class Character implements java.io.Serializable, Comparable { ALCHEMICAL_SYMBOLS, GEOMETRIC_SHAPES_EXTENDED, SUPPLEMENTAL_ARROWS_C, + SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS, null, CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B, null, CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C, CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D, + CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E, null, CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT, null, @@ -4214,6 +4325,42 @@ class Character implements java.io.Serializable, Comparable { */ WARANG_CITI, + /** + * Unicode script "Ahom". + * @since 1.9 + */ + AHOM, + + /** + * Unicode script "Anatolian Hieroglyphs". + * @since 1.9 + */ + ANATOLIAN_HIEROGLYPHS, + + /** + * Unicode script "Hatran". + * @since 1.9 + */ + HATRAN, + + /** + * Unicode script "Multani". + * @since 1.9 + */ + MULTANI, + + /** + * Unicode script "Old Hungarian". + * @since 1.9 + */ + OLD_HUNGARIAN, + + /** + * Unicode script "SignWriting". + * @since 1.9 + */ + SIGNWRITING, + /** * Unicode script "Unknown". */ @@ -4295,9 +4442,7 @@ class Character implements java.io.Serializable, Comparable { 0x0640, // 0640 ; COMMON 0x0641, // 0641..064A; ARABIC 0x064B, // 064B..0655; INHERITED - 0x0656, // 0656..065F; ARABIC - 0x0660, // 0660..0669; COMMON - 0x066A, // 066A..066F; ARABIC + 0x0656, // 0656..066F; ARABIC 0x0670, // 0670 ; INHERITED 0x0671, // 0671..06DC; ARABIC 0x06DD, // 06DD ; COMMON @@ -4320,9 +4465,9 @@ class Character implements java.io.Serializable, Comparable { 0x085C, // 085C..085D; UNKNOWN 0x085E, // 085E ; MANDAIC 0x085F, // 085F..089F; UNKNOWN - 0x08A0, // 08A0..08B2; ARABIC - 0x08B3, // 08B3..08E3; UNKNOWN - 0x08E4, // 08E4..08FF; ARABIC + 0x08A0, // 08A0..08B4; ARABIC + 0x08B5, // 08B5..08E2; UNKNOWN + 0x08E3, // 08E3..08FF; ARABIC 0x0900, // 0900..0950; DEVANAGARI 0x0951, // 0951..0952; INHERITED 0x0953, // 0953..0963; DEVANAGARI @@ -4413,7 +4558,9 @@ class Character implements java.io.Serializable, Comparable { 0x0AE0, // 0AE0..0AE3; GUJARATI 0x0AE4, // 0AE4..0AE5; UNKNOWN 0x0AE6, // 0AE6..0AF1; GUJARATI - 0x0AF2, // 0AF2..0B00; UNKNOWN + 0x0AF2, // 0AF2..0AF8; UNKNOWN + 0x0AF9, // 0AF9 ; GUJARATI + 0x0AFA, // 0AFA..0B00; UNKNOWN 0x0B01, // 0B01..0B03; ORIYA 0x0B04, // 0B04 ; UNKNOWN 0x0B05, // 0B05..0B0C; ORIYA @@ -4492,8 +4639,8 @@ class Character implements java.io.Serializable, Comparable { 0x0C4E, // 0C4E..0C54; UNKNOWN 0x0C55, // 0C55..0C56; TELUGU 0x0C57, // 0C57 ; UNKNOWN - 0x0C58, // 0C58..0C59; TELUGU - 0x0C5A, // 0C5A..0C5F; UNKNOWN + 0x0C58, // 0C58..0C5A; TELUGU + 0x0C5B, // 0C5B..0C5F; UNKNOWN 0x0C60, // 0C60..0C63; TELUGU 0x0C64, // 0C64..0C65; UNKNOWN 0x0C66, // 0C66..0C6F; TELUGU @@ -4543,8 +4690,8 @@ class Character implements java.io.Serializable, Comparable { 0x0D4A, // 0D4A..0D4E; MALAYALAM 0x0D4F, // 0D4F..0D56; UNKNOWN 0x0D57, // 0D57 ; MALAYALAM - 0x0D58, // 0D58..0D5F; UNKNOWN - 0x0D60, // 0D60..0D63; MALAYALAM + 0x0D58, // 0D58..0D5E; UNKNOWN + 0x0D5F, // 0D5F..0D63; MALAYALAM 0x0D64, // 0D64..0D65; UNKNOWN 0x0D66, // 0D66..0D75; MALAYALAM 0x0D76, // 0D76..0D78; UNKNOWN @@ -4676,8 +4823,10 @@ class Character implements java.io.Serializable, Comparable { 0x137D, // 137D..137F; UNKNOWN 0x1380, // 1380..1399; ETHIOPIC 0x139A, // 139A..139F; UNKNOWN - 0x13A0, // 13A0..13F4; CHEROKEE - 0x13F5, // 13F5..13FF; UNKNOWN + 0x13A0, // 13A0..13F5; CHEROKEE + 0x13F6, // 13F6..13F7; UNKNOWN + 0x13F8, // 13F8..13FD; CHEROKEE + 0x13FE, // 13FE..13FF; UNKNOWN 0x1400, // 1400..167F; CANADIAN_ABORIGINAL 0x1680, // 1680..169C; OGHAM 0x169D, // 169D..169F; UNKNOWN @@ -4846,8 +4995,8 @@ class Character implements java.io.Serializable, Comparable { 0x208F, // 208F ; UNKNOWN 0x2090, // 2090..209C; LATIN 0x209D, // 209D..209F; UNKNOWN - 0x20A0, // 20A0..20BD; COMMON - 0x20BE, // 20BE..20CF; UNKNOWN + 0x20A0, // 20A0..20BE; COMMON + 0x20BF, // 20BF..20CF; UNKNOWN 0x20D0, // 20D0..20F0; INHERITED 0x20F1, // 20F1..20FF; UNKNOWN 0x2100, // 2100..2125; COMMON @@ -4860,8 +5009,8 @@ class Character implements java.io.Serializable, Comparable { 0x214E, // 214E ; LATIN 0x214F, // 214F..215F; COMMON 0x2160, // 2160..2188; LATIN - 0x2189, // 2189 ; COMMON - 0x218A, // 218A..218F; UNKNOWN + 0x2189, // 2189..218B; COMMON + 0x218C, // 218C..218F; UNKNOWN 0x2190, // 2190..23FA; COMMON 0x23FB, // 23FB..23FF; UNKNOWN 0x2400, // 2400..2426; COMMON @@ -4879,7 +5028,9 @@ class Character implements java.io.Serializable, Comparable { 0x2BBD, // 2BBD..2BC8; COMMON 0x2BC9, // 2BC9 ; UNKNOWN 0x2BCA, // 2BCA..2BD1; COMMON - 0x2BD2, // 2BD2..2BFF; UNKNOWN + 0x2BD2, // 2BD2..2BEB; UNKNOWN + 0x2BEC, // 2BEC..2BEF; COMMON + 0x2BF0, // 2BF0..2BFF; UNKNOWN 0x2C00, // 2C00..2C2E; GLAGOLITIC 0x2C2F, // 2C2F ; UNKNOWN 0x2C30, // 2C30..2C5E; GLAGOLITIC @@ -4972,8 +5123,8 @@ class Character implements java.io.Serializable, Comparable { 0x3400, // 3400..4DB5; HAN 0x4DB6, // 4DB6..4DBF; UNKNOWN 0x4DC0, // 4DC0..4DFF; COMMON - 0x4E00, // 4E00..9FCC; HAN - 0x9FCD, // 9FCD..9FFF; UNKNOWN + 0x4E00, // 4E00..9FD5; HAN + 0x9FD6, // 9FD6..9FFF; UNKNOWN 0xA000, // A000..A48C; YI 0xA48D, // A48D..A48F; UNKNOWN 0xA490, // A490..A4C6; YI @@ -4981,20 +5132,16 @@ class Character implements java.io.Serializable, Comparable { 0xA4D0, // A4D0..A4FF; LISU 0xA500, // A500..A62B; VAI 0xA62C, // A62C..A63F; UNKNOWN - 0xA640, // A640..A69D; CYRILLIC - 0xA69E, // A69E ; UNKNOWN - 0xA69F, // A69F ; CYRILLIC + 0xA640, // A640..A69F; CYRILLIC 0xA6A0, // A6A0..A6F7; BAMUM 0xA6F8, // A6F8..A6FF; UNKNOWN 0xA700, // A700..A721; COMMON 0xA722, // A722..A787; LATIN 0xA788, // A788..A78A; COMMON - 0xA78B, // A78B..A78E; LATIN - 0xA78F, // A78F ; UNKNOWN - 0xA790, // A790..A7AD; LATIN + 0xA78B, // A78B..A7AD; LATIN 0xA7AE, // A7AE..A7AF; UNKNOWN - 0xA7B0, // A7B0..A7B1; LATIN - 0xA7B2, // A7B2..A7F6; UNKNOWN + 0xA7B0, // A7B0..A7B7; LATIN + 0xA7B8, // A7B8..A7F6; UNKNOWN 0xA7F7, // A7F7..A7FF; LATIN 0xA800, // A800..A82B; SYLOTI_NAGRI 0xA82C, // A82C..A82F; UNKNOWN @@ -5006,8 +5153,8 @@ class Character implements java.io.Serializable, Comparable { 0xA8C5, // A8C5..A8CD; UNKNOWN 0xA8CE, // A8CE..A8D9; SAURASHTRA 0xA8DA, // A8DA..A8DF; UNKNOWN - 0xA8E0, // A8E0..A8FB; DEVANAGARI - 0xA8FC, // A8FC..A8FF; UNKNOWN + 0xA8E0, // A8E0..A8FD; DEVANAGARI + 0xA8FE, // A8FE..A8FF; UNKNOWN 0xA900, // A900..A92D; KAYAH_LI 0xA92E, // A92E ; COMMON 0xA92F, // A92F ; KAYAH_LI @@ -5049,11 +5196,10 @@ class Character implements java.io.Serializable, Comparable { 0xAB2F, // AB2F ; UNKNOWN 0xAB30, // AB30..AB5A; LATIN 0xAB5B, // AB5B ; COMMON - 0xAB5C, // AB5C..AB5F; LATIN - 0xAB60, // AB60..AB63; UNKNOWN - 0xAB64, // AB64 ; LATIN + 0xAB5C, // AB5C..AB64; LATIN 0xAB65, // AB65 ; GREEK - 0xAB66, // AB66..ABBF; UNKNOWN + 0xAB66, // AB66..AB6F; UNKNOWN + 0xAB70, // AB70..ABBF; CHEROKEE 0xABC0, // ABC0..ABED; MEETEI_MAYEK 0xABEE, // ABEE..ABEF; UNKNOWN 0xABF0, // ABF0..ABF9; MEETEI_MAYEK @@ -5098,7 +5244,7 @@ class Character implements java.io.Serializable, Comparable { 0xFE10, // FE10..FE19; COMMON 0xFE1A, // FE1A..FE1F; UNKNOWN 0xFE20, // FE20..FE2D; INHERITED - 0xFE2E, // FE2E..FE2F; UNKNOWN + 0xFE2E, // FE2E..FE2F; CYRILLIC 0xFE30, // FE30..FE52; COMMON 0xFE53, // FE53 ; UNKNOWN 0xFE54, // FE54..FE66; COMMON @@ -5220,7 +5366,12 @@ class Character implements java.io.Serializable, Comparable { 0x10880, // 10880..1089E; NABATAEAN 0x1089F, // 1089F..108A6; UNKNOWN 0x108A7, // 108A7..108AF; NABATAEAN - 0x108B0, // 108B0..108FF; UNKNOWN + 0x108B0, // 108B0..108DF; UNKNOWN + 0x108E0, // 108E0..108F2; HATRAN + 0x108F3, // 108F3 ; UNKNOWN + 0x108F4, // 108F4..108F5; HATRAN + 0x108F6, // 108F6..108FA; UNKNOWN + 0x108FB, // 108FB..108FF; HATRAN 0x10900, // 10900..1091B; PHOENICIAN 0x1091C, // 1091C..1091E; UNKNOWN 0x1091F, // 1091F ; PHOENICIAN @@ -5230,9 +5381,10 @@ class Character implements java.io.Serializable, Comparable { 0x10940, // 10940..1097F; UNKNOWN 0x10980, // 10980..1099F; MEROITIC_HIEROGLYPHS 0x109A0, // 109A0..109B7; MEROITIC_CURSIVE - 0x109B8, // 109B8..109BD; UNKNOWN - 0x109BE, // 109BE..109BF; MEROITIC_CURSIVE - 0x109C0, // 109C0..109FF; UNKNOWN + 0x109B8, // 109B8..109BB; UNKNOWN + 0x109BC, // 109BC..109CF; MEROITIC_CURSIVE + 0x109D0, // 109D0..109D1; UNKNOWN + 0x109D2, // 109D2..109FF; MEROITIC_CURSIVE 0x10A00, // 10A00..10A03; KHAROSHTHI 0x10A04, // 10A04 ; UNKNOWN 0x10A05, // 10A05..10A06; KHAROSHTHI @@ -5272,7 +5424,13 @@ class Character implements java.io.Serializable, Comparable { 0x10BA9, // 10BA9..10BAF; PSALTER_PAHLAVI 0x10BB0, // 10BB0..10BFF; UNKNOWN 0x10C00, // 10C00..10C48; OLD_TURKIC - 0x10C49, // 10C49..10E5F; UNKNOWN + 0x10C49, // 10C49..10C7F; UNKNOWN + 0x10C80, // 10C80..10CB2; OLD_HUNGARIAN + 0x10CB3, // 10CB3..10CBF; UNKNOWN + 0x10CC0, // 10CC0..10CF2; OLD_HUNGARIAN + 0x10CF3, // 10CF3..10CF9; UNKNOWN + 0x10CFA, // 10CFA..10CFF; OLD_HUNGARIAN + 0x10D00, // 10D00..10E5F; UNKNOWN 0x10E60, // 10E60..10E7E; ARABIC 0x10E7F, // 10E7F..10FFF; UNKNOWN 0x11000, // 11000..1104D; BRAHMI @@ -5292,23 +5450,31 @@ class Character implements java.io.Serializable, Comparable { 0x11144, // 11144..1114F; UNKNOWN 0x11150, // 11150..11176; MAHAJANI 0x11177, // 11177..1117F; UNKNOWN - 0x11180, // 11180..111C8; SHARADA - 0x111C9, // 111C9..111CC; UNKNOWN - 0x111CD, // 111CD ; SHARADA + 0x11180, // 11180..111CD; SHARADA 0x111CE, // 111CE..111CF; UNKNOWN - 0x111D0, // 111D0..111DA; SHARADA - 0x111DB, // 111DB..111E0; UNKNOWN + 0x111D0, // 111D0..111DF; SHARADA + 0x111E0, // 111E0 ; UNKNOWN 0x111E1, // 111E1..111F4; SINHALA 0x111F5, // 111F5..111FF; UNKNOWN 0x11200, // 11200..11211; KHOJKI 0x11212, // 11212 ; UNKNOWN 0x11213, // 11213..1123D; KHOJKI - 0x1123E, // 1123E..112AF; UNKNOWN + 0x1123E, // 1123E..1127F; UNKNOWN + 0x11280, // 11280..11286; MULTANI + 0x11287, // 11287 ; UNKNOWN + 0x11288, // 11288 ; MULTANI + 0x11289, // 11289 ; UNKNOWN + 0x1128A, // 1128A..1128D; MULTANI + 0x1128E, // 1128E ; UNKNOWN + 0x1128F, // 1128F..1129D; MULTANI + 0x1129E, // 1129E ; UNKNOWN + 0x1129F, // 1129F..112A9; MULTANI + 0x112AA, // 112AA..112AF; UNKNOWN 0x112B0, // 112B0..112EA; KHUDAWADI 0x112EB, // 112EB..112EF; UNKNOWN 0x112F0, // 112F0..112F9; KHUDAWADI - 0x112FA, // 112FA..11300; UNKNOWN - 0x11301, // 11301..11303; GRANTHA + 0x112FA, // 112FA..112FF; UNKNOWN + 0x11300, // 11300..11303; GRANTHA 0x11304, // 11304 ; UNKNOWN 0x11305, // 11305..1130C; GRANTHA 0x1130D, // 1130D..1130E; UNKNOWN @@ -5327,7 +5493,9 @@ class Character implements java.io.Serializable, Comparable { 0x11347, // 11347..11348; GRANTHA 0x11349, // 11349..1134A; UNKNOWN 0x1134B, // 1134B..1134D; GRANTHA - 0x1134E, // 1134E..11356; UNKNOWN + 0x1134E, // 1134E..1134F; UNKNOWN + 0x11350, // 11350 ; GRANTHA + 0x11351, // 11351..11356; UNKNOWN 0x11357, // 11357 ; GRANTHA 0x11358, // 11358..1135C; UNKNOWN 0x1135D, // 1135D..11363; GRANTHA @@ -5342,8 +5510,8 @@ class Character implements java.io.Serializable, Comparable { 0x114DA, // 114DA..1157F; UNKNOWN 0x11580, // 11580..115B5; SIDDHAM 0x115B6, // 115B6..115B7; UNKNOWN - 0x115B8, // 115B8..115C9; SIDDHAM - 0x115CA, // 115CA..115FF; UNKNOWN + 0x115B8, // 115B8..115DD; SIDDHAM + 0x115DE, // 115DE..115FF; UNKNOWN 0x11600, // 11600..11644; MODI 0x11645, // 11645..1164F; UNKNOWN 0x11650, // 11650..11659; MODI @@ -5351,21 +5519,31 @@ class Character implements java.io.Serializable, Comparable { 0x11680, // 11680..116B7; TAKRI 0x116B8, // 116B8..116BF; UNKNOWN 0x116C0, // 116C0..116C9; TAKRI - 0x116CA, // 116CA..1189F; UNKNOWN + 0x116CA, // 116CA..116FF; UNKNOWN + 0x11700, // 11700..11719; AHOM + 0x1171A, // 1171A..1171C; UNKNOWN + 0x1171D, // 1171D..1172B; AHOM + 0x1172C, // 1172C..1172F; UNKNOWN + 0x11730, // 11730..1173F; AHOM + 0x11740, // 11740..1189F; UNKNOWN 0x118A0, // 118A0..118F2; WARANG_CITI 0x118F3, // 118F3..118FE; UNKNOWN 0x118FF, // 118FF ; WARANG_CITI 0x11900, // 11900..11ABF; UNKNOWN 0x11AC0, // 11AC0..11AF8; PAU_CIN_HAU 0x11AF9, // 11AF9..11FFF; UNKNOWN - 0x12000, // 12000..12398; CUNEIFORM - 0x12399, // 12399..123FF; UNKNOWN + 0x12000, // 12000..12399; CUNEIFORM + 0x1239A, // 1239A..123FF; UNKNOWN 0x12400, // 12400..1246E; CUNEIFORM 0x1246F, // 1246F ; UNKNOWN 0x12470, // 12470..12474; CUNEIFORM - 0x12475, // 12475..12FFF; UNKNOWN + 0x12475, // 12475..1247F; UNKNOWN + 0x12480, // 12480..12543; CUNEIFORM + 0x12544, // 12544..12FFF; UNKNOWN 0x13000, // 13000..1342E; EGYPTIAN_HIEROGLYPHS - 0x1342F, // 1342F..167FF; UNKNOWN + 0x1342F, // 1342F..143FF; UNKNOWN + 0x14400, // 14400..14646; ANATOLIAN_HIEROGLYPHS + 0x14647, // 14647..167FF; UNKNOWN 0x16800, // 16800..16A38; BAMUM 0x16A39, // 16A39..16A3F; UNKNOWN 0x16A40, // 16A40..16A5E; MRO @@ -5420,8 +5598,8 @@ class Character implements java.io.Serializable, Comparable { 0x1D185, // 1D185..1D18B; INHERITED 0x1D18C, // 1D18C..1D1A9; COMMON 0x1D1AA, // 1D1AA..1D1AD; INHERITED - 0x1D1AE, // 1D1AE..1D1DD; COMMON - 0x1D1DE, // 1D1DE..1D1FF; UNKNOWN + 0x1D1AE, // 1D1AE..1D1E8; COMMON + 0x1D1E9, // 1D1E9..1D1FF; UNKNOWN 0x1D200, // 1D200..1D245; GREEK 0x1D246, // 1D246..1D2FF; UNKNOWN 0x1D300, // 1D300..1D356; COMMON @@ -5469,7 +5647,12 @@ class Character implements java.io.Serializable, Comparable { 0x1D6A8, // 1D6A8..1D7CB; COMMON 0x1D7CC, // 1D7CC..1D7CD; UNKNOWN 0x1D7CE, // 1D7CE..1D7FF; COMMON - 0x1D800, // 1D800..1E7FF; UNKNOWN + 0x1D800, // 1D800..1DA8B; SIGNWRITING + 0x1DA8C, // 1DA8C..1DA9A; UNKNOWN + 0x1DA9B, // 1DA9B..1DA9F; SIGNWRITING + 0x1DAA0, // 1DAA0 ; UNKNOWN + 0x1DAA1, // 1DAA1..1DAAF; SIGNWRITING + 0x1DAB0, // 1DAB0..1E7FF; UNKNOWN 0x1E800, // 1E800..1E8C4; MENDE_KIKAKUI 0x1E8C5, // 1E8C5..1E8C6; UNKNOWN 0x1E8C7, // 1E8C7..1E8D6; MENDE_KIKAKUI @@ -5572,26 +5755,12 @@ class Character implements java.io.Serializable, Comparable { 0x1F249, // 1F249..1F24F; UNKNOWN 0x1F250, // 1F250..1F251; COMMON 0x1F252, // 1F252..1F2FF; UNKNOWN - 0x1F300, // 1F300..1F32C; COMMON - 0x1F32D, // 1F32D..1F32F; UNKNOWN - 0x1F330, // 1F330..1F37D; COMMON - 0x1F37E, // 1F37E..1F37F; UNKNOWN - 0x1F380, // 1F380..1F3CE; COMMON - 0x1F3CF, // 1F3CF..1F3D3; UNKNOWN - 0x1F3D4, // 1F3D4..1F3F7; COMMON - 0x1F3F8, // 1F3F8..1F3FF; UNKNOWN - 0x1F400, // 1F400..1F4FE; COMMON - 0x1F4FF, // 1F4FF ; UNKNOWN - 0x1F500, // 1F500..1F54A; COMMON - 0x1F54B, // 1F54B..1F54F; UNKNOWN - 0x1F550, // 1F550..1F579; COMMON + 0x1F300, // 1F300..1F579; COMMON 0x1F57A, // 1F57A ; UNKNOWN 0x1F57B, // 1F57B..1F5A3; COMMON 0x1F5A4, // 1F5A4 ; UNKNOWN - 0x1F5A5, // 1F5A5..1F642; COMMON - 0x1F643, // 1F643..1F644; UNKNOWN - 0x1F645, // 1F645..1F6CF; COMMON - 0x1F6D0, // 1F6D0..1F6DF; UNKNOWN + 0x1F5A5, // 1F5A5..1F6D0; COMMON + 0x1F6D1, // 1F6D1..1F6DF; UNKNOWN 0x1F6E0, // 1F6E0..1F6EC; COMMON 0x1F6ED, // 1F6ED..1F6EF; UNKNOWN 0x1F6F0, // 1F6F0..1F6F3; COMMON @@ -5609,13 +5778,21 @@ class Character implements java.io.Serializable, Comparable { 0x1F860, // 1F860..1F887; COMMON 0x1F888, // 1F888..1F88F; UNKNOWN 0x1F890, // 1F890..1F8AD; COMMON - 0x1F8AE, // 1F8AE..1FFFF; UNKNOWN + 0x1F8AE, // 1F8AE..1F90F; UNKNOWN + 0x1F910, // 1F910..1F918; COMMON + 0x1F919, // 1F919..1F97F; UNKNOWN + 0x1F980, // 1F980..1F984; COMMON + 0x1F985, // 1F985..1F9BF; UNKNOWN + 0x1F9C0, // 1F9C0 ; COMMON + 0x1F9C1, // 1F9C1..1FFFF; UNKNOWN 0x20000, // 20000..2A6D6; HAN 0x2A6D7, // 2A6D7..2A6FF; UNKNOWN 0x2A700, // 2A700..2B734; HAN 0x2B735, // 2B735..2B73F; UNKNOWN 0x2B740, // 2B740..2B81D; HAN - 0x2B81E, // 2B81E..2F7FF; UNKNOWN + 0x2B81E, // 2B81E..2B81F; UNKNOWN + 0x2B820, // 2B820..2CEA1; HAN + 0x2CEA2, // 2CEA2..2F7FF; UNKNOWN 0x2F800, // 2F800..2FA1D; HAN 0x2FA1E, // 2FA1E..E0000; UNKNOWN 0xE0001, // E0001 ; COMMON @@ -5702,9 +5879,7 @@ class Character implements java.io.Serializable, Comparable { COMMON, // 0640 ARABIC, // 0641..064A INHERITED, // 064B..0655 - ARABIC, // 0656..065F - COMMON, // 0660..0669 - ARABIC, // 066A..066F + ARABIC, // 0656..066F INHERITED, // 0670 ARABIC, // 0671..06DC COMMON, // 06DD @@ -5727,9 +5902,9 @@ class Character implements java.io.Serializable, Comparable { UNKNOWN, // 085C..085D MANDAIC, // 085E UNKNOWN, // 085F..089F - ARABIC, // 08A0..08B2 - UNKNOWN, // 08B3..08E3 - ARABIC, // 08E4..08FF + ARABIC, // 08A0..08B4 + UNKNOWN, // 08B5..08E2 + ARABIC, // 08E3..08FF DEVANAGARI, // 0900..0950 INHERITED, // 0951..0952 DEVANAGARI, // 0953..0963 @@ -5820,7 +5995,9 @@ class Character implements java.io.Serializable, Comparable { GUJARATI, // 0AE0..0AE3 UNKNOWN, // 0AE4..0AE5 GUJARATI, // 0AE6..0AF1 - UNKNOWN, // 0AF2..0B00 + UNKNOWN, // 0AF2..0AF8 + GUJARATI, // 0AF9 + UNKNOWN, // 0AFA..0B00 ORIYA, // 0B01..0B03 UNKNOWN, // 0B04 ORIYA, // 0B05..0B0C @@ -5899,8 +6076,8 @@ class Character implements java.io.Serializable, Comparable { UNKNOWN, // 0C4E..0C54 TELUGU, // 0C55..0C56 UNKNOWN, // 0C57 - TELUGU, // 0C58..0C59 - UNKNOWN, // 0C5A..0C5F + TELUGU, // 0C58..0C5A + UNKNOWN, // 0C5B..0C5F TELUGU, // 0C60..0C63 UNKNOWN, // 0C64..0C65 TELUGU, // 0C66..0C6F @@ -5950,8 +6127,8 @@ class Character implements java.io.Serializable, Comparable { MALAYALAM, // 0D4A..0D4E UNKNOWN, // 0D4F..0D56 MALAYALAM, // 0D57 - UNKNOWN, // 0D58..0D5F - MALAYALAM, // 0D60..0D63 + UNKNOWN, // 0D58..0D5E + MALAYALAM, // 0D5F..0D63 UNKNOWN, // 0D64..0D65 MALAYALAM, // 0D66..0D75 UNKNOWN, // 0D76..0D78 @@ -6083,8 +6260,10 @@ class Character implements java.io.Serializable, Comparable { UNKNOWN, // 137D..137F ETHIOPIC, // 1380..1399 UNKNOWN, // 139A..139F - CHEROKEE, // 13A0..13F4 - UNKNOWN, // 13F5..13FF + CHEROKEE, // 13A0..13F5 + UNKNOWN, // 13F6..13F7 + CHEROKEE, // 13F8..13FD + UNKNOWN, // 13FE..13FF CANADIAN_ABORIGINAL, // 1400..167F OGHAM, // 1680..169C UNKNOWN, // 169D..169F @@ -6253,8 +6432,8 @@ class Character implements java.io.Serializable, Comparable { UNKNOWN, // 208F LATIN, // 2090..209C UNKNOWN, // 209D..209F - COMMON, // 20A0..20BD - UNKNOWN, // 20BE..20CF + COMMON, // 20A0..20BE + UNKNOWN, // 20BF..20CF INHERITED, // 20D0..20F0 UNKNOWN, // 20F1..20FF COMMON, // 2100..2125 @@ -6267,8 +6446,8 @@ class Character implements java.io.Serializable, Comparable { LATIN, // 214E COMMON, // 214F..215F LATIN, // 2160..2188 - COMMON, // 2189 - UNKNOWN, // 218A..218F + COMMON, // 2189..218B + UNKNOWN, // 218C..218F COMMON, // 2190..23FA UNKNOWN, // 23FB..23FF COMMON, // 2400..2426 @@ -6286,7 +6465,9 @@ class Character implements java.io.Serializable, Comparable { COMMON, // 2BBD..2BC8 UNKNOWN, // 2BC9 COMMON, // 2BCA..2BD1 - UNKNOWN, // 2BD2..2BFF + UNKNOWN, // 2BD2..2BEB + COMMON, // 2BEC..2BEF + UNKNOWN, // 2BF0..2BFF GLAGOLITIC, // 2C00..2C2E UNKNOWN, // 2C2F GLAGOLITIC, // 2C30..2C5E @@ -6379,8 +6560,8 @@ class Character implements java.io.Serializable, Comparable { HAN, // 3400..4DB5 UNKNOWN, // 4DB6..4DBF COMMON, // 4DC0..4DFF - HAN, // 4E00..9FCC - UNKNOWN, // 9FCD..9FFF + HAN, // 4E00..9FD5 + UNKNOWN, // 9FD6..9FFF YI, // A000..A48C UNKNOWN, // A48D..A48F YI, // A490..A4C6 @@ -6388,20 +6569,16 @@ class Character implements java.io.Serializable, Comparable { LISU, // A4D0..A4FF VAI, // A500..A62B UNKNOWN, // A62C..A63F - CYRILLIC, // A640..A69D - UNKNOWN, // A69E - CYRILLIC, // A69F + CYRILLIC, // A640..A69F BAMUM, // A6A0..A6F7 UNKNOWN, // A6F8..A6FF COMMON, // A700..A721 LATIN, // A722..A787 COMMON, // A788..A78A - LATIN, // A78B..A78E - UNKNOWN, // A78F - LATIN, // A790..A7AD + LATIN, // A78B..A7AD UNKNOWN, // A7AE..A7AF - LATIN, // A7B0..A7B1 - UNKNOWN, // A7B2..A7F6 + LATIN, // A7B0..A7B7 + UNKNOWN, // A7B8..A7F6 LATIN, // A7F7..A7FF SYLOTI_NAGRI, // A800..A82B UNKNOWN, // A82C..A82F @@ -6413,8 +6590,8 @@ class Character implements java.io.Serializable, Comparable { UNKNOWN, // A8C5..A8CD SAURASHTRA, // A8CE..A8D9 UNKNOWN, // A8DA..A8DF - DEVANAGARI, // A8E0..A8FB - UNKNOWN, // A8FC..A8FF + DEVANAGARI, // A8E0..A8FD + UNKNOWN, // A8FE..A8FF KAYAH_LI, // A900..A92D COMMON, // A92E KAYAH_LI, // A92F @@ -6456,11 +6633,10 @@ class Character implements java.io.Serializable, Comparable { UNKNOWN, // AB2F LATIN, // AB30..AB5A COMMON, // AB5B - LATIN, // AB5C..AB5F - UNKNOWN, // AB60..AB63 - LATIN, // AB64 + LATIN, // AB5C..AB64 GREEK, // AB65 - UNKNOWN, // AB66..ABBF + UNKNOWN, // AB66..AB6F + CHEROKEE, // AB70..ABBF MEETEI_MAYEK, // ABC0..ABED UNKNOWN, // ABEE..ABEF MEETEI_MAYEK, // ABF0..ABF9 @@ -6505,7 +6681,7 @@ class Character implements java.io.Serializable, Comparable { COMMON, // FE10..FE19 UNKNOWN, // FE1A..FE1F INHERITED, // FE20..FE2D - UNKNOWN, // FE2E..FE2F + CYRILLIC, // FE2E..FE2F COMMON, // FE30..FE52 UNKNOWN, // FE53 COMMON, // FE54..FE66 @@ -6627,7 +6803,12 @@ class Character implements java.io.Serializable, Comparable { NABATAEAN, // 10880..1089E UNKNOWN, // 1089F..108A6 NABATAEAN, // 108A7..108AF - UNKNOWN, // 108B0..108FF + UNKNOWN, // 108B0..108DF + HATRAN, // 108E0..108F2 + UNKNOWN, // 108F3 + HATRAN, // 108F4..108F5 + UNKNOWN, // 108F6..108FA + HATRAN, // 108FB..108FF PHOENICIAN, // 10900..1091B UNKNOWN, // 1091C..1091E PHOENICIAN, // 1091F @@ -6637,9 +6818,10 @@ class Character implements java.io.Serializable, Comparable { UNKNOWN, // 10940..1097F MEROITIC_HIEROGLYPHS, // 10980..1099F MEROITIC_CURSIVE, // 109A0..109B7 - UNKNOWN, // 109B8..109BD - MEROITIC_CURSIVE, // 109BE..109BF - UNKNOWN, // 109C0..109FF + UNKNOWN, // 109B8..109BB + MEROITIC_CURSIVE, // 109BC..109CF + UNKNOWN, // 109D0..109D1 + MEROITIC_CURSIVE, // 109D2..109FF KHAROSHTHI, // 10A00..10A03 UNKNOWN, // 10A04 KHAROSHTHI, // 10A05..10A06 @@ -6679,7 +6861,13 @@ class Character implements java.io.Serializable, Comparable { PSALTER_PAHLAVI, // 10BA9..10BAF UNKNOWN, // 10BB0..10BFF OLD_TURKIC, // 10C00..10C48 - UNKNOWN, // 10C49..10E5F + UNKNOWN, // 10C49..10C7F + OLD_HUNGARIAN, // 10C80..10CB2 + UNKNOWN, // 10CB3..10CBF + OLD_HUNGARIAN, // 10CC0..10CF2 + UNKNOWN, // 10CF3..10CF9 + OLD_HUNGARIAN, // 10CFA..10CFF + UNKNOWN, // 10D00..10E5F ARABIC, // 10E60..10E7E UNKNOWN, // 10E7F..10FFF BRAHMI, // 11000..1104D @@ -6699,23 +6887,31 @@ class Character implements java.io.Serializable, Comparable { UNKNOWN, // 11144..1114F MAHAJANI, // 11150..11176 UNKNOWN, // 11177..1117F - SHARADA, // 11180..111C8 - UNKNOWN, // 111C9..111CC - SHARADA, // 111CD + SHARADA, // 11180..111CD UNKNOWN, // 111CE..111CF - SHARADA, // 111D0..111DA - UNKNOWN, // 111DB..111E0 + SHARADA, // 111D0..111DF + UNKNOWN, // 111E0 SINHALA, // 111E1..111F4 UNKNOWN, // 111F5..111FF KHOJKI, // 11200..11211 UNKNOWN, // 11212 KHOJKI, // 11213..1123D - UNKNOWN, // 1123E..112AF + UNKNOWN, // 1123E..1127F + MULTANI, // 11280..11286 + UNKNOWN, // 11287 + MULTANI, // 11288 + UNKNOWN, // 11289 + MULTANI, // 1128A..1128D + UNKNOWN, // 1128E + MULTANI, // 1128F..1129D + UNKNOWN, // 1129E + MULTANI, // 1129F..112A9 + UNKNOWN, // 112AA..112AF KHUDAWADI, // 112B0..112EA UNKNOWN, // 112EB..112EF KHUDAWADI, // 112F0..112F9 - UNKNOWN, // 112FA..11300 - GRANTHA, // 11301..11303 + UNKNOWN, // 112FA..112FF + GRANTHA, // 11300..11303 UNKNOWN, // 11304 GRANTHA, // 11305..1130C UNKNOWN, // 1130D..1130E @@ -6734,7 +6930,9 @@ class Character implements java.io.Serializable, Comparable { GRANTHA, // 11347..11348 UNKNOWN, // 11349..1134A GRANTHA, // 1134B..1134D - UNKNOWN, // 1134E..11356 + UNKNOWN, // 1134E..1134F + GRANTHA, // 11350 + UNKNOWN, // 11351..11356 GRANTHA, // 11357 UNKNOWN, // 11358..1135C GRANTHA, // 1135D..11363 @@ -6749,8 +6947,8 @@ class Character implements java.io.Serializable, Comparable { UNKNOWN, // 114DA..1157F SIDDHAM, // 11580..115B5 UNKNOWN, // 115B6..115B7 - SIDDHAM, // 115B8..115C9 - UNKNOWN, // 115CA..115FF + SIDDHAM, // 115B8..115DD + UNKNOWN, // 115DE..115FF MODI, // 11600..11644 UNKNOWN, // 11645..1164F MODI, // 11650..11659 @@ -6758,21 +6956,31 @@ class Character implements java.io.Serializable, Comparable { TAKRI, // 11680..116B7 UNKNOWN, // 116B8..116BF TAKRI, // 116C0..116C9 - UNKNOWN, // 116CA..1189F + UNKNOWN, // 116CA..116FF + AHOM, // 11700..11719 + UNKNOWN, // 1171A..1171C + AHOM, // 1171D..1172B + UNKNOWN, // 1172C..1172F + AHOM, // 11730..1173F + UNKNOWN, // 11740..1189F WARANG_CITI, // 118A0..118F2 UNKNOWN, // 118F3..118FE WARANG_CITI, // 118FF UNKNOWN, // 11900..11ABF PAU_CIN_HAU, // 11AC0..11AF8 UNKNOWN, // 11AF9..11FFF - CUNEIFORM, // 12000..12398 - UNKNOWN, // 12399..123FF + CUNEIFORM, // 12000..12399 + UNKNOWN, // 1239A..123FF CUNEIFORM, // 12400..1246E UNKNOWN, // 1246F CUNEIFORM, // 12470..12474 - UNKNOWN, // 12475..12FFF + UNKNOWN, // 12475..1247F + CUNEIFORM, // 12480..12543 + UNKNOWN, // 12544..12FFF EGYPTIAN_HIEROGLYPHS, // 13000..1342E - UNKNOWN, // 1342F..167FF + UNKNOWN, // 1342F..143FF + ANATOLIAN_HIEROGLYPHS, // 14400..14646 + UNKNOWN, // 14647..167FF BAMUM, // 16800..16A38 UNKNOWN, // 16A39..16A3F MRO, // 16A40..16A5E @@ -6827,8 +7035,8 @@ class Character implements java.io.Serializable, Comparable { INHERITED, // 1D185..1D18B COMMON, // 1D18C..1D1A9 INHERITED, // 1D1AA..1D1AD - COMMON, // 1D1AE..1D1DD - UNKNOWN, // 1D1DE..1D1FF + COMMON, // 1D1AE..1D1E8 + UNKNOWN, // 1D1E9..1D1FF GREEK, // 1D200..1D245 UNKNOWN, // 1D246..1D2FF COMMON, // 1D300..1D356 @@ -6876,7 +7084,12 @@ class Character implements java.io.Serializable, Comparable { COMMON, // 1D6A8..1D7CB UNKNOWN, // 1D7CC..1D7CD COMMON, // 1D7CE..1D7FF - UNKNOWN, // 1D800..1E7FF + SIGNWRITING, // 1D800..1DA8B + UNKNOWN, // 1DA8C..1DA9A + SIGNWRITING, // 1DA9B..1DA9F + UNKNOWN, // 1DAA0 + SIGNWRITING, // 1DAA1..1DAAF + UNKNOWN, // 1DAB0..1E7FF MENDE_KIKAKUI, // 1E800..1E8C4 UNKNOWN, // 1E8C5..1E8C6 MENDE_KIKAKUI, // 1E8C7..1E8D6 @@ -6979,26 +7192,12 @@ class Character implements java.io.Serializable, Comparable { UNKNOWN, // 1F249..1F24F COMMON, // 1F250..1F251 UNKNOWN, // 1F252..1F2FF - COMMON, // 1F300..1F32C - UNKNOWN, // 1F32D..1F32F - COMMON, // 1F330..1F37D - UNKNOWN, // 1F37E..1F37F - COMMON, // 1F380..1F3CE - UNKNOWN, // 1F3CF..1F3D3 - COMMON, // 1F3D4..1F3F7 - UNKNOWN, // 1F3F8..1F3FF - COMMON, // 1F400..1F4FE - UNKNOWN, // 1F4FF - COMMON, // 1F500..1F54A - UNKNOWN, // 1F54B..1F54F - COMMON, // 1F550..1F579 + COMMON, // 1F300..1F579 UNKNOWN, // 1F57A COMMON, // 1F57B..1F5A3 UNKNOWN, // 1F5A4 - COMMON, // 1F5A5..1F642 - UNKNOWN, // 1F643..1F644 - COMMON, // 1F645..1F6CF - UNKNOWN, // 1F6D0..1F6DF + COMMON, // 1F5A5..1F6D0 + UNKNOWN, // 1F6D1..1F6DF COMMON, // 1F6E0..1F6EC UNKNOWN, // 1F6ED..1F6EF COMMON, // 1F6F0..1F6F3 @@ -7016,13 +7215,21 @@ class Character implements java.io.Serializable, Comparable { COMMON, // 1F860..1F887 UNKNOWN, // 1F888..1F88F COMMON, // 1F890..1F8AD - UNKNOWN, // 1F8AE..1FFFF + UNKNOWN, // 1F8AE..1F90F + COMMON, // 1F910..1F918 + UNKNOWN, // 1F919..1F97F + COMMON, // 1F980..1F984 + UNKNOWN, // 1F985..1F9BF + COMMON, // 1F9C0 + UNKNOWN, // 1F9C1..1FFFF HAN, // 20000..2A6D6 UNKNOWN, // 2A6D7..2A6FF HAN, // 2A700..2B734 UNKNOWN, // 2B735..2B73F HAN, // 2B740..2B81D - UNKNOWN, // 2B81E..2F7FF + UNKNOWN, // 2B81E..2B81F + HAN, // 2B820..2CEA1 + UNKNOWN, // 2CEA2..2F7FF HAN, // 2F800..2FA1D UNKNOWN, // 2FA1E..E0000 COMMON, // E0001 @@ -7035,8 +7242,9 @@ class Character implements java.io.Serializable, Comparable { private static HashMap aliases; static { - aliases = new HashMap<>(128); + aliases = new HashMap<>(134); aliases.put("AGHB", CAUCASIAN_ALBANIAN); + aliases.put("AHOM", AHOM); aliases.put("ARAB", ARABIC); aliases.put("ARMI", IMPERIAL_ARAMAIC); aliases.put("ARMN", ARMENIAN); @@ -7075,11 +7283,14 @@ class Character implements java.io.Serializable, Comparable { aliases.put("HANG", HANGUL); aliases.put("HANI", HAN); aliases.put("HANO", HANUNOO); + aliases.put("HATR", HATRAN); aliases.put("HEBR", HEBREW); aliases.put("HIRA", HIRAGANA); + aliases.put("HLUW", ANATOLIAN_HIEROGLYPHS); aliases.put("HMNG", PAHAWH_HMONG); // it appears we don't have the KATAKANA_OR_HIRAGANA //aliases.put("HRKT", KATAKANA_OR_HIRAGANA); + aliases.put("HUNG", OLD_HUNGARIAN); aliases.put("ITAL", OLD_ITALIC); aliases.put("JAVA", JAVANESE); aliases.put("KALI", KAYAH_LI); @@ -7110,6 +7321,7 @@ class Character implements java.io.Serializable, Comparable { aliases.put("MONG", MONGOLIAN); aliases.put("MROO", MRO); aliases.put("MTEI", MEETEI_MAYEK); + aliases.put("MULT", MULTANI); aliases.put("MYMR", MYANMAR); aliases.put("NARB", OLD_NORTH_ARABIAN); aliases.put("NBAT", NABATAEAN); @@ -7133,6 +7345,7 @@ class Character implements java.io.Serializable, Comparable { aliases.put("SAMR", SAMARITAN); aliases.put("SARB", OLD_SOUTH_ARABIAN); aliases.put("SAUR", SAURASHTRA); + aliases.put("SGNW", SIGNWRITING); aliases.put("SHAW", SHAVIAN); aliases.put("SHRD", SHARADA); aliases.put("SIDD", SIDDHAM); @@ -9356,7 +9569,7 @@ class Character implements java.io.Serializable, Comparable { * {@code FORM FEED} * {@code '\r'} {@code U+000D} * {@code CARRIAGE RETURN} - * {@code ' '} {@code U+0020} + * {@code ' '} {@code U+0020} * {@code SPACE} * * diff --git a/jdk/src/java.base/share/classes/java/lang/String.java b/jdk/src/java.base/share/classes/java/lang/String.java index dcee90e0e54..ce4262eee19 100644 --- a/jdk/src/java.base/share/classes/java/lang/String.java +++ b/jdk/src/java.base/share/classes/java/lang/String.java @@ -102,6 +102,10 @@ import jdk.internal.HotSpotIntrinsicCandidate; * Unicode code points (i.e., characters), in addition to those for * dealing with Unicode code units (i.e., {@code char} values). * + *

      Unless otherwise noted, methods for comparing Strings do not take locale + * into account. The {@link java.text.Collator} class provides methods for + * finer-grain, locale-sensitive String comparison. + * * @author Lee Boynton * @author Arthur van Hoff * @author Martin Buchholz @@ -971,6 +975,9 @@ public final class String * String} object that represents the same sequence of characters as this * object. * + *

      For finer-grained String comparison, refer to + * {@link java.text.Collator}. + * * @param anObject * The object to compare this {@code String} against * @@ -1008,6 +1015,9 @@ public final class String * sequence of characters as the specified {@code StringBuffer}. This method * synchronizes on the {@code StringBuffer}. * + *

      For finer-grained String comparison, refer to + * {@link java.text.Collator}. + * * @param sb * The {@code StringBuffer} to compare this {@code String} against * @@ -1043,6 +1053,9 @@ public final class String * {@code CharSequence} is a {@code StringBuffer} then the method * synchronizes on it. * + *

      For finer-grained String comparison, refer to + * {@link java.text.Collator}. + * * @param cs * The sequence to compare this {@code String} against * @@ -1092,14 +1105,14 @@ public final class String *

        *
      • The two characters are the same (as compared by the * {@code ==} operator) - *
      • Applying the method {@link - * java.lang.Character#toUpperCase(char)} to each character - * produces the same result - *
      • Applying the method {@link - * java.lang.Character#toLowerCase(char)} to each character - * produces the same result + *
      • Calling {@code Character.toLowerCase(Character.toUpperCase(char))} + * on each character produces the same result *
      * + *

      Note that this method does not take locale into account, and + * will result in unsatisfactory results for certain locales. The + * {@link java.text.Collator} class provides locale-sensitive comparison. + * * @param anotherString * The {@code String} to compare this {@code String} against * @@ -1150,6 +1163,9 @@ public final class String * this.length()-anotherString.length() * * + *

      For finer-grained String comparison, refer to + * {@link java.text.Collator}. + * * @param anotherString the {@code String} to be compared. * @return the value {@code 0} if the argument string is equal to * this string; a value less than {@code 0} if this string @@ -1181,10 +1197,9 @@ public final class String *

      * Note that this Comparator does not take locale into account, * and will result in an unsatisfactory ordering for certain locales. - * The java.text package provides Collators to allow - * locale-sensitive ordering. + * The {@link java.text.Collator} class provides locale-sensitive comparison. * - * @see java.text.Collator#compare(String, String) + * @see java.text.Collator * @since 1.2 */ public static final Comparator CASE_INSENSITIVE_ORDER @@ -1231,14 +1246,13 @@ public final class String *

      * Note that this method does not take locale into account, * and will result in an unsatisfactory ordering for certain locales. - * The java.text package provides collators to allow - * locale-sensitive ordering. + * The {@link java.text.Collator} class provides locale-sensitive comparison. * * @param str the {@code String} to be compared. * @return a negative integer, zero, or a positive integer as the * specified String is greater than, equal to, or less * than this String, ignoring case considerations. - * @see java.text.Collator#compare(String, String) + * @see java.text.Collator * @since 1.2 */ public int compareToIgnoreCase(String str) { @@ -1268,6 +1282,9 @@ public final class String * k{@code )} * * + *

      Note that this method does not take locale into account. The + * {@link java.text.Collator} class provides locale-sensitive comparison. + * * @param toffset the starting offset of the subregion in this string. * @param other the string argument. * @param ooffset the starting offset of the subregion in the string @@ -1323,16 +1340,16 @@ public final class String *

    • {@code ignoreCase} is {@code true} and there is some nonnegative * integer k less than {@code len} such that: *
      -     * Character.toLowerCase(this.charAt(toffset+k)) !=
      -     Character.toLowerCase(other.charAt(ooffset+k))
      -     * 
      - * and: - *
      -     * Character.toUpperCase(this.charAt(toffset+k)) !=
      -     *         Character.toUpperCase(other.charAt(ooffset+k))
      +     * Character.toLowerCase(Character.toUpperCase(this.charAt(toffset+k))) !=
      +     Character.toLowerCase(Character.toUpperCase(other.charAt(ooffset+k)))
            * 
      * * + *

      Note that this method does not take locale into account, + * and will result in unsatisfactory results for certain locales when + * {@code ignoreCase} is {@code true}. The {@link java.text.Collator} class + * provides locale-sensitive comparison. + * * @param ignoreCase if {@code true}, ignore case when comparing * characters. * @param toffset the starting offset of the subregion in this diff --git a/jdk/src/java.base/share/classes/java/lang/Throwable.java b/jdk/src/java.base/share/classes/java/lang/Throwable.java index f86ee0df424..9c694058761 100644 --- a/jdk/src/java.base/share/classes/java/lang/Throwable.java +++ b/jdk/src/java.base/share/classes/java/lang/Throwable.java @@ -211,8 +211,7 @@ public class Throwable implements Serializable { // Setting this static field introduces an acceptable // initialization dependency on a few java.util classes. - private static final List SUPPRESSED_SENTINEL = - Collections.unmodifiableList(new ArrayList(0)); + private static final List SUPPRESSED_SENTINEL = Collections.emptyList(); /** * The list of suppressed exceptions, as returned by {@link diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java index 659759b882d..b8f9c52d19f 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java @@ -404,14 +404,6 @@ import jdk.internal.org.objectweb.asm.Type; d = lookupCache(types); // Class loading must have upgraded the cache. assert(d != null && !d.isPlaceholder()); - if (OBSERVE_BMH_SPECIES_CREATION) { - if (d == null) { - throw new IllegalStateException("d == null"); - } - if (d.isPlaceholder()) { - throw new IllegalStateException("d is place holder"); - } - } return d; } static SpeciesData getForClass(String types, Class clazz) { @@ -423,9 +415,6 @@ import jdk.internal.org.objectweb.asm.Type; if (d != null) return d; d = new SpeciesData(types); assert(d.isPlaceholder()); - if (OBSERVE_BMH_SPECIES_CREATION && !d.isPlaceholder()) { - throw new IllegalStateException("d is not place holder"); - } CACHE.put(types, d); return d; } @@ -433,15 +422,6 @@ import jdk.internal.org.objectweb.asm.Type; SpeciesData d2; assert((d2 = CACHE.get(types)) == null || d2.isPlaceholder()); assert(!d.isPlaceholder()); - if (OBSERVE_BMH_SPECIES_CREATION) { - d2 = CACHE.get(types); - if (d2 != null && !d2.isPlaceholder()) { - throw new IllegalStateException("non-null d2 is not place holder"); - } - if (d.isPlaceholder()) { - throw new IllegalStateException("d is place holder"); - } - } CACHE.put(types, d); return d; } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java index 3b10ea08b0b..aae6053acf2 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java @@ -51,12 +51,8 @@ import sun.misc.Unsafe; static final boolean PROFILE_GWT; static final int CUSTOMIZE_THRESHOLD; - // This is a temporary property added for improved error reporting; it will - // be removed once it has served its purpose. - static final boolean OBSERVE_BMH_SPECIES_CREATION; - static { - final Object[] values = new Object[10]; + final Object[] values = new Object[9]; AccessController.doPrivileged(new PrivilegedAction<>() { public Void run() { values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); @@ -68,7 +64,6 @@ import sun.misc.Unsafe; values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0); values[7] = Boolean.parseBoolean(System.getProperty("java.lang.invoke.MethodHandle.PROFILE_GWT", "true")); values[8] = Integer.getInteger("java.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD", 127); - values[9] = Boolean.getBoolean("java.lang.invoke.MethodHandle.OBSERVE_BMH_SPECIES_CREATION"); return null; } }); @@ -82,8 +77,6 @@ import sun.misc.Unsafe; PROFILE_GWT = (Boolean) values[7]; CUSTOMIZE_THRESHOLD = (Integer) values[8]; - OBSERVE_BMH_SPECIES_CREATION = (Boolean) values[9]; - if (CUSTOMIZE_THRESHOLD < -1 || CUSTOMIZE_THRESHOLD > 127) { throw newInternalError("CUSTOMIZE_THRESHOLD should be in [-1...127] range"); } diff --git a/jdk/src/java.base/share/classes/java/net/Inet4Address.java b/jdk/src/java.base/share/classes/java/net/Inet4Address.java index 6b0f765cd0e..1a2f7b6166b 100644 --- a/jdk/src/java.base/share/classes/java/net/Inet4Address.java +++ b/jdk/src/java.base/share/classes/java/net/Inet4Address.java @@ -117,11 +117,13 @@ class Inet4Address extends InetAddress { holder().address = address; } } + holder().originalHostName = hostName; } Inet4Address(String hostName, int address) { holder().hostName = hostName; holder().family = IPv4; holder().address = address; + holder().originalHostName = hostName; } /** diff --git a/jdk/src/java.base/share/classes/java/net/InetAddress.java b/jdk/src/java.base/share/classes/java/net/InetAddress.java index 936a2d65414..a2d89b25d31 100644 --- a/jdk/src/java.base/share/classes/java/net/InetAddress.java +++ b/jdk/src/java.base/share/classes/java/net/InetAddress.java @@ -221,7 +221,7 @@ class InetAddress implements java.io.Serializable { * * Note: May define a new public method in the future if necessary. */ - private String originalHostName; + String originalHostName; InetAddressHolder() {} diff --git a/jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template b/jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template index 8ef6b8d0841..cf2cc29c864 100644 --- a/jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template +++ b/jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template @@ -242,7 +242,7 @@ class Direct$Type$Buffer$RW$$BO$ } private long ix(int i) { - return address + (i << $LG_BYTES_PER_VALUE$); + return address + ((long)i << $LG_BYTES_PER_VALUE$); } public $type$ get() { @@ -261,7 +261,7 @@ class Direct$Type$Buffer$RW$$BO$ public $Type$Buffer get($type$[] dst, int offset, int length) { #if[rw] - if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) { + if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) { checkBounds(offset, length, dst.length); int pos = position(); int lim = limit(); @@ -273,13 +273,13 @@ class Direct$Type$Buffer$RW$$BO$ #if[!byte] if (order() != ByteOrder.nativeOrder()) Bits.copyTo$Memtype$Array(ix(pos), dst, - offset << $LG_BYTES_PER_VALUE$, - length << $LG_BYTES_PER_VALUE$); + (long)offset << $LG_BYTES_PER_VALUE$, + (long)length << $LG_BYTES_PER_VALUE$); else #end[!byte] Bits.copyToArray(ix(pos), dst, arrayBaseOffset, - offset << $LG_BYTES_PER_VALUE$, - length << $LG_BYTES_PER_VALUE$); + (long)offset << $LG_BYTES_PER_VALUE$, + (long)length << $LG_BYTES_PER_VALUE$); position(pos + length); } else { super.get(dst, offset, length); @@ -329,7 +329,7 @@ class Direct$Type$Buffer$RW$$BO$ if (srem > rem) throw new BufferOverflowException(); - unsafe.copyMemory(sb.ix(spos), ix(pos), srem << $LG_BYTES_PER_VALUE$); + unsafe.copyMemory(sb.ix(spos), ix(pos), (long)srem << $LG_BYTES_PER_VALUE$); sb.position(spos + srem); position(pos + srem); } else if (src.hb != null) { @@ -353,7 +353,7 @@ class Direct$Type$Buffer$RW$$BO$ public $Type$Buffer put($type$[] src, int offset, int length) { #if[rw] - if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) { + if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) { checkBounds(offset, length, src.length); int pos = position(); int lim = limit(); @@ -364,12 +364,16 @@ class Direct$Type$Buffer$RW$$BO$ #if[!byte] if (order() != ByteOrder.nativeOrder()) - Bits.copyFrom$Memtype$Array(src, offset << $LG_BYTES_PER_VALUE$, - ix(pos), length << $LG_BYTES_PER_VALUE$); + Bits.copyFrom$Memtype$Array(src, + (long)offset << $LG_BYTES_PER_VALUE$, + ix(pos), + (long)length << $LG_BYTES_PER_VALUE$); else #end[!byte] - Bits.copyFromArray(src, arrayBaseOffset, offset << $LG_BYTES_PER_VALUE$, - ix(pos), length << $LG_BYTES_PER_VALUE$); + Bits.copyFromArray(src, arrayBaseOffset, + (long)offset << $LG_BYTES_PER_VALUE$, + ix(pos), + (long)length << $LG_BYTES_PER_VALUE$); position(pos + length); } else { super.put(src, offset, length); @@ -387,7 +391,7 @@ class Direct$Type$Buffer$RW$$BO$ assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); - unsafe.copyMemory(ix(pos), ix(0), rem << $LG_BYTES_PER_VALUE$); + unsafe.copyMemory(ix(pos), ix(0), (long)rem << $LG_BYTES_PER_VALUE$); position(rem); limit(capacity()); discardMark(); diff --git a/jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java b/jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java index 5c03453d8fd..36b2a65cbfa 100644 --- a/jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java +++ b/jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java @@ -138,6 +138,13 @@ public class AlgorithmParameterGenerator { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param algorithm the name of the algorithm this * parameter generator is associated with. * See the AlgorithmParameterGenerator section in the diff --git a/jdk/src/java.base/share/classes/java/security/KeyFactory.java b/jdk/src/java.base/share/classes/java/security/KeyFactory.java index 8e761ff41f7..76076cea2f2 100644 --- a/jdk/src/java.base/share/classes/java/security/KeyFactory.java +++ b/jdk/src/java.base/share/classes/java/security/KeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,6 +153,13 @@ public class KeyFactory { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param algorithm the name of the requested key algorithm. * See the KeyFactory section in the diff --git a/jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java b/jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java index 277231b568d..246f140b435 100644 --- a/jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java +++ b/jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java @@ -195,6 +195,13 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param algorithm the standard string name of the algorithm. * See the KeyPairGenerator section in the diff --git a/jdk/src/java.base/share/classes/java/security/KeyStore.java b/jdk/src/java.base/share/classes/java/security/KeyStore.java index 6ab121ea629..40df29cdd6c 100644 --- a/jdk/src/java.base/share/classes/java/security/KeyStore.java +++ b/jdk/src/java.base/share/classes/java/security/KeyStore.java @@ -841,6 +841,13 @@ public class KeyStore { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param type the type of keystore. * See the KeyStore section in the diff --git a/jdk/src/java.base/share/classes/java/security/MessageDigest.java b/jdk/src/java.base/share/classes/java/security/MessageDigest.java index 5a58f0997d0..0892140c581 100644 --- a/jdk/src/java.base/share/classes/java/security/MessageDigest.java +++ b/jdk/src/java.base/share/classes/java/security/MessageDigest.java @@ -146,6 +146,13 @@ public abstract class MessageDigest extends MessageDigestSpi { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param algorithm the name of the algorithm requested. * See the MessageDigest section in the diff --git a/jdk/src/java.base/share/classes/java/security/Policy.java b/jdk/src/java.base/share/classes/java/security/Policy.java index 1351ed7db10..9d02d76f8d8 100644 --- a/jdk/src/java.base/share/classes/java/security/Policy.java +++ b/jdk/src/java.base/share/classes/java/security/Policy.java @@ -355,6 +355,13 @@ public abstract class Policy { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param type the specified Policy type. See the Policy section in the * diff --git a/jdk/src/java.base/share/classes/java/security/SecureRandom.java b/jdk/src/java.base/share/classes/java/security/SecureRandom.java index feae08b90c9..2f8d734ac00 100644 --- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java +++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -268,6 +268,13 @@ public class SecureRandom extends java.util.Random { * This self-seeding will not occur if {@code setSeed} was * previously called. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param algorithm the name of the RNG algorithm. * See the SecureRandom section in the diff --git a/jdk/src/java.base/share/classes/java/security/Signature.java b/jdk/src/java.base/share/classes/java/security/Signature.java index 75e318c8b94..73fb85c8566 100644 --- a/jdk/src/java.base/share/classes/java/security/Signature.java +++ b/jdk/src/java.base/share/classes/java/security/Signature.java @@ -203,6 +203,13 @@ public abstract class Signature extends SignatureSpi { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param algorithm the standard name of the algorithm requested. * See the Signature section in the diff --git a/jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java b/jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java index 307cbec4924..8cd1ec09d0c 100644 --- a/jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java +++ b/jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -142,6 +142,13 @@ public class CertPathBuilder { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param algorithm the name of the requested {@code CertPathBuilder} * algorithm. See the CertPathBuilder section in the diff --git a/jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java b/jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java index 857fa2faa8c..3a22c37cb04 100644 --- a/jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java +++ b/jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,6 +143,13 @@ public class CertPathValidator { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param algorithm the name of the requested {@code CertPathValidator} * algorithm. See the CertPathValidator section in the diff --git a/jdk/src/java.base/share/classes/java/security/cert/CertStore.java b/jdk/src/java.base/share/classes/java/security/cert/CertStore.java index 79835d8ba3b..cb281633929 100644 --- a/jdk/src/java.base/share/classes/java/security/cert/CertStore.java +++ b/jdk/src/java.base/share/classes/java/security/cert/CertStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -201,6 +201,13 @@ public class CertStore { * Note that the specified {@code CertStoreParameters} object is * cloned. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param type the name of the requested {@code CertStore} type. * See the CertStore section in the diff --git a/jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java b/jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java index f45866d1b74..735c2df21fc 100644 --- a/jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java +++ b/jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -163,6 +163,13 @@ public class CertificateFactory { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param type the name of the requested certificate type. * See the CertificateFactory section in the diff --git a/jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index d64fa567e6b..6727197ef81 100644 --- a/jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -384,6 +384,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { */ public String getCurrencySymbol() { + initializeCurrency(locale); return currencySymbol; } @@ -396,6 +397,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { */ public void setCurrencySymbol(String currency) { + initializeCurrency(locale); currencySymbol = currency; } @@ -408,6 +410,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { */ public String getInternationalCurrencySymbol() { + initializeCurrency(locale); return intlCurrencySymbol; } @@ -429,6 +432,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { */ public void setInternationalCurrencySymbol(String currencyCode) { + initializeCurrency(locale); intlCurrencySymbol = currencyCode; currency = null; if (currencyCode != null) { @@ -449,6 +453,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { * @since 1.4 */ public Currency getCurrency() { + initializeCurrency(locale); return currency; } @@ -468,6 +473,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { if (currency == null) { throw new NullPointerException(); } + initializeCurrency(locale); this.currency = currency; intlCurrencySymbol = currency.getCurrencyCode(); currencySymbol = currency.getSymbol(locale); @@ -507,14 +513,15 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { { return exponential; } - /** - * Returns the string used to separate the mantissa from the exponent. - * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. - * - * @return the exponent separator string - * @see #setExponentSeparator(java.lang.String) - * @since 1.6 - */ + + /** + * Returns the string used to separate the mantissa from the exponent. + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. + * + * @return the exponent separator string + * @see #setExponentSeparator(java.lang.String) + * @since 1.6 + */ public String getExponentSeparator() { return exponentialSeparator; @@ -528,22 +535,22 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { exponential = exp; } - /** - * Sets the string used to separate the mantissa from the exponent. - * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. - * - * @param exp the exponent separator string - * @exception NullPointerException if exp is null - * @see #getExponentSeparator() - * @since 1.6 - */ + /** + * Sets the string used to separate the mantissa from the exponent. + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. + * + * @param exp the exponent separator string + * @exception NullPointerException if exp is null + * @see #getExponentSeparator() + * @since 1.6 + */ public void setExponentSeparator(String exp) { if (exp == null) { throw new NullPointerException(); } exponentialSeparator = exp; - } + } //------------------------------------------------------------ @@ -582,7 +589,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { patternSeparator == other.patternSeparator && infinity.equals(other.infinity) && NaN.equals(other.NaN) && - currencySymbol.equals(other.currencySymbol) && + getCurrencySymbol().equals(other.getCurrencySymbol()) && // possible currency init occurs here intlCurrencySymbol.equals(other.intlCurrencySymbol) && currency == other.currency && monetarySeparator == other.monetarySeparator && @@ -629,6 +636,24 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { infinity = numberElements[9]; NaN = numberElements[10]; + // maybe filled with previously cached values, or null. + intlCurrencySymbol = (String) data[1]; + currencySymbol = (String) data[2]; + + // Currently the monetary decimal separator is the same as the + // standard decimal separator for all locales that we support. + // If that changes, add a new entry to NumberElements. + monetarySeparator = decimalSeparator; + } + + /** + * Lazy initialization for currency related fields + */ + private void initializeCurrency(Locale locale) { + if (currencyInitialized) { + return; + } + // Try to obtain the currency used in the locale's country. // Check for empty country string separately because it's a valid // country ID for Locale (and used for the C locale), but not a valid @@ -640,7 +665,16 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { // use default values below for compatibility } } + if (currency != null) { + // get resource bundle data + LocaleProviderAdapter adapter = + LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale); + // Avoid potential recursions + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); + } + Object[] data = adapter.getLocaleResources(locale).getDecimalFormatSymbolsData(); intlCurrencySymbol = currency.getCurrencyCode(); if (data[1] != null && data[1] == intlCurrencySymbol) { currencySymbol = (String) data[2]; @@ -658,10 +692,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { } currencySymbol = "\u00A4"; } - // Currently the monetary decimal separator is the same as the - // standard decimal separator for all locales that we support. - // If that changes, add a new entry to NumberElements. - monetarySeparator = decimalSeparator; + + currencyInitialized = true; } /** @@ -705,6 +737,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { currency = Currency.getInstance(intlCurrencySymbol); } catch (IllegalArgumentException e) { } + currencyInitialized = true; } } @@ -820,16 +853,16 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { */ private char exponential; // Field new in JDK 1.1.6 - /** - * The string used to separate the mantissa from the exponent. - * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. - *

      - * If both exponential and exponentialSeparator - * exist, this exponentialSeparator has the precedence. - * - * @serial - * @since 1.6 - */ + /** + * The string used to separate the mantissa from the exponent. + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. + *

      + * If both exponential and exponentialSeparator + * exist, this exponentialSeparator has the precedence. + * + * @serial + * @since 1.6 + */ private String exponentialSeparator; // Field new in JDK 1.6 /** @@ -842,6 +875,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { // currency; only the ISO code is serialized. private transient Currency currency; + private transient volatile boolean currencyInitialized = false; // Proclaim JDK 1.1 FCS compatibility static final long serialVersionUID = 5772796243397350300L; diff --git a/jdk/src/java.base/share/classes/java/time/Instant.java b/jdk/src/java.base/share/classes/java/time/Instant.java index 9b9efa582a7..f49c3b7a506 100644 --- a/jdk/src/java.base/share/classes/java/time/Instant.java +++ b/jdk/src/java.base/share/classes/java/time/Instant.java @@ -758,7 +758,7 @@ public final class Instant throw new UnsupportedTemporalTypeException("Unit must divide into a standard day without remainder"); } long nod = (seconds % LocalTime.SECONDS_PER_DAY) * LocalTime.NANOS_PER_SECOND + nanos; - long result = (nod / dur) * dur; + long result = Math.floorDiv(nod, dur) * dur ; return plusNanos(result - nod); } diff --git a/jdk/src/java.base/share/classes/java/util/Objects.java b/jdk/src/java.base/share/classes/java/util/Objects.java index 0d8d9e16833..65089553b87 100644 --- a/jdk/src/java.base/share/classes/java/util/Objects.java +++ b/jdk/src/java.base/share/classes/java/util/Objects.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -281,6 +281,43 @@ public final class Objects { return obj != null; } + /** + * Returns the first argument if it is non-{@code null} and + * otherwise returns the non-{@code null} second argument. + * + * @param obj an object + * @param defaultObj a non-{@code null} object to return if the first argument + * is {@code null} + * @param the type of the reference + * @return the first argument if it is non-{@code null} and + * otherwise the second argument if it is non-{@code null} + * @throws NullPointerException if both {@code obj} is null and + * {@code defaultObj} is {@code null} + * @since 9 + */ + public static T nonNullElse(T obj, T defaultObj) { + return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj"); + } + + /** + * Returns the first argument if it is non-{@code null} and otherwise + * returns the non-{@code null} value of {@code supplier.get()}. + * + * @param obj an object + * @param supplier of a non-{@code null} object to return if the first argument + * is {@code null} + * @param the type of the first argument and return type + * @return the first argument if it is non-{@code null} and otherwise + * the value from {@code supplier.get()} if it is non-{@code null} + * @throws NullPointerException if both {@code obj} is null and + * either the {@code supplier} is {@code null} or + * the {@code supplier.get()} value is {@code null} + * @since 9 + */ + public static T nonNullElseGet(T obj, Supplier supplier) { + return (obj != null) ? obj : requireNonNull(requireNonNull(supplier, "supplier").get(), "supplier.get()"); + } + /** * Checks that the specified object reference is not {@code null} and * throws a customized {@link NullPointerException} if it is. diff --git a/jdk/src/java.base/share/classes/java/util/Optional.java b/jdk/src/java.base/share/classes/java/util/Optional.java index cc5c1309663..514632b5ccc 100644 --- a/jdk/src/java.base/share/classes/java/util/Optional.java +++ b/jdk/src/java.base/share/classes/java/util/Optional.java @@ -31,21 +31,22 @@ import java.util.function.Supplier; import java.util.stream.Stream; /** - * A container object which may or may not contain a non-null value. - * If a value is present, {@code isPresent()} will return {@code true} and - * {@code get()} will return the value. + * A container object which may or may not contain a non-{@code null} value. + * If a value is present, {@code isPresent()} returns {@code true} and + * {@code get()} returns the value. * *

      Additional methods that depend on the presence or absence of a contained * value are provided, such as {@link #orElse(java.lang.Object) orElse()} - * (return a default value if value not present) and - * {@link #ifPresent(java.util.function.Consumer) ifPresent()} (perform an - * action if the value is present). + * (returns a default value if no value is present) and + * {@link #ifPresent(java.util.function.Consumer) ifPresent()} (performs an + * action if a value is present). * *

      This is a value-based * class; use of identity-sensitive operations (including reference equality * ({@code ==}), identity hash code, or synchronization) on instances of * {@code Optional} may have unpredictable results and should be avoided. * + * @param the type of value * @since 1.8 */ public final class Optional { @@ -71,14 +72,15 @@ public final class Optional { /** * Returns an empty {@code Optional} instance. No value is present for this - * Optional. + * {@code Optional}. * - * @apiNote Though it may be tempting to do so, avoid testing if an object - * is empty by comparing with {@code ==} against instances returned by - * {@code Option.empty()}. There is no guarantee that it is a singleton. + * @apiNote + * Though it may be tempting to do so, avoid testing if an object is empty + * by comparing with {@code ==} against instances returned by + * {@code Optional.empty()}. There is no guarantee that it is a singleton. * Instead, use {@link #isPresent()}. * - * @param Type of the non-existent value + * @param The type of the non-existent value * @return an empty {@code Optional} */ public static Optional empty() { @@ -88,47 +90,47 @@ public final class Optional { } /** - * Constructs an instance with the value present. + * Constructs an instance with the described value. * - * @param value the non-null value to be present - * @throws NullPointerException if value is null + * @param value the non-{@code null} value to describe + * @throws NullPointerException if value is {@code null} */ private Optional(T value) { this.value = Objects.requireNonNull(value); } /** - * Returns an {@code Optional} with the specified present non-null value. + * Returns an {@code Optional} describing the given non-{@code null} + * value. * - * @param the class of the value - * @param value the value to be present, which must be non-null + * @param value the value to describe, which must be non-{@code null} + * @param the type of the value * @return an {@code Optional} with the value present - * @throws NullPointerException if value is null + * @throws NullPointerException if value is {@code null} */ public static Optional of(T value) { return new Optional<>(value); } /** - * Returns an {@code Optional} describing the specified value, if non-null, - * otherwise returns an empty {@code Optional}. + * Returns an {@code Optional} describing the given value, if + * non-{@code null}, otherwise returns an empty {@code Optional}. * - * @param the class of the value - * @param value the possibly-null value to describe + * @param value the possibly-{@code null} value to describe + * @param the type of the value * @return an {@code Optional} with a present value if the specified value - * is non-null, otherwise an empty {@code Optional} + * is non-{@code null}, otherwise an empty {@code Optional} */ public static Optional ofNullable(T value) { return value == null ? empty() : of(value); } /** - * If a value is present in this {@code Optional}, returns the value, - * otherwise throws {@code NoSuchElementException}. - * - * @return the non-null value held by this {@code Optional} - * @throws NoSuchElementException if there is no value present + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * + * @return the non-{@code null} value described by this {@code Optional} + * @throws NoSuchElementException if no value is present * @see Optional#isPresent() */ public T get() { @@ -139,21 +141,21 @@ public final class Optional { } /** - * Return {@code true} if there is a value present, otherwise {@code false}. + * If a value is present, returns {@code true}, otherwise {@code false}. * - * @return {@code true} if there is a value present, otherwise {@code false} + * @return {@code true} if a value is present, otherwise {@code false} */ public boolean isPresent() { return value != null; } /** - * If a value is present, perform the given action with the value, - * otherwise do nothing. + * If a value is present, performs the given action with the value, + * otherwise does nothing. * - * @param action the action to be performed if a value is present - * @throws NullPointerException if a value is present and {@code action} is - * null + * @param action the action to be performed, if a value is present + * @throws NullPointerException if value is present and the given action is + * {@code null} */ public void ifPresent(Consumer action) { if (value != null) { @@ -162,15 +164,16 @@ public final class Optional { } /** - * If a value is present, perform the given action with the value, - * otherwise perform the given empty-based action. + * If a value is present, performs the given action with the value, + * otherwise performs the given empty-based action. * - * @param action the action to be performed if a value is present - * @param emptyAction the empty-based action to be performed if a value is - * not present - * @throws NullPointerException if a value is present and {@code action} is - * null, or a value is not present and {@code emptyAction} is null. - * @since 1.9 + * @param action the action to be performed, if a value is present + * @param emptyAction the empty-based action to be performed, if no value is + * present + * @throws NullPointerException if a value is present and the given action + * is {@code null}, or no value is present and the given empty-based + * action is {@code null}. + * @since 9 */ public void ifPresentOrElse(Consumer action, Runnable emptyAction) { if (value != null) { @@ -182,14 +185,14 @@ public final class Optional { /** * If a value is present, and the value matches the given predicate, - * return an {@code Optional} describing the value, otherwise return an + * returns an {@code Optional} describing the value, otherwise returns an * empty {@code Optional}. * - * @param predicate a predicate to apply to the value, if present - * @return an {@code Optional} describing the value of this {@code Optional} - * if a value is present and the value matches the given predicate, - * otherwise an empty {@code Optional} - * @throws NullPointerException if the predicate is null + * @param predicate the predicate to apply to a value, if present + * @return an {@code Optional} describing the value of this + * {@code Optional}, if a value is present and the value matches the + * given predicate, otherwise an empty {@code Optional} + * @throws NullPointerException if the predicate is {@code null} */ public Optional filter(Predicate predicate) { Objects.requireNonNull(predicate); @@ -201,14 +204,18 @@ public final class Optional { } /** - * If a value is present, apply the provided mapping function to it, - * and if the result is non-null, return an {@code Optional} describing the - * result. Otherwise return an empty {@code Optional}. + * If a value is present, returns an {@code Optional} describing (as if by + * {@link #ofNullable}) the result of applying the given mapping function to + * the value, otherwise returns an empty {@code Optional}. * - * @apiNote This method supports post-processing on optional values, without + *

      If the mapping function returns a {@code null} result then this method + * returns an empty {@code Optional}. + * + * @apiNote + * This method supports post-processing on {@code Optional} values, without * the need to explicitly check for a return status. For example, the - * following code traverses a stream of file names, selects one that has - * not yet been processed, and then opens that file, returning an + * following code traverses a stream of file names, selects one that has not + * yet been processed, and then opens that file, returning an * {@code Optional}: * *

      {@code
      @@ -222,12 +229,12 @@ public final class Optional {
            * {@code map} returns an {@code Optional} for the desired
            * file if one exists.
            *
      -     * @param  The type of the result of the mapping function
      -     * @param mapper a mapping function to apply to the value, if present
      +     * @param mapper the mapping function to apply to a value, if present
      +     * @param  The type of the value returned from the mapping function
            * @return an {@code Optional} describing the result of applying a mapping
      -     * function to the value of this {@code Optional}, if a value is present,
      -     * otherwise an empty {@code Optional}
      -     * @throws NullPointerException if the mapping function is null
      +     *         function to the value of this {@code Optional}, if a value is
      +     *         present, otherwise an empty {@code Optional}
      +     * @throws NullPointerException if the mapping function is {@code null}
            */
           public Optional map(Function mapper) {
               Objects.requireNonNull(mapper);
      @@ -239,21 +246,23 @@ public final class Optional {
           }
       
           /**
      -     * If a value is present, apply the provided {@code Optional}-bearing
      -     * mapping function to it, return that result, otherwise return an empty
      -     * {@code Optional}.  This method is similar to {@link #map(Function)},
      -     * but the provided mapper is one whose result is already an {@code Optional},
      -     * and if invoked, {@code flatMap} does not wrap it with an additional
      +     * If a value is present, returns the result of applying the given
      +     * {@code Optional}-bearing mapping function to the value, otherwise returns
      +     * an empty {@code Optional}.
      +     *
      +     * 

      This method is similar to {@link #map(Function)}, but the mapping + * function is one whose result is already an {@code Optional}, and if + * invoked, {@code flatMap} does not wrap it within an additional * {@code Optional}. * - * @param The type parameter to the {@code Optional} returned by - * @param mapper a mapping function to apply to the value, if present - * the mapping function + * @param The type of value of the {@code Optional} returned by the + * mapping function + * @param mapper the mapping function to apply to a value, if present * @return the result of applying an {@code Optional}-bearing mapping - * function to the value of this {@code Optional}, if a value is present, - * otherwise an empty {@code Optional} - * @throws NullPointerException if the mapping function is null or returns - * a null result + * function to the value of this {@code Optional}, if a value is + * present, otherwise an empty {@code Optional} + * @throws NullPointerException if the mapping function is {@code null} or + * returns a {@code null} result */ public Optional flatMap(Function> mapper) { Objects.requireNonNull(mapper); @@ -265,19 +274,41 @@ public final class Optional { } /** - * If a value is present return a sequential {@link Stream} containing only - * that value, otherwise return an empty {@code Stream}. + * If a value is present, returns an {@code Optional} describing the value, + * otherwise returns an {@code Optional} produced by the supplying function. * - * @apiNote This method can be used to transform a {@code Stream} of - * optional elements to a {@code Stream} of present value elements: + * @param supplier the supplying function that produces an {@code Optional} + * to be returned + * @return returns an {@code Optional} describing the value of this + * {@code Optional}, if a value is present, otherwise an + * {@code Optional} produced by the supplying function. + * @throws NullPointerException if the supplying function is {@code null} or + * produces a {@code null} result + * @since 9 + */ + public Optional or(Supplier> supplier) { + Objects.requireNonNull(supplier); + if (isPresent()) { + return this; + } else { + return Objects.requireNonNull(supplier.get()); + } + } + + /** + * If a value is present, returns a sequential {@link Stream} containing + * only that value, otherwise returns an empty {@code Stream}. * + * @apiNote + * This method can be used to transform a {@code Stream} of optional + * elements to a {@code Stream} of present value elements: *

      {@code
            *     Stream> os = ..
            *     Stream s = os.flatMap(Optional::stream)
            * }
      * * @return the optional value as a {@code Stream} - * @since 1.9 + * @since 9 */ public Stream stream() { if (!isPresent()) { @@ -288,10 +319,11 @@ public final class Optional { } /** - * Return the value if present, otherwise return {@code other}. + * If a value is present, returns the value, otherwise returns + * {@code other}. * - * @param other the value to be returned if there is no value present, may - * be null + * @param other the value to be returned, if no value is present. + * May be {@code null}. * @return the value, if present, otherwise {@code other} */ public T orElse(T other) { @@ -299,34 +331,35 @@ public final class Optional { } /** - * Return the value if present, otherwise invoke {@code other} and return - * the result of that invocation. + * If a value is present, returns the value, otherwise returns the result + * produced by the supplying function. * - * @param other a {@code Supplier} whose result is returned if no value - * is present - * @return the value if present otherwise the result of {@code other.get()} - * @throws NullPointerException if value is not present and {@code other} is - * null + * @param supplier the supplying function that produces a value to be returned + * @return the value, if present, otherwise the result produced by the + * supplying function + * @throws NullPointerException if no value is present and the supplying + * function is {@code null} */ - public T orElseGet(Supplier other) { - return value != null ? value : other.get(); + public T orElseGet(Supplier supplier) { + return value != null ? value : supplier.get(); } /** - * Return the contained value, if present, otherwise throw an exception - * to be created by the provided supplier. + * If a value is present, returns the value, otherwise throws an exception + * produced by the exception supplying function. * - * @apiNote A method reference to the exception constructor with an empty - * argument list can be used as the supplier. For example, + * @apiNote + * A method reference to the exception constructor with an empty argument + * list can be used as the supplier. For example, * {@code IllegalStateException::new} * * @param Type of the exception to be thrown - * @param exceptionSupplier The supplier which will return the exception to - * be thrown - * @return the present value - * @throws X if there is no value present - * @throws NullPointerException if no value is present and - * {@code exceptionSupplier} is null + * @param exceptionSupplier the supplying function that produces an + * exception to be thrown + * @return the value, if present + * @throws X if no value is present + * @throws NullPointerException if no value is present and the exception + * supplying function is {@code null} */ public T orElseThrow(Supplier exceptionSupplier) throws X { if (value != null) { @@ -337,8 +370,8 @@ public final class Optional { } /** - * Indicates whether some other object is "equal to" this Optional. The - * other object is considered equal if: + * Indicates whether some other object is "equal to" this {@code Optional}. + * The other object is considered equal if: *
        *
      • it is also an {@code Optional} and; *
      • both instances have no value present or; @@ -347,7 +380,7 @@ public final class Optional { * * @param obj an object to be tested for equality * @return {@code true} if the other object is "equal to" this object - * otherwise {@code false} + * otherwise {@code false} */ @Override public boolean equals(Object obj) { @@ -364,10 +397,11 @@ public final class Optional { } /** - * Returns the hash code value of the present value, if any, or 0 (zero) if - * no value is present. + * Returns the hash code of the value, if present, otherwise {@code 0} + * (zero) if no value is present. * - * @return hash code value of the present value or 0 if no value is present + * @return hash code value of the present value or {@code 0} if no value is + * present */ @Override public int hashCode() { @@ -375,13 +409,14 @@ public final class Optional { } /** - * Returns a non-empty string representation of this Optional suitable for - * debugging. The exact presentation format is unspecified and may vary - * between implementations and versions. + * Returns a non-empty string representation of this {@code Optional} + * suitable for debugging. The exact presentation format is unspecified and + * may vary between implementations and versions. * - * @implSpec If a value is present the result must include its string - * representation in the result. Empty and present Optionals must be - * unambiguously differentiable. + * @implSpec + * If a value is present the result must include its string representation + * in the result. Empty and present {@code Optional}s must be unambiguously + * differentiable. * * @return the string representation of this instance */ diff --git a/jdk/src/java.base/share/classes/java/util/OptionalDouble.java b/jdk/src/java.base/share/classes/java/util/OptionalDouble.java index 88c4cbf04b2..5a637d87b03 100644 --- a/jdk/src/java.base/share/classes/java/util/OptionalDouble.java +++ b/jdk/src/java.base/share/classes/java/util/OptionalDouble.java @@ -30,15 +30,15 @@ import java.util.function.Supplier; import java.util.stream.DoubleStream; /** - * A container object which may or may not contain a {@code double} value. - * If a value is present, {@code isPresent()} will return {@code true} and - * {@code getAsDouble()} will return the value. + * A container object which may or may not contain a {@code double} value. If a + * value is present, {@code isPresent()} returns {@code true} and + * {@code getAsDouble()} returns the value. * *

        Additional methods that depend on the presence or absence of a contained * value are provided, such as {@link #orElse(double) orElse()} - * (return a default value if value not present) and - * {@link #ifPresent(java.util.function.DoubleConsumer) ifPresent()} (perform an - * action if the value is present). + * (returns a default value if no value is present) and + * {@link #ifPresent(java.util.function.DoubleConsumer) ifPresent()} (performs + * an action if a value is present). * *

        This is a value-based * class; use of identity-sensitive operations (including reference equality @@ -71,12 +71,13 @@ public final class OptionalDouble { } /** - * Returns an empty {@code OptionalDouble} instance. No value is present for this - * OptionalDouble. + * Returns an empty {@code OptionalDouble} instance. No value is present + * for this {@code OptionalDouble}. * - * @apiNote Though it may be tempting to do so, avoid testing if an object - * is empty by comparing with {@code ==} against instances returned by - * {@code Option.empty()}. There is no guarantee that it is a singleton. + * @apiNote + * Though it may be tempting to do so, avoid testing if an object is empty + * by comparing with {@code ==} against instances returned by + * {@code OptionalDouble.empty()}. There is no guarantee that it is a singleton. * Instead, use {@link #isPresent()}. * * @return an empty {@code OptionalDouble}. @@ -86,9 +87,9 @@ public final class OptionalDouble { } /** - * Construct an instance with the value present. + * Construct an instance with the described value. * - * @param value the double value to be present. + * @param value the double value to describe. */ private OptionalDouble(double value) { this.isPresent = true; @@ -96,9 +97,9 @@ public final class OptionalDouble { } /** - * Return an {@code OptionalDouble} with the specified value present. + * Returns an {@code OptionalDouble} describing the given value. * - * @param value the value to be present + * @param value the value to describe * @return an {@code OptionalDouble} with the value present */ public static OptionalDouble of(double value) { @@ -106,12 +107,11 @@ public final class OptionalDouble { } /** - * If a value is present in this {@code OptionalDouble}, returns the value, - * otherwise throws {@code NoSuchElementException}. - * - * @return the value held by this {@code OptionalDouble} - * @throws NoSuchElementException if there is no value present + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * + * @return the value described by this {@code OptionalDouble} + * @throws NoSuchElementException if no value is present * @see OptionalDouble#isPresent() */ public double getAsDouble() { @@ -122,21 +122,21 @@ public final class OptionalDouble { } /** - * Return {@code true} if there is a value present, otherwise {@code false}. + * If a value is present, returns {@code true}, otherwise {@code false}. * - * @return {@code true} if there is a value present, otherwise {@code false} + * @return {@code true} if a value is present, otherwise {@code false} */ public boolean isPresent() { return isPresent; } /** - * If a value is present, perform the given action with the value, - * otherwise do nothing. + * If a value is present, performs the given action with the value, + * otherwise does nothing. * - * @param action the action to be performed if a value is present - * @throws NullPointerException if a value is present and {@code action} is - * null + * @param action the action to be performed, if a value is present + * @throws NullPointerException if value is present and the given action is + * {@code null} */ public void ifPresent(DoubleConsumer action) { if (isPresent) { @@ -145,15 +145,16 @@ public final class OptionalDouble { } /** - * If a value is present, perform the given action with the value, - * otherwise perform the given empty-based action. + * If a value is present, performs the given action with the value, + * otherwise performs the given empty-based action. * - * @param action the action to be performed if a value is present - * @param emptyAction the empty-based action to be performed if a value is - * not present - * @throws NullPointerException if a value is present and {@code action} is - * null, or a value is not present and {@code emptyAction} is null. - * @since 1.9 + * @param action the action to be performed, if a value is present + * @param emptyAction the empty-based action to be performed, if no value is + * present + * @throws NullPointerException if a value is present and the given action + * is {@code null}, or no value is present and the given empty-based + * action is {@code null}. + * @since 9 */ public void ifPresentOrElse(DoubleConsumer action, Runnable emptyAction) { if (isPresent) { @@ -164,19 +165,20 @@ public final class OptionalDouble { } /** - * If a value is present return a sequential {@link DoubleStream} containing - * only that value, otherwise return an empty {@code DoubleStream}. - * - * @apiNote This method can be used to transform a {@code Stream} of - * optional doubles to a {@code DoubleStream} of present doubles: + * If a value is present, returns a sequential {@link DoubleStream} + * containing only that value, otherwise returns an empty + * {@code DoubleStream}. * + * @apiNote + * This method can be used to transform a {@code Stream} of optional doubles + * to a {@code DoubleStream} of present doubles: *

        {@code
              *     Stream os = ..
              *     DoubleStream s = os.flatMapToDouble(OptionalDouble::stream)
              * }
        * * @return the optional value as a {@code DoubleStream} - * @since 1.9 + * @since 9 */ public DoubleStream stream() { if (isPresent) { @@ -187,9 +189,10 @@ public final class OptionalDouble { } /** - * Return the value if present, otherwise return {@code other}. + * If a value is present, returns the value, otherwise returns + * {@code other}. * - * @param other the value to be returned if there is no value present + * @param other the value to be returned, if no value is present * @return the value, if present, otherwise {@code other} */ public double orElse(double other) { @@ -197,34 +200,35 @@ public final class OptionalDouble { } /** - * Return the value if present, otherwise invoke {@code other} and return - * the result of that invocation. + * If a value is present, returns the value, otherwise returns the result + * produced by the supplying function. * - * @param other a {@code DoubleSupplier} whose result is returned if no value - * is present - * @return the value if present otherwise the result of {@code other.getAsDouble()} - * @throws NullPointerException if value is not present and {@code other} is - * null + * @param supplier the supplying function that produces a value to be returned + * @return the value, if present, otherwise the result produced by the + * supplying function + * @throws NullPointerException if no value is present and the supplying + * function is {@code null} */ - public double orElseGet(DoubleSupplier other) { - return isPresent ? value : other.getAsDouble(); + public double orElseGet(DoubleSupplier supplier) { + return isPresent ? value : supplier.getAsDouble(); } /** - * Return the contained value, if present, otherwise throw an exception - * to be created by the provided supplier. + * If a value is present, returns the value, otherwise throws an exception + * produced by the exception supplying function. * - * @apiNote A method reference to the exception constructor with an empty - * argument list can be used as the supplier. For example, + * @apiNote + * A method reference to the exception constructor with an empty argument + * list can be used as the supplier. For example, * {@code IllegalStateException::new} * * @param Type of the exception to be thrown - * @param exceptionSupplier The supplier which will return the exception to - * be thrown - * @return the present value - * @throws X if there is no value present - * @throws NullPointerException if no value is present and - * {@code exceptionSupplier} is null + * @param exceptionSupplier the supplying function that produces an + * exception to be thrown + * @return the value, if present + * @throws X if no value is present + * @throws NullPointerException if no value is present and the exception + * supplying function is {@code null} */ public double orElseThrow(Supplier exceptionSupplier) throws X { if (isPresent) { @@ -235,17 +239,18 @@ public final class OptionalDouble { } /** - * Indicates whether some other object is "equal to" this OptionalDouble. The - * other object is considered equal if: + * Indicates whether some other object is "equal to" this + * {@code OptionalDouble}. The other object is considered equal if: *
          *
        • it is also an {@code OptionalDouble} and; *
        • both instances have no value present or; - *
        • the present values are "equal to" each other via {@code Double.compare() == 0}. + *
        • the present values are "equal to" each other via + * {@code Double.compare() == 0}. *
        * * @param obj an object to be tested for equality * @return {@code true} if the other object is "equal to" this object - * otherwise {@code false} + * otherwise {@code false} */ @Override public boolean equals(Object obj) { @@ -264,10 +269,11 @@ public final class OptionalDouble { } /** - * Returns the hash code value of the present value, if any, or 0 (zero) if - * no value is present. + * Returns the hash code of the value, if present, otherwise {@code 0} + * (zero) if no value is present. * - * @return hash code value of the present value or 0 if no value is present + * @return hash code value of the present value or {@code 0} if no value is + * present */ @Override public int hashCode() { @@ -275,14 +281,13 @@ public final class OptionalDouble { } /** - * {@inheritDoc} + * Returns a non-empty string representation of this {@code OptionalDouble} + * suitable for debugging. The exact presentation format is unspecified and + * may vary between implementations and versions. * - * Returns a non-empty string representation of this object suitable for - * debugging. The exact presentation format is unspecified and may vary - * between implementations and versions. - * - * @implSpec If a value is present the result must include its string - * representation in the result. Empty and present instances must be + * @implSpec + * If a value is present the result must include its string representation + * in the result. Empty and present {@code OptionalDouble}s must be * unambiguously differentiable. * * @return the string representation of this instance diff --git a/jdk/src/java.base/share/classes/java/util/OptionalInt.java b/jdk/src/java.base/share/classes/java/util/OptionalInt.java index 92a1d855be8..cc56f47e4ba 100644 --- a/jdk/src/java.base/share/classes/java/util/OptionalInt.java +++ b/jdk/src/java.base/share/classes/java/util/OptionalInt.java @@ -30,15 +30,15 @@ import java.util.function.Supplier; import java.util.stream.IntStream; /** - * A container object which may or may not contain a {@code int} value. - * If a value is present, {@code isPresent()} will return {@code true} and - * {@code getAsInt()} will return the value. + * A container object which may or may not contain an {@code int} value. If a + * value is present, {@code isPresent()} returns {@code true} and + * {@code getAsInt()} returns the value. * *

        Additional methods that depend on the presence or absence of a contained * value are provided, such as {@link #orElse(int) orElse()} - * (return a default value if value not present) and - * {@link #ifPresent(java.util.function.IntConsumer) ifPresent()} (perform an - * action if the value is present). + * (returns a default value if no value is present) and + * {@link #ifPresent(java.util.function.IntConsumer) ifPresent()} (performs an + * action if a value is present). * *

        This is a value-based * class; use of identity-sensitive operations (including reference equality @@ -71,24 +71,25 @@ public final class OptionalInt { } /** - * Returns an empty {@code OptionalInt} instance. No value is present for this - * OptionalInt. + * Returns an empty {@code OptionalInt} instance. No value is present for + * this {@code OptionalInt}. * - * @apiNote Though it may be tempting to do so, avoid testing if an object - * is empty by comparing with {@code ==} against instances returned by - * {@code Option.empty()}. There is no guarantee that it is a singleton. + * @apiNote + * Though it may be tempting to do so, avoid testing if an object is empty + * by comparing with {@code ==} against instances returned by + * {@code OptionalInt.empty()}. There is no guarantee that it is a singleton. * Instead, use {@link #isPresent()}. * - * @return an empty {@code OptionalInt} + * @return an empty {@code OptionalInt} */ public static OptionalInt empty() { return EMPTY; } /** - * Construct an instance with the value present. + * Construct an instance with the described value. * - * @param value the int value to be present + * @param value the int value to describe */ private OptionalInt(int value) { this.isPresent = true; @@ -96,9 +97,9 @@ public final class OptionalInt { } /** - * Return an {@code OptionalInt} with the specified value present. + * Returns an {@code OptionalInt} describing the given value. * - * @param value the value to be present + * @param value the value to describe * @return an {@code OptionalInt} with the value present */ public static OptionalInt of(int value) { @@ -106,12 +107,11 @@ public final class OptionalInt { } /** - * If a value is present in this {@code OptionalInt}, returns the value, - * otherwise throws {@code NoSuchElementException}. - * - * @return the value held by this {@code OptionalInt} - * @throws NoSuchElementException if there is no value present + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * + * @return the value described by this {@code OptionalInt} + * @throws NoSuchElementException if no value is present * @see OptionalInt#isPresent() */ public int getAsInt() { @@ -122,21 +122,21 @@ public final class OptionalInt { } /** - * Return {@code true} if there is a value present, otherwise {@code false}. + * If a value is present, returns {@code true}, otherwise {@code false}. * - * @return {@code true} if there is a value present, otherwise {@code false} + * @return {@code true} if a value is present, otherwise {@code false} */ public boolean isPresent() { return isPresent; } /** - * If a value is present, perform the given action with the value, - * otherwise do nothing. + * If a value is present, performs the given action with the value, + * otherwise does nothing. * - * @param action the action to be performed if a value is present - * @throws NullPointerException if value is present and {@code action} is - * null + * @param action the action to be performed, if a value is present + * @throws NullPointerException if value is present and the given action is + * {@code null} */ public void ifPresent(IntConsumer action) { if (isPresent) { @@ -145,15 +145,16 @@ public final class OptionalInt { } /** - * If a value is present, perform the given action with the value, - * otherwise perform the given empty-based action. + * If a value is present, performs the given action with the value, + * otherwise performs the given empty-based action. * - * @param action the action to be performed if a value is present - * @param emptyAction the empty-based action to be performed if a value is - * not present - * @throws NullPointerException if a value is present and {@code action} is - * null, or a value is not present and {@code emptyAction} is null. - * @since 1.9 + * @param action the action to be performed, if a value is present + * @param emptyAction the empty-based action to be performed, if no value is + * present + * @throws NullPointerException if a value is present and the given action + * is {@code null}, or no value is present and the given empty-based + * action is {@code null}. + * @since 9 */ public void ifPresentOrElse(IntConsumer action, Runnable emptyAction) { if (isPresent) { @@ -164,19 +165,19 @@ public final class OptionalInt { } /** - * If a value is present return a sequential {@link IntStream} containing - * only that value, otherwise return an empty {@code IntStream}. - * - * @apiNote This method can be used to transform a {@code Stream} of - * optional integers to an {@code IntStream} of present integers: + * If a value is present, returns a sequential {@link IntStream} containing + * only that value, otherwise returns an empty {@code IntStream}. * + * @apiNote + * This method can be used to transform a {@code Stream} of optional + * integers to an {@code IntStream} of present integers: *

        {@code
              *     Stream os = ..
              *     IntStream s = os.flatMapToInt(OptionalInt::stream)
              * }
        * * @return the optional value as an {@code IntStream} - * @since 1.9 + * @since 9 */ public IntStream stream() { if (isPresent) { @@ -187,9 +188,10 @@ public final class OptionalInt { } /** - * Return the value if present, otherwise return {@code other}. + * If a value is present, returns the value, otherwise returns + * {@code other}. * - * @param other the value to be returned if there is no value present + * @param other the value to be returned, if no value is present * @return the value, if present, otherwise {@code other} */ public int orElse(int other) { @@ -197,34 +199,35 @@ public final class OptionalInt { } /** - * Return the value if present, otherwise invoke {@code other} and return - * the result of that invocation. + * If a value is present, returns the value, otherwise returns the result + * produced by the supplying function. * - * @param other a {@code IntSupplier} whose result is returned if no value - * is present - * @return the value if present otherwise the result of {@code other.getAsInt()} - * @throws NullPointerException if value is not present and {@code other} is - * null + * @param supplier the supplying function that produces a value to be returned + * @return the value, if present, otherwise the result produced by the + * supplying function + * @throws NullPointerException if no value is present and the supplying + * function is {@code null} */ - public int orElseGet(IntSupplier other) { - return isPresent ? value : other.getAsInt(); + public int orElseGet(IntSupplier supplier) { + return isPresent ? value : supplier.getAsInt(); } /** - * Return the contained value, if present, otherwise throw an exception - * to be created by the provided supplier. + * If a value is present, returns the value, otherwise throws an exception + * produced by the exception supplying function. * - * @apiNote A method reference to the exception constructor with an empty - * argument list can be used as the supplier. For example, + * @apiNote + * A method reference to the exception constructor with an empty argument + * list can be used as the supplier. For example, * {@code IllegalStateException::new} * * @param Type of the exception to be thrown - * @param exceptionSupplier The supplier which will return the exception to - * be thrown - * @return the present value - * @throws X if there is no value present - * @throws NullPointerException if no value is present and - * {@code exceptionSupplier} is null + * @param exceptionSupplier the supplying function that produces an + * exception to be thrown + * @return the value, if present + * @throws X if no value is present + * @throws NullPointerException if no value is present and the exception + * supplying function is {@code null} */ public int orElseThrow(Supplier exceptionSupplier) throws X { if (isPresent) { @@ -235,8 +238,8 @@ public final class OptionalInt { } /** - * Indicates whether some other object is "equal to" this OptionalInt. The - * other object is considered equal if: + * Indicates whether some other object is "equal to" this + * {@code OptionalInt}. The other object is considered equal if: *
      * + *

      Please note that granting this permission with the "modifyPrincipals", + * "modifyPublicCredentials" or "modifyPrivateCredentials" target allows + * a JAAS login module to populate principal or credential objects into + * the Subject. Although reading information inside the private credentials + * set requires a {@link PrivateCredentialPermission} of the credential type to + * be granted, reading information inside the principals set and the public + * credentials set requires no additional permission. These objects can contain + * potentially sensitive information. For example, login modules that read + * local user information or perform a Kerberos login are able to add + * potentially sensitive information such as user ids, groups and domain names + * to the principals set. + * *

      The following target name has been deprecated in favor of * {@code createLoginContext.{name}}. * diff --git a/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java b/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java index c0b1865ee0b..b5a2a2cd107 100644 --- a/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java +++ b/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java @@ -311,6 +311,13 @@ public abstract class Configuration { *

      Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} property to determine + * the preferred provider order for the specified algorithm. This + * may be different than the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}. + * * @param type the specified Configuration type. See the Configuration * section in the diff --git a/jdk/src/java.base/share/classes/jdk/internal/HotSpotIntrinsicCandidate.java b/jdk/src/java.base/share/classes/jdk/internal/HotSpotIntrinsicCandidate.java index e3efada1a7c..95ea0b44b87 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/HotSpotIntrinsicCandidate.java +++ b/jdk/src/java.base/share/classes/jdk/internal/HotSpotIntrinsicCandidate.java @@ -28,8 +28,8 @@ package jdk.internal; import java.lang.annotation.*; /** - * The {@code @HotSpotIntrinsicCandidate} annotation is specific to the Oracle Java - * HotSpot Virtual Machine implementation and indicates that an annotated method + * The {@code @HotSpotIntrinsicCandidate} annotation is specific to the + * HotSpot Virtual Machine. It indicates that an annotated method * may be (but is not guaranteed to be) intrinsified by the HotSpot VM. A method * is intrinsified if the HotSpot VM replaces the annotated method with hand-written * assembly and/or hand-written compiler IR -- a compiler intrinsic -- to improve diff --git a/jdk/src/java.base/share/classes/overview-core.html b/jdk/src/java.base/share/classes/overview-core.html index 3249e46a89a..5c2d54994fb 100644 --- a/jdk/src/java.base/share/classes/overview-core.html +++ b/jdk/src/java.base/share/classes/overview-core.html @@ -3,7 +3,7 @@ + + + CopyAreaSpeed + + + +

      CopyAreaSpeed

      +
      +
      Thanh Nguyen
      + + +Last modified: Tue Jan 19 16:18:37 PST 1999 + + + + diff --git a/jdk/test/sun/java2d/loops/CopyAreaSpeed.java b/jdk/test/sun/java2d/loops/CopyAreaSpeed.java new file mode 100644 index 00000000000..00d1cff5c38 --- /dev/null +++ b/jdk/test/sun/java2d/loops/CopyAreaSpeed.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 4189070 + * @summary This test prints out the time it takes for a certain amount of + * copyArea calls to be completed. Because the performance measurement is + * relative, this code only provides a benchmark to run with different releases + * to compare the outcomes. + * @run applet/manual=done CopyAreaSpeed.html + */ + +import java.applet.Applet; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +public class CopyAreaSpeed extends Applet implements Runnable { + int top = 0; + + public void init() { + } + + public CopyAreaSpeed() + { + super(); + String[] instructions = + { + "This test prints out the time it takes for a certain amount ", + "of copyArea calls to be completed. Because the performance ", + "measurement is relative, this code only provides a benchmark ", + "to run with different releases to compare the outcomes." + }; + Sysout.createDialogWithInstructions( instructions ); + (new Thread(this)).start(); + Button bt = new Button("Hello"); + bt.setBounds(50, 10, 50, 22); + bt.setVisible(false); + add(bt); + } + + public void update(Graphics g) + { + paint(g); + } + + public void paint(Graphics g) + { + synchronized(this) { + Rectangle rct = g.getClipBounds(); + g.setColor(Color.white); + g.fillRect(rct.x, rct.y, rct.width, rct.height); + g.setFont(getFont()); + g.setColor(Color.black); + + Dimension dm = getSize(); + for (int y = 0; y <= (dm.height + 10); y += 20) { + if (y > rct.y) { + int z = y / 20 + top; + g.drawString("" + z, 10, y); + } /* endif */ + } // endfor + } + } + + static long millsec(Date s, Date e) { + long ts = s.getTime(); + long te = e.getTime(); + return te-ts; + } + + public void run() + { + int count = 1000; + int loops = count; + Date start; + Date end; + + start = new Date(); + while (count-- > 0) { + Dimension dm = getSize(); + if (dm != null && dm.width != 0 && dm.height != 0) { + synchronized(this) { + top++; + Graphics g = getGraphics(); + g.copyArea(0, 20, dm.width, dm.height - 20, 0, -20); + g.setClip(0, dm.height - 20, dm.width, 20); + paint(g); + g.dispose(); + } + } + try { + Thread.sleep(1); + } catch(Exception ex) { + ex.printStackTrace(); + } + } + end = new Date(); + Sysout.println("copyArea X "+loops+" = "+ millsec(start, end) + " msec"); + } + + public static void main(String args[]) { + Frame frm = new Frame("CopyAreaSpeed"); + frm.add(new CopyAreaSpeed()); + frm.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + System.exit(0); + } + }); + frm.setSize(500, 500); + frm.show(); + } +} +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ +class Sysout +{ + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.show(); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.show(); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("South", messageText); + + pack(); + + show(); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) { + posOfSpace = maxStringLength - 1; + } + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + else //else just print + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + } + +}// TestDialog class diff --git a/jdk/test/sun/management/LazyCompositeDataTest.java b/jdk/test/sun/management/LazyCompositeDataTest.java new file mode 100644 index 00000000000..c3d06523022 --- /dev/null +++ b/jdk/test/sun/management/LazyCompositeDataTest.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.HashMap; +import java.util.Map; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import sun.management.LazyCompositeData; + +/** + * @test + * @bug 8139870 + * @summary sun.management.LazyCompositeData.isTypeMatched() fails for composite types with items of ArrayType + * @modules java.management/sun.management + * @author Jaroslav Bachorik + */ + +public class LazyCompositeDataTest { + private final static CompositeData dataV1, dataV2; + + static { + try { + // *** + // prepare the composite types + + // composite type stored in an array; V1 + CompositeType subtypeV1 = new CompositeType( + "Subtype1", + "Version 1", + new String[]{"item1"}, + new String[]{"Item 1"}, + new OpenType[]{ + SimpleType.STRING + } + ); + + // composite type stored in an array; V2 + CompositeType subtypeV2 = new CompositeType( + "Subtype2", + "Version 2", + new String[]{"item1", "item2"}, + new String[]{"Item 1", "Item 2"}, + new OpenType[]{ + SimpleType.STRING, + SimpleType.INTEGER + } + ); + + + // main composite type; V1 + // one of the items is array of 'subtypeV1' instances + CompositeType typeV1 = new CompositeType( + "MyDataV1", + "Version 1", + new String[]{"item1", "item2"}, + new String[]{"Item 1", "Item 2"}, + new OpenType[]{ + SimpleType.STRING, + ArrayType.getArrayType(subtypeV1) + } + ); + + // main composite type; V2 + // one of the items is array of 'subtypeV2' instances + CompositeType typeV2 = new CompositeType( + "MyDataV2", + "Version 2", + new String[]{"item1", "item2"}, + new String[]{"Item 1", "Item 2"}, + new OpenType[]{ + SimpleType.STRING, + ArrayType.getArrayType(subtypeV2) + } + ); + // *** + + // *** + // construct the data + Map subitemsV1 = new HashMap<>(); + Map subitemsV2 = new HashMap<>(); + + Map itemsV1 = new HashMap<>(); + Map itemsV2 = new HashMap<>(); + + subitemsV1.put("item1", "item1"); + subitemsV2.put("item1", "item1"); + subitemsV2.put("item2", 42); + + itemsV1.put("item1", "item1"); + itemsV1.put("item2", new CompositeData[]{new CompositeDataSupport(subtypeV1, subitemsV1)}); + + itemsV2.put("item1", "item1"); + itemsV2.put("item2", new CompositeData[]{new CompositeDataSupport(subtypeV2, subitemsV2)}); + + dataV1 = new CompositeDataSupport(typeV1, itemsV1); + dataV2 = new CompositeDataSupport(typeV2, itemsV2); + // *** + } catch (OpenDataException e) { + throw new Error(e); + } + } + + private static class MyDataV1 extends LazyCompositeData { + @Override + protected CompositeData getCompositeData() { + return dataV1; + } + + public boolean isTypeMached(CompositeType type) { + return isTypeMatched(this.getCompositeType(), type); + } + } + + private static class MyDataV2 extends LazyCompositeData { + @Override + protected CompositeData getCompositeData() { + return dataV2; + } + + } + + public static void main(String[] args) throws Exception { + System.out.println("Checking LazyCompositeData.isTypeMatched()"); + MyDataV1 v1 = new MyDataV1(); + MyDataV2 v2 = new MyDataV2(); + + if (!v1.isTypeMached(v2.getCompositeType())) { + System.err.println("=== FAILED"); + System.err.println("V1 should be matched by V2"); + System.err.println("\n=== V1"); + System.err.println(v1.getCompositeType()); + System.err.println("\n=== V2"); + System.err.println(v2.getCompositeType()); + throw new Error(); + } + System.out.println("=== PASSED"); + } +} \ No newline at end of file diff --git a/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java b/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java index 8542c98515f..5e61420ddeb 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java +++ b/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java @@ -255,8 +255,7 @@ public class CustomLauncherTest { // and set the executable flag Path localLauncherPath = FS.getPath(WORK_DIR, "launcher"); Files.copy(launcherPath, localLauncherPath, - StandardCopyOption.REPLACE_EXISTING, - StandardCopyOption.COPY_ATTRIBUTES); + StandardCopyOption.REPLACE_EXISTING); if (!Files.isExecutable(localLauncherPath)) { Set perms = new HashSet<>( Files.getPosixFilePermissions( diff --git a/jdk/test/sun/management/jmxremote/startstop/JMXStatus1Test.java b/jdk/test/sun/management/jmxremote/startstop/JMXStatus1Test.java new file mode 100644 index 00000000000..059c9b45e30 --- /dev/null +++ b/jdk/test/sun/management/jmxremote/startstop/JMXStatus1Test.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +/** + * A flavor of {@linkplain JMXStatusTest} test where the test application + * is started without the management agent initialized. + */ +public class JMXStatus1Test extends JMXStatusTest { + @Override + protected List getCustomVmArgs() { + return Collections.emptyList(); + } + + @Override + protected Pattern getDefaultPattern() { + return JMXStatusTest.DISABLED_AGENT_STATUS; + } +} \ No newline at end of file diff --git a/jdk/test/sun/management/jmxremote/startstop/JMXStatus2Test.java b/jdk/test/sun/management/jmxremote/startstop/JMXStatus2Test.java new file mode 100644 index 00000000000..d4ce0085457 --- /dev/null +++ b/jdk/test/sun/management/jmxremote/startstop/JMXStatus2Test.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +/** + * A flavor of {@linkplain JMXStatusTest} test where the test application + * is started with the management agent initialized. + */ +public class JMXStatus2Test extends JMXStatusTest { + @Override + protected List getCustomVmArgs() { + // not specifying the jmxremote.port > only local agent started + return Arrays.asList( + "-Dcom.sun.management.jmxremote" + ); + } + + @Override + protected Pattern getDefaultPattern() { + return JMXStatusTest.LOCAL_AGENT_STATUS; + } +} \ No newline at end of file diff --git a/jdk/test/sun/management/jmxremote/startstop/JMXStatusTest.java b/jdk/test/sun/management/jmxremote/startstop/JMXStatusTest.java index 0f516b6b504..84943bd69d9 100644 --- a/jdk/test/sun/management/jmxremote/startstop/JMXStatusTest.java +++ b/jdk/test/sun/management/jmxremote/startstop/JMXStatusTest.java @@ -22,6 +22,8 @@ */ import java.net.BindException; +import java.util.ArrayList; +import java.util.List; import java.util.function.Predicate; import java.util.regex.Pattern; import org.testng.annotations.*; @@ -31,23 +33,25 @@ import jdk.testlibrary.ProcessTools; /** * @test - * @bug 8023093 + * @bug 8023093 8138748 * @summary Performs a sanity test for the ManagementAgent.status diagnostic command. - * Management agent may be disable, started (only local connections) and started. + * Management agent may be disabled, started (only local connections) and started. * The test asserts that the expected text is being printed. * @library /lib/testlibrary * @modules java.management/sun.management * @build jdk.testlibrary.* PortAllocator TestApp ManagementAgentJcmd - * @run testng/othervm -XX:+UsePerfData JMXStatusTest + * JMXStatusTest JMXStatus1Test JMXStatus2Test + * @run testng/othervm -XX:+UsePerfData JMXStatus1Test + * @run testng/othervm -XX:+UsePerfData JMXStatus2Test */ -public class JMXStatusTest { +abstract public class JMXStatusTest { private final static String TEST_APP_NAME = "TestApp"; - private final static Pattern DISABLE_AGENT_STATUS = Pattern.compile( + protected final static Pattern DISABLED_AGENT_STATUS = Pattern.compile( "Agent\\s*\\: disabled$" ); - private final static Pattern LOCAL_AGENT_STATUS = Pattern.compile( + protected final static Pattern LOCAL_AGENT_STATUS = Pattern.compile( "Agent\\s*\\:\\s*enabled\\n+" + "Connection Type\\s*\\:\\s*local\\n+" + "Protocol\\s*\\:\\s*[a-z]+\\n+" + @@ -56,14 +60,15 @@ public class JMXStatusTest { Pattern.MULTILINE ); - private final static Pattern REMOTE_AGENT_STATUS = Pattern.compile( + protected final static Pattern REMOTE_AGENT_STATUS = Pattern.compile( "Agent\\s*\\: enabled\\n+" + + ".*" + "Connection Type\\s*\\: remote\\n+" + "Protocol\\s*\\: [a-z]+\\n+" + "Host\\s*\\: .+\\n+" + "URL\\s*\\: service\\:jmx\\:.+\\n+" + "Properties\\s*\\:\\n+(\\s*\\S+\\s*=\\s*\\S+\\n*)+", - Pattern.MULTILINE + Pattern.MULTILINE | Pattern.DOTALL ); private static ProcessBuilder testAppPb; @@ -71,22 +76,24 @@ public class JMXStatusTest { private ManagementAgentJcmd jcmd; - @BeforeClass - public static void setupClass() throws Exception { - testAppPb = ProcessTools.createJavaProcessBuilder( - "-cp", System.getProperty("test.class.path"), - "-XX:+UsePerfData", - TEST_APP_NAME - ); - } + abstract protected List getCustomVmArgs(); + abstract protected Pattern getDefaultPattern(); @BeforeTest - public void setup() { + public final void setup() throws Exception { + List args = new ArrayList<>(); + args.add("-cp"); + args.add(System.getProperty("test.class.path")); + args.add("-XX:+UsePerfData"); + args.addAll(getCustomVmArgs()); + args.add(TEST_APP_NAME); + testAppPb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[args.size()])); + jcmd = new ManagementAgentJcmd(TEST_APP_NAME, false); } @BeforeMethod - public void startTestApp() throws Exception { + public final void startTestApp() throws Exception { testApp = ProcessTools.startProcess( TEST_APP_NAME, testAppPb, (Predicate)l->l.trim().equals("main enter") @@ -94,7 +101,7 @@ public class JMXStatusTest { } @AfterMethod - public void stopTestApp() throws Exception { + public final void stopTestApp() throws Exception { testApp.getOutputStream().write(1); testApp.getOutputStream().flush(); testApp.waitFor(); @@ -102,13 +109,7 @@ public class JMXStatusTest { } @Test - public void testAgentDisabled() throws Exception { - String status = jcmd.status(); - assertStatusMatches(DISABLE_AGENT_STATUS, status); - } - - @Test - public void testAgentLocal() throws Exception { + public final void testAgentLocal() throws Exception { jcmd.startLocal(); String status = jcmd.status(); @@ -116,7 +117,7 @@ public class JMXStatusTest { } @Test - public void testAgentRemote() throws Exception { + public final void testAgentRemote() throws Exception { while (true) { try { int[] ports = PortAllocator.allocatePorts(1); @@ -135,11 +136,17 @@ public class JMXStatusTest { } } - private void assertStatusMatches(Pattern expected, String value) { + @Test + public final void testAgentDefault() throws Exception { + String status = jcmd.status(); + assertStatusMatches(getDefaultPattern(), status); + } + + protected void assertStatusMatches(Pattern expected, String value) { assertStatusMatches(expected, value, ""); } - private void assertStatusMatches(Pattern expected, String value, String msg) { + protected void assertStatusMatches(Pattern expected, String value, String msg) { int idx = value.indexOf('\n'); if (idx > -1) { value = value.substring(idx + 1).trim(); diff --git a/jdk/test/sun/security/krb5/auto/KDC.java b/jdk/test/sun/security/krb5/auto/KDC.java index 0964e08f69f..066bb8d518b 100644 --- a/jdk/test/sun/security/krb5/auto/KDC.java +++ b/jdk/test/sun/security/krb5/auto/KDC.java @@ -889,8 +889,9 @@ public class KDC { PrincipalName service = asReq.reqBody.sname; if (options.containsKey(KDC.Option.RESP_NT)) { - service = new PrincipalName(service.getNameStrings(), - (int)options.get(KDC.Option.RESP_NT)); + service = new PrincipalName((int)options.get(KDC.Option.RESP_NT), + service.getNameStrings(), + Realm.getDefault()); } try { System.out.println(realm + "> " + asReq.reqBody.cname + diff --git a/jdk/test/sun/security/krb5/auto/SSL.java b/jdk/test/sun/security/krb5/auto/SSL.java index 02317138102..471f63c7e44 100644 --- a/jdk/test/sun/security/krb5/auto/SSL.java +++ b/jdk/test/sun/security/krb5/auto/SSL.java @@ -76,7 +76,10 @@ public class SSL extends SecurityManager { return; } ServicePermission p = (ServicePermission)perm; - permChecks = permChecks + p.getActions().toUpperCase().charAt(0); + // ServicePermissions required to create GSSName are ignored + if (!p.getActions().isEmpty()) { + permChecks = permChecks + p.getActions().toUpperCase().charAt(0); + } } public static void main(String[] args) throws Exception { diff --git a/jdk/test/sun/security/krb5/name/Constructors.java b/jdk/test/sun/security/krb5/name/Constructors.java index c57a731d5ce..f3943cc88ef 100644 --- a/jdk/test/sun/security/krb5/name/Constructors.java +++ b/jdk/test/sun/security/krb5/name/Constructors.java @@ -41,22 +41,22 @@ public class Constructors { // Good ones type = PrincipalName.KRB_NT_UNKNOWN; - checkName("a", type, "R", "R", "a"); - checkName("a@R2", type, "R", "R", "a"); - checkName("a/b", type, "R", "R", "a", "b"); - checkName("a/b@R2", type, "R", "R", "a", "b"); - checkName("a/b/c", type, "R", "R", "a", "b", "c"); - checkName("a/b/c@R2", type, "R", "R", "a", "b", "c"); + checkName("a", type, "R", "R", false, "a"); + checkName("a@R2", type, "R", "R", false, "a"); + checkName("a/b", type, "R", "R", false, "a", "b"); + checkName("a/b@R2", type, "R", "R", false, "a", "b"); + checkName("a/b/c", type, "R", "R", false, "a", "b", "c"); + checkName("a/b/c@R2", type, "R", "R", false, "a", "b", "c"); // Weird ones - checkName("a\\/b", type, "R", "R", "a/b"); - checkName("a\\/b\\/c", type, "R", "R", "a/b/c"); - checkName("a\\/b\\@R2", type, "R", "R", "a/b@R2"); + checkName("a\\/b", type, "R", "R", false, "a/b"); + checkName("a\\/b\\/c", type, "R", "R", false, "a/b/c"); + checkName("a\\/b\\@R2", type, "R", "R", false, "a/b@R2"); // Bad ones - checkName("a", type, "", null); - checkName("a/", type, "R", null); - checkName("/a", type, "R", null); - checkName("a//b", type, "R", null); - checkName("a@", type, null, null); + checkName("a", type, "", null, false); + checkName("a/", type, "R", null, false); + checkName("/a", type, "R", null, false); + checkName("a//b", type, "R", null, false); + checkName("a@", type, null, null, false); type = PrincipalName.KRB_NT_SRV_HST; // Part 2: on realm choices @@ -78,17 +78,17 @@ public class Constructors { if (testNoDefaultDomain) { type = PrincipalName.KRB_NT_UNKNOWN; - checkName("a", type, "R1", "R1", "a"); // arg - checkName("a@R1", type, null, "R1", "a"); // or r in name - checkName("a@R2", type, "R1", "R1", "a"); // arg over r - checkName("a", type, null, null); // fail if none - checkName("a/b@R1", type, null, "R1", "a", "b"); + checkName("a", type, "R1", "R1", false, "a"); // arg + checkName("a@R1", type, null, "R1", false, "a"); // or r in name + checkName("a@R2", type, "R1", "R1", false, "a"); // arg over r + checkName("a", type, null, null, false); // fail if none + checkName("a/b@R1", type, null, "R1", false, "a", "b"); type = PrincipalName.KRB_NT_SRV_HST; // Let's pray "b.h" won't be canonicalized - checkName("a/b.h", type, "R1", "R1", "a", "b.h"); // arg - checkName("a/b.h@R1", type, null, "R1", "a", "b.h"); // or r in name - checkName("a/b.h@R1", type, "R2", "R2", "a", "b.h"); // arg over r - checkName("a/b.h", type, null, null); // fail if none + checkName("a/b.h", type, "R1", "R1", false, "a", "b.h"); // arg + checkName("a/b.h@R1", type, null, "R1", false, "a", "b.h"); // or r in name + checkName("a/b.h@R1", type, "R2", "R2", false, "a", "b.h"); // arg over r + checkName("a/b.h", type, null, null, false); // fail if none } // When there is default realm @@ -97,25 +97,25 @@ public class Constructors { Config.refresh(); type = PrincipalName.KRB_NT_UNKNOWN; - checkName("a", type, "R1", "R1", "a"); // arg - checkName("a@R1", type, null, "R1", "a"); // or r in name - checkName("a@R2", type, "R1", "R1", "a"); // arg over r - checkName("a", type, null, "R", "a"); // default - checkName("a/b", type, null, "R", "a", "b"); + checkName("a", type, "R1", "R1", false, "a"); // arg + checkName("a@R1", type, null, "R1", false, "a"); // or r in name + checkName("a@R2", type, "R1", "R1", false, "a"); // arg over r + checkName("a", type, null, "R", true, "a"); // default + checkName("a/b", type, null, "R", true, "a", "b"); type = PrincipalName.KRB_NT_SRV_HST; - checkName("a/b.h3", type, "R1", "R1", "a", "b.h3"); // arg - checkName("a/b.h@R1", type, null, "R1", "a", "b.h"); // or r in name - checkName("a/b.h3@R2", type, "R1", "R1", "a", "b.h3"); // arg over r - checkName("a/b.h2", type, "R1", "R1", "a", "b.h2"); // arg over map - checkName("a/b.h2@R1", type, null, "R1", "a", "b.h2"); // r over map - checkName("a/b.h2", type, null, "R2", "a", "b.h2"); // map - checkName("a/b.h", type, null, "R", "a", "b.h"); // default + checkName("a/b.h3", type, "R1", "R1", false, "a", "b.h3"); // arg + checkName("a/b.h@R1", type, null, "R1", false, "a", "b.h"); // or r in name + checkName("a/b.h3@R2", type, "R1", "R1", false, "a", "b.h3"); // arg over r + checkName("a/b.h2", type, "R1", "R1", false, "a", "b.h2"); // arg over map + checkName("a/b.h2@R1", type, null, "R1", false, "a", "b.h2"); // r over map + checkName("a/b.h2", type, null, "R2", true, "a", "b.h2"); // map + checkName("a/b.h", type, null, "R", true, "a", "b.h"); // default } // Check if the creation matches the expected output. // Note: realm == null means creation failure static void checkName(String n, int t, String s, - String realm, String... parts) + String realm, boolean deduced, String... parts) throws Exception { PrincipalName pn = null; try { @@ -132,5 +132,8 @@ public class Constructors { throw new Exception(pn.toString() + " vs " + Arrays.toString(parts) + "@" + realm); } + if (deduced != pn.isRealmDeduced()) { + throw new Exception("pn.realmDeduced is " + pn.isRealmDeduced()); + } } } diff --git a/jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java b/jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java index 4581d385c2c..3b449315e17 100644 --- a/jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java +++ b/jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java @@ -31,34 +31,34 @@ * @bug 6956398 * @summary make ephemeral DH key match the length of the certificate key * @run main/othervm - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 * * @run main/othervm - * DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 292 75 + * DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 229 75 * * @run main/othervm - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1510 139 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1383 139 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1414 107 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1319 107 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1894 267 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1639 267 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1510 139 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1383 139 * * @run main/othervm - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 484 139 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 388 107 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 293 107 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 484 139 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 484 139 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139 */ /* @@ -90,10 +90,10 @@ * Here is a summary of the record length in the test case. * * | ServerHello Series | ClientKeyExchange | ServerHello Anon - * 512-bit | 1318 bytes | 75 bytes | 292 bytes - * 768-bit | 1414 bytes | 107 bytes | 388 bytes - * 1024-bit | 1510 bytes | 139 bytes | 484 bytes - * 2048-bit | 1894 bytes | 267 bytes | 484 bytes + * 512-bit | 1255 bytes | 75 bytes | 229 bytes + * 768-bit | 1319 bytes | 107 bytes | 293 bytes + * 1024-bit | 1383 bytes | 139 bytes | 357 bytes + * 2048-bit | 1639 bytes | 267 bytes | 357 bytes */ import javax.net.ssl.*; diff --git a/jdk/test/sun/tools/jstack/DeadlockDetectionTest.java b/jdk/test/sun/tools/jstack/DeadlockDetectionTest.java new file mode 100644 index 00000000000..31cdf311830 --- /dev/null +++ b/jdk/test/sun/tools/jstack/DeadlockDetectionTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.apps.LingeredAppWithDeadlock; + +import jdk.testlibrary.Utils; +import jdk.testlibrary.Platform; +import jdk.testlibrary.JDKToolLauncher; +import jdk.testlibrary.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; + +/* + * @test + * @summary Test deadlock detection + * @library /../../test/lib/share/classes + * @library /lib/testlibrary + * @modules java.management + * @build jdk.testlibrary.* + * @build jdk.test.lib.apps.* + * @build DeadlockDetectionTest + * @run main DeadlockDetectionTest + */ +public class DeadlockDetectionTest { + + private static LingeredAppWithDeadlock theApp = null; + private static ProcessBuilder processBuilder = new ProcessBuilder(); + + private static OutputAnalyzer jstack(String... toolArgs) throws Exception { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstack"); + launcher.addVMArg("-XX:+UsePerfData"); + if (toolArgs != null) { + for (String toolArg : toolArgs) { + launcher.addToolArg(toolArg); + } + } + + processBuilder.command(launcher.getCommand()); + System.out.println(processBuilder.command().stream().collect(Collectors.joining(" "))); + OutputAnalyzer output = ProcessTools.executeProcess(processBuilder); + System.out.println(output.getOutput()); + + return output; + } + + public static void main(String[] args) throws Exception { + System.out.println("Starting DeadlockDetectionTest"); + + if (!Platform.shouldSAAttach()) { + // Silently skip the test if we don't have enough permissions to attach + System.err.println("Error! Insufficient permissions to attach."); + return; + } + + if (!LingeredApp.isLastModifiedWorking()) { + // Exact behaviour of the test depends on operating system and the test nature, + // so just print the warning and continue + System.err.println("Warning! Last modified time doesn't work."); + } + + try { + List vmArgs = new ArrayList(); + vmArgs.add("-XX:+UsePerfData"); + vmArgs.addAll(Utils.getVmOptions()); + + theApp = new LingeredAppWithDeadlock(); + LingeredApp.startApp(vmArgs, theApp); + OutputAnalyzer output = jstack(Long.toString(theApp.getPid())); + System.out.println(output.getOutput()); + + if (output.getExitValue() == 3) { + System.out.println("Test can't run for some reason. Skipping"); + } + else { + output.shouldHaveExitValue(0); + output.shouldContain("Found 1 deadlock."); + } + + } finally { + LingeredApp.stopApp(theApp); + } + } +} diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index 2524e193eca..7df66e8c030 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -438,6 +438,18 @@ jdk.jvmstat_COPY := aliasmap ################################################################################ +jdk.vm.ci_EXCLUDE_FILES += \ + jdk/vm/ci/options/processor/OptionProcessor.java \ + jdk/vm/ci/service/processor/ServiceProviderProcessor.java \ + # + +jdk.vm.ci_EXCLUDES += \ + META-INF/jvmci.options \ + META-INF/jvmci.providers \ + # + +################################################################################ + jdk.xml.bind_SETUP := GENERATE_JDKBYTECODE_NOWARNINGS jdk.xml.bind_CLEAN := .properties jdk.xml.bind_COPY := .xsd JAXBContextFactory.java ZeroOneBooleanAdapter.java @@ -479,6 +491,7 @@ ifneq ($(OPENJDK_TARGET_OS), $(OPENJDK_TARGET_OS_TYPE)) endif SHARE_SRC_DIRS += \ + $(HOTSPOT_TOPDIR)/src/$1/share/classes \ $(JDK_TOPDIR)/src/$1/share/classes \ $(LANGTOOLS_TOPDIR)/src/$1/share/classes \ $(CORBA_TOPDIR)/src/$1/share/classes \ @@ -531,7 +544,7 @@ define SetupModuleCompilation $$(eval $$(call SetupJavaCompilation,$1, \ SETUP := $$(if $$($1_SETUP), $$($1_SETUP), GENERATE_JDKBYTECODE), \ - SRC := $$(wildcard $$(call ALL_SRC_DIRS,$1)), \ + SRC := $$(if $$($1_SRC), $$($1_SRC), $$(wildcard $$(call ALL_SRC_DIRS,$1))), \ INCLUDES := $(JDK_USER_DEFINED_FILTER),\ BIN := $$(if $$($1_BIN), $$($1_BIN), $(JDK_OUTPUTDIR)/modules/$1), \ HEADERS := $(SUPPORT_OUTPUTDIR)/headers/$1, \ diff --git a/make/Images.gmk b/make/Images.gmk index c404a89ee3b..031ccb66924 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -39,7 +39,8 @@ $(eval $(call IncludeCustomExtension, , Images-pre.gmk)) MAIN_MODULES += java.se java.smartcardio jdk.httpserver jdk.sctp \ jdk.security.auth jdk.security.jgss jdk.pack200 jdk.xml.dom \ - jdk.accessibility jdk.internal.le jdk.scripting.nashorn.shell + jdk.accessibility jdk.internal.le jdk.scripting.nashorn.shell \ + jdk.vm.ci # providers PROVIDER_MODULES += jdk.charsets jdk.crypto.ec jdk.crypto.pkcs11 jdk.jvmstat jdk.localedata \ @@ -48,7 +49,8 @@ PROVIDER_MODULES += jdk.charsets jdk.crypto.ec jdk.crypto.pkcs11 jdk.jvmstat jdk # tools TOOLS_MODULES += jdk.attach jdk.compiler jdk.dev \ jdk.javadoc jdk.jcmd jdk.jconsole jdk.hotspot.agent jdk.jartool \ - jdk.jdeps jdk.jdi jdk.jdwp.agent jdk.policytool jdk.rmic jdk.xml.bind jdk.xml.ws + jdk.jdeps jdk.jdi jdk.jdwp.agent jdk.jshell jdk.policytool jdk.rmic \ + jdk.xml.bind jdk.xml.ws ifeq ($(OPENJDK_TARGET_OS), windows) PROVIDER_MODULES += jdk.crypto.mscapi diff --git a/make/Init.gmk b/make/Init.gmk index 6f18f1fea51..b2aa7ce7a22 100644 --- a/make/Init.gmk +++ b/make/Init.gmk @@ -137,7 +137,9 @@ ifeq ($(HAS_SPEC),) # The spec files depend on the autoconf source code. This check makes sure # the configuration is up to date after changes to configure. - $(SPECS): $(wildcard $(topdir)/common/autoconf/*) + CUSTOM_CONFIG_DIR ?= $(topdir)/closed/autoconf + + $(SPECS): $(wildcard $(topdir)/common/autoconf/*) $(wildcard $(CUSTOM_CONFIG_DIR)/*) ifeq ($(CONF_CHECK), fail) @echo "Error: The configuration is not up to date for '$(lastword $(subst /, , $(dir $@)))'." $(call PrintConfCheckFailed) diff --git a/make/Main.gmk b/make/Main.gmk index 5e842fdebcd..47ba102d6ed 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -107,6 +107,7 @@ $(eval $(call DeclareRecipesForPhase, GENSRC, \ JDK_GENSRC_TARGETS := $(filter %-gensrc-jdk, $(GENSRC_TARGETS)) LANGTOOLS_GENSRC_TARGETS := $(filter %-gensrc-langtools, $(GENSRC_TARGETS)) CORBA_GENSRC_TARGETS := $(filter %-gensrc-corba, $(GENSRC_TARGETS)) +HOTSPOT_GENSRC_TARGETS := $(filter %-gensrc-hotspot, $(GENSRC_TARGETS)) ALL_TARGETS += $(GENSRC_TARGETS) @@ -128,7 +129,8 @@ $(eval $(call DeclareRecipesForPhase, COPY, \ FILE_PREFIX := Copy, \ MAKE_SUBDIR := copy, \ CHECK_MODULES := $(ALL_MODULES), \ - USE_WRAPPER := true)) + USE_WRAPPER := true, \ + MULTIPLE_MAKEFILES := true)) ALL_TARGETS += $(COPY_TARGETS) @@ -352,6 +354,8 @@ else $(CORBA_GENSRC_TARGETS): interim-langtools + $(HOTSPOT_GENSRC_TARGETS): interim-langtools + $(JDK_GENSRC_TARGETS): interim-langtools buildtools-jdk $(GENDATA_TARGETS): interim-langtools buildtools-jdk @@ -415,6 +419,9 @@ else # Explicitly add dependencies for special targets java.base-java: unpack-sec + # The copy target copies files generated by gensrc + java.base-copy-hotspot: java.base-gensrc-hotspot + jdk.jdeps-gendata: java rmic zip-security: java.base-java java.security.jgss-java java.security.jgss-libs \ diff --git a/make/MainSupport.gmk b/make/MainSupport.gmk index 3564f8bc794..29c212a5c9d 100644 --- a/make/MainSupport.gmk +++ b/make/MainSupport.gmk @@ -50,6 +50,8 @@ define CleanTest @$(PRINTF) "Cleaning test $(strip $1) ..." @$(PRINTF) "\n" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/test/$(strip $(subst -,/,$1)) + # Remove as much of the test directory structure as is empty + $(RMDIR) -p $(dir $(SUPPORT_OUTPUTDIR)/test/$(strip $(subst -,/,$1))) 2> /dev/null || true @$(PRINTF) " done\n" endef @@ -108,7 +110,8 @@ endef ################################################################################ -MAKE_TOPDIR_LIST := $(JDK_TOPDIR) $(CORBA_TOPDIR) $(LANGTOOLS_TOPDIR) +MAKE_TOPDIR_LIST := $(JDK_TOPDIR) $(CORBA_TOPDIR) $(LANGTOOLS_TOPDIR) \ + $(HOTSPOT_TOPDIR) MAKE_MAKEDIR_LIST := make # Helper macro for DeclareRecipesForPhase @@ -179,7 +182,7 @@ endef # FILE_PREFIX : File prefix for this build phase # USE_WRAPPER : Set to true to use ModuleWrapper.gmk # CHECK_MODULES : List of modules to try -# MULTIPLE_MAKEFILES : Set to true to handle makefils for the same module in +# MULTIPLE_MAKEFILES : Set to true to handle makefiles for the same module and # phase in multiple repos # Exported variables: # $1_MODULES : All modules that had rules generated diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index 8ced9d558c6..112275355da 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -59,6 +59,7 @@ FALSE_FIND_PATTERN:=-name FILE_NAME_THAT_DOESNT_EXIST # FLAGS:=Flags to be supplied to javac # SERVER_DIR:=Use a javac server (-XDserver) and store the server related files here # SERVER_JVM:=Use this JVM for the server. Defaults to the JVM above. +# DISABLE_SJAVAC:=Set to true if this setup does not support sjavac SetupJavaCompiler = $(NamedParamsMacroTemplate) define SetupJavaCompilerBody # The port file contains the tcp/ip on which the server listens @@ -439,6 +440,7 @@ define SetupJavaCompilationBody endif $1_SJAVAC_PORTFILE := $$($$($1_SETUP)_SJAVAC_PORTFILE) $1_SERVER_JVM := $$($$($1_SETUP)_SERVER_JVM) + $1_DISABLE_SJAVAC := $$($$($1_SETUP)_DISABLE_SJAVAC) # Handle addons and overrides. $1_SRC:=$$(call ADD_SRCS,$$($1_SRC)) @@ -552,6 +554,15 @@ define SetupJavaCompilationBody # and remove .java at the end. $1_REWRITE_INTO_CLASSES:=$$(foreach i,$$($1_SRC),-e 's|$$i/||g') -e 's|/|.|g' -e 's|.java$$$$||g' + # Create SJAVAC variable from JAVAC variable. Expects $1_JAVAC to be + # "bootclasspathprepend -cp .../javac.jar com.sun.tools.javac.Main" + # and javac is simply replaced with sjavac. + $1_SJAVAC:=$$(subst com.sun.tools.javac.Main,com.sun.tools.sjavac.Main,$$($1_JAVAC)) + + # Set the $1_REMOTE to spawn a background javac server. + $1_REMOTE:=--server:portfile=$$($1_SJAVAC_PORTFILE),id=$1,sjavac=$$(subst \ + $$(SPACE),%20,$$(subst $$(COMMA),%2C,$$(strip $$($1_SERVER_JVM) $$($1_SJAVAC)))) + ifeq ($$($1_DISABLE_SJAVAC)x$$(ENABLE_SJAVAC),xyes) ifneq (,$$($1_HEADERS)) $1_HEADERS_ARG := -h $$($1_HEADERS) @@ -560,15 +571,6 @@ define SetupJavaCompilationBody # Using sjavac to compile. $1_COMPILE_TARGETS := $$($1_BIN)/_the.$1_batch - # Create SJAVAC variable form JAVAC variable. Expects $1_JAVAC to be - # "bootclasspathprepend -cp .../javac.jar com.sun.tools.javac.Main" - # and javac is simply replaced with sjavac. - $1_SJAVAC:=$$(subst com.sun.tools.javac.Main,com.sun.tools.sjavac.Main,$$($1_JAVAC)) - - # Set the $1_REMOTE to spawn a background javac server. - $1_REMOTE:=--server:portfile=$$($1_SJAVAC_PORTFILE),id=$1,sjavac=$$(subst \ - $$(SPACE),%20,$$(subst $$(COMMA),%2C,$$(strip $$($1_SERVER_JVM) $$($1_SJAVAC)))) - $1_VARDEPS := $$($1_JVM) $$($1_SJAVAC) $$($1_SJAVAC_ARGS) $$($1_FLAGS) \ $$($1_HEADERS_ARG) $$($1_BIN) $$($1_EXCLUDES) $$($1_INCLUDES) \ $$($1_EXCLUDE_FILES) $$($1_INCLUDE_FILES) @@ -632,13 +634,19 @@ define SetupJavaCompilationBody $$($1_EXCLUDE_FILES) $$($1_INCLUDE_FILES) $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BIN)/_the.$1.vardeps) + ifeq ($$($1_DISABLE_SJAVAC)x$(ENABLE_JAVAC_SERVER), xyes) + $1_JAVAC_CMD := $$($1_SJAVAC) $$($1_REMOTE) + else + $1_JAVAC_CMD := $$($1_JAVAC) + endif + # When not using sjavac, pass along all sources to javac using an @file. $$($1_BIN)/_the.$1_batch: $$($1_SRCS) $$($1_DEPENDS) $$($1_VARDEPS_FILE) $(MKDIR) -p $$(@D) $$(eval $$(call ListPathsSafely,$1_SRCS, $$($1_BIN)/_the.$1_batch.tmp)) $(ECHO) Compiling `$(WC) $$($1_BIN)/_the.$1_batch.tmp | $(TR) -s ' ' | $(CUT) -f 2 -d ' '` files for $1 $(call LogFailures, $$($1_BIN)/_the.$$($1_SAFE_NAME)_batch.log, $$($1_SAFE_NAME), \ - $$($1_JVM) $$($1_JAVAC) $$($1_FLAGS) \ + $$($1_JVM) $$($1_JAVAC_CMD) $$($1_FLAGS) \ -implicit:none \ -d $$($1_BIN) $$($1_HEADERS_ARG) @$$($1_BIN)/_the.$1_batch.tmp) && \ $(MV) $$($1_BIN)/_the.$1_batch.tmp $$($1_BIN)/_the.$1_batch diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index 1593223939e..14f8d41d3cf 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -640,7 +640,8 @@ DependOnVariableHelper = \ $(if $(findstring $(LOG_LEVEL), trace), \ $(info NewVariable $1: >$(strip $($1))<) \ $(info OldVariable $1: >$(strip $($1_old))<)) \ - $(call WriteFile, $1_old:=$($1), $(call DependOnVariableFileName, $1, $2))) \ + $(call WriteFile, $1_old:=$(call DoubleDollar,$($1)), \ + $(call DependOnVariableFileName, $1, $2))) \ $(call DependOnVariableFileName, $1, $2) \ ) diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 4bfd6538b2b..007634c18cb 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -33,6 +33,7 @@ include SetupJavaCompilers.gmk # Module list macros ALL_TOP_SRC_DIRS := \ + $(HOTSPOT_TOPDIR)/src \ $(JDK_TOPDIR)/src \ $(LANGTOOLS_TOPDIR)/src \ $(CORBA_TOPDIR)/src \ diff --git a/make/common/SetupJavaCompilers.gmk b/make/common/SetupJavaCompilers.gmk index 6cee7c1214e..fc021d7860c 100644 --- a/make/common/SetupJavaCompilers.gmk +++ b/make/common/SetupJavaCompilers.gmk @@ -38,7 +38,9 @@ JAVAC_WARNINGS := -Xlint:all -Werror # and the interim javac, to be run by the boot jdk. $(eval $(call SetupJavaCompiler,BOOT_JAVAC, \ JAVAC := $(JAVAC), \ - FLAGS := -XDignore.symbol.file=true -g -Xlint:all$(COMMA)-deprecation -Werror)) + FLAGS := -XDignore.symbol.file=true -g -Xlint:all$(COMMA)-deprecation -Werror, \ + DISABLE_SJAVAC := true, \ +)) # Any java code executed during a JDK build to build other parts of the JDK must be # executed by the bootstrap JDK (probably with -Xbootclasspath/p: ) and for this diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index c2460105b7f..dc004b9b491 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -49,9 +49,9 @@ ARCH := $(word 1,$(subst -, ,$(TARGET))) # Define external dependencies # Latest that could be made to work. -gcc_ver := gcc-4.8.2 -binutils_ver := binutils-2.24 -ccache_ver := ccache-3.1.9 +gcc_ver := gcc-4.9.2 +binutils_ver := binutils-2.25 +ccache_ver := ccache-3.2.1 mpfr_ver := mpfr-3.0.1 gmp_ver := gmp-4.3.2 mpc_ver := mpc-1.0.1 diff --git a/make/devkit/createWindowsDevkit.sh b/make/devkit/createWindowsDevkit.sh index ed8e5022a31..187a4c7c154 100644 --- a/make/devkit/createWindowsDevkit.sh +++ b/make/devkit/createWindowsDevkit.sh @@ -32,10 +32,11 @@ VS_VERSION="2013" VS_VERSION_NUM="12.0" VS_VERSION_NUM_NODOT="120" SDK_VERSION="8.1" +VS_VERSION_SP="SP4" SCRIPT_DIR="$(cd "$(dirname $0)" > /dev/null && pwd)" BUILD_DIR="${SCRIPT_DIR}/../../build/devkit" -DEVKIT_ROOT="${BUILD_DIR}/VS${VS_VERSION}-devkit" +DEVKIT_ROOT="${BUILD_DIR}/VS${VS_VERSION}${VS_VERSION_SP}-devkit" DEVKIT_BUNDLE="${DEVKIT_ROOT}.tar.gz" echo "Creating devkit in $DEVKIT_ROOT" @@ -103,7 +104,7 @@ echo-info() { echo "Generating devkit.info..." rm -f $DEVKIT_ROOT/devkit.info echo-info "# This file describes to configure how to interpret the contents of this devkit" -echo-info "DEVKIT_NAME=\"Microsoft Visual Studio $VS_VERSION (devkit)\"" +echo-info "DEVKIT_NAME=\"Microsoft Visual Studio $VS_VERSION $VS_VERSION_SP (devkit)\"" echo-info "DEVKIT_VS_VERSION=\"$VS_VERSION\"" echo-info "" echo-info "DEVKIT_TOOLCHAIN_PATH_x86=\"\$DEVKIT_ROOT/VC/bin:\$DEVKIT_ROOT/$SDK_VERSION/bin/x86\"" diff --git a/make/jprt.properties b/make/jprt.properties index e882b8a21a9..7e5182b4dbd 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -122,11 +122,18 @@ jprt.i586.fastdebugOpen.build.configure.args= \ jprt.i586.productOpen.build.configure.args= \ ${my.i586.default.build.configure.args} \ ${jprt.productOpen.build.configure.args} +jprt.linux_i586.build.configure.args= \ + --with-devkit=$GCC492_OEL64_HOME \ + ${jprt.i586.build.configure.args} +jprt.linux_x64.build.configure.args= \ + --with-devkit=$GCC492_OEL64_HOME jprt.windows_i586.build.configure.args= \ - --with-devkit=$VS2013_HOME \ + --with-devkit=$VS2013SP4_HOME \ ${jprt.i586.build.configure.args} jprt.windows_x64.build.configure.args= \ - --with-devkit=$VS2013_HOME + --with-devkit=$VS2013SP4_HOME +jprt.macosx_x64.build.configure.args= \ + --with-devkit=$XCODE_511_HOME ######## # diff --git a/make/test/BuildTestLib.gmk b/make/test/BuildTestLib.gmk index 70c9da3c783..74a58d3c7d4 100644 --- a/make/test/BuildTestLib.gmk +++ b/make/test/BuildTestLib.gmk @@ -39,6 +39,7 @@ TEST_LIB_SUPPORT := $(SUPPORT_OUTPUTDIR)/test/lib $(eval $(call SetupJavaCompiler, BOOT_JAVAC_NOWARNINGS, \ JAVAC := $(JAVAC), \ FLAGS := -XDignore.symbol.file=true -g, \ + DISABLE_SJAVAC := true, \ )) $(eval $(call SetupJavaCompilation, BUILD_WB_JAR, \ diff --git a/modules.xml b/modules.xml index 2c8ddccc9a2..94b55f7c691 100644 --- a/modules.xml +++ b/modules.xml @@ -237,6 +237,7 @@ java.instrument jdk.jfr jdk.scripting.nashorn + jdk.vm.ci jdk.internal.org.objectweb.asm.commons @@ -290,6 +291,7 @@ jdk.security.auth jdk.security.jgss jdk.snmp + jdk.vm.ci java.instrument @@ -787,6 +789,19 @@ jdk.accessibility + + jdk.jshell + java.base + java.compiler + jdk.compiler + java.desktop + java.prefs + jdk.jdi + jdk.internal.le + + jdk.jshell + + java.instrument java.base @@ -1547,14 +1562,17 @@ com.sun.tools.javac.api + jdk.jshell jdk.javadoc com.sun.tools.javac.code + jdk.jshell jdk.javadoc com.sun.tools.javac.comp + jdk.jshell jdk.javadoc @@ -1564,16 +1582,22 @@ com.sun.tools.javac.jvm + jdk.jshell jdk.javadoc com.sun.tools.javac.main + jdk.jshell jdk.javadoc com.sun.tools.javac.nio jdk.javadoc + + com.sun.tools.javac.parser + jdk.jshell + com.sun.tools.javac.platform jdk.javadoc @@ -1584,10 +1608,12 @@ com.sun.tools.javac.tree + jdk.jshell jdk.javadoc com.sun.tools.javac.util + jdk.jshell jdk.javadoc jdk.jdeps @@ -1648,22 +1674,27 @@ java.base jdk.internal.jline + jdk.jshell jdk.scripting.nashorn.shell jdk.internal.jline.console + jdk.jshell jdk.scripting.nashorn.shell jdk.internal.jline.console.completer + jdk.jshell jdk.scripting.nashorn.shell jdk.internal.jline.console.history + jdk.jshell jdk.scripting.nashorn.shell jdk.internal.jline.internal + jdk.jshell jdk.scripting.nashorn.shell @@ -1871,6 +1902,18 @@ com.sun.security.jgss + + jdk.vm.ci + java.base + + jdk.vm.ci.hotspot + jdk.jfr + + + jdk.vm.ci.hotspot.events + jdk.jfr + + jdk.xml.bind java.activation diff --git a/nashorn/.hgtags b/nashorn/.hgtags index c53ae09ca40..4d176aa9820 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -321,3 +321,4 @@ ab231613d7206431ba31917a02e7cedd70e88e70 jdk9-b76 285628dac94332d95979de365630c93ab8fa9962 jdk9-b85 e4283eeb182cbdf5004740728a404aac6afa1104 jdk9-b86 0bf2fe0c7b3277cd247ed4f6faaf2b56d83139cf jdk9-b87 +a2aa804daac974289e20bf8f9106740732f08b34 jdk9-b88 diff --git a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/PackagesHelper.java b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/PackagesHelper.java index 57b7440e6e5..a726edc7063 100644 --- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/PackagesHelper.java +++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/PackagesHelper.java @@ -51,7 +51,11 @@ import javax.tools.ToolProvider; */ final class PackagesHelper { // JavaCompiler may be null on certain platforms (eg. JRE) - private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + private static final JavaCompiler compiler; + static { + // Use javac only if security manager is not around! + compiler = System.getSecurityManager() == null? ToolProvider.getSystemJavaCompiler() : null; + } /** * Is Java package properties helper available? diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java index cf0604dd4ae..e9d8a981e74 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java @@ -83,92 +83,205 @@ package jdk.internal.dynalink; +import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; -import jdk.internal.dynalink.support.CallSiteDescriptorFactory; +import java.util.Objects; /** - * An immutable descriptor of a call site. It is an immutable object that contains all the information about a call - * site: the class performing the lookups, the name of the method being invoked, and the method signature. The library - * has a default {@link CallSiteDescriptorFactory} for descriptors that you can use, or you can create your own - * descriptor classes, especially if you need to add further information (values passed in additional parameters to the - * bootstrap method) to them. Call site descriptors are used in this library in place of passing a real call site to - * guarding linkers so they aren't tempted to directly manipulate the call sites. The constructors of built-in - * {@link RelinkableCallSite} implementations all need a call site descriptor. Even if you create your own call site - * descriptors consider using {@link CallSiteDescriptorFactory#tokenizeName(String)} in your implementation. + * Call site descriptors contain all the information necessary for linking a + * call site. This information is normally passed as parameters to bootstrap + * methods and consists of the {@code MethodHandles.Lookup} object on the caller + * class in which the call site occurs, the dynamic operation at the call + * site, and the method type of the call site. {@code CallSiteDescriptor} + * objects are used in Dynalink to capture and store these parameters for + * subsequent use by the {@link DynamicLinker}. + *

      + * The constructors of built-in {@link RelinkableCallSite} implementations all + * take a call site descriptor. + *

      + * Call site descriptors must be immutable. You can use this class as-is or you + * can subclass it, especially if you need to add further information to the + * descriptors (typically, values passed in additional parameters to the + * bootstrap method. Since the descriptors must be immutable, you can set up a + * cache for equivalent descriptors to have the call sites share them. */ -public interface CallSiteDescriptor { - /** - * The index of the name token that will carry the operation scheme prefix (usually, "dyn"). - */ - public static final int SCHEME = 0; - /** - * The index of the name token that will usually carry the operation name. - */ - - public static final int OPERATOR=1; - /** - * The index of the name token that will usually carry a name of an operand (of a property, method, etc.) - */ - - public static final int NAME_OPERAND=2; +public class CallSiteDescriptor { + private final MethodHandles.Lookup lookup; + private final Operation operation; + private final MethodType methodType; /** - * Character used to delimit tokens in an call site name. + * The name of a runtime permission to invoke the {@link #getLookup()} + * method. */ - public static final String TOKEN_DELIMITER = ":"; + public static final String GET_LOOKUP_PERMISSION_NAME = "dynalink.getLookup"; + + private static final RuntimePermission GET_LOOKUP_PERMISSION = new RuntimePermission(GET_LOOKUP_PERMISSION_NAME); /** - * Character used to delimit operation names in a composite operation specification. + * Creates a new call site descriptor. + * @param lookup the lookup object describing the class the call site belongs to. + * @param operation the dynamic operation at the call site. + * @param methodType the method type of the call site. */ - public static final String OPERATOR_DELIMITER = "|"; + public CallSiteDescriptor(final Lookup lookup, final Operation operation, final MethodType methodType) { + this.lookup = Objects.requireNonNull(lookup, "lookup"); + this.operation = Objects.requireNonNull(operation, "name"); + this.methodType = Objects.requireNonNull(methodType, "methodType"); + } /** - * Returns the number of tokens in the name of the method at the call site. Method names are tokenized with the - * colon ":" character, i.e. "dyn:getProp:color" would be the name used to describe a method that retrieves the - * property named "color" on the object it is invoked on. - * @return the number of tokens in the name of the method at the call site. + * Returns the operation at the call site. + * @return the operation at the call site. */ - public int getNameTokenCount(); - - /** - * Returns the ith token in the method name at the call site. Method names are tokenized with the - * colon ":" character. - * @param i the index of the token. Must be between 0 (inclusive) and {@link #getNameTokenCount()} (exclusive) - * @throws IllegalArgumentException if the index is outside the allowed range. - * @return the ith token in the method name at the call site. The returned strings are interned. - */ - public String getNameToken(int i); - - /** - * Returns the name of the method at the call site. Note that the object internally only stores the tokenized name, - * and has to reconstruct the full name from tokens on each invocation. - * @return the name of the method at the call site. - */ - public String getName(); + public final Operation getOperation() { + return operation; + } /** * The type of the method at the call site. * * @return type of the method at the call site. */ - public MethodType getMethodType(); + public final MethodType getMethodType() { + return methodType; + } /** - * Returns the lookup passed to the bootstrap method. If the lookup isn't the public lookup, the - * implementation must check the {@code RuntimePermission("dynalink.getLookup")} permission if a security - * manager is present. - * @return the lookup passed to the bootstrap method. + * Returns the lookup that should be used to find method handles to set as + * targets of the call site described by this descriptor. When creating + * descriptors from a {@link java.lang.invoke} bootstrap method, it should + * be the lookup passed to the bootstrap. + * @return the lookup that should be used to find method handles to set as + * targets of the call site described by this descriptor. + * @throws SecurityException if the lookup isn't the + * {@link MethodHandles#publicLookup()} and a security manager is present, + * and a check for {@code RuntimePermission("dynalink.getLookup")} fails. */ - public Lookup getLookup(); + public final Lookup getLookup() { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null && lookup != MethodHandles.publicLookup()) { + sm.checkPermission(GET_LOOKUP_PERMISSION); + } + return lookup; + } /** - * Creates a new call site descriptor from this descriptor, which is identical to this, except it changes the method - * type. + * Returns the value of {@link #getLookup()} without a security check. Can + * be used by subclasses to access the lookup quickly. + * @return same as returned value of {@link #getLookup()}. + */ + protected final Lookup getLookupPrivileged() { + return lookup; + } + + /** + * Creates a new call site descriptor from this descriptor, which is + * identical to this, except it changes the method type. Invokes + * {@link #changeMethodTypeInternal(MethodType)} and checks that it returns + * a descriptor of the same class as this descriptor. + * + * @param newMethodType the new method type + * @return a new call site descriptor, with the method type changed. + * @throws RuntimeException if {@link #changeMethodTypeInternal(MethodType)} + * returned a descriptor of different class than this object. + * @throws NullPointerException if {@link #changeMethodTypeInternal(MethodType)} + * returned null. + */ + public final CallSiteDescriptor changeMethodType(final MethodType newMethodType) { + final CallSiteDescriptor changed = Objects.requireNonNull( + changeMethodTypeInternal(newMethodType), + "changeMethodTypeInternal() must not return null."); + + if (getClass() != changed.getClass()) { + throw new RuntimeException( + "changeMethodTypeInternal() must return an object of the same class it is invoked on."); + } + + return changed; + } + + /** + * Creates a new call site descriptor from this descriptor, which is + * identical to this, except it changes the method type. Subclasses must + * override this method to return an object of their exact class. * * @param newMethodType the new method type * @return a new call site descriptor, with the method type changed. */ - public CallSiteDescriptor changeMethodType(MethodType newMethodType); + protected CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) { + return new CallSiteDescriptor(lookup, operation, newMethodType); + } + /** + * Returns true if this call site descriptor is equal to the passed object. + * It is considered equal if the other object is of the exact same class, + * their operations and method types are equal, and their lookups have the + * same {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and + * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()}. + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } else if (obj == null) { + return false; + } else if (obj.getClass() != getClass()) { + return false; + } + final CallSiteDescriptor other = (CallSiteDescriptor)obj; + return operation.equals(other.operation) && + methodType.equals(other.methodType) && + lookupsEqual(lookup, other.lookup); + } + + /** + * Compares two lookup objects for value-based equality. They are considered + * equal if they have the same + * {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and + * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()}. + * @param l1 first lookup + * @param l2 second lookup + * @return true if the two lookups are equal, false otherwise. + */ + private static boolean lookupsEqual(final Lookup l1, final Lookup l2) { + return l1.lookupClass() == l2.lookupClass() && l1.lookupModes() == l2.lookupModes(); + } + + /** + * Returns a value-based hash code of this call site descriptor computed + * from its operation, method type, and lookup object's lookup class and + * lookup modes. + * @return value-based hash code for this call site descriptor. + */ + @Override + public int hashCode() { + return operation.hashCode() + 31 * methodType.hashCode() + 31 * 31 * lookupHashCode(lookup); + } + + /** + * Returns a value-based hash code for the passed lookup object. It is + * based on the lookup object's + * {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and + * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()} values. + * @param lookup the lookup object. + * @return a hash code for the object.. + */ + private static int lookupHashCode(final Lookup lookup) { + return lookup.lookupClass().hashCode() + 31 * lookup.lookupModes(); + } + + /** + * Returns the string representation of this call site descriptor, of the + * format {@code name(parameterTypes)returnType@lookup}. + */ + @Override + public String toString() { + final String mt = methodType.toString(); + final String l = lookup.toString(); + final String o = operation.toString(); + final StringBuilder b = new StringBuilder(o.length() + mt.length() + 1 + l.length()); + return b.append(o).append(mt).append('@').append(l).toString(); + } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/ClassMap.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/ClassMap.java similarity index 89% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/ClassMap.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/ClassMap.java index 97e37d7ee66..fcbf0ad7525 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/ClassMap.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/ClassMap.java @@ -81,16 +81,19 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink; import java.lang.ref.Reference; import java.lang.ref.SoftReference; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import jdk.internal.dynalink.internal.AccessControlContextFactory; +import jdk.internal.dynalink.internal.InternalTypeUtilities; /** * A dual map that can either strongly or weakly reference a given class depending on whether the class is visible from @@ -98,7 +101,10 @@ import java.util.concurrent.ConcurrentMap; * * @param the type of the values in the map */ -public abstract class ClassMap { +abstract class ClassMap { + private static final AccessControlContext GET_CLASS_LOADER_CONTEXT = + AccessControlContextFactory.createAccessControlContext("getClassLoader"); + private final ConcurrentMap, T> map = new ConcurrentHashMap<>(); private final Map, Reference> weakMap = new WeakHashMap<>(); private final ClassLoader classLoader; @@ -109,7 +115,7 @@ public abstract class ClassMap { * * @param classLoader the classloader that determines strong referenceability. */ - protected ClassMap(final ClassLoader classLoader) { + ClassMap(final ClassLoader classLoader) { this.classLoader = classLoader; } @@ -120,7 +126,7 @@ public abstract class ClassMap { * @param clazz the class to compute the value for * @return the return value. Must not be null. */ - protected abstract T computeValue(Class clazz); + abstract T computeValue(Class clazz); /** * Returns the value associated with the class @@ -128,7 +134,7 @@ public abstract class ClassMap { * @param clazz the class * @return the value associated with the class */ - public T get(final Class clazz) { + T get(final Class clazz) { // Check in fastest first - objects we're allowed to strongly reference final T v = map.get(clazz); if(v != null) { @@ -149,15 +155,15 @@ public abstract class ClassMap { final T newV = computeValue(clazz); assert newV != null; - final ClassLoader clazzLoader = AccessController.doPrivileged(new PrivilegedAction() { + final Boolean canReferenceDirectly = AccessController.doPrivileged(new PrivilegedAction() { @Override - public ClassLoader run() { - return clazz.getClassLoader(); + public Boolean run() { + return InternalTypeUtilities.canReferenceDirectly(classLoader, clazz.getClassLoader()); } - }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT); + }, GET_CLASS_LOADER_CONTEXT); // If allowed to strongly reference, put it in the fast map - if(Guards.canReferenceDirectly(classLoader, clazzLoader)) { + if(canReferenceDirectly) { final T oldV = map.putIfAbsent(clazz, newV); return oldV != null ? oldV : newV; } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CompositeOperation.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CompositeOperation.java new file mode 100644 index 00000000000..a24b4999ad8 --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CompositeOperation.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2015 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package jdk.internal.dynalink; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Describes an operation that is composed of at least two other operations. The + * component operations are treated as alternatives to each other in order of + * preference. The semantics of the composite operation is "first successful". + * That is, a composite of {@code GET_PROPERTY|GET_ELEMENT:color} should be + * interpreted as get the property named "color" on the object, but if the + * property does not exist, then get the collection element named "color" + * instead. + *

      + * Composite operations are helpful in implementation of languages that + * don't distinguish between one or more of the property, method, and element + * namespaces, or when expressing operations against objects that can be + * considered both ordinary objects and collections, e.g. Java + * {@link java.util.Map} objects. A composite operation + * {@code GET_PROPERTY|GET_ELEMENT:empty} against a Java map will always match + * the {@link java.util.Map#isEmpty()} property, but + * {@code GET_ELEMENT|GET_PROPERTY:empty} will actually match a map element with + * key {@code "empty"} if the map contains that key, and only fall back to the + * {@code isEmpty()} property getter if the map does not contain the key. If + * the source language mandates this semantics, it can be easily achieved using + * composite operations. + *

      + * Even if the language itself doesn't distinguish between some of the + * namespaces, it can be helpful to map different syntaxes to different + * compositions. E.g. the source expression {@code obj.color} could map to + * {@code GET_PROPERTY|GET_ELEMENT|GET_METHOD:color}, but a different source + * expression that looks like collection element access {@code obj[key]} could + * be expressed instead as {@code GET_ELEMENT|GET_PROPERTY|GET_METHOD}. + * Finally, if the retrieved value is subsequently called, then it makes sense + * to bring {@code GET_METHOD} to the front of the list: the getter part of the + * source expression {@code obj.color()} should be + * {@code GET_METHOD|GET_PROPERTY|GET_ELEMENT:color} and the one for + * {@code obj[key]()} should be {@code GET_METHOD|GET_ELEMENT|GET_PROPERTY}. + *

      + * The elements of a composite operation can not be composites or named + * operations, but rather simple operations such are elements of + * {@link StandardOperation}. A composite operation itself can serve as the base + * operation of a named operation, though; a typical way to construct e.g. the + * {@code GET_ELEMENT|GET_PROPERTY:empty} from above would be: + *

      + * Operation getElementOrPropertyEmpty = new NamedOperation(
      + *     new CompositeOperation(
      + *         StandardOperation.GET_ELEMENT,
      + *         StandardOperation.GET_PROPERTY),
      + *     "empty");
      + * 
      + *

      + * Not all compositions make sense. Typically, any combination in any order of + * standard getter operations {@code GET_PROPERTY}, {@code GET_ELEMENT}, and + * {@code GET_METHOD} make sense, as do combinations of {@code SET_PROPERTY} and + * {@code SET_ELEMENT}; other standard operations should not be combined. The + * constructor will allow any combination of operations, though. + */ +public class CompositeOperation implements Operation { + private final Operation[] operations; + + /** + * Constructs a new composite operation. + * @param operations the components for this composite operation. The passed + * array will be cloned. + * @throws IllegalArgumentException if less than two components are + * specified, or any component is itself a {@link CompositeOperation} or a + * {@link NamedOperation}. + * @throws NullPointerException if either the operations array or any of its + * elements are {@code null}. + */ + public CompositeOperation(final Operation... operations) { + Objects.requireNonNull(operations, "operations array is null"); + if (operations.length < 2) { + throw new IllegalArgumentException("Must have at least two operations"); + } + final Operation[] clonedOps = operations.clone(); + for(int i = 0; i < clonedOps.length; ++i) { + final Operation op = clonedOps[i]; + if (op == null) { + throw new NullPointerException("operations[" + i + "] is null"); + } else if (op instanceof NamedOperation) { + throw new IllegalArgumentException("operations[" + i + "] is a NamedOperation"); + } else if (op instanceof CompositeOperation) { + throw new IllegalArgumentException("operations[" + i + "] is a CompositeOperation"); + } + } + this.operations = clonedOps; + } + + /** + * Returns the component operations in this composite operation. The + * returned array is a copy and changes to it don't have effect on this + * object. + * @return the component operations in this composite operation. + */ + public Operation[] getOperations() { + return operations.clone(); + } + + /** + * Returns the number of component operations in this composite operation. + * @return the number of component operations in this composite operation. + */ + public int getOperationCount() { + return operations.length; + } + + /** + * Returns the i-th component operation in this composite operation. + * @param i the operation index + * @return the i-th component operation in this composite operation. + * @throws IndexOutOfBoundsException if the index is out of range. + */ + public Operation getOperation(final int i) { + try { + return operations[i]; + } catch (final ArrayIndexOutOfBoundsException e) { + throw new IndexOutOfBoundsException(Integer.toString(i)); + } + } + + /** + * Returns true if this composite operation contains an operation equal to + * the specified operation. + * @param operation the operation being searched for. Must not be null. + * @return true if the if this composite operation contains an operation + * equal to the specified operation. + */ + public boolean contains(final Operation operation) { + Objects.requireNonNull(operation); + for(final Operation component: operations) { + if (component.equals(operation)) { + return true; + } + } + return false; + } + + /** + * Returns true if the other object is also a composite operation and their + * component operations are equal. + * @param obj the object to compare to + * @return true if this object is equal to the other one, false otherwise. + */ + @Override + public boolean equals(final Object obj) { + if (obj == null || obj.getClass() != CompositeOperation.class) { + return false; + } + return Arrays.equals(operations, ((CompositeOperation)obj).operations); + } + + /** + * Returns the hash code of this composite operation. Defined to be equal + * to {@code java.util.Arrays.hashCode(operations)}. + */ + @Override + public int hashCode() { + return Arrays.hashCode(operations); + }; + + /** + * Returns the string representation of this composite operation. Defined to + * be the {@code toString} of its component operations, each separated by + * the vertical line character (e.g. {@code "GET_PROPERTY|GET_ELEMENT"}). + * @return the string representation of this composite operation. + */ + @Override + public String toString() { + final StringBuilder b = new StringBuilder(); + b.append(operations[0]); + for(int i = 1; i < operations.length; ++i) { + b.append('|').append(operations[i]); + } + return b.toString(); + } + + /** + * Returns the components of the passed operation if it is a composite + * operation, otherwise returns an array containing the operation itself. + * This allows for returning an array of component even if it is not known + * whether the operation is itself a composite (treating a non-composite + * operation as if it were a single-element composite of itself). + * @param op the operation whose components are retrieved. + * @return if the passed operation is a composite operation, returns its + * {@link #getOperations()}, otherwise returns the operation itself. + */ + public static Operation[] getOperations(final Operation op) { + return op instanceof CompositeOperation + ? ((CompositeOperation)op).operations.clone() + : new Operation[] { op }; + } + + /** + * Returns true if the specified potentially composite operation is a + * {@link CompositeOperation} and contains an operation equal to the + * specified operation. If {@code composite} is not a + * {@link CompositeOperation}, then the two operations are compared for + * equality. + * @param composite the potentially composite operation. Must not be null. + * @param operation the operation being searched for. Must not be null. + * @return true if the if the passed operation is a + * {@link CompositeOperation} and contains a component operation equal to + * the specified operation, or if it is not a {@link CompositeOperation} and + * is equal to {@code operation}. + */ + public static boolean contains(final Operation composite, final Operation operation) { + if (composite instanceof CompositeOperation) { + return ((CompositeOperation)composite).contains(operation); + } + return composite.equals(Objects.requireNonNull(operation)); + } +} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DefaultBootstrapper.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DefaultBootstrapper.java deleted file mode 100644 index de609fd6096..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DefaultBootstrapper.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink; - -import java.lang.invoke.CallSite; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import jdk.internal.dynalink.support.CallSiteDescriptorFactory; - -/** - * A convenience default bootstrapper that exposes static bootstrap methods which language runtimes that need the very - * default behavior can use with minimal setup. When first referenced, it will create a dynamic linker with default - * settings for the {@link DynamicLinkerFactory}, and its bootstrap methods will create {@link MonomorphicCallSite} for - * all call sites. It has two bootstrap methods: one creates call sites that use the - * {@link MethodHandles#publicLookup()} as the lookup for all call sites and disregard the one passed in as the caller, - * and one that just uses the passed caller as the lookup scope. Using the public lookup one is advised if your language - * runtime has no concept of interacting with Java visibility scopes, as it results in a more lightweight runtime - * information. - */ -public class DefaultBootstrapper { - private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker(); - - private DefaultBootstrapper() { - } - - /** - * Use this method as your bootstrap method (see the documentation of the java.lang.invoke package for how to do - * this). In case your language runtime doesn't have a concept of interaction with Java access scopes, you might - * want to consider using - * {@link #publicBootstrap(java.lang.invoke.MethodHandles.Lookup, String, MethodType)} instead. - * - * @param caller the caller's lookup - * @param name the name of the method at the call site - * @param type the method signature at the call site - * @return a new {@link MonomorphicCallSite} linked with the default dynamic linker. - */ - public static CallSite bootstrap(final MethodHandles.Lookup caller, final String name, final MethodType type) { - return bootstrapInternal(caller, name, type); - } - - /** - * Use this method as your bootstrap method (see the documentation of the java.lang.invoke package for how to do - * this) when your language runtime doesn't have a concept of interaction with Java access scopes. If you need to - * preserve the different caller Lookup objects in the call sites, use - * {@link #bootstrap(java.lang.invoke.MethodHandles.Lookup, String, MethodType)} instead - * - * @param caller the caller's lookup. It is ignored as the call sites will be created with - * {@link MethodHandles#publicLookup()} instead. - * @param name the name of the method at the call site - * @param type the method signature at the call site - * @return a new {@link MonomorphicCallSite} linked with the default dynamic linker. - */ - public static CallSite publicBootstrap(final MethodHandles.Lookup caller, final String name, final MethodType type) { - return bootstrapInternal(MethodHandles.publicLookup(), name, type); - } - - private static CallSite bootstrapInternal(final MethodHandles.Lookup caller, final String name, final MethodType type) { - return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(caller, name, type))); - } -} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java index 0c3f9a21aea..461fe5eee5c 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java @@ -87,26 +87,31 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.MutableCallSite; -import java.util.List; import java.util.Objects; import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardedInvocationTransformer; import jdk.internal.dynalink.linker.GuardingDynamicLinker; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; -import jdk.internal.dynalink.support.CallSiteDescriptorFactory; -import jdk.internal.dynalink.support.LinkRequestImpl; -import jdk.internal.dynalink.support.Lookup; -import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl; +import jdk.internal.dynalink.linker.support.Lookup; +import jdk.internal.dynalink.linker.support.SimpleLinkRequest; +import jdk.internal.dynalink.support.ChainedCallSite; +import jdk.internal.dynalink.support.SimpleRelinkableCallSite; /** - * The linker for {@link RelinkableCallSite} objects. Users of it (scripting - * frameworks and language runtimes) have to create a linker using the - * {@link DynamicLinkerFactory} and invoke its link method from the invokedynamic - * bootstrap methods to set the target of all the call sites in the code they - * generate. Usual usage would be to create one class per language runtime to - * contain one linker instance as: - * + * The linker for {@link RelinkableCallSite} objects. A dynamic linker is a main + * objects when using Dynalink, it coordinates linking of call sites with + * linkers of available language runtimes that are represented by + * {@link GuardingDynamicLinker} objects (you only need to deal with these if + * you are yourself implementing a language runtime with its own object model + * and/or type conversions). To use Dynalink, you have to create one or more + * dynamic linkers using a {@link DynamicLinkerFactory}. Subsequently, you need + * to invoke its {@link #link(RelinkableCallSite)} method from + * {@code invokedynamic} bootstrap methods to let it manage all the call sites + * they create. Usual usage would be to create at least one class per language + * runtime to contain one linker instance as: *

      + *
        * class MyLanguageRuntime {
        *     private static final GuardingDynamicLinker myLanguageLinker = new MyLanguageLinker();
        *     private static final DynamicLinker dynamicLinker = createDynamicLinker();
      @@ -118,33 +123,44 @@ import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl;
        *     }
        *
        *     public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
      - *         return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(lookup, name, type)));
      + *         return dynamicLinker.link(
      + *             new SimpleRelinkableCallSite(
      + *                 new CallSiteDescriptor(lookup, parseOperation(name), type)));
      + *     }
      + *
      + *     private static Operation parseOperation(String name) {
      + *         ...
        *     }
        * }
        * 
      - * - * Note how there are three components you will need to provide here: + * The above setup of one static linker instance is often too simple. You will + * often have your language runtime have a concept of some kind of + * "context class loader" and you will want to create one dynamic linker per + * such class loader, to ensure it incorporates linkers for all other language + * runtimes visible to that class loader (see + * {@link DynamicLinkerFactory#setClassLoader(ClassLoader)}). + *

      + * There are three components you need to provide in the above example: *

        * - *
      • You're expected to provide a {@link GuardingDynamicLinker} for your own - * language. If your runtime doesn't have its own language and/or object model - * (i.e., it's a generic scripting shell), you don't need to implement a dynamic - * linker; you would simply not invoke the {@code setPrioritizedLinker} method - * on the factory, or even better, simply use {@link DefaultBootstrapper}.
      • + *
      • You are expected to provide a {@link GuardingDynamicLinker} for your own + * language. If your runtime doesn't have its own object model or type + * conversions, you don't need to implement a {@code GuardingDynamicLinker}; you + * would simply not invoke the {@code setPrioritizedLinker} method on the factory.
      • * *
      • The performance of the programs can depend on your choice of the class to - * represent call sites. The above example used {@link MonomorphicCallSite}, but - * you might want to use {@link ChainedCallSite} instead. You'll need to - * experiment and decide what fits your language runtime the best. You can - * subclass either of these or roll your own if you need to.
      • + * represent call sites. The above example used + * {@link SimpleRelinkableCallSite}, but you might want to use + * {@link ChainedCallSite} instead. You'll need to experiment and decide what + * fits your runtime the best. You can further subclass either of these or + * implement your own. * *
      • You also need to provide {@link CallSiteDescriptor}s to your call sites. * They are immutable objects that contain all the information about the call - * site: the class performing the lookups, the name of the method being invoked, - * and the method signature. The library has a default {@link CallSiteDescriptorFactory} - * for descriptors that you can use, or you can create your own descriptor - * classes, especially if you need to add further information (values passed in - * additional parameters to the bootstrap method) to them.
      • + * site: the class performing the lookups, the operation being invoked, and the + * method signature. You will have to supply your own scheme to encode and + * decode operations in the call site name or static parameters, that is why + * in the above example the {@code parseOperation} method is left unimplemented. * *
      */ @@ -157,8 +173,7 @@ public final class DynamicLinker { private static final String INVOKE_PACKAGE_PREFIX = "java.lang.invoke."; private final LinkerServices linkerServices; - private final GuardedInvocationFilter prelinkFilter; - private final int runtimeContextArgCount; + private final GuardedInvocationTransformer prelinkTransformer; private final boolean syncOnRelink; private final int unstableRelinkThreshold; @@ -166,20 +181,17 @@ public final class DynamicLinker { * Creates a new dynamic linker. * * @param linkerServices the linkerServices used by the linker, created by the factory. - * @param prelinkFilter see {@link DynamicLinkerFactory#setPrelinkFilter(GuardedInvocationFilter)} - * @param runtimeContextArgCount see {@link DynamicLinkerFactory#setRuntimeContextArgCount(int)} + * @param prelinkTransformer see {@link DynamicLinkerFactory#setPrelinkTransformer(GuardedInvocationTransformer)} + * @param syncOnRelink see {@link DynamicLinkerFactory#setSyncOnRelink(boolean)} + * @param unstableRelinkThreshold see {@link DynamicLinkerFactory#setUnstableRelinkThreshold(int)} */ - DynamicLinker(final LinkerServices linkerServices, final GuardedInvocationFilter prelinkFilter, final int runtimeContextArgCount, + DynamicLinker(final LinkerServices linkerServices, final GuardedInvocationTransformer prelinkTransformer, final boolean syncOnRelink, final int unstableRelinkThreshold) { - if(runtimeContextArgCount < 0) { - throw new IllegalArgumentException("runtimeContextArgCount < 0"); - } if(unstableRelinkThreshold < 0) { throw new IllegalArgumentException("unstableRelinkThreshold < 0"); } this.linkerServices = linkerServices; - this.prelinkFilter = prelinkFilter; - this.runtimeContextArgCount = runtimeContextArgCount; + this.prelinkTransformer = prelinkTransformer; this.syncOnRelink = syncOnRelink; this.unstableRelinkThreshold = unstableRelinkThreshold; } @@ -202,12 +214,13 @@ public final class DynamicLinker { } /** - * Returns the object representing the lower level linker services of this - * class that are normally exposed to individual language-specific linkers. - * While as a user of this class you normally only care about the - * {@link #link(RelinkableCallSite)} method, in certain circumstances you - * might want to use the lower level services directly; either to lookup - * specific method handles, to access the type converters, and so on. + * Returns the object representing the linker services of this class that + * are normally exposed to individual {@link GuardingDynamicLinker + * language-specific linkers}. While as a user of this class you normally + * only care about the {@link #link(RelinkableCallSite)} method, in certain + * circumstances you might want to use the lower level services directly; + * either to lookup specific method handles, to access the type converters, + * and so on. * * @return the object representing the linker services of this class. */ @@ -244,10 +257,7 @@ public final class DynamicLinker { final CallSiteDescriptor callSiteDescriptor = callSite.getDescriptor(); final boolean unstableDetectionEnabled = unstableRelinkThreshold > 0; final boolean callSiteUnstable = unstableDetectionEnabled && relinkCount >= unstableRelinkThreshold; - final LinkRequest linkRequest = - runtimeContextArgCount == 0 ? - new LinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments) : - new RuntimeContextLinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments, runtimeContextArgCount); + final LinkRequest linkRequest = new SimpleLinkRequest(callSiteDescriptor, callSiteUnstable, arguments); GuardedInvocation guardedInvocation = linkerServices.getGuardedInvocation(linkRequest); @@ -256,21 +266,9 @@ public final class DynamicLinker { throw new NoSuchDynamicMethodException(callSiteDescriptor.toString()); } - // If our call sites have a runtime context, and the linker produced a context-stripped invocation, adapt the - // produced invocation into contextual invocation (by dropping the context...) - if(runtimeContextArgCount > 0) { - final MethodType origType = callSiteDescriptor.getMethodType(); - final MethodHandle invocation = guardedInvocation.getInvocation(); - if(invocation.type().parameterCount() == origType.parameterCount() - runtimeContextArgCount) { - final List> prefix = origType.parameterList().subList(1, runtimeContextArgCount + 1); - final MethodHandle guard = guardedInvocation.getGuard(); - guardedInvocation = guardedInvocation.dropArguments(1, prefix); - } - } - - // Make sure we filter the invocation before linking it into the call site. This is typically used to match the + // Make sure we transform the invocation before linking it into the call site. This is typically used to match the // return type of the invocation to the call site. - guardedInvocation = prelinkFilter.filter(guardedInvocation, linkRequest, linkerServices); + guardedInvocation = prelinkTransformer.filter(guardedInvocation, linkRequest, linkerServices); Objects.requireNonNull(guardedInvocation); int newRelinkCount = relinkCount; @@ -290,11 +288,12 @@ public final class DynamicLinker { } /** - * Returns a stack trace element describing the location of the call site - * currently being linked on the current thread. The operation internally - * creates a Throwable object and inspects its stack trace, so it's - * potentially expensive. The recommended usage for it is in writing - * diagnostics code. + * Returns a stack trace element describing the location of the + * {@code invokedynamic} call site currently being linked on the current + * thread. The operation is potentially expensive as it needs to generate a + * stack trace to inspect it and is intended for use in diagnostics code. + * For "free-floating" call sites (not associated with an + * {@code invokedynamic} instruction), the result is not well-defined. * * @return a stack trace element describing the location of the call site * currently being linked, or null if it is not invoked while a call diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinkerFactory.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinkerFactory.java index ec16e9888aa..4b3ca5444a4 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinkerFactory.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinkerFactory.java @@ -83,43 +83,59 @@ package jdk.internal.dynalink; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; import java.lang.invoke.MutableCallSite; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Objects; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; import java.util.Set; +import java.util.function.Supplier; import jdk.internal.dynalink.beans.BeansLinker; +import jdk.internal.dynalink.internal.AccessControlContextFactory; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardedInvocationTransformer; import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.GuardingDynamicLinkerExporter; import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.MethodHandleTransformer; import jdk.internal.dynalink.linker.MethodTypeConversionStrategy; -import jdk.internal.dynalink.support.AutoDiscovery; -import jdk.internal.dynalink.support.BottomGuardingDynamicLinker; -import jdk.internal.dynalink.support.ClassLoaderGetterContextProvider; -import jdk.internal.dynalink.support.CompositeGuardingDynamicLinker; -import jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker; -import jdk.internal.dynalink.support.DefaultPrelinkFilter; -import jdk.internal.dynalink.support.LinkerServicesImpl; -import jdk.internal.dynalink.support.TypeConverterFactory; -import jdk.internal.dynalink.support.TypeUtilities; +import jdk.internal.dynalink.linker.support.CompositeGuardingDynamicLinker; +import jdk.internal.dynalink.linker.support.CompositeTypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.linker.support.DefaultInternalObjectFilter; +import jdk.internal.dynalink.linker.support.TypeUtilities; /** - * A factory class for creating {@link DynamicLinker}s. The usual dynamic linker is a linker composed of all - * {@link GuardingDynamicLinker}s known and pre-created by the caller as well as any - * {@link AutoDiscovery automatically discovered} guarding linkers and the standard fallback - * {@link BeansLinker} and a {@link DefaultPrelinkFilter}. See {@link DynamicLinker} documentation for tips on - * how to use this class. + * A factory class for creating {@link DynamicLinker} objects. Dynamic linkers + * are the central objects in Dynalink; these are composed of several + * {@link GuardingDynamicLinker} objects and coordinate linking of call sites + * with them. The usual dynamic linker is a linker + * composed of all {@link GuardingDynamicLinker} objects explicitly pre-created + * by the user of the factory and configured with + * {@link #setPrioritizedLinkers(List)}, as well as any + * {@link #setClassLoader(ClassLoader) automatically discovered} ones, and + * finally the ones configured with {@link #setFallbackLinkers(List)}; this last + * category usually includes {@link BeansLinker}. */ public final class DynamicLinkerFactory { + private static final AccessControlContext GET_CLASS_LOADER_CONTEXT = + AccessControlContextFactory.createAccessControlContext("getClassLoader"); + /** - * Default value for {@link #setUnstableRelinkThreshold(int) unstable relink threshold}. + * Default value for {@link #setUnstableRelinkThreshold(int) unstable relink + * threshold}. */ public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8; @@ -128,18 +144,40 @@ public final class DynamicLinkerFactory { private List prioritizedLinkers; private List fallbackLinkers; - private int runtimeContextArgCount = 0; private boolean syncOnRelink = false; private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD; - private GuardedInvocationFilter prelinkFilter; + private GuardedInvocationTransformer prelinkTransformer; private MethodTypeConversionStrategy autoConversionStrategy; private MethodHandleTransformer internalObjectsFilter; + private List autoLoadingErrors = Collections.emptyList(); + /** - * Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread - * context class loader at the time of {@link #createLinker()} invocation will be used. + * Creates a new dynamic linker factory with default configuration. Upon + * creation, the factory can be configured using various {@code setXxx()} + * methods and used to create one or more dynamic linkers according to its + * current configuration using {@link #createLinker()}. + */ + public DynamicLinkerFactory() { + } + + /** + * Sets the class loader for automatic discovery of available guarding + * dynamic linkers. {@link GuardingDynamicLinkerExporter} implementations + * available through this class loader will be automatically instantiated + * using the {@link ServiceLoader} mechanism and the linkers they provide + * will be incorporated into {@code DynamicLinker}s that this factory + * creates. This allows for cross-language interoperability where call sites + * belonging to this language runtime can be linked by linkers from these + * automatically discovered runtimes if their native objects are passed to + * this runtime. If class loader is not set explicitly by invoking this + * method, then the thread context class loader of the thread invoking + * {@link #createLinker()} will be used. If this method is invoked + * explicitly with null then {@link ServiceLoader#loadInstalled(Class)} will + * be used to load the linkers. * - * @param classLoader the class loader used for the autodiscovery of available linkers. + * @param classLoader the class loader used for the automatic discovery of + * available linkers. */ public void setClassLoader(final ClassLoader classLoader) { this.classLoader = classLoader; @@ -147,90 +185,84 @@ public final class DynamicLinkerFactory { } /** - * Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker - * for their own language. These linkers will be consulted first in the resulting dynamic linker, before any - * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized - * linkers, it will be ignored and the explicit prioritized instance will be used. + * Sets the prioritized guarding dynamic linkers. Language runtimes using + * Dynalink will usually have at least one linker for their own language. + * These linkers will be consulted first by the resulting dynamic linker + * when it is linking call sites, before any autodiscovered and fallback + * linkers. If the factory also autodiscovers a linker class matching one + * of the prioritized linkers, the autodiscovered class will be ignored and + * the explicit prioritized instance will be used. * - * @param prioritizedLinkers the list of prioritized linkers. Null can be passed to indicate no prioritized linkers - * (this is also the default value). + * @param prioritizedLinkers the list of prioritized linkers. Can be null. + * @throws NullPointerException if any of the list elements are null. */ public void setPrioritizedLinkers(final List prioritizedLinkers) { - this.prioritizedLinkers = - prioritizedLinkers == null ? null : new ArrayList<>(prioritizedLinkers); + this.prioritizedLinkers = copyListRequireNonNullElements(prioritizedLinkers); } /** - * Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker - * for their own language. These linkers will be consulted first in the resulting dynamic linker, before any - * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized - * linkers, it will be ignored and the explicit prioritized instance will be used. + * Sets the prioritized guarding dynamic linkers. Identical to calling + * {@link #setPrioritizedLinkers(List)} with + * {@code Arrays.asList(prioritizedLinkers)}. * - * @param prioritizedLinkers a list of prioritized linkers. + * @param prioritizedLinkers an array of prioritized linkers. Can be null. + * @throws NullPointerException if any of the array elements are null. */ public void setPrioritizedLinkers(final GuardingDynamicLinker... prioritizedLinkers) { - setPrioritizedLinkers(Arrays.asList(prioritizedLinkers)); + setPrioritizedLinkers(prioritizedLinkers == null ? null : Arrays.asList(prioritizedLinkers)); } /** - * Sets a single prioritized linker. Identical to calling {@link #setPrioritizedLinkers(List)} with a single-element - * list. + * Sets a single prioritized linker. Identical to calling + * {@link #setPrioritizedLinkers(List)} with a single-element list. * * @param prioritizedLinker the single prioritized linker. Must not be null. - * @throws IllegalArgumentException if null is passed. + * @throws NullPointerException if null is passed. */ public void setPrioritizedLinker(final GuardingDynamicLinker prioritizedLinker) { - if(prioritizedLinker == null) { - throw new IllegalArgumentException("prioritizedLinker == null"); - } - this.prioritizedLinkers = Collections.singletonList(prioritizedLinker); + this.prioritizedLinkers = Collections.singletonList(Objects.requireNonNull(prioritizedLinker)); } /** - * Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any - * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback - * linkers, it will be ignored and the explicit fallback instance will be used. + * Sets the fallback guarding dynamic linkers. These linkers will be + * consulted last by the resulting dynamic linker when it is linking call + * sites, after any autodiscovered and prioritized linkers. If the factory + * also autodiscovers a linker class matching one of the fallback linkers, + * the autodiscovered class will be ignored and the explicit fallback + * instance will be used. * - * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no - * fallback linkers. + * @param fallbackLinkers the list of fallback linkers. Can be empty to + * indicate the caller wishes to set no fallback linkers. Note that if this + * method is not invoked explicitly or is passed null, then the factory + * will create an instance of {@link BeansLinker} to serve as the default + * fallback linker. + * @throws NullPointerException if any of the list elements are null. */ public void setFallbackLinkers(final List fallbackLinkers) { - this.fallbackLinkers = fallbackLinkers == null ? null : new ArrayList<>(fallbackLinkers); + this.fallbackLinkers = copyListRequireNonNullElements(fallbackLinkers); } /** - * Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any - * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback - * linkers, it will be ignored and the explicit fallback instance will be used. + * Sets the fallback guarding dynamic linkers. Identical to calling + * {@link #setFallbackLinkers(List)} with + * {@code Arrays.asList(fallbackLinkers)}. * - * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no - * fallback linkers. If it is left as null, the standard fallback {@link BeansLinker} will be used. + * @param fallbackLinkers an array of fallback linkers. Can be empty to + * indicate the caller wishes to set no fallback linkers. Note that if this + * method is not invoked explicitly or is passed null, then the factory + * will create an instance of {@link BeansLinker} to serve as the default + * fallback linker. + * @throws NullPointerException if any of the array elements are null. */ public void setFallbackLinkers(final GuardingDynamicLinker... fallbackLinkers) { - setFallbackLinkers(Arrays.asList(fallbackLinkers)); + setFallbackLinkers(fallbackLinkers == null ? null : Arrays.asList(fallbackLinkers)); } /** - * Sets the number of arguments in the call sites that represent the stack context of the language runtime creating - * the linker. If the language runtime uses no context information passed on stack, then it should be zero - * (the default value). If it is set to nonzero value, then every dynamic call site emitted by this runtime must - * have the argument list of the form: {@code (this, contextArg1[, contextArg2[, ...]], normalArgs)}. It is - * advisable to only pass one context-specific argument, though, of an easily recognizable, runtime specific type - * encapsulating the runtime thread local state. - * - * @param runtimeContextArgCount the number of language runtime context arguments in call sites. - */ - public void setRuntimeContextArgCount(final int runtimeContextArgCount) { - if(runtimeContextArgCount < 0) { - throw new IllegalArgumentException("runtimeContextArgCount < 0"); - } - this.runtimeContextArgCount = runtimeContextArgCount; - } - - /** - * Sets whether the linker created by this factory will invoke {@link MutableCallSite#syncAll(MutableCallSite[])} - * after a call site is relinked. Defaults to false. You probably want to set it to true if your runtime supports - * multithreaded execution of dynamically linked code. + * Sets whether the dynamic linker created by this factory will invoke + * {@link MutableCallSite#syncAll(MutableCallSite[])} after a call site is + * relinked. Defaults to false. You probably want to set it to true if your + * runtime supports multithreaded execution of dynamically linked code. * @param syncOnRelink true for invoking sync on relink, false otherwise. */ public void setSyncOnRelink(final boolean syncOnRelink) { @@ -238,10 +270,12 @@ public final class DynamicLinkerFactory { } /** - * Sets the unstable relink threshold; the number of times a call site is relinked after which it will be - * considered unstable, and subsequent link requests for it will indicate this. - * @param unstableRelinkThreshold the new threshold. Must not be less than zero. The value of zero means that - * call sites will never be considered unstable. + * Sets the unstable relink threshold; the number of times a call site is + * relinked after which it will be considered unstable, and subsequent link + * requests for it will indicate this. + * @param unstableRelinkThreshold the new threshold. Must not be less than + * zero. The value of zero means that call sites will never be considered + * unstable. * @see LinkRequest#isCallSiteUnstable() */ public void setUnstableRelinkThreshold(final int unstableRelinkThreshold) { @@ -252,52 +286,85 @@ public final class DynamicLinkerFactory { } /** - * Set the pre-link filter. This is a {@link GuardedInvocationFilter} that will get the final chance to modify the - * guarded invocation after it has been created by a component linker and before the dynamic linker links it into - * the call site. It is normally used to adapt the return value type of the invocation to the type of the call site. - * When not set explicitly, {@link DefaultPrelinkFilter} will be used. - * @param prelinkFilter the pre-link filter for the dynamic linker. + * Set the pre-link transformer. This is a + * {@link GuardedInvocationTransformer} that will get the final chance to + * modify the guarded invocation after it has been created by a component + * linker and before the dynamic linker links it into the call site. It is + * normally used to adapt the return value type of the invocation to the + * type of the call site. When not set explicitly, a default pre-link + * transformer will be used that simply calls + * {@link GuardedInvocation#asType(LinkerServices, MethodType)}. Customized + * pre-link transformers are rarely needed; they are mostly used as a + * building block for implementing advanced techniques such as code + * deoptimization strategies. + * @param prelinkTransformer the pre-link transformer for the dynamic + * linker. Can be null to have the factory use the default transformer. */ - public void setPrelinkFilter(final GuardedInvocationFilter prelinkFilter) { - this.prelinkFilter = prelinkFilter; + public void setPrelinkTransformer(final GuardedInvocationTransformer prelinkTransformer) { + this.prelinkTransformer = prelinkTransformer; } /** - * Sets an object representing the conversion strategy for automatic type conversions. After - * {@link TypeConverterFactory#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} has - * applied all custom conversions to a method handle, it still needs to effect - * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method invocation conversions} that - * can usually be automatically applied as per - * {@link java.lang.invoke.MethodHandle#asType(java.lang.invoke.MethodType)}. - * However, sometimes language runtimes will want to customize even those conversions for their own call - * sites. A typical example is allowing unboxing of null return values, which is by default prohibited by - * ordinary {@code MethodHandles.asType}. In this case, a language runtime can install its own custom - * automatic conversion strategy, that can deal with null values. Note that when the strategy's - * {@link MethodTypeConversionStrategy#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} - * is invoked, the custom language conversions will already have been applied to the method handle, so by - * design the difference between the handle's current method type and the desired final type will always - * only be ones that can be subjected to method invocation conversions. The strategy also doesn't need to - * invoke a final {@code MethodHandle.asType()} as the converter factory will do that as the final step. - * @param autoConversionStrategy the strategy for applying method invocation conversions for the linker - * created by this factory. + * Sets an object representing the conversion strategy for automatic type + * conversions. After + * {@link LinkerServices#asType(MethodHandle, MethodType)} has applied all + * custom conversions to a method handle, it still needs to effect + * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method + * invocation conversions} that can usually be automatically applied as per + * {@link MethodHandle#asType(MethodType)}. However, sometimes language + * runtimes will want to customize even those conversions for their own call + * sites. A typical example is allowing unboxing of null return values, + * which is by default prohibited by ordinary + * {@code MethodHandles.asType()}. In this case, a language runtime can + * install its own custom automatic conversion strategy, that can deal with + * null values. Note that when the strategy's + * {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)} + * is invoked, the custom language conversions will already have been + * applied to the method handle, so by design the difference between the + * handle's current method type and the desired final type will always only + * be ones that can be subjected to method invocation conversions. The + * strategy also doesn't need to invoke a final + * {@code MethodHandle.asType()} as that will be done internally as the + * final step. + * @param autoConversionStrategy the strategy for applying method invocation + * conversions for the linker created by this factory. Can be null for no + * custom strategy. */ public void setAutoConversionStrategy(final MethodTypeConversionStrategy autoConversionStrategy) { this.autoConversionStrategy = autoConversionStrategy; } /** - * Sets a method handle transformer that is supposed to act as the implementation of this linker factory's linkers' - * services {@link LinkerServices#filterInternalObjects(java.lang.invoke.MethodHandle)} method. - * @param internalObjectsFilter a method handle transformer filtering out internal objects, or null. + * Sets a method handle transformer that is supposed to act as the + * implementation of + * {@link LinkerServices#filterInternalObjects(MethodHandle)} for linker + * services of dynamic linkers created by this factory. Some language + * runtimes can have internal objects that should not escape their scope. + * They can add a transformer here that will modify the method handle so + * that any parameters that can receive potentially internal language + * runtime objects will have a filter added on them to prevent them from + * escaping, potentially by wrapping them. The transformer can also + * potentially add an unwrapping filter to the return value. + * {@link DefaultInternalObjectFilter} is provided as a convenience class + * for easily creating such filtering transformers. + * @param internalObjectsFilter a method handle transformer filtering out + * internal objects, or null. */ public void setInternalObjectsFilter(final MethodHandleTransformer internalObjectsFilter) { this.internalObjectsFilter = internalObjectsFilter; } /** - * Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers as well as - * the pre-link filter. - * + * Creates a new dynamic linker based on the current configuration. This + * method can be invoked more than once to create multiple dynamic linkers. + * Automatically discovered linkers are newly instantiated on every + * invocation of this method. It is allowed to change the factory's + * configuration between invocations. The method is not thread safe. After + * invocation, callers can invoke {@link #getAutoLoadingErrors()} to + * retrieve a list of {@link ServiceConfigurationError}s that occurred while + * trying to load automatically discovered linkers. These are never thrown + * from the call to this method as it makes every effort to recover from + * them and ignore the failing linkers. * @return the new dynamic Linker */ public DynamicLinker createLinker() { @@ -316,8 +383,8 @@ public final class DynamicLinkerFactory { addClasses(knownLinkerClasses, prioritizedLinkers); addClasses(knownLinkerClasses, fallbackLinkers); - final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader(); - final List discovered = AutoDiscovery.loadLinkers(effectiveClassLoader); + final List discovered = discoverAutoLoadLinkers(); + // Now, concatenate ... final List linkers = new ArrayList<>(prioritizedLinkers.size() + discovered.size() @@ -336,7 +403,7 @@ public final class DynamicLinkerFactory { final GuardingDynamicLinker composite; switch(linkers.size()) { case 0: { - composite = BottomGuardingDynamicLinker.INSTANCE; + composite = (r, s) -> null; // linker that can't link anything break; } case 1: { @@ -356,22 +423,84 @@ public final class DynamicLinkerFactory { } } - if(prelinkFilter == null) { - prelinkFilter = new DefaultPrelinkFilter(); + if(prelinkTransformer == null) { + prelinkTransformer = (inv, request, linkerServices) -> inv.asType(linkerServices, request.getCallSiteDescriptor().getMethodType()); } return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters, - autoConversionStrategy), composite, internalObjectsFilter), prelinkFilter, runtimeContextArgCount, + autoConversionStrategy), composite, internalObjectsFilter), prelinkTransformer, syncOnRelink, unstableRelinkThreshold); } + /** + * Returns a list of {@link ServiceConfigurationError}s that were + * encountered while loading automatically discovered linkers during the + * last invocation of {@link #createLinker()}. They can be any non-Dynalink + * specific service configuration issues, as well as some Dynalink-specific + * errors when an exporter that the factory tried to automatically load: + *
        + *
      • did not have the runtime permission named + * {@link GuardingDynamicLinkerExporter#AUTOLOAD_PERMISSION_NAME} in a + * system with a security manager, or
      • + *
      • returned null from {@link GuardingDynamicLinkerExporter#get()}, or
      • + *
      • the list returned from {@link GuardingDynamicLinkerExporter#get()} + * had a null element.
      • + *
      + * @return an immutable list of encountered + * {@link ServiceConfigurationError}s. Can be empty. + */ + public List getAutoLoadingErrors() { + return Collections.unmodifiableList(autoLoadingErrors); + } + + private List discoverAutoLoadLinkers() { + autoLoadingErrors = new LinkedList<>(); + final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader(); + final List discovered = new LinkedList<>(); + try { + final ServiceLoader linkerLoader = + AccessController.doPrivileged((PrivilegedAction>)()-> { + if (effectiveClassLoader == null) { + return ServiceLoader.loadInstalled(GuardingDynamicLinkerExporter.class); + } + return ServiceLoader.load(GuardingDynamicLinkerExporter.class, effectiveClassLoader); + }); + + for(final Iterator it = linkerLoader.iterator(); it.hasNext();) { + try { + final GuardingDynamicLinkerExporter autoLoader = it.next(); + try { + discovered.addAll(requireNonNullElements( + Objects.requireNonNull(autoLoader.get(), + ()->(autoLoader.getClass().getName() + " returned null from get()")), + ()->(autoLoader.getClass().getName() + " returned a list with at least one null element"))); + } catch (final ServiceConfigurationError|VirtualMachineError e) { + // Don't wrap a SCE in another SCE. Also, don't ignore + // any VME (e.g. StackOverflowError or OutOfMemoryError). + throw e; + } catch (final Throwable t) { + throw new ServiceConfigurationError(t.getMessage(), t); + } + } catch (final ServiceConfigurationError e) { + // Catch SCE with an individual exporter, carry on with it.hasNext(). + autoLoadingErrors.add(e); + } + } + } catch (final ServiceConfigurationError e) { + // Catch a top-level SCE; one either in ServiceLoader.load(), + // ServiceLoader.iterator(), or Iterator.hasNext(). + autoLoadingErrors.add(e); + } + return discovered; + } + private static ClassLoader getThreadContextClassLoader() { return AccessController.doPrivileged(new PrivilegedAction() { @Override public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } - }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT); + }, GET_CLASS_LOADER_CONTEXT); } private static void addClasses(final Set> knownLinkerClasses, @@ -380,4 +509,19 @@ public final class DynamicLinkerFactory { knownLinkerClasses.add(linker.getClass()); } } + + private static List copyListRequireNonNullElements(final List list) { + if (list == null) { + return null; + } + return new ArrayList<>(requireNonNullElements(list, ()->"List has at least one null element")); + } + + private static List requireNonNullElements(final List list, final Supplier msgSupplier) { + for(final T t: list) { + Objects.requireNonNull(t, msgSupplier); + } + return list; + } + } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/LinkerServicesImpl.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/LinkerServicesImpl.java similarity index 88% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/LinkerServicesImpl.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/LinkerServicesImpl.java index 51165a44dcf..db4100d4d7b 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/LinkerServicesImpl.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/LinkerServicesImpl.java @@ -81,9 +81,10 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import jdk.internal.dynalink.linker.ConversionComparator.Comparison; import jdk.internal.dynalink.linker.GuardedInvocation; @@ -95,9 +96,7 @@ import jdk.internal.dynalink.linker.MethodHandleTransformer; /** * Default implementation of the {@link LinkerServices} interface. */ -public class LinkerServicesImpl implements LinkerServices { - - private static final RuntimePermission GET_CURRENT_LINK_REQUEST = new RuntimePermission("dynalink.getCurrentLinkRequest"); +final class LinkerServicesImpl implements LinkerServices { private static final ThreadLocal threadLinkRequest = new ThreadLocal<>(); private final TypeConverterFactory typeConverterFactory; @@ -112,7 +111,7 @@ public class LinkerServicesImpl implements LinkerServices { * @param internalObjectsFilter a method handle transformer that is supposed to act as the implementation of this * services' {@link #filterInternalObjects(java.lang.invoke.MethodHandle)} method. */ - public LinkerServicesImpl(final TypeConverterFactory typeConverterFactory, + LinkerServicesImpl(final TypeConverterFactory typeConverterFactory, final GuardingDynamicLinker topLevelLinker, final MethodHandleTransformer internalObjectsFilter) { this.typeConverterFactory = typeConverterFactory; this.topLevelLinker = topLevelLinker; @@ -155,17 +154,11 @@ public class LinkerServicesImpl implements LinkerServices { return internalObjectsFilter != null ? internalObjectsFilter.transform(target) : target; } - /** - * Returns the currently processed link request, or null if the method is invoked outside of the linking process. - * @return the currently processed link request, or null. - * @throws SecurityException if the calling code doesn't have the {@code "dynalink.getCurrentLinkRequest"} runtime - * permission. - */ - public static LinkRequest getCurrentLinkRequest() { - final SecurityManager sm = System.getSecurityManager(); - if(sm != null) { - sm.checkPermission(GET_CURRENT_LINK_REQUEST); + static MethodHandles.Lookup getCurrentLookup() { + final LinkRequest currentRequest = threadLinkRequest.get(); + if (currentRequest != null) { + return currentRequest.getCallSiteDescriptor().getLookup(); } - return threadLinkRequest.get(); + return MethodHandles.publicLookup(); } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/NamedOperation.java similarity index 50% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/NamedOperation.java index 7e31b4d2fb2..b75b3e9feb2 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/NamedOperation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * license: */ /* - Copyright 2009-2013 Attila Szegedi + Copyright 2015 Attila Szegedi Licensed under both the Apache License, Version 2.0 (the "Apache License") and the BSD License (the "BSD License"), with licensee being free to @@ -81,105 +81,117 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; import java.util.Objects; -import jdk.internal.dynalink.CallSiteDescriptor; /** - * A base class for call site descriptor implementations. Provides reconstruction of the name from the tokens, as well - * as a generally useful {@code equals} and {@code hashCode} methods. + * Operation that associates a name with another operation. Typically used with + * operations that normally take a name or an index to bind them to a fixed + * name. E.g. {@code new NamedOperation(StandardOperation.GET_PROPERTY, "color")} + * will be a named operation for getting the property named "color" on the + * object it is applied to, and + * {@code new NamedOperation(StandardOperation.GET_ELEMENT, 3)} will be a named + * operation for getting the element at index 3 from the collection it is + * applied to. In these cases, the expected signature of the call site for the + * operation will change to no longer include the name parameter. Specifically, + * the documentation for all {@link StandardOperation} members describes how + * they are affected by being incorporated into a named operation. */ -public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor { +public class NamedOperation implements Operation { + private final Operation baseOperation; + private final Object name; - @Override - public String getName() { - return appendName(new StringBuilder(getNameLength())).toString(); - } - - @Override - public Lookup getLookup() { - return MethodHandles.publicLookup(); - } - - @Override - public boolean equals(final Object obj) { - return obj instanceof CallSiteDescriptor && equals((CallSiteDescriptor)obj); + /** + * Creates a new named operation. + * @param baseOperation the base operation that is associated with a name. + * @param name the name associated with the base operation. Note that the + * name is not necessarily a string, but can be an arbitrary object. As the + * name is used for addressing, it can be an {@link Integer} when meant + * to be used as an index into an array or list etc. + * @throws NullPointerException if either {@code baseOperation} or + * {@code name} is null. + * @throws IllegalArgumentException if {@code baseOperation} is itself a + * {@code NamedOperation}. + */ + public NamedOperation(final Operation baseOperation, final Object name) { + if (baseOperation instanceof NamedOperation) { + throw new IllegalArgumentException("baseOperation is a named operation"); + } + this.baseOperation = Objects.requireNonNull(baseOperation, "baseOperation is null"); + this.name = Objects.requireNonNull(name, "name is null"); } /** - * Returns true if this call site descriptor is equal to the passed call site descriptor. - * @param csd the other call site descriptor. - * @return true if they are equal. + * Returns the base operation of this named operation. + * @return the base operation of this named operation. */ - public boolean equals(final CallSiteDescriptor csd) { - if(csd == null) { - return false; - } - if(csd == this) { - return true; - } - final int ntc = getNameTokenCount(); - if(ntc != csd.getNameTokenCount()) { - return false; - } - for(int i = ntc; i-- > 0;) { // Reverse order as variability is higher at the end - if(!Objects.equals(getNameToken(i), csd.getNameToken(i))) { - return false; - } - } - if(!getMethodType().equals(csd.getMethodType())) { - return false; - } - return lookupsEqual(getLookup(), csd.getLookup()); + public Operation getBaseOperation() { + return baseOperation; } + /** + * Returns the name of this named operation. + * @return the name of this named operation. + */ + public Object getName() { + return name; + } + + /** + * Compares this named operation to another object. Returns true if the + * other object is also a named operation, and both their base operations + * and name are equal. + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } else if(obj.getClass() != NamedOperation.class) { + return false; + } + final NamedOperation other = (NamedOperation)obj; + return baseOperation.equals(other.baseOperation) && name.equals(other.name); + } + + /** + * Returns the hash code of this named operation. It is defined to be equal + * to {@code baseOperation.hashCode() + 31 * name.hashCode()}. + */ @Override public int hashCode() { - final MethodHandles.Lookup lookup = getLookup(); - int h = lookup.lookupClass().hashCode() + 31 * lookup.lookupModes(); - final int c = getNameTokenCount(); - for(int i = 0; i < c; ++i) { - h = h * 31 + getNameToken(i).hashCode(); - } - return h * 31 + getMethodType().hashCode(); + return baseOperation.hashCode() + 31 * name.hashCode(); } + /** + * Returns the string representation of this named operation. It is defined + * to be equal to {@code baseOperation.toString() + ":" + name.toString()}. + */ @Override public String toString() { - final String mt = getMethodType().toString(); - final String l = getLookup().toString(); - final StringBuilder b = new StringBuilder(l.length() + 1 + mt.length() + getNameLength()); - return appendName(b).append(mt).append("@").append(l).toString(); + return baseOperation.toString() + ":" + name.toString(); } - private int getNameLength() { - final int c = getNameTokenCount(); - int l = 0; - for(int i = 0; i < c; ++i) { - l += getNameToken(i).length(); - } - return l + c - 1; + /** + * If the passed operation is a named operation, returns its + * {@link #getBaseOperation()}, otherwise returns the operation as is. + * @param op the operation + * @return the base operation of the passed operation. + */ + public static Operation getBaseOperation(final Operation op) { + return op instanceof NamedOperation ? ((NamedOperation)op).baseOperation : op; } - private StringBuilder appendName(final StringBuilder b) { - b.append(getNameToken(0)); - final int c = getNameTokenCount(); - for(int i = 1; i < c; ++i) { - b.append(':').append(getNameToken(i)); - } - return b; - } - - private static boolean lookupsEqual(final Lookup l1, final Lookup l2) { - if(l1 == l2) { - return true; - } - if(l1.lookupClass() != l2.lookupClass()) { - return false; - } - return l1.lookupModes() == l2.lookupModes(); + /** + * If the passed operation is a named operation, returns its + * {@link #getName()}, otherwise returns null. Note that a named operation + * object can never have a null name, therefore returning null is indicative + * that the passed operation is not, in fact, a named operation. + * @param op the operation + * @return the name in the passed operation, or null if it is not a named + * operation. + */ + public static Object getName(final Operation op) { + return op instanceof NamedOperation ? ((NamedOperation)op).name : null; } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/Operation.java similarity index 78% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/Operation.java index f9470215409..c32a7654ae4 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/Operation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * license: */ /* - Copyright 2009-2013 Attila Szegedi + Copyright 2015 Attila Szegedi Licensed under both the Apache License, Version 2.0 (the "Apache License") and the BSD License (the "BSD License"), with licensee being free to @@ -81,27 +81,19 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; - -import java.security.AccessControlContext; -import java.security.Permissions; -import java.security.ProtectionDomain; +package jdk.internal.dynalink; /** - * This class exposes a canonical {@link AccessControlContext} with a single {@link RuntimePermission} for - * {@code "getClassLoader"} permission that is used by other parts of the code to narrow their set of permissions when - * they're retrieving class loaders in privileged blocks. + * An object that describes a dynamic operation. Dynalink defines a set of + * standard operations with the {@link StandardOperation} class, as well as a + * way to attach a fixed name to an operation using {@link NamedOperation} and + * to express a set of alternative operations using {@link CompositeOperation}. + * When presenting examples in this documentation, we will refer to standard + * operations using their name (e.g. {@code GET_PROPERTY}), to composite + * operations by separating their components with the vertical line character + * (e.g. {@code GET_PROPERTY|GET_ELEMENT}), and finally to named operations by + * separating the base operation and the name with the colon character (e.g. + * {@code GET_PROPERTY|GET_ELEMENT:color}). */ -public class ClassLoaderGetterContextProvider { - /** - * Canonical instance of {@link AccessControlContext} with a single {@link RuntimePermission} for - * {@code "getClassLoader"} permission. - */ - public static final AccessControlContext GET_CLASS_LOADER_CONTEXT; - static { - final Permissions perms = new Permissions(); - perms.add(new RuntimePermission("getClassLoader")); - GET_CLASS_LOADER_CONTEXT = new AccessControlContext( - new ProtectionDomain[] { new ProtectionDomain(null, perms) }); - } +public interface Operation { } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/RelinkableCallSite.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/RelinkableCallSite.java index b99dde98323..f7710fb80da 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/RelinkableCallSite.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/RelinkableCallSite.java @@ -85,23 +85,37 @@ package jdk.internal.dynalink; import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MutableCallSite; -import java.lang.invoke.VolatileCallSite; import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.support.ChainedCallSite; +import jdk.internal.dynalink.support.SimpleRelinkableCallSite; /** - * Interface for relinkable call sites. Language runtimes wishing to use this framework must use subclasses of - * {@link CallSite} that also implement this interface as their call sites. There is a readily usable - * {@link MonomorphicCallSite} subclass that implements monomorphic inline caching strategy as well as a - * {@link ChainedCallSite} that retains a chain of already linked method handles. The reason this is defined as an - * interface instead of a concrete, albeit abstract class is that it allows independent implementations to choose - * between {@link MutableCallSite} and {@link VolatileCallSite} as they see fit. + * Interface for call sites managed by a {@link DynamicLinker}. Users of + * Dynalink must use subclasses of {@link CallSite} that also implement this + * interface as their call site implementations. There is a readily usable + * {@link SimpleRelinkableCallSite} subclass that implements monomorphic inline + * caching strategy as well as {@link ChainedCallSite} that implements a + * polymorphic inline caching strategy and retains a chain of previously linked + * method handles. A relinkable call site will be managed by a + * {@link DynamicLinker} object after being associated with it using its + * {@link DynamicLinker#link(RelinkableCallSite)} method. */ public interface RelinkableCallSite { /** - * Initializes the relinkable call site by setting a relink-and-invoke method handle. The call site - * implementation is supposed to set this method handle as its target. - * @param relinkAndInvoke a relink-and-invoke method handle supplied by the {@link DynamicLinker}. + * Invoked by dynamic linker to initialize the relinkable call site by + * setting a relink-and-invoke method handle. The call site implementation + * is supposed to set this method handle as its target using + * {@link CallSite#setTarget(MethodHandle)}. Relink-and-invoke is the + * initial method handle set by + * {@link DynamicLinker#link(RelinkableCallSite)} that will cause the call + * site to be relinked to an appropriate target on its first invocation + * based on its arguments, and that linked target will then be invoked + * (hence the name). This linking protocol effectively delays linking until + * the call site is invoked with actual arguments and thus ensures that + * linkers can make nuanced linking decisions based on those arguments and + * not just on the static method type of the call site. + * @param relinkAndInvoke a relink-and-invoke method handle supplied by + * Dynalink. */ public void initialize(MethodHandle relinkAndInvoke); @@ -113,33 +127,52 @@ public interface RelinkableCallSite { public CallSiteDescriptor getDescriptor(); /** - * This method will be called by the dynamic linker every time the call site is normally relinked. It will be passed - * a {@code GuardedInvocation} that the call site should incorporate into its target method handle. When this method - * is called, the call site is allowed to keep other non-invalidated invocations around for implementation of - * polymorphic inline caches and compose them with this invocation to form its final target. + * This method will be called by the dynamic linker every time the call site + * is relinked (but see + * {@link #resetAndRelink(GuardedInvocation, MethodHandle)} for an + * exception). It will be passed a {@code GuardedInvocation} that the call + * site should incorporate into its target method handle. When this method + * is called, the call site is allowed to keep other non-invalidated + * invocations around for implementation of polymorphic inline caches and + * compose them with this invocation to form its final target. * - * @param guardedInvocation the guarded invocation that the call site should incorporate into its target method - * handle. - * @param fallback the fallback method. This is a method matching the method type of the call site that is supplied - * by the {@link DynamicLinker} to be used by this call site as a fallback when it can't invoke its target with the - * passed arguments. The fallback method is such that when it's invoked, it'll try to discover the adequate target - * for the invocation, subsequently invoke {@link #relink(GuardedInvocation, MethodHandle)} or - * {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally invoke the target. + * @param guardedInvocation the guarded invocation that the call site should + * incorporate into its target method handle. + * @param relinkAndInvoke a relink-and-invoke method handle. This is a + * method handle matching the method type of the call site that is supplied + * by the {@link DynamicLinker} as a callback. It should be used by this + * call site as the ultimate fallback when it can't invoke its target with + * the passed arguments. The fallback method is such that when it's invoked, + * it'll try to obtain an adequate target {@link GuardedInvocation} for the + * invocation, and subsequently invoke + * {@link #relink(GuardedInvocation, MethodHandle)} or + * {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally + * invoke the target. */ - public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback); + public void relink(GuardedInvocation guardedInvocation, MethodHandle relinkAndInvoke); /** - * This method will be called by the dynamic linker every time the call site is relinked and the linker wishes the - * call site to throw away any prior linkage state. It will be passed a {@code GuardedInvocation} that the call site - * should use to build its target method handle. When this method is called, the call site is discouraged from - * keeping previous state around, and is supposed to only link the current invocation. + * This method will be called by the dynamic linker every time the call site + * is relinked and the linker wishes the call site to throw away any + * prior linkage state (that is how it differs from + * {@link #relink(GuardedInvocation, MethodHandle)}). It will be passed a + * {@code GuardedInvocation} that the call site should use to build its new + * target method handle. When this method is called, the call site is + * discouraged from keeping any previous state, and is supposed to only + * link the current invocation. * - * @param guardedInvocation the guarded invocation that the call site should use to build its target method handle. - * @param fallback the fallback method. This is a method matching the method type of the call site that is supplied - * by the {@link DynamicLinker} to be used by this call site as a fallback when it can't invoke its target with the - * passed arguments. The fallback method is such that when it's invoked, it'll try to discover the adequate target - * for the invocation, subsequently invoke {@link #relink(GuardedInvocation, MethodHandle)} or - * {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally invoke the target. + * @param guardedInvocation the guarded invocation that the call site should + * use to build its target method handle. + * @param relinkAndInvoke a relink-and-invoke method handle. This is a + * method handle matching the method type of the call site that is supplied + * by the {@link DynamicLinker} as a callback. It should be used by this + * call site as the ultimate fallback when it can't invoke its target with + * the passed arguments. The fallback method is such that when it's invoked, + * it'll try to obtain an adequate target {@link GuardedInvocation} for the + * invocation, and subsequently invoke + * {@link #relink(GuardedInvocation, MethodHandle)} or + * {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally + * invoke the target. */ - public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback); + public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle relinkAndInvoke); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/StandardOperation.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/StandardOperation.java new file mode 100644 index 00000000000..80de9f15986 --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/StandardOperation.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2015 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package jdk.internal.dynalink; + +/** + * Defines the standard dynamic operations. Getter and setter operations defined + * in this enumeration can be composed into a {@link CompositeOperation}, and + * {@link NamedOperation} can be used to bind the name parameter of operations + * that take one, in which case it disappears from the type signature. + */ +public enum StandardOperation implements Operation { + /** + * Get the value of a property defined on an object. Call sites with this + * operation should have a signature of + * (receiver, propertyName)→value or + * (receiver)→value when used with {@link NamedOperation}, with + * all parameters and return type being of any type (either primitive or + * reference). + */ + GET_PROPERTY, + /** + * Set the value of a property defined on an object. Call sites with this + * operation should have a signature of + * (receiver, propertyName, value)→void or + * (receiver, value)→void when used with {@link NamedOperation}, + * with all parameters and return type being of any type (either primitive + * or reference). + */ + SET_PROPERTY, + /** + * Get the value of an element of a collection. Call sites with this + * operation should have a signature of + * (receiver, index)→value or + * (receiver)→value when used with {@link NamedOperation}, with + * all parameters and return type being of any type (either primitive or + * reference). + */ + GET_ELEMENT, + /** + * Set the value of an element of a collection. Call sites with this + * operation should have a signature of + * (receiver, index, value)→void or + * (receiver, value)→void when used with {@link NamedOperation}, + * with all parameters and return type being of any type (either primitive + * or reference). + */ + SET_ELEMENT, + /** + * Get the length of an array of size of a collection. Call sites with + * this operation should have a signature of (receiver)→value, + * with all parameters and return type being of any type (either primitive + * or reference). + */ + GET_LENGTH, + /** + * Gets an object representing a method defined on an object. Call sites + * with this operation should have a signature of + * (receiver, methodName)→value, or + * (receiver)→value when used with {@link NamedOperation} + * with all parameters and return type being of any type (either primitive + * or reference). + */ + GET_METHOD, + /** + * Calls a method defined on an object. Call sites with this + * operation should have a signature of + * (receiver, methodName, arguments...)→value or + * (receiver, arguments...)→value when used with {@link NamedOperation}, + * with all parameters and return type being of any type (either primitive + * or reference). + */ + CALL_METHOD, + /** + * Calls a callable object. Call sites with this operation should have a + * signature of (receiver, arguments...)→value, with all + * parameters and return type being of any type (either primitive or + * reference). Typically, if the callable is a method of an object, the + * first argument will act as the "this" value passed to the called method. + * The CALL operation is allowed to be used with a + * {@link NamedOperation} even though it does not take a name. Using it with + * a named operation won't affect its signature; the name is solely meant to + * be used as a diagnostic description for error messages. + */ + CALL, + /** + * Calls a constructor object. Call sites with this operation should have a + * signature of (receiver, arguments...)→value, with all + * parameters and return type being of any type (either primitive or + * reference). The NEW operation is allowed to be used with a + * {@link NamedOperation} even though it does not take a name. Using it with + * a named operation won't affect its signature; the name is solely meant to + * be used as a diagnostic description for error messages. + */ + NEW +} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/TypeConverterFactory.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/TypeConverterFactory.java similarity index 89% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/TypeConverterFactory.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/TypeConverterFactory.java index 6235ab5f1dd..ea2cd97764a 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/TypeConverterFactory.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/TypeConverterFactory.java @@ -81,30 +81,36 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; import java.lang.invoke.WrongMethodTypeException; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.LinkedList; import java.util.List; +import java.util.function.Supplier; +import jdk.internal.dynalink.internal.AccessControlContextFactory; import jdk.internal.dynalink.linker.ConversionComparator; import jdk.internal.dynalink.linker.ConversionComparator.Comparison; import jdk.internal.dynalink.linker.GuardedInvocation; -import jdk.internal.dynalink.linker.GuardedTypeConversion; import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.MethodTypeConversionStrategy; +import jdk.internal.dynalink.linker.support.TypeUtilities; /** * A factory for type converters. This class is the main implementation behind the * {@link LinkerServices#asType(MethodHandle, MethodType)}. It manages the known {@link GuardingTypeConverterFactory} * instances and creates appropriate converters for method handles. */ -public class TypeConverterFactory { +final class TypeConverterFactory { + private static final AccessControlContext GET_CLASS_LOADER_CONTEXT = + AccessControlContextFactory.createAccessControlContext("getClassLoader"); private final GuardingTypeConverterFactory[] factories; private final ConversionComparator[] comparators; @@ -170,7 +176,7 @@ public class TypeConverterFactory { public ClassLoader run() { return clazz.getClassLoader(); } - }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT); + }, GET_CLASS_LOADER_CONTEXT); } /** @@ -193,7 +199,7 @@ public class TypeConverterFactory { * only be ones that can be subjected to method invocation conversions. Can be null, in which case no * custom strategy is employed. */ - public TypeConverterFactory(final Iterable factories, + TypeConverterFactory(final Iterable factories, final MethodTypeConversionStrategy autoConversionStrategy) { final List l = new LinkedList<>(); final List c = new LinkedList<>(); @@ -226,7 +232,7 @@ public class TypeConverterFactory { * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with * {@link GuardingTypeConverterFactory} produced type converters as filters. */ - public MethodHandle asType(final MethodHandle handle, final MethodType fromType) { + MethodHandle asType(final MethodHandle handle, final MethodType fromType) { MethodHandle newHandle = handle; final MethodType toType = newHandle.type(); final int l = toType.parameterCount(); @@ -295,7 +301,7 @@ public class TypeConverterFactory { * @param to the target type for the conversion * @return true if there can be a conversion, false if there can not. */ - public boolean canConvert(final Class from, final Class to) { + boolean canConvert(final Class from, final Class to) { return canAutoConvert(from, to) || canConvert.get(from).get(to); } @@ -309,7 +315,7 @@ public class TypeConverterFactory { * @return one of Comparison constants that establish which - if any - of the target types is preferable for the * conversion. */ - public Comparison compareConversion(final Class sourceType, final Class targetType1, final Class targetType2) { + Comparison compareConversion(final Class sourceType, final Class targetType1, final Class targetType2) { for(final ConversionComparator comparator: comparators) { final Comparison result = comparator.compareConversion(sourceType, targetType1, targetType2); if(result != Comparison.INDETERMINATE) { @@ -363,7 +369,7 @@ public class TypeConverterFactory { * @param targetType the type to convert to * @return a method handle performing the conversion. */ - public MethodHandle getTypeConverter(final Class sourceType, final Class targetType) { + MethodHandle getTypeConverter(final Class sourceType, final Class targetType) { try { return converterIdentityMap.get(sourceType).get(targetType); } catch(final NotCacheableConverter e) { @@ -371,26 +377,49 @@ public class TypeConverterFactory { } } + private static class LookupSupplier implements Supplier { + volatile boolean returnedLookup; + volatile boolean closed; + + @Override + public Lookup get() { + if (closed) { + // Something held on to this supplier and tried to invoke it + // after we're done with it. + throw new IllegalStateException(); + } + final Lookup lookup = LinkerServicesImpl.getCurrentLookup(); + returnedLookup = true; + return lookup; + } + } + /*private*/ MethodHandle createConverter(final Class sourceType, final Class targetType) throws Exception { final MethodType type = MethodType.methodType(targetType, sourceType); final MethodHandle identity = IDENTITY_CONVERSION.asType(type); MethodHandle last = identity; - boolean cacheable = true; - for(int i = factories.length; i-- > 0;) { - final GuardedTypeConversion next = factories[i].convertToType(sourceType, targetType); - if(next != null) { - cacheable = cacheable && next.isCacheable(); - final GuardedInvocation conversionInvocation = next.getConversionInvocation(); - conversionInvocation.assertType(type); - last = conversionInvocation.compose(last); + + final LookupSupplier lookupSupplier = new LookupSupplier(); + try { + for(int i = factories.length; i-- > 0;) { + final GuardedInvocation next = factories[i].convertToType(sourceType, targetType, lookupSupplier); + if(next != null) { + last = next.compose(last); + } } + } finally { + lookupSupplier.closed = true; } + if(last == identity) { return IDENTITY_CONVERSION; } - if(cacheable) { + if(!lookupSupplier.returnedLookup) { return last; } + // At least one of the consulted converter factories obtained the + // lookup, so we must presume the created converter is sensitive to the + // lookup class and thus we will not cache it. throw new NotCacheableConverter(last); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java index f42e0bc8898..47321e67572 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java @@ -92,21 +92,26 @@ import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.CompositeOperation; +import jdk.internal.dynalink.NamedOperation; +import jdk.internal.dynalink.Operation; +import jdk.internal.dynalink.StandardOperation; import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; +import jdk.internal.dynalink.internal.InternalTypeUtilities; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardingDynamicLinker; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; -import jdk.internal.dynalink.support.CallSiteDescriptorFactory; -import jdk.internal.dynalink.support.Guards; -import jdk.internal.dynalink.support.Lookup; -import jdk.internal.dynalink.support.TypeUtilities; +import jdk.internal.dynalink.linker.support.Guards; +import jdk.internal.dynalink.linker.support.Lookup; +import sun.reflect.CallerSensitive; /** * A base class for both {@link StaticClassLinker} and {@link BeanLinker}. Deals with common aspects of property @@ -284,7 +289,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { * @return the single dynamic method representing the reflective member */ private static SingleDynamicMethod createDynamicMethod(final AccessibleObject m) { - if(CallerSensitiveDetector.isCallerSensitive(m)) { + if (m.isAnnotationPresent(CallerSensitive.class)) { // Method has @CallerSensitive annotation return new CallerSensitiveDynamicMethod(m); } @@ -342,18 +347,27 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { @Override public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) throws Exception { - final LinkRequest ncrequest = request.withoutRuntimeContext(); - // BeansLinker already checked that the name is at least 2 elements long and the first element is "dyn". - final CallSiteDescriptor callSiteDescriptor = ncrequest.getCallSiteDescriptor(); - final String op = callSiteDescriptor.getNameToken(CallSiteDescriptor.OPERATOR); - // Either dyn:callMethod:name(this[,args]) or dyn:callMethod(this,name[,args]). - if("callMethod" == op) { - return getCallPropWithThis(callSiteDescriptor, linkerServices); + final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor(); + + // Handle NamedOperation(CALL_METHOD, name) separately + final Operation operation = callSiteDescriptor.getOperation(); + if (operation instanceof NamedOperation) { + final NamedOperation namedOperation = (NamedOperation)operation; + if (namedOperation.getBaseOperation() == StandardOperation.CALL_METHOD) { + return createGuardedDynamicMethodInvocation(callSiteDescriptor, + linkerServices, namedOperation.getName().toString(), methods); + } } - List operations = CallSiteDescriptorFactory.tokenizeOperators(callSiteDescriptor); + + List operations = Arrays.asList( + CompositeOperation.getOperations( + NamedOperation.getBaseOperation(operation))); + final Object name = NamedOperation.getName(operation); + while(!operations.isEmpty()) { - final GuardedInvocationComponent gic = getGuardedInvocationComponent(callSiteDescriptor, linkerServices, - operations); + final GuardedInvocationComponent gic = + getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, operations, name); if(gic != null) { return gic.getGuardedInvocation(); } @@ -362,23 +376,26 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { return null; } - protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations) throws Exception { + protected GuardedInvocationComponent getGuardedInvocationComponent( + final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, + final List operations, final Object name) + throws Exception { if(operations.isEmpty()) { return null; } - final String op = operations.get(0); - // Either dyn:getProp:name(this) or dyn:getProp(this, name) - if("getProp".equals(op)) { - return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations)); + final Operation op = operations.get(0); + // Either GET_PROPERTY:name(this) or GET_PROPERTY(this, name) + if(op == StandardOperation.GET_PROPERTY) { + return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations), name); } - // Either dyn:setProp:name(this, value) or dyn:setProp(this, name, value) - if("setProp".equals(op)) { - return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations)); + // Either SET_PROPERTY:name(this, value) or SET_PROPERTY(this, name, value) + if(op == StandardOperation.SET_PROPERTY) { + return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations), name); } - // Either dyn:getMethod:name(this), or dyn:getMethod(this, name) - if("getMethod".equals(op)) { - return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations)); + // Either GET_METHOD:name(this), or GET_METHOD(this, name) + if(op == StandardOperation.GET_METHOD) { + return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations), name); } return null; } @@ -407,18 +424,6 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { return Guards.asType(assignableGuard, type); } - private GuardedInvocation getCallPropWithThis(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) { - switch(callSiteDescriptor.getNameTokenCount()) { - case 3: { - return createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices, - callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods); - } - default: { - return null; - } - } - } - private GuardedInvocation createGuardedDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices, final String methodName, final Map methodMap){ final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap); @@ -481,84 +486,86 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { MethodHandles.constant(Object.class, null), 0, MethodHandle.class); private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations) throws Exception { - switch(callSiteDescriptor.getNameTokenCount()) { - case 2: { - // Must have three arguments: target object, property name, and property value. - assertParameterCount(callSiteDescriptor, 3); - - // We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be - // valid for us to convert return values proactively. Also, since we don't know what setters will be - // invoked, we'll conservatively presume Object return type. The one exception is void return. - final MethodType origType = callSiteDescriptor.getMethodType(); - final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class); - - // What's below is basically: - // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation), - // get_setter_handle(type, linkerServices)) - // only with a bunch of method signature adjustments. Basically, retrieve method setter - // MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next - // component's invocation. - - // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll - // abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using - // Object return type). - final MethodType setterType = type.dropParameterTypes(1, 2); - // Bind property setter handle to the expected setter type and linker services. Type is - // MethodHandle(Object, String, Object) - final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0, - callSiteDescriptor.changeMethodType(setterType), linkerServices); - - // Cast getter to MethodHandle(O, N, V) - final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType( - MethodHandle.class)); - - // Handle to invoke the setter R(MethodHandle, O, V) - final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType); - // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V) - final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType( - 1)); - final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations); - - final MethodHandle fallbackFolded; - if(nextComponent == null) { - // Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null - fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1, - type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class)); - } else { - // Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the - // extra argument resulting from fold - fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), - 0, MethodHandle.class); - } - - // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V)) - final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( - IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); - if(nextComponent == null) { - return getClassGuardedInvocationComponent(compositeSetter, type); - } - return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); - } - case 3: { - // Must have two arguments: target object and property value - assertParameterCount(callSiteDescriptor, 2); - final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices, - callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters); - // If we have a property setter with this name, this composite operation will always stop here - if(gi != null) { - return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS); - } - // If we don't have a property setter with this name, always fall back to the next operation in the - // composite (if any) - return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations); - } - default: { - // More than two name components; don't know what to do with it. - return null; - } + final LinkerServices linkerServices, final List operations, final Object name) throws Exception { + if (name == null) { + return getUnnamedPropertySetter(callSiteDescriptor, linkerServices, operations); } + return getNamedPropertySetter(callSiteDescriptor, linkerServices, operations, name); + } + + private GuardedInvocationComponent getUnnamedPropertySetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List operations) throws Exception { + // Must have three arguments: target object, property name, and property value. + assertParameterCount(callSiteDescriptor, 3); + + // We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be + // valid for us to convert return values proactively. Also, since we don't know what setters will be + // invoked, we'll conservatively presume Object return type. The one exception is void return. + final MethodType origType = callSiteDescriptor.getMethodType(); + final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class); + + // What's below is basically: + // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation), + // get_setter_handle(type, linkerServices)) + // only with a bunch of method signature adjustments. Basically, retrieve method setter + // MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next + // component's invocation. + + // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll + // abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using + // Object return type). + final MethodType setterType = type.dropParameterTypes(1, 2); + // Bind property setter handle to the expected setter type and linker services. Type is + // MethodHandle(Object, String, Object) + final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0, + callSiteDescriptor.changeMethodType(setterType), linkerServices); + + // Cast getter to MethodHandle(O, N, V) + final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType( + MethodHandle.class)); + + // Handle to invoke the setter R(MethodHandle, O, V) + final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType); + // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V) + final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType( + 1)); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, operations, null); + + final MethodHandle fallbackFolded; + if(nextComponent == null) { + // Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null + fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1, + type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class)); + } else { + // Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the + // extra argument resulting from fold + fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), + 0, MethodHandle.class); + } + + // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V)) + final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( + IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); + if(nextComponent == null) { + return getClassGuardedInvocationComponent(compositeSetter, type); + } + return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); + } + + private GuardedInvocationComponent getNamedPropertySetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List operations, final Object name) throws Exception { + // Must have two arguments: target object and property value + assertParameterCount(callSiteDescriptor, 2); + final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices, + name.toString(), propertySetters); + // If we have a property setter with this name, this composite operation will always stop here + if(gi != null) { + return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS); + } + // If we don't have a property setter with this name, always fall back to the next operation in the + // composite (if any) + return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations, name); } private static final Lookup privateLookup = new Lookup(MethodHandles.lookup()); @@ -568,91 +575,93 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments( MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class); private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class, - "getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class, LinkerServices.class)); + "getTarget", MethodType.methodType(MethodHandle.class, CallSiteDescriptor.class, LinkerServices.class)); private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)); private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops) throws Exception { - switch(callSiteDescriptor.getNameTokenCount()) { - case 2: { - // Since we can't know what kind of a getter we'll get back on different invocations, we'll just - // conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking - // runtime might not allow coercing at that call site. - final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); - // Must have exactly two arguments: receiver and name - assertParameterCount(callSiteDescriptor, 2); - - // What's below is basically: - // foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle) - // only with a bunch of method signature adjustments. Basically, retrieve method getter - // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null, - // or delegate to next component's invocation. - - final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType( - AnnotatedDynamicMethod.class)); - final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments( - GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup(), linkerServices); - final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0, - callSiteBoundMethodGetter); - // Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0) - final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker, - MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0))); - // Since it's in the target of a fold, drop the unnecessary second argument - // Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1) - final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2, - type.parameterType(1)); - final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, ops); - - final MethodHandle fallbackFolded; - if(nextComponent == null) { - // Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null - fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1, - type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class)); - } else { - // Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to - // drop the extra argument resulting from fold and to change its return type to Object. - final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation(); - final MethodType nextType = nextInvocation.type(); - fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType( - nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class); - } - - // fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1)) - final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( - IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); - if(nextComponent == null) { - return getClassGuardedInvocationComponent(compositeGetter, type); - } - return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); - } - case 3: { - // Must have exactly one argument: receiver - assertParameterCount(callSiteDescriptor, 1); - // Fixed name - final AnnotatedDynamicMethod annGetter = propertyGetters.get(callSiteDescriptor.getNameToken( - CallSiteDescriptor.NAME_OPERAND)); - if(annGetter == null) { - // We have no such property, always delegate to the next component operation - return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops); - } - final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices); - // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being - // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the - // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If - // we're linking against a field getter, don't make the assumption. - // NOTE: No delegation to the next component operation if we have a property with this name, even if its - // value is null. - final ValidationType validationType = annGetter.validationType; - // TODO: we aren't using the type that declares the most generic getter here! - return new GuardedInvocationComponent(getter, getGuard(validationType, - callSiteDescriptor.getMethodType()), clazz, validationType); - } - default: { - // Can't do anything with more than 3 name components - return null; - } + final LinkerServices linkerServices, final List ops, final Object name) throws Exception { + if (name == null) { + return getUnnamedPropertyGetter(callSiteDescriptor, linkerServices, ops); } + + return getNamedPropertyGetter(callSiteDescriptor, linkerServices, ops, name); + } + + private GuardedInvocationComponent getUnnamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List ops) throws Exception { + // Since we can't know what kind of a getter we'll get back on different invocations, we'll just + // conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking + // runtime might not allow coercing at that call site. + final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); + // Must have exactly two arguments: receiver and name + assertParameterCount(callSiteDescriptor, 2); + + // What's below is basically: + // foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle) + // only with a bunch of method signature adjustments. Basically, retrieve method getter + // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null, + // or delegate to next component's invocation. + + final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType( + AnnotatedDynamicMethod.class)); + final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments( + GET_ANNOTATED_METHOD, 1, callSiteDescriptor, linkerServices); + final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0, + callSiteBoundMethodGetter); + // Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0) + final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker, + MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0))); + // Since it's in the target of a fold, drop the unnecessary second argument + // Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1) + final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2, + type.parameterType(1)); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, ops, null); + + final MethodHandle fallbackFolded; + if(nextComponent == null) { + // Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null + fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1, + type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class)); + } else { + // Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to + // drop the extra argument resulting from fold and to change its return type to Object. + final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation(); + final MethodType nextType = nextInvocation.type(); + fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType( + nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class); + } + + // fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1)) + final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( + IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); + if(nextComponent == null) { + return getClassGuardedInvocationComponent(compositeGetter, type); + } + return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); + } + + private GuardedInvocationComponent getNamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List ops, final Object name) throws Exception { + // Must have exactly one argument: receiver + assertParameterCount(callSiteDescriptor, 1); + // Fixed name + final AnnotatedDynamicMethod annGetter = propertyGetters.get(name.toString()); + if(annGetter == null) { + // We have no such property, always delegate to the next component operation + return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name); + } + final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices); + // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being + // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the + // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If + // we're linking against a field getter, don't make the assumption. + // NOTE: No delegation to the next component operation if we have a property with this name, even if its + // value is null. + final ValidationType validationType = annGetter.validationType; + // TODO: we aren't using the type that declares the most generic getter here! + return new GuardedInvocationComponent(getter, getGuard(validationType, + callSiteDescriptor.getMethodType()), clazz, validationType); } private MethodHandle getGuard(final ValidationType validationType, final MethodType methodType) { @@ -680,64 +689,67 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class); private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops) throws Exception { + final LinkerServices linkerServices, final List ops, final Object name) throws Exception { // The created method handle will always return a DynamicMethod (or null), but since we don't want that type to // be visible outside of this linker, declare it to return Object. final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); - switch(callSiteDescriptor.getNameTokenCount()) { - case 2: { - // Must have exactly two arguments: receiver and name - assertParameterCount(callSiteDescriptor, 2); - final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, ops); - if(nextComponent == null || !TypeUtilities.areAssignable(DynamicMethod.class, - nextComponent.getGuardedInvocation().getInvocation().type().returnType())) { - // No next component operation, or it can never produce a dynamic method; just return a component - // for this operation. - return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type); - } - - // What's below is basically: - // foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a - // bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null - // DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation. - - final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type); - // Since it is part of the foldArgument() target, it will have extra args that we need to drop. - final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments( - OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class)); - final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation(); - // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the - // return type. - assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type); - // Since it is part of the foldArgument() target, we have to drop an extra arg it receives. - final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0, - Object.class); - // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get) - final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( - IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter); - - return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); - } - case 3: { - // Must have exactly one argument: receiver - assertParameterCount(callSiteDescriptor, 1); - final DynamicMethod method = getDynamicMethod(callSiteDescriptor.getNameToken( - CallSiteDescriptor.NAME_OPERAND)); - if(method == null) { - // We have no such method, always delegate to the next component - return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops); - } - // No delegation to the next component of the composite operation; if we have a method with that name, - // we'll always return it at this point. - return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments( - MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type); - } - default: { - // Can't do anything with more than 3 name components - return null; - } + if (name == null) { + return getUnnamedMethodGetter(callSiteDescriptor, linkerServices, ops, type); } + + return getNamedMethodGetter(callSiteDescriptor, linkerServices, ops, name, type); + } + + private GuardedInvocationComponent getUnnamedMethodGetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List ops, final MethodType type) throws Exception { + // Must have exactly two arguments: receiver and name + assertParameterCount(callSiteDescriptor, 2); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, ops, null); + if(nextComponent == null || !InternalTypeUtilities.areAssignable(DynamicMethod.class, + nextComponent.getGuardedInvocation().getInvocation().type().returnType())) { + // No next component operation, or it can never produce a dynamic method; just return a component + // for this operation. + return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type); + } + + // What's below is basically: + // foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a + // bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null + // DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation. + + final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type); + // Since it is part of the foldArgument() target, it will have extra args that we need to drop. + final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments( + OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class)); + final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation(); + // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the + // return type. + assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type); + // Since it is part of the foldArgument() target, we have to drop an extra arg it receives. + final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0, + Object.class); + // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get) + final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( + IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter); + + return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); + } + + private GuardedInvocationComponent getNamedMethodGetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List ops, final Object name, final MethodType type) + throws Exception { + // Must have exactly one argument: receiver + assertParameterCount(callSiteDescriptor, 1); + final DynamicMethod method = getDynamicMethod(name.toString()); + if(method == null) { + // We have no such method, always delegate to the next component + return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name); + } + // No delegation to the next component of the composite operation; if we have a method with that name, + // we'll always return it at this point. + return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments( + MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type); } static class MethodPair { @@ -757,7 +769,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { static MethodPair matchReturnTypes(final MethodHandle m1, final MethodHandle m2) { final MethodType type1 = m1.type(); final MethodType type2 = m2.type(); - final Class commonRetType = TypeUtilities.getCommonLosslessConversionType(type1.returnType(), + final Class commonRetType = InternalTypeUtilities.getCommonLosslessConversionType(type1.returnType(), type2.returnType()); return new MethodPair( m1.asType(type1.changeReturnType(commonRetType)), @@ -766,7 +778,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) { if(descriptor.getMethodType().parameterCount() != paramCount) { - throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters."); + throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters."); } } @@ -805,7 +817,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { @SuppressWarnings("unused") // This method is marked to return Object instead of DynamicMethod as it's used as a linking component and we don't // want to make the DynamicMethod type observable externally (e.g. as the return type of a MethodHandle returned for - // "dyn:getMethod" linking). + // GET_METHOD linking). private Object getDynamicMethod(final Object name) { return getDynamicMethod(String.valueOf(name), methods); } @@ -871,8 +883,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { } @SuppressWarnings("unused") - MethodHandle getTarget(final MethodHandles.Lookup lookup, final LinkerServices linkerServices) { - final MethodHandle inv = linkerServices.filterInternalObjects(method.getTarget(lookup)); + MethodHandle getTarget(final CallSiteDescriptor desc, final LinkerServices linkerServices) { + final MethodHandle inv = linkerServices.filterInternalObjects(method.getTarget(desc)); assert inv != null; return inv; } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java index d459063b4d5..53f66a07552 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java @@ -86,7 +86,7 @@ package jdk.internal.dynalink.beans; import java.lang.invoke.MethodType; import java.util.LinkedList; import java.util.List; -import jdk.internal.dynalink.support.TypeUtilities; +import jdk.internal.dynalink.linker.support.TypeUtilities; /** * Represents overloaded methods applicable to a specific call site signature. diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java index cbf93a7194a..9b9b8005118 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java @@ -91,13 +91,15 @@ import java.util.Collection; import java.util.List; import java.util.Map; import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.Operation; +import jdk.internal.dynalink.StandardOperation; import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; -import jdk.internal.dynalink.support.Guards; -import jdk.internal.dynalink.support.Lookup; -import jdk.internal.dynalink.support.TypeUtilities; +import jdk.internal.dynalink.linker.support.Guards; +import jdk.internal.dynalink.linker.support.Lookup; +import jdk.internal.dynalink.linker.support.TypeUtilities; /** * A class that provides linking capabilities for a single POJO class. Normally not used directly, but managed by @@ -109,7 +111,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL if(clazz.isArray()) { // Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an // explicit property is beneficial for them. - // REVISIT: is it maybe a code smell that "dyn:getLength" is not needed? + // REVISIT: is it maybe a code smell that StandardOperation.GET_LENGTH is not needed? setPropertyGetter("length", GET_ARRAY_LENGTH, ValidationType.IS_ARRAY); } else if(List.class.isAssignableFrom(clazz)) { setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF); @@ -128,27 +130,23 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL @Override protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations) throws Exception { + final LinkerServices linkerServices, final List operations, final Object name) throws Exception { final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations); + linkerServices, operations, name); if(superGic != null) { return superGic; } if(operations.isEmpty()) { return null; } - final String op = operations.get(0); - // dyn:getElem(this, id) - // id is typically either an int (for arrays and lists) or an object (for maps). linkerServices can provide - // conversion from call site argument type though. - if("getElem".equals(op)) { - return getElementGetter(callSiteDescriptor, linkerServices, pop(operations)); + final Operation op = operations.get(0); + if(op == StandardOperation.GET_ELEMENT) { + return getElementGetter(callSiteDescriptor, linkerServices, pop(operations), name); } - if("setElem".equals(op)) { - return getElementSetter(callSiteDescriptor, linkerServices, pop(operations)); + if(op == StandardOperation.SET_ELEMENT) { + return getElementSetter(callSiteDescriptor, linkerServices, pop(operations), name); } - // dyn:getLength(this) (works on Java arrays, collections, and maps) - if("getLength".equals(op)) { + if(op == StandardOperation.GET_LENGTH) { return getLengthGetter(callSiteDescriptor); } return null; @@ -168,11 +166,11 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL }; private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations) throws Exception { + final LinkerServices linkerServices, final List operations, final Object name) throws Exception { final MethodType callSiteType = callSiteDescriptor.getMethodType(); final Class declaredType = callSiteType.parameterType(0); final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations); + linkerServices, operations, name); // If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing // is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're @@ -206,22 +204,20 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL return nextComponent; } - // We can have "dyn:getElem:foo", especially in composites, i.e. "dyn:getElem|getProp|getMethod:foo" - final String fixedKey = getFixedKey(callSiteDescriptor); // Convert the key to a number if we're working with a list or array - final Object typedFixedKey; - if(collectionType != CollectionType.MAP && fixedKey != null) { - typedFixedKey = convertKeyToInteger(fixedKey, linkerServices); - if(typedFixedKey == null) { + final Object typedName; + if(collectionType != CollectionType.MAP && name != null) { + typedName = convertKeyToInteger(name, linkerServices); + if(typedName == null) { // key is not numeric, it can never succeed return nextComponent; } } else { - typedFixedKey = fixedKey; + typedName = name; } final GuardedInvocation gi = gic.getGuardedInvocation(); - final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey); + final Binder binder = new Binder(linkerServices, callSiteType, typedName); final MethodHandle invocation = gi.getInvocation(); if(nextComponent == null) { @@ -263,40 +259,50 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL validatorClass, validationType); } - private static String getFixedKey(final CallSiteDescriptor callSiteDescriptor) { - return callSiteDescriptor.getNameTokenCount() == 2 ? null : callSiteDescriptor.getNameToken( - CallSiteDescriptor.NAME_OPERAND); - } + private static Integer convertKeyToInteger(final Object fixedKey, final LinkerServices linkerServices) throws Exception { + if (fixedKey instanceof Integer) { + return (Integer)fixedKey; + } - private static Object convertKeyToInteger(final String fixedKey, final LinkerServices linkerServices) throws Exception { - try { - if(linkerServices.canConvert(String.class, Number.class)) { + final Number n; + if (fixedKey instanceof Number) { + n = (Number)fixedKey; + } else { + final Class keyClass = fixedKey.getClass(); + if(linkerServices.canConvert(keyClass, Number.class)) { + final Object val; try { - final Object val = linkerServices.getTypeConverter(String.class, Number.class).invoke(fixedKey); - if(!(val instanceof Number)) { - return null; // not a number - } - final Number n = (Number)val; - if(n instanceof Integer) { - return n; - } - final int intIndex = n.intValue(); - final double doubleValue = n.doubleValue(); - if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinites trigger IOOBE - return null; // not an exact integer - } - return intIndex; + val = linkerServices.getTypeConverter(keyClass, Number.class).invoke(fixedKey); } catch(Exception|Error e) { throw e; } catch(final Throwable t) { throw new RuntimeException(t); } + if(!(val instanceof Number)) { + return null; // not a number + } + n = (Number)val; + } else if (fixedKey instanceof String){ + try { + return Integer.valueOf((String)fixedKey); + } catch(final NumberFormatException e) { + // key is not a number + return null; + } + } else { + return null; } - return Integer.valueOf(fixedKey); - } catch(final NumberFormatException e) { - // key is not a number - return null; } + + if(n instanceof Integer) { + return (Integer)n; + } + final int intIndex = n.intValue(); + final double doubleValue = n.doubleValue(); + if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinites trigger IOOBE + return null; // not an exact integer + } + return intIndex; } private static MethodHandle convertArgToInt(final MethodHandle mh, final LinkerServices ls, final CallSiteDescriptor desc) { @@ -389,7 +395,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL MethodType.methodType(Object.class, Object.class, Object.class)); private GuardedInvocationComponent getElementSetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations) throws Exception { + final LinkerServices linkerServices, final List operations, final Object name) throws Exception { final MethodType callSiteType = callSiteDescriptor.getMethodType(); final Class declaredType = callSiteType.parameterType(0); @@ -431,27 +437,25 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL // as maps will always succeed in setting the element and will never need to fall back to the next component // operation. final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getGuardedInvocationComponent( - callSiteDescriptor, linkerServices, operations); + callSiteDescriptor, linkerServices, operations, name); if(gic == null) { return nextComponent; } - // We can have "dyn:setElem:foo", especially in composites, i.e. "dyn:setElem|setProp:foo" - final String fixedKey = getFixedKey(callSiteDescriptor); // Convert the key to a number if we're working with a list or array - final Object typedFixedKey; - if(collectionType != CollectionType.MAP && fixedKey != null) { - typedFixedKey = convertKeyToInteger(fixedKey, linkerServices); - if(typedFixedKey == null) { + final Object typedName; + if(collectionType != CollectionType.MAP && name != null) { + typedName = convertKeyToInteger(name, linkerServices); + if(typedName == null) { // key is not numeric, it can never succeed return nextComponent; } } else { - typedFixedKey = fixedKey; + typedName = name; } final GuardedInvocation gi = gic.getGuardedInvocation(); - final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey); + final Binder binder = new Binder(linkerServices, callSiteType, typedName); final MethodHandle invocation = gi.getInvocation(); if(nextComponent == null) { @@ -510,7 +514,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) { if(descriptor.getMethodType().parameterCount() != paramCount) { - throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters."); + throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters."); } } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeansLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeansLinker.java index 0cee06f3c55..0e9c7131b2f 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeansLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeansLinker.java @@ -83,11 +83,11 @@ package jdk.internal.dynalink.beans; -import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; import java.util.Collection; import java.util.Collections; -import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.DynamicLinkerFactory; +import jdk.internal.dynalink.StandardOperation; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardingDynamicLinker; import jdk.internal.dynalink.linker.LinkRequest; @@ -95,36 +95,61 @@ import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; /** - * A linker for POJOs. Normally used as the ultimate fallback linker by the {@link DynamicLinkerFactory} so it is given - * the chance to link calls to all objects that no other language runtime recognizes. Specifically, this linker will: + * A linker for ordinary Java objects. Normally used as the ultimate fallback + * linker by the {@link DynamicLinkerFactory} so it is given the chance to link + * calls to all objects that no other linker recognized. Specifically, this + * linker will: *
        - *
      • expose all public methods of form {@code setXxx()}, {@code getXxx()}, and {@code isXxx()} as property setters and - * getters for {@code dyn:setProp} and {@code dyn:getProp} operations;
      • - *
      • expose all public methods for invocation through {@code dyn:callMethod} operation;
      • - *
      • expose all public methods for retrieval for {@code dyn:getMethod} operation; the methods thus retrieved can then - * be invoked using {@code dyn:call};
      • - *
      • expose all public fields as properties, unless there are getters or setters for the properties of the same name;
      • - *
      • expose {@code dyn:getLength}, {@code dyn:getElem} and {@code dyn:setElem} on native Java arrays, as well as - * {@link java.util.List} and {@link java.util.Map} objects; ({@code dyn:getLength} works on any - * {@link java.util.Collection});
      • + *
      • expose all public methods of form {@code setXxx()}, {@code getXxx()}, + * and {@code isXxx()} as property setters and getters for + * {@link StandardOperation#SET_PROPERTY} and {@link StandardOperation#GET_PROPERTY} + * operations;
      • + *
      • expose all public methods for invocation through + * {@link StandardOperation#CALL_METHOD} operation;
      • + *
      • expose all public methods for retrieval for + * {@link StandardOperation#GET_METHOD} operation; the methods thus retrieved + * can then be invoked using {@link StandardOperation#CALL}.
      • + *
      • expose all public fields as properties, unless there are getters or + * setters for the properties of the same name;
      • + *
      • expose {@link StandardOperation#GET_LENGTH}, + * {@link StandardOperation#GET_ELEMENT} and {@link StandardOperation#SET_ELEMENT} + * on native Java arrays, as well as {@link java.util.List} and + * {@link java.util.Map} objects; ({@link StandardOperation#GET_LENGTH} works on + * any {@link java.util.Collection});
      • *
      • expose a virtual property named {@code length} on Java arrays;
      • - *
      • expose {@code dyn:new} on instances of {@link StaticClass} as calls to constructors, including those static class - * objects that represent Java arrays (their constructors take a single {@code int} parameter representing the length of - * the array to create);
      • - *
      • expose static methods, fields, and properties of classes in a similar manner to how instance method, fields, and - * properties are exposed, on {@link StaticClass} objects.
      • - *
      • expose a virtual property named {@code static} on instances of {@link java.lang.Class} to access their - * {@link StaticClass}.
      • + *
      • expose {@link StandardOperation#NEW} on instances of {@link StaticClass} + * as calls to constructors, including those static class objects that represent + * Java arrays (their constructors take a single {@code int} parameter + * representing the length of the array to create);
      • + *
      • expose static methods, fields, and properties of classes in a similar + * manner to how instance method, fields, and properties are exposed, on + * {@link StaticClass} objects.
      • + *
      • expose a virtual property named {@code static} on instances of + * {@link java.lang.Class} to access their {@link StaticClass}.
      • *
      - *

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

      - *

      Variable argument invocation is handled for both methods and constructors.

      - *

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

      + *

      Overloaded method resolution is performed automatically + * for property setters, methods, and constructors. Additionally, manual + * overloaded method selection is supported by having a call site specify a name + * for a method that contains an explicit signature, i.e. + * {@code NamedMethod(GET_METHOD, "parseInt(String,int)")}. You can use + * non-qualified class names in such signatures regardless of those classes' + * packages, they will match any class with the same non-qualified name. You + * only have to use a fully qualified class name in case non-qualified class + * names would cause selection ambiguity (that is extremely rare). Overloaded + * resolution for constructors is not automatic as there is no logical place to + * attach that functionality to but if a language wishes to provide this + * functionality, it can use {@link #getConstructorMethod(Class, String)} as a + * useful building block for it.

      + *

      Variable argument invocation is handled for both methods + * and constructors.

      + *

      Caller sensitive methods can be linked as long as they + * are otherwise public and link requests have call site descriptors carrying + * full-strength {@link Lookup} objects and not weakened lookups or the public + * lookup.

      + *

      The class also exposes various static methods for discovery of available + * property and method names on classes and class instances, as well as access + * to per-class linkers using the {@link #getLinkerForClass(Class)} + * method.

      */ public class BeansLinker implements GuardingDynamicLinker { private static final ClassValue linkers = new ClassValue() { @@ -140,15 +165,16 @@ public class BeansLinker implements GuardingDynamicLinker { }; /** - * Creates a new POJO linker. + * Creates a new beans linker. */ public BeansLinker() { } /** - * Returns a bean linker for a particular single class. Useful when you need to override or extend the behavior of - * linking for some classes in your language runtime's linker, but still want to delegate to the default behavior in - * some cases. + * Returns a bean linker for a particular single class. Useful when you need + * to override or extend the behavior of linking for some classes in your + * language runtime's linker, but still want to delegate to the default + * behavior in some cases. * @param clazz the class * @return a bean linker for that class */ @@ -157,9 +183,12 @@ public class BeansLinker implements GuardingDynamicLinker { } /** - * Returns true if the object is a Dynalink Java dynamic method. + * Returns true if the object is a Java dynamic method (e.g., one + * obtained through a {@code GET_METHOD} operation on a Java object or + * {@link StaticClass} or through + * {@link #getConstructorMethod(Class, String)}. * - * @param obj the object we want to test for being a dynamic method + * @param obj the object we want to test for being a Java dynamic method. * @return true if it is a dynamic method, false otherwise. */ public static boolean isDynamicMethod(final Object obj) { @@ -167,9 +196,10 @@ public class BeansLinker implements GuardingDynamicLinker { } /** - * Returns true if the object is a Dynalink Java constructor. + * Returns true if the object is a Java constructor (obtained through + * {@link #getConstructorMethod(Class, String)}}. * - * @param obj the object we want to test for being a constructor + * @param obj the object we want to test for being a Java constructor. * @return true if it is a constructor, false otherwise. */ public static boolean isDynamicConstructor(final Object obj) { @@ -177,10 +207,22 @@ public class BeansLinker implements GuardingDynamicLinker { } /** - * Return the dynamic method of constructor of the given class and the given signature. + * Return the dynamic method of constructor of the given class and the given + * signature. This method is useful for exposing a functionality for + * selecting an overloaded constructor based on an explicit signature, as + * this functionality is not otherwise exposed by Dynalink as + * {@link StaticClass} objects act as overloaded constructors without + * explicit signature selection. Example usage would be: + * {@code getConstructorMethod(java.awt.Color.class, "int, int, int")}. * @param clazz the class - * @param signature full signature of the constructor - * @return DynamicMethod for the constructor + * @param signature full signature of the constructor. Note how you can use + * names of primitive types, array names with normal Java notation (e.g. + * {@code "int[]"}), and normally you can even use unqualified class names + * (e.g. {@code "String, List"} instead of + * {@code "java.lang.String, java.util.List"} as long as they don't cause + * ambiguity in the specific parameter position. + * @return dynamic method for the constructor or null if no constructor with + * the specified signature exists. */ public static Object getConstructorMethod(final Class clazz, final String signature) { return StaticClassLinker.getConstructorMethod(clazz, signature); @@ -255,13 +297,6 @@ public class BeansLinker implements GuardingDynamicLinker { @Override public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) throws Exception { - final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor(); - final int l = callSiteDescriptor.getNameTokenCount(); - // All names conforming to the dynalang MOP should have at least two tokens, the first one being "dyn" - if(l < 2 || "dyn" != callSiteDescriptor.getNameToken(CallSiteDescriptor.SCHEME)) { - return null; - } - final Object receiver = request.getReceiver(); if(receiver == null) { // Can't operate on null diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDetector.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDetector.java deleted file mode 100644 index e4ada355e53..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDetector.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink.beans; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AccessibleObject; -import sun.reflect.CallerSensitive; - -/** - * Utility class that determines if a method or constructor is caller sensitive. It actually encapsulates two different - * strategies for determining caller sensitivity; a more robust one that works if Dynalink runs as code with access - * to {@code sun.reflect} package, and an unprivileged one that is used when Dynalink doesn't have access to that - * package. Note that even the unprivileged strategy is ordinarily robust, but it relies on the {@code toString} method - * of the annotation. If an attacker were to use a different annotation to spoof the string representation of the - * {@code CallerSensitive} annotation, they could designate their own methods as caller sensitive. This however does not - * escalate privileges, only causes Dynalink to never cache method handles for such methods, so all it would do would - * decrease the performance in linking such methods. In the opposite case when an attacker could trick Dynalink into not - * recognizing genuine {@code CallerSensitive} annotations, Dynalink would treat caller sensitive methods as ordinary - * methods, and would cache them bound to a zero-privilege delegate as the caller (just what Dynalink did before it - * could handle caller-sensitive methods). That would practically render caller-sensitive methods exposed through - * Dynalink unusable, but again, can not lead to any privilege escalations. Therefore, even the less robust unprivileged - * strategy is safe; the worst thing a successful attack against it can achieve is slight reduction in Dynalink-exposed - * functionality or performance. - */ -public class CallerSensitiveDetector { - - private static final DetectionStrategy DETECTION_STRATEGY = getDetectionStrategy(); - - static boolean isCallerSensitive(final AccessibleObject ao) { - return DETECTION_STRATEGY.isCallerSensitive(ao); - } - - private static DetectionStrategy getDetectionStrategy() { - try { - return new PrivilegedDetectionStrategy(); - } catch(final Throwable t) { - return new UnprivilegedDetectionStrategy(); - } - } - - private abstract static class DetectionStrategy { - abstract boolean isCallerSensitive(AccessibleObject ao); - } - - private static class PrivilegedDetectionStrategy extends DetectionStrategy { - private static final Class CALLER_SENSITIVE_ANNOTATION_CLASS = CallerSensitive.class; - - @Override - boolean isCallerSensitive(final AccessibleObject ao) { - return ao.getAnnotation(CALLER_SENSITIVE_ANNOTATION_CLASS) != null; - } - } - - private static class UnprivilegedDetectionStrategy extends DetectionStrategy { - private static final String CALLER_SENSITIVE_ANNOTATION_STRING = "@sun.reflect.CallerSensitive()"; - - @Override - boolean isCallerSensitive(final AccessibleObject o) { - for(final Annotation a: o.getAnnotations()) { - if(String.valueOf(a).equals(CALLER_SENSITIVE_ANNOTATION_STRING)) { - return true; - } - } - return false; - } - } -} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java index b47e9ec57b7..ab25e29d052 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java @@ -91,15 +91,24 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import jdk.internal.dynalink.support.Lookup; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.internal.AccessControlContextFactory; +import jdk.internal.dynalink.linker.support.Lookup; /** * A dynamic method bound to exactly one Java method or constructor that is caller sensitive. Since the target method is * caller sensitive, it doesn't cache a method handle but rather uses the passed lookup object in - * {@link #getTarget(java.lang.invoke.MethodHandles.Lookup)} to unreflect a method handle from the reflective member on + * {@link #getTarget(CallSiteDescriptor)} to unreflect a method handle from the reflective member on * every request. */ class CallerSensitiveDynamicMethod extends SingleDynamicMethod { + private static final AccessControlContext GET_LOOKUP_CONTEXT = + AccessControlContextFactory.createAccessControlContext( + CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME); + // Typed as "AccessibleObject" as it can be either a method or a constructor. // If we were Java8-only, we could use java.lang.reflect.Executable private final AccessibleObject target; @@ -143,7 +152,11 @@ class CallerSensitiveDynamicMethod extends SingleDynamicMethod { } @Override - MethodHandle getTarget(final MethodHandles.Lookup lookup) { + MethodHandle getTarget(final CallSiteDescriptor desc) { + final MethodHandles.Lookup lookup = AccessController.doPrivileged( + (PrivilegedAction)()->desc.getLookup(), + GET_LOOKUP_CONTEXT); + if(target instanceof Method) { final MethodHandle mh = Lookup.unreflect(lookup, (Method)target); if(Modifier.isStatic(((Member)target).getModifiers())) { diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CheckRestrictedPackage.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CheckRestrictedPackage.java index 49723a12d38..dda6d1225de 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CheckRestrictedPackage.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CheckRestrictedPackage.java @@ -86,15 +86,15 @@ package jdk.internal.dynalink.beans; import java.lang.reflect.Modifier; import java.security.AccessControlContext; import java.security.AccessController; -import java.security.Permissions; import java.security.PrivilegedAction; -import java.security.ProtectionDomain; +import jdk.internal.dynalink.internal.AccessControlContextFactory; /** * A utility class to check whether a given class is in a package with restricted access e.g. "sun.*" etc. */ class CheckRestrictedPackage { - private static final AccessControlContext NO_PERMISSIONS_CONTEXT = createNoPermissionsContext(); + private static final AccessControlContext NO_PERMISSIONS_CONTEXT = + AccessControlContextFactory.createAccessControlContext(); /** * Returns true if the class is either not public, or it resides in a package with restricted access. @@ -131,8 +131,4 @@ class CheckRestrictedPackage { } return false; } - - private static AccessControlContext createNoPermissionsContext() { - return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }); - } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassLinker.java index 89a73ccb8e7..7a3bd2f7787 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassLinker.java @@ -87,7 +87,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; -import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.linker.support.Lookup; /** * A linker for java.lang.Class objects. Provides a synthetic property "static" that allows access to static fields and diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassString.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassString.java index 65c5e259736..8dd342ef401 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassString.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassString.java @@ -85,11 +85,15 @@ package jdk.internal.dynalink.beans; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.LinkedList; import java.util.List; +import jdk.internal.dynalink.internal.AccessControlContextFactory; +import jdk.internal.dynalink.internal.InternalTypeUtilities; import jdk.internal.dynalink.linker.LinkerServices; -import jdk.internal.dynalink.support.Guards; -import jdk.internal.dynalink.support.TypeUtilities; +import jdk.internal.dynalink.linker.support.TypeUtilities; /** * Represents a sequence of {@link Class} objects, useful for representing method signatures. Provides value @@ -97,6 +101,9 @@ import jdk.internal.dynalink.support.TypeUtilities; * JLS. */ final class ClassString { + private static final AccessControlContext GET_CLASS_LOADER_CONTEXT = + AccessControlContextFactory.createAccessControlContext("getClassLoader"); + /** * An anonymous inner class used solely to represent the "type" of null values for method applicability checking. */ @@ -143,12 +150,17 @@ final class ClassString { } boolean isVisibleFrom(final ClassLoader classLoader) { - for(int i = 0; i < classes.length; ++i) { - if(!Guards.canReferenceDirectly(classLoader, classes[i].getClassLoader())) { - return false; + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + for(final Class clazz: classes) { + if(!InternalTypeUtilities.canReferenceDirectly(classLoader, clazz.getClassLoader())) { + return false; + } + } + return true; } - } - return true; + }, GET_CLASS_LOADER_CONTEXT); } List getMaximallySpecifics(final List methods, final LinkerServices linkerServices, final boolean varArg) { diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/DynamicMethodLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/DynamicMethodLinker.java index 7067c2ce236..e88d016a12e 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/DynamicMethodLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/DynamicMethodLinker.java @@ -86,16 +86,19 @@ package jdk.internal.dynalink.beans; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.NamedOperation; +import jdk.internal.dynalink.Operation; +import jdk.internal.dynalink.StandardOperation; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; -import jdk.internal.dynalink.support.CallSiteDescriptorFactory; -import jdk.internal.dynalink.support.Guards; +import jdk.internal.dynalink.linker.support.Guards; /** - * Simple linker that implements the "dyn:call" operation for {@link DynamicMethod} objects - the objects returned by - * "dyn:getMethod" from {@link AbstractJavaLinker}. + * Simple linker that implements the {@link StandardOperation#CALL} operation + * for {@link DynamicMethod} objects - the objects returned by + * {@link StandardOperation#GET_METHOD} through {@link AbstractJavaLinker}. */ class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker { @Override @@ -109,19 +112,16 @@ class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker { if(!(receiver instanceof DynamicMethod)) { return null; } - final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); - if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") { - return null; - } - final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR); final DynamicMethod dynMethod = (DynamicMethod)receiver; final boolean constructor = dynMethod.isConstructor(); final MethodHandle invocation; - if (operator == "call" && !constructor) { - invocation = dynMethod.getInvocation( - CallSiteDescriptorFactory.dropParameterTypes(desc, 0, 1), linkerServices); - } else if (operator == "new" && constructor) { + final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); + final Operation op = NamedOperation.getBaseOperation(desc.getOperation()); + if (op == StandardOperation.CALL && !constructor) { + invocation = dynMethod.getInvocation(desc.changeMethodType( + desc.getMethodType().dropParameterTypes(0, 1)), linkerServices); + } else if (op == StandardOperation.NEW && constructor) { final MethodHandle ctorInvocation = dynMethod.getInvocation(desc, linkerServices); if(ctorInvocation == null) { return null; diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/FacetIntrospector.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/FacetIntrospector.java index 3c467cb7e19..dc9ac5c2e78 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/FacetIntrospector.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/FacetIntrospector.java @@ -92,7 +92,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Map; -import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.linker.support.Lookup; /** * Base for classes that expose class field and method information to an {@link AbstractJavaLinker}. There are diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/MaximallySpecific.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/MaximallySpecific.java index 5eab4412e08..0f990b5b010 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/MaximallySpecific.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/MaximallySpecific.java @@ -90,7 +90,7 @@ import java.util.LinkedList; import java.util.List; import jdk.internal.dynalink.linker.ConversionComparator.Comparison; import jdk.internal.dynalink.linker.LinkerServices; -import jdk.internal.dynalink.support.TypeUtilities; +import jdk.internal.dynalink.linker.support.TypeUtilities; /** * Utility class that encapsulates the algorithm for choosing the maximally specific methods. diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java index 82c376d2e26..7b377b689e9 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java @@ -84,18 +84,24 @@ package jdk.internal.dynalink.beans; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Set; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest; +import jdk.internal.dynalink.internal.AccessControlContextFactory; +import jdk.internal.dynalink.internal.InternalTypeUtilities; import jdk.internal.dynalink.linker.LinkerServices; -import jdk.internal.dynalink.support.TypeUtilities; /** * Represents a group of {@link SingleDynamicMethod} objects that represents all overloads of a particular name (or all @@ -216,14 +222,25 @@ class OverloadedDynamicMethod extends DynamicMethod { // methods here to their handles, as the OverloadedMethod instance is specific to a call site, so it // has an already determined Lookup. final List methodHandles = new ArrayList<>(invokables.size()); - final MethodHandles.Lookup lookup = callSiteDescriptor.getLookup(); for(final SingleDynamicMethod method: invokables) { - methodHandles.add(method.getTarget(lookup)); + methodHandles.add(method.getTarget(callSiteDescriptor)); } - return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker(); + return new OverloadedMethod(methodHandles, this, getCallSiteClassLoader(callSiteDescriptor), callSiteType, linkerServices).getInvoker(); } } + } + private static final AccessControlContext GET_CALL_SITE_CLASS_LOADER_CONTEXT = + AccessControlContextFactory.createAccessControlContext( + "getClassLoader", CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME); + + private static ClassLoader getCallSiteClassLoader(final CallSiteDescriptor callSiteDescriptor) { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return callSiteDescriptor.getLookup().lookupClass().getClassLoader(); + } + }, GET_CALL_SITE_CLASS_LOADER_CONTEXT); } @Override @@ -324,7 +341,7 @@ class OverloadedDynamicMethod extends DynamicMethod { private static boolean isApplicableDynamically(final LinkerServices linkerServices, final Class callSiteType, final Class methodType) { - return TypeUtilities.isPotentiallyConvertible(callSiteType, methodType) + return isPotentiallyConvertible(callSiteType, methodType) || linkerServices.canConvert(callSiteType, methodType); } @@ -345,4 +362,72 @@ class OverloadedDynamicMethod extends DynamicMethod { private boolean constructorFlagConsistent(final SingleDynamicMethod method) { return methods.isEmpty()? true : (methods.getFirst().isConstructor() == method.isConstructor()); } + + /** + * Determines whether one type can be potentially converted to another type at runtime. Allows a conversion between + * any subtype and supertype in either direction, and also allows a conversion between any two primitive types, as + * well as between any primitive type and any reference type that can hold a boxed primitive. + * + * @param callSiteType the parameter type at the call site + * @param methodType the parameter type in the method declaration + * @return true if callSiteType is potentially convertible to the methodType. + */ + private static boolean isPotentiallyConvertible(final Class callSiteType, final Class methodType) { + // Widening or narrowing reference conversion + if(InternalTypeUtilities.areAssignable(callSiteType, methodType)) { + return true; + } + if(callSiteType.isPrimitive()) { + // Allow any conversion among primitives, as well as from any + // primitive to any type that can receive a boxed primitive. + // TODO: narrow this a bit, i.e. allow, say, boolean to Character? + // MethodHandles.convertArguments() allows it, so we might need to + // too. + return methodType.isPrimitive() || isAssignableFromBoxedPrimitive(methodType); + } + if(methodType.isPrimitive()) { + // Allow conversion from any reference type that can contain a + // boxed primitive to any primitive. + // TODO: narrow this a bit too? + return isAssignableFromBoxedPrimitive(callSiteType); + } + return false; + } + + private static final Set> PRIMITIVE_WRAPPER_TYPES = createPrimitiveWrapperTypes(); + + private static Set> createPrimitiveWrapperTypes() { + final Map, Class> classes = new IdentityHashMap<>(); + addClassHierarchy(classes, Boolean.class); + addClassHierarchy(classes, Byte.class); + addClassHierarchy(classes, Character.class); + addClassHierarchy(classes, Short.class); + addClassHierarchy(classes, Integer.class); + addClassHierarchy(classes, Long.class); + addClassHierarchy(classes, Float.class); + addClassHierarchy(classes, Double.class); + return classes.keySet(); + } + + private static void addClassHierarchy(final Map, Class> map, final Class clazz) { + if(clazz == null) { + return; + } + map.put(clazz, clazz); + addClassHierarchy(map, clazz.getSuperclass()); + for(final Class itf: clazz.getInterfaces()) { + addClassHierarchy(map, itf); + } + } + + /** + * Returns true if the class can be assigned from any boxed primitive. + * + * @param clazz the class + * @return true if the class can be assigned from any boxed primitive. Basically, it is true if the class is any + * primitive wrapper class, or a superclass or superinterface of any primitive wrapper class. + */ + private static boolean isAssignableFromBoxedPrimitive(final Class clazz) { + return PRIMITIVE_WRAPPER_TYPES.contains(clazz); + } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedMethod.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedMethod.java index 0c23e3c8a3b..aec78f6163e 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedMethod.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedMethod.java @@ -91,9 +91,9 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import jdk.internal.dynalink.internal.InternalTypeUtilities; import jdk.internal.dynalink.linker.LinkerServices; -import jdk.internal.dynalink.support.Lookup; -import jdk.internal.dynalink.support.TypeUtilities; +import jdk.internal.dynalink.linker.support.Lookup; /** * Represents a subset of overloaded methods for a certain method name on a certain class. It can be either a fixarg or @@ -104,15 +104,20 @@ import jdk.internal.dynalink.support.TypeUtilities; class OverloadedMethod { private final Map argTypesToMethods = new ConcurrentHashMap<>(); private final OverloadedDynamicMethod parent; + private final ClassLoader callSiteClassLoader; private final MethodType callSiteType; private final MethodHandle invoker; private final LinkerServices linkerServices; private final ArrayList fixArgMethods; private final ArrayList varArgMethods; - OverloadedMethod(final List methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType, + OverloadedMethod(final List methodHandles, + final OverloadedDynamicMethod parent, + final ClassLoader callSiteClassLoader, + final MethodType callSiteType, final LinkerServices linkerServices) { this.parent = parent; + this.callSiteClassLoader = callSiteClassLoader; final Class commonRetType = getCommonReturnType(methodHandles); this.callSiteType = callSiteType.changeReturnType(commonRetType); this.linkerServices = linkerServices; @@ -177,9 +182,9 @@ class OverloadedMethod { break; } } - // Avoid keeping references to unrelated classes; this ruins the performance a bit, but avoids class loader - // memory leaks. - if(classString.isVisibleFrom(parent.getClassLoader())) { + // Avoid keeping references to unrelated classes; this ruins the + // performance a bit, but avoids class loader memory leaks. + if(classString.isVisibleFrom(callSiteClassLoader)) { argTypesToMethods.put(classString, method); } } @@ -268,7 +273,7 @@ class OverloadedMethod { final Iterator it = methodHandles.iterator(); Class retType = it.next().type().returnType(); while(it.hasNext()) { - retType = TypeUtilities.getCommonLosslessConversionType(retType, it.next().type().returnType()); + retType = InternalTypeUtilities.getCommonLosslessConversionType(retType, it.next().type().returnType()); } return retType; } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java index f54b850f5f7..8c5d704f51d 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java @@ -84,13 +84,13 @@ package jdk.internal.dynalink.beans; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; /** * A dynamic method bound to exactly one Java method or constructor that is not caller sensitive. Since its target is * not caller sensitive, this class pre-caches its method handle and always returns it from the call to - * {@link #getTarget(Lookup)}. Can be used in general to represents dynamic methods bound to a single method handle, + * {@link #getTarget(CallSiteDescriptor)}. Can be used in general to represents dynamic methods bound to a single method handle, * even if that handle is not mapped to a Java method, i.e. as a wrapper around field getters/setters, array element * getters/setters, etc. */ @@ -140,7 +140,7 @@ class SimpleDynamicMethod extends SingleDynamicMethod { } @Override - MethodHandle getTarget(final Lookup lookup) { + MethodHandle getTarget(final CallSiteDescriptor desc) { return target; } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java index c135ab2b3d4..cc341835ecf 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java @@ -90,8 +90,8 @@ import java.lang.reflect.Array; import java.util.StringTokenizer; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.LinkerServices; -import jdk.internal.dynalink.support.Guards; -import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.linker.support.Guards; +import jdk.internal.dynalink.linker.support.Lookup; /** * Base class for dynamic methods that dispatch to a single target Java method or constructor. Handles adaptation of the @@ -119,15 +119,17 @@ abstract class SingleDynamicMethod extends DynamicMethod { abstract MethodType getMethodType(); /** - * Given a specified lookup, returns a method handle to this method's target. - * @param lookup the lookup to use. + * Given a specified call site descriptor, returns a method handle to this method's target. The target + * should only depend on the descriptor's lookup, and it should only retrieve it (as a privileged + * operation) when it is absolutely needed. + * @param desc the call site descriptor to use. * @return the handle to this method's target method. */ - abstract MethodHandle getTarget(MethodHandles.Lookup lookup); + abstract MethodHandle getTarget(CallSiteDescriptor desc); @Override MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) { - return getInvocation(getTarget(callSiteDescriptor.getLookup()), callSiteDescriptor.getMethodType(), + return getInvocation(getTarget(callSiteDescriptor), callSiteDescriptor.getMethodType(), linkerServices); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClass.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClass.java index 153c12cfbaa..0d5e2bfbdae 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClass.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClass.java @@ -85,16 +85,48 @@ package jdk.internal.dynalink.beans; import java.io.Serializable; import java.util.Objects; +import jdk.internal.dynalink.StandardOperation; /** - * Object that represents the static facet of a class (its static methods, properties, and fields, as well as - * construction of instances using "dyn:new"). Objects of this class are recognized by the {@link BeansLinker} as being - * special, and operations on them will be linked against the represented class' static facet. The "class" synthetic - * property is additionally recognized and returns the Java {@link Class} object, as per {@link #getRepresentedClass()} - * method. Conversely, {@link Class} objects exposed through {@link BeansLinker} expose the "static" synthetic property - * which returns an instance of this class. + * Object that allows access to the static members of a class (its static + * methods, properties, and fields), as well as construction of instances using + * {@link StandardOperation#NEW} operation. In Dynalink, {@link Class} objects + * are not treated specially and act as ordinary Java objects; you can use e.g. + * {@code NamedOperation(GET_PROPERTY, "superclass")} as a property getter to + * invoke {@code clazz.getSuperclass()}. On the other hand, you can not use + * {@code Class} objects to access static members of a class, nor to create new + * instances of the class using {@code NEW}. This is consistent with how + * {@code Class} objects behave in Java: in Java, you write e.g. + * {@code new BitSet()} instead of {@code new BitSet.class()}. Similarly, you + * write {@code System.out} and not {@code System.class.out}. It is this aspect + * of using a class name as the constructor and a namespace for static members + * that {@code StaticClass} embodies. + *

      + * Objects of this class are recognized by the {@link BeansLinker} as being + * special, and operations on them will be linked against the represented class' + * static members. The {@code "class"} synthetic property is additionally + * recognized and returns the Java {@link Class} object, just as in Java + * {@code System.class} evaluates to the {@code Class} object for the + * {@code} System class. Conversely, {@link Class} objects exposed through + * {@link BeansLinker} expose the {@code "static"} synthetic property which + * returns their {@code StaticClass} object (there is no equivalent to this in + * Java). + *

      + * In summary, instances of this class act as namespaces for static members and + * as constructors for classes, much the same way as specifying a class name in + * Java language does, except that in Java this is just a syntactic element, + * while in Dynalink they are expressed as actual objects. + *

      {@code StaticClass} objects representing Java array types will act as + * constructors taking a single int argument and create an array of the + * specified size. + *

      + * If the class has several constructors, {@link StandardOperation#NEW} on + * {@code StaticClass} will try to select the most specific applicable + * constructor. You might want to expose a mechanism in your language for + * selecting a constructor with an explicit signature through + * {@link BeansLinker#getConstructorMethod(Class, String)}. */ -public class StaticClass implements Serializable { +public final class StaticClass implements Serializable { private static final ClassValue staticClasses = new ClassValue() { @Override protected StaticClass computeValue(final Class type) { @@ -129,7 +161,7 @@ public class StaticClass implements Serializable { @Override public String toString() { - return "JavaClassStatics[" + clazz.getName() + "]"; + return "StaticClass[" + clazz.getName() + "]"; } private Object readResolve() { diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClassLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClassLinker.java index 2b78a9c07d5..90e57c6b8fa 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClassLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClassLinker.java @@ -90,12 +90,14 @@ import java.lang.reflect.Array; import java.util.Arrays; import java.util.Collection; import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.NamedOperation; +import jdk.internal.dynalink.StandardOperation; import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; -import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.linker.support.Lookup; /** * Provides a linker for the {@link StaticClass} objects. @@ -150,8 +152,7 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker { return gi; } final CallSiteDescriptor desc = request.getCallSiteDescriptor(); - final String op = desc.getNameToken(CallSiteDescriptor.OPERATOR); - if("new" == op && constructor != null) { + if(NamedOperation.getBaseOperation(desc.getOperation()) == StandardOperation.NEW && constructor != null) { final MethodHandle ctorInvocation = constructor.getInvocation(desc, linkerServices); if(ctorInvocation != null) { return new GuardedInvocation(ctorInvocation, getClassGuard(desc.getMethodType())); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardedTypeConversion.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/package-info.java similarity index 80% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardedTypeConversion.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/package-info.java index b070ed6e395..42bcd81e4be 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardedTypeConversion.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,38 +81,9 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.linker; - /** - * Guarded type conversion + * Contains the linker for ordinary Java objects. + * @since 1.9 */ -public class GuardedTypeConversion { - private final GuardedInvocation conversionInvocation; - private final boolean cacheable; - - /** - * Constructor - * @param conversionInvocation guarded invocation for this type conversion - * @param cacheable is this invocation cacheable - */ - public GuardedTypeConversion(final GuardedInvocation conversionInvocation, final boolean cacheable) { - this.conversionInvocation = conversionInvocation; - this.cacheable = cacheable; - } - - /** - * Get the invocation - * @return invocation - */ - public GuardedInvocation getConversionInvocation() { - return conversionInvocation; - } - - /** - * Check if invocation is cacheable - * @return true if cacheable, false otherwise - */ - public boolean isCacheable() { - return cacheable; - } -} +@jdk.Exported +package jdk.internal.dynalink.beans; diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/package.html b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/package.html deleted file mode 100644 index f405d1649e2..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/package.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - -

      - Contains the linker for POJOs. -

      - diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/internal/AccessControlContextFactory.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/internal/AccessControlContextFactory.java new file mode 100644 index 00000000000..92b5a3c5b69 --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/internal/AccessControlContextFactory.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.dynalink.internal; + +import java.security.AccessControlContext; +import java.security.Permission; +import java.security.Permissions; +import java.security.ProtectionDomain; +import java.util.stream.Stream; + +/** + * Utility class for creating permission-restricting {@link AccessControlContext}s. + */ +public final class AccessControlContextFactory { + private AccessControlContextFactory () { + } + + /** + * Creates an access control context with no permissions. + * @return an access control context with no permissions. + */ + public static AccessControlContext createAccessControlContext() { + return createAccessControlContext(new Permission[0]); + } + + /** + * Creates an access control context limited to only the specified permissions. + * @param permissions the permissions for the newly created access control context. + * @return a new access control context limited to only the specified permissions. + */ + public static AccessControlContext createAccessControlContext(final Permission... permissions) { + final Permissions perms = new Permissions(); + for(final Permission permission: permissions) { + perms.add(permission); + } + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + /** + * Creates an access control context limited to only the {@link RuntimePermission}s + * of the given names. + * @param runtimePermissionNames the names of runtime permissions for the + * newly created access control context. + * @return a new access control context limited to only the runtime + * permissions with the specified names. + */ + public static AccessControlContext createAccessControlContext(final String... runtimePermissionNames) { + return createAccessControlContext(makeRuntimePermissions(runtimePermissionNames)); + } + + private static Permission[] makeRuntimePermissions(final String... runtimePermissionNames) { + return Stream.of(runtimePermissionNames).map(RuntimePermission::new).toArray(Permission[]::new); + } +} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/internal/InternalTypeUtilities.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/internal/InternalTypeUtilities.java new file mode 100644 index 00000000000..a8365edb3be --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/internal/InternalTypeUtilities.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.dynalink.internal; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import jdk.internal.dynalink.linker.support.TypeUtilities; + +/** + * Various static utility methods for testing type relationships; internal to Dynalink. + */ +public class InternalTypeUtilities { + private InternalTypeUtilities() { + } + + /** + * Returns true if either of the types is assignable from the other. + * @param c1 one type + * @param c2 another type + * @return true if either c1 is assignable from c2 or c2 is assignable from c1. + */ + public static boolean areAssignable(final Class c1, final Class c2) { + return c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1); + } + + /** + * Return true if it is safe to strongly reference a class from the referred + * class loader from a class associated with the referring class loader + * without risking a class loader memory leak. Generally, it is only safe + * to reference classes from the same or ancestor class loader. {@code null} + * indicates the system class loader; classes from it can always be + * directly referenced, and it can only directly reference classes from + * itself. This method can be used by language runtimes to ensure they are + * using weak references in their linkages when they need to link to methods + * in unrelated class loaders. + * + * @param referrerLoader the referrer class loader. + * @param referredLoader the referred class loader + * @return true if it is safe to strongly reference the class from referred + * in referred. + * @throws SecurityException if the caller does not have the + * {@code RuntimePermission("getClassLoader")} permission and the method + * needs to traverse the parent class loader chain. + */ + public static boolean canReferenceDirectly(final ClassLoader referrerLoader, final ClassLoader referredLoader) { + if(referredLoader == null) { + // Can always refer directly to a system class + return true; + } + if(referrerLoader == null) { + // System classes can't refer directly to any non-system class + return false; + } + // Otherwise, can only refer directly to classes residing in same or + // parent class loader. + + ClassLoader referrer = referrerLoader; + do { + if(referrer == referredLoader) { + return true; + } + referrer = referrer.getParent(); + } while(referrer != null); + return false; + } + + /** + * Given two types represented by c1 and c2, returns a type that is their + * most specific common supertype for purposes of lossless conversions. + * + * @param c1 one type + * @param c2 another type + * @return their most common superclass or superinterface for purposes of + * lossless conversions. If they have several unrelated superinterfaces as + * their most specific common type, or the types themselves are completely + * unrelated interfaces, {@link java.lang.Object} is returned. + */ + public static Class getCommonLosslessConversionType(final Class c1, final Class c2) { + if(c1 == c2) { + return c1; + } else if (c1 == void.class || c2 == void.class) { + return Object.class; + } else if(TypeUtilities.isConvertibleWithoutLoss(c2, c1)) { + return c1; + } else if(TypeUtilities.isConvertibleWithoutLoss(c1, c2)) { + return c2; + } else if(c1.isPrimitive() && c2.isPrimitive()) { + if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) { + // byte + char = int + return int.class; + } else if((c1 == short.class && c2 == char.class) || (c1 == char.class && c2 == short.class)) { + // short + char = int + return int.class; + } else if((c1 == int.class && c2 == float.class) || (c1 == float.class && c2 == int.class)) { + // int + float = double + return double.class; + } + } + // For all other cases. This will handle long + (float|double) = Number case as well as boolean + anything = Object case too. + return getMostSpecificCommonTypeUnequalNonprimitives(c1, c2); + } + + private static Class getMostSpecificCommonTypeUnequalNonprimitives(final Class c1, final Class c2) { + final Class npc1 = c1.isPrimitive() ? TypeUtilities.getWrapperType(c1) : c1; + final Class npc2 = c2.isPrimitive() ? TypeUtilities.getWrapperType(c2) : c2; + final Set> a1 = getAssignables(npc1, npc2); + final Set> a2 = getAssignables(npc2, npc1); + a1.retainAll(a2); + if(a1.isEmpty()) { + // Can happen when at least one of the arguments is an interface, + // as they don't have Object at the root of their hierarchy. + return Object.class; + } + // Gather maximally specific elements. Yes, there can be more than one + // thank to interfaces. I.e., if you call this method for String.class + // and Number.class, you'll have Comparable, Serializable, and Object + // as maximal elements. + final List> max = new ArrayList<>(); + outer: for(final Class clazz: a1) { + for(final Iterator> maxiter = max.iterator(); maxiter.hasNext();) { + final Class maxClazz = maxiter.next(); + if(TypeUtilities.isSubtype(maxClazz, clazz)) { + // It can't be maximal, if there's already a more specific + // maximal than it. + continue outer; + } + if(TypeUtilities.isSubtype(clazz, maxClazz)) { + // If it's more specific than a currently maximal element, + // that currently maximal is no longer a maximal. + maxiter.remove(); + } + } + // If we get here, no current maximal is more specific than the + // current class, so it is considered maximal as well + max.add(clazz); + } + if(max.size() > 1) { + return Object.class; + } + return max.get(0); + } + + private static Set> getAssignables(final Class c1, final Class c2) { + final Set> s = new HashSet<>(); + collectAssignables(c1, c2, s); + return s; + } + + private static void collectAssignables(final Class c1, final Class c2, final Set> s) { + if(c1.isAssignableFrom(c2)) { + s.add(c1); + } + final Class sc = c1.getSuperclass(); + if(sc != null) { + collectAssignables(sc, c2, s); + } + final Class[] itf = c1.getInterfaces(); + for(int i = 0; i < itf.length; ++i) { + collectAssignables(itf[i], c2, s); + } + } +} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/ConversionComparator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/ConversionComparator.java index 72e1d322437..ed2db7c121d 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/ConversionComparator.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/ConversionComparator.java @@ -85,11 +85,14 @@ package jdk.internal.dynalink.linker; /** - * Optional interface to be implemented by {@link GuardingTypeConverterFactory} implementers. Language-specific - * conversions can cause increased overloaded method resolution ambiguity, as many methods can become applicable because - * of additional conversions. The static way of selecting the "most specific" method will fail more often, because there - * will be multiple maximally specific method with unrelated signatures. In these cases, language runtimes can be asked - * to resolve the ambiguity by expressing preferences for one conversion over the other. + * Optional interface to be implemented by {@link GuardingTypeConverterFactory} + * implementers. Language-specific conversions can cause increased overloaded + * method resolution ambiguity, as many methods can become applicable because of + * additional conversions. The static way of selecting the "most specific" + * method will fail more often, because there will be multiple maximally + * specific method with unrelated signatures. In these cases, language runtimes + * can be asked to resolve the ambiguity by expressing preferences for one + * conversion over the other. */ public interface ConversionComparator { /** @@ -105,12 +108,13 @@ public interface ConversionComparator { } /** - * Determines which of the two target types is the preferred conversion target from a source type. + * Determines which of the two target types is the preferred conversion + * target from a source type. * @param sourceType the source type. * @param targetType1 one potential target type * @param targetType2 another potential target type. - * @return one of Comparison constants that establish which - if any - of the target types is preferred for the - * conversion. + * @return one of Comparison constants that establish which - if any - of + * the target types is preferred for the conversion. */ public Comparison compareConversion(Class sourceType, Class targetType1, Class targetType2); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardedInvocation.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardedInvocation.java index 627ed3d779a..f4e6ffc0e53 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardedInvocation.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardedInvocation.java @@ -83,24 +83,32 @@ package jdk.internal.dynalink.linker; -import static jdk.nashorn.internal.lookup.Lookup.MH; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.SwitchPoint; -import java.lang.invoke.WrongMethodTypeException; import java.util.List; import java.util.Objects; +import java.util.function.Supplier; import jdk.internal.dynalink.CallSiteDescriptor; -import jdk.internal.dynalink.support.Guards; +import jdk.internal.dynalink.linker.support.Guards; /** - * Represents a conditionally valid method handle. It is an immutable triple of an invocation method handle, a guard - * method handle that defines the applicability of the invocation handle, and a switch point that can be used for - * external invalidation of the invocation handle. The invocation handle is suitable for invocation if the guard - * handle returns true for its arguments, and as long as the switch point is not invalidated. Both the guard and the - * switch point are optional; neither, one, or both can be present. + * Represents a conditionally valid method handle. Usually produced as a return + * value of + * {@link GuardingDynamicLinker#getGuardedInvocation(LinkRequest, LinkerServices)} + * and + * {@link GuardingTypeConverterFactory#convertToType(Class, Class, Supplier)}. + * It is an immutable tuple of an invocation method handle, a guard method + * handle that defines the applicability of the invocation handle, zero or more + * switch points that can be used for external invalidation of the invocation + * handle, and an exception type that if thrown during an invocation of the + * method handle also invalidates it. The invocation handle is suitable for + * invocation if the guard handle returns true for its arguments, and as long + * as any of the switch points are not invalidated, and as long as it does not + * throw an exception of the designated type. The guard, the switch points, and + * the exception type are all optional (a guarded invocation having none of them + * is unconditionally valid). */ public class GuardedInvocation { private final MethodHandle invocation; @@ -109,9 +117,11 @@ public class GuardedInvocation { private final SwitchPoint[] switchPoints; /** - * Creates a new guarded invocation. This invocation is unconditional as it has no invalidations. + * Creates a new unconditional guarded invocation. It is unconditional as it + * has no invalidations. * - * @param invocation the method handle representing the invocation. Must not be null. + * @param invocation the method handle representing the invocation. Must not + * be null. * @throws NullPointerException if invocation is null. */ public GuardedInvocation(final MethodHandle invocation) { @@ -119,12 +129,15 @@ public class GuardedInvocation { } /** - * Creates a new guarded invocation. + * Creates a new guarded invocation, with a guard method handle. * - * @param invocation the method handle representing the invocation. Must not be null. - * @param guard the method handle representing the guard. Must have the same method type as the invocation, except - * it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null to represent - * an unconditional invocation, although that is unusual. + * @param invocation the method handle representing the invocation. Must not + * be null. + * @param guard the method handle representing the guard. Must have be + * compatible with the {@code invocation} handle as per + * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. + * For some useful guards, check out the {@link Guards} class. It can be + * null to represent an unconditional invocation. * @throws NullPointerException if invocation is null. */ public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard) { @@ -132,10 +145,14 @@ public class GuardedInvocation { } /** - * Creates a new guarded invocation. + * Creates a new guarded invocation that can be invalidated by a switch + * point. * - * @param invocation the method handle representing the invocation. Must not be null. - * @param switchPoint the optional switch point that can be used to invalidate this linkage. + * @param invocation the method handle representing the invocation. Must + * not be null. + * @param switchPoint the optional switch point that can be used to + * invalidate this linkage. It can be null. If it is null, this represents + * an unconditional invocation. * @throws NullPointerException if invocation is null. */ public GuardedInvocation(final MethodHandle invocation, final SwitchPoint switchPoint) { @@ -143,13 +160,19 @@ public class GuardedInvocation { } /** - * Creates a new guarded invocation. + * Creates a new guarded invocation, with both a guard method handle and a + * switch point that can be used to invalidate it. * - * @param invocation the method handle representing the invocation. Must not be null. - * @param guard the method handle representing the guard. Must have the same method type as the invocation, except - * it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it - * and the switch point are null, this represents an unconditional invocation, which is legal but unusual. - * @param switchPoint the optional switch point that can be used to invalidate this linkage. + * @param invocation the method handle representing the invocation. Must + * not be null. + * @param guard the method handle representing the guard. Must have be + * compatible with the {@code invocation} handle as per + * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. + * For some useful guards, check out the {@link Guards} class. It can be + * null. If both it and the switch point are null, this represents an + * unconditional invocation. + * @param switchPoint the optional switch point that can be used to + * invalidate this linkage. * @throws NullPointerException if invocation is null. */ public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint switchPoint) { @@ -157,15 +180,22 @@ public class GuardedInvocation { } /** - * Creates a new guarded invocation. + * Creates a new guarded invocation, with a guard method handle, a + * switch point that can be used to invalidate it, and an exception that if + * thrown when invoked also invalidates it. * - * @param invocation the method handle representing the invocation. Must not be null. - * @param guard the method handle representing the guard. Must have the same method type as the invocation, except - * it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it - * and the switch point are null, this represents an unconditional invocation, which is legal but unusual. - * @param switchPoint the optional switch point that can be used to invalidate this linkage. - * @param exception the optional exception type that is expected to be thrown by the invocation and that also - * invalidates the linkage. + * @param invocation the method handle representing the invocation. Must not + * be null. + * @param guard the method handle representing the guard. Must have be + * compatible with the {@code invocation} handle as per + * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. + * For some useful guards, check out the {@link Guards} class. It can be + * null. If it and the switch point and the exception are all null, this + * represents an unconditional invocation. + * @param switchPoint the optional switch point that can be used to + * invalidate this linkage. + * @param exception the optional exception type that is when thrown by the + * invocation also invalidates it. * @throws NullPointerException if invocation is null. */ public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint switchPoint, final Class exception) { @@ -176,15 +206,22 @@ public class GuardedInvocation { } /** - * Creates a new guarded invocation + * Creates a new guarded invocation, with a guard method handle, any number + * of switch points that can be used to invalidate it, and an exception that + * if thrown when invoked also invalidates it. * - * @param invocation the method handle representing the invocation. Must not be null. - * @param guard the method handle representing the guard. Must have the same method type as the invocation, except - * it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it - * and the switch point are null, this represents an unconditional invocation, which is legal but unusual. - * @param switchPoints the optional switch points that can be used to invalidate this linkage. - * @param exception the optional exception type that is expected to be thrown by the invocation and that also - * invalidates the linkage. + * @param invocation the method handle representing the invocation. Must not + * be null. + * @param guard the method handle representing the guard. Must have be + * compatible with the {@code invocation} handle as per + * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. + * For some useful guards, check out the {@link Guards} class. It can be + * null. If it and the exception are both null, and no switch points were + * specified, this represents an unconditional invocation. + * @param switchPoints optional switch points that can be used to + * invalidate this linkage. + * @param exception the optional exception type that is when thrown by the + * invocation also invalidates it. * @throws NullPointerException if invocation is null. */ public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint[] switchPoints, final Class exception) { @@ -213,26 +250,32 @@ public class GuardedInvocation { } /** - * Returns the switch point that can be used to invalidate the invocation handle. + * Returns the switch points that can be used to invalidate the linkage of + * this invocation handle. * - * @return the switch point that can be used to invalidate the invocation handle. Can be null. + * @return the switch points that can be used to invalidate the linkage of + * this invocation handle. Can be null. */ public SwitchPoint[] getSwitchPoints() { return switchPoints == null ? null : switchPoints.clone(); } /** - * Returns the exception type that if thrown should be used to invalidate the linkage. + * Returns the exception type that if thrown by the invocation should + * invalidate the linkage of this guarded invocation. * - * @return the exception type that if thrown should be used to invalidate the linkage. Can be null. + * @return the exception type that if thrown should be used to invalidate + * the linkage. Can be null. */ public Class getException() { return exception; } /** - * Returns true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated. - * @return true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated. + * Returns true if and only if this guarded invocation has at least one + * invalidated switch point. + * @return true if and only if this guarded invocation has at least one + * invalidated switch point. */ public boolean hasBeenInvalidated() { if (switchPoints == null) { @@ -246,20 +289,6 @@ public class GuardedInvocation { return false; } - /** - * Asserts that the invocation is of the specified type, and the guard (if present) is of the specified type with a - * boolean return type. - * - * @param type the asserted type - * @throws WrongMethodTypeException if the invocation and the guard are not of the expected method type. - */ - public void assertType(final MethodType type) { - assertType(invocation, type); - if (guard != null) { - assertType(guard, type.changeReturnType(Boolean.TYPE)); - } - } - /** * Creates a new guarded invocation with different methods, preserving the switch point. * @@ -272,9 +301,10 @@ public class GuardedInvocation { } /** - * Add a switchpoint to this guarded invocation - * @param newSwitchPoint new switchpoint, or null for nop - * @return new guarded invocation with the extra switchpoint + * Create a new guarded invocation with an added switch point. + * @param newSwitchPoint new switch point. Can be null in which case this + * method return the current guarded invocation with no changes. + * @return a guarded invocation with the added switch point. */ public GuardedInvocation addSwitchPoint(final SwitchPoint newSwitchPoint) { if (newSwitchPoint == null) { @@ -301,9 +331,11 @@ public class GuardedInvocation { } /** - * Changes the type of the invocation, as if {@link MethodHandle#asType(MethodType)} was applied to its invocation - * and its guard, if it has one (with return type changed to boolean, and parameter count potentially truncated for - * the guard). If the invocation already is of the required type, returns this object. + * Changes the type of the invocation, as if + * {@link MethodHandle#asType(MethodType)} was applied to its invocation + * and its guard, if it has one (with return type changed to boolean, and + * parameter count potentially truncated for the guard). If the invocation + * already is of the required type, returns this object. * @param newType the new type of the invocation. * @return a guarded invocation with the new type applied to it. */ @@ -312,9 +344,11 @@ public class GuardedInvocation { } /** - * Changes the type of the invocation, as if {@link LinkerServices#asType(MethodHandle, MethodType)} was applied to - * its invocation and its guard, if it has one (with return type changed to boolean, and parameter count potentially - * truncated for the guard). If the invocation already is of the required type, returns this object. + * Changes the type of the invocation, as if + * {@link LinkerServices#asType(MethodHandle, MethodType)} was applied to + * its invocation and its guard, if it has one (with return type changed to + * boolean, and parameter count potentially truncated for the guard). If the + * invocation already is of the required type, returns this object. * @param linkerServices the linker services to use for the conversion * @param newType the new type of the invocation. * @return a guarded invocation with the new type applied to it. @@ -325,10 +359,13 @@ public class GuardedInvocation { } /** - * Changes the type of the invocation, as if {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)} was - * applied to its invocation and {@link LinkerServices#asType(MethodHandle, MethodType)} applied to its guard, if it - * has one (with return type changed to boolean, and parameter count potentially truncated for the guard). If the - * invocation doesn't change its type, returns this object. + * Changes the type of the invocation, as if + * {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)} was + * applied to its invocation and + * {@link LinkerServices#asType(MethodHandle, MethodType)} applied to its + * guard, if it has one (with return type changed to boolean, and parameter + * count potentially truncated for the guard). If the invocation doesn't + * change its type, returns this object. * @param linkerServices the linker services to use for the conversion * @param newType the new type of the invocation. * @return a guarded invocation with the new type applied to it. @@ -339,9 +376,11 @@ public class GuardedInvocation { } /** - * Changes the type of the invocation, as if {@link MethodHandle#asType(MethodType)} was applied to its invocation - * and its guard, if it has one (with return type changed to boolean for guard). If the invocation already is of the - * required type, returns this object. + * Changes the type of the invocation, as if + * {@link MethodHandle#asType(MethodType)} was applied to its invocation + * and its guard, if it has one (with return type changed to boolean for + * guard). If the invocation already is of the required type, returns this + * object. * @param desc a call descriptor whose method type is adapted. * @return a guarded invocation with the new type applied to it. */ @@ -350,7 +389,8 @@ public class GuardedInvocation { } /** - * Applies argument filters to both the invocation and the guard (if there is one). + * Applies argument filters to both the invocation and the guard (if there + * is one) with {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}. * @param pos the position of the first argument being filtered * @param filters the argument filters * @return a filtered invocation @@ -361,7 +401,8 @@ public class GuardedInvocation { } /** - * Makes an invocation that drops arguments in both the invocation and the guard (if there is one). + * Makes an invocation that drops arguments in both the invocation and the + * guard (if there is one) with {@link MethodHandles#dropArguments(MethodHandle, int, List)}. * @param pos the position of the first argument being dropped * @param valueTypes the types of the values being dropped * @return an invocation that drops arguments @@ -372,7 +413,8 @@ public class GuardedInvocation { } /** - * Makes an invocation that drops arguments in both the invocation and the guard (if there is one). + * Makes an invocation that drops arguments in both the invocation and the + * guard (if there is one) with {@link MethodHandles#dropArguments(MethodHandle, int, Class...)}. * @param pos the position of the first argument being dropped * @param valueTypes the types of the values being dropped * @return an invocation that drops arguments @@ -384,8 +426,11 @@ public class GuardedInvocation { /** - * Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back. - * @param fallback the fallback method handle in case switchpoint is invalidated or guard returns false. + * Composes the invocation, guard, switch points, and the exception into a + * composite method handle that knows how to fall back when the guard fails + * or the invocation is invalidated. + * @param fallback the fallback method handle for when a switch point is + * invalidated, a guard returns false, or invalidating exception is thrown. * @return a composite method handle. */ public MethodHandle compose(final MethodHandle fallback) { @@ -393,10 +438,15 @@ public class GuardedInvocation { } /** - * Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back. - * @param switchpointFallback the fallback method handle in case switchpoint is invalidated. - * @param guardFallback the fallback method handle in case guard returns false. - * @param catchFallback the fallback method in case the exception handler triggers + * Composes the invocation, guard, switch points, and the exception into a + * composite method handle that knows how to fall back when the guard fails + * or the invocation is invalidated. + * @param switchpointFallback the fallback method handle in case a switch + * point is invalidated. + * @param guardFallback the fallback method handle in case guard returns + * false. + * @param catchFallback the fallback method in case the exception handler + * triggers. * @return a composite method handle. */ public MethodHandle compose(final MethodHandle guardFallback, final MethodHandle switchpointFallback, final MethodHandle catchFallback) { @@ -411,7 +461,7 @@ public class GuardedInvocation { final MethodHandle catchGuarded = exception == null ? guarded : - MH.catchException( + MethodHandles.catchException( guarded, exception, MethodHandles.dropArguments( @@ -430,10 +480,4 @@ public class GuardedInvocation { return spGuarded; } - - private static void assertType(final MethodHandle mh, final MethodType type) { - if(!mh.type().equals(type)) { - throw new WrongMethodTypeException("Expected type: " + type + " actual type: " + mh.type()); - } - } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/GuardedInvocationFilter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardedInvocationTransformer.java similarity index 81% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/GuardedInvocationFilter.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardedInvocationTransformer.java index 8560d82f68d..5665d928dcc 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/GuardedInvocationFilter.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardedInvocationTransformer.java @@ -81,25 +81,33 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink; +package jdk.internal.dynalink.linker; -import jdk.internal.dynalink.linker.GuardedInvocation; -import jdk.internal.dynalink.linker.LinkRequest; -import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.DynamicLinkerFactory; /** - * Interface for objects that are used to transform one guarded invocation into another one. Typical usage is for - * implementing {@link DynamicLinkerFactory#setPrelinkFilter(GuardedInvocationFilter) pre-link filters}. + * Interface for objects that are used to transform one guarded invocation into + * another one. Typical usage is for implementing + * {@link DynamicLinkerFactory#setPrelinkTransformer(GuardedInvocationTransformer) + * pre-link transformers}. */ -public interface GuardedInvocationFilter { +@FunctionalInterface +public interface GuardedInvocationTransformer { /** - * Given a guarded invocation, return a potentially different guarded invocation. - * @param inv the original guarded invocation. Null is never passed. - * @param linkRequest the link request for which the invocation was generated (usually by some linker). - * @param linkerServices the linker services that can be used during creation of a new invocation. - * @return either the passed guarded invocation or a different one, with the difference usually determined based on - * information in the link request and the differing invocation created with the assistance of the linker services. - * Whether or not {@code null} is an accepted return value is dependent on the user of the filter. + * Given a guarded invocation, return either the same or potentially + * different guarded invocation. + * @param inv the original guarded invocation. + * @param linkRequest the link request for which the invocation was + * generated (usually by some linker). + * @param linkerServices the linker services that can be used during + * creation of a new invocation. + * @return either the passed guarded invocation or a different one, with + * the difference usually determined based on information in the link + * request and the differing invocation created with the assistance of the + * linker services. Whether or not {@code null} is an accepted return value + * is dependent on the user of the filter. + * @throws NullPointerException is allowed to be thrown by implementations + * if any of the passed arguments is null. */ public GuardedInvocation filter(GuardedInvocation inv, LinkRequest linkRequest, LinkerServices linkerServices); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingDynamicLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingDynamicLinker.java index a578be4548b..d6aa1553499 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingDynamicLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingDynamicLinker.java @@ -83,32 +83,58 @@ package jdk.internal.dynalink.linker; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.List; +import jdk.internal.dynalink.DynamicLinkerFactory; + /** - * The base interface for language-specific dynamic linkers. Such linkers always have to produce method handles with - * guards, as the validity of the method handle for calls at a call site inevitably depends on some condition (at the - * very least, it depends on the receiver belonging to the language runtime of the linker). Language runtime - * implementors will normally implement one for their own language, and declare it in the - * META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker file within their JAR file. + * The base interface for language-specific dynamic linkers. Such linkers + * always have to produce method handles with guards, as the validity of the + * method handle for calls at a call site inevitably depends on some condition + * (at the very least, it depends on the receiver belonging to the language + * runtime of the linker). Language runtime implementors will normally implement + * the linking logic for their own language as one or more + * {@link GuardingDynamicLinker} classes. They will typically set them as + * {@link DynamicLinkerFactory#setPrioritizedLinkers(List) prioritized linkers} + * in the {@code DynamicLinkerFactory} they configure for themselves, and maybe also + * set some as {@link DynamicLinkerFactory#setFallbackLinkers(List) fallback + * linkers} to handle language-specific "property not found" etc. conditions. + *

      + * Consider implementing {@link TypeBasedGuardingDynamicLinker} interface + * instead of this interface for those linkers that are based on the Java class + * of the objects. If you need to implement language-specific type conversions, + * have your {@code GuardingDynamicLinker} also implement the + * {@link GuardingTypeConverterFactory} interface. + *

      + * Languages can export linkers to other language runtimes for + * {@link DynamicLinkerFactory#setClassLoader(ClassLoader) automatic discovery} + * using a {@link GuardingDynamicLinkerExporter}. */ public interface GuardingDynamicLinker { /** - * Creates a guarded invocation appropriate for a particular invocation with the specified arguments at a call site. + * Creates a guarded invocation appropriate for a particular invocation with + * the specified arguments at a call site. * - * @param linkRequest the object describing the request for linking a particular invocation + * @param linkRequest the object describing the request for linking a + * particular invocation * @param linkerServices linker services - * @return a guarded invocation with a method handle suitable for the arguments, as well as a guard condition that - * if fails should trigger relinking. Must return null if it can't resolve the invocation. If the returned - * invocation is unconditional (which is actually quite rare), the guard in the return value can be null. The - * invocation can also have a switch point for asynchronous invalidation of the linkage, as well as a - * {@link Throwable} subclass that describes an expected exception condition that also triggers relinking (often it - * is faster to rely on an infrequent but expected {@link ClassCastException} than on an always evaluated - * {@code instanceof} guard). If the linker does not recognize any native language runtime contexts in arguments, or - * does recognize its own, but receives a call site descriptor without its recognized context in the arguments, it - * should invoke {@link LinkRequest#withoutRuntimeContext()} and link for that. While the linker must produce an - * invocation with parameter types matching those in the call site descriptor of the link request, it should not try - * to match the return type expected at the call site except when it can do it with only the conversions that lose - * neither precision nor magnitude, see {@link LinkerServices#asTypeLosslessReturn(java.lang.invoke.MethodHandle, - * java.lang.invoke.MethodType)}. + * @return a guarded invocation with a method handle suitable for the + * arguments, as well as a guard condition that if fails should trigger + * relinking. Must return null if it can't resolve the invocation. If the + * returned invocation is unconditional (which is actually quite rare), the + * guard in the return value can be null. The invocation can also have any + * number of switch points for asynchronous invalidation of the linkage, as + * well as a {@link Throwable} subclass that describes an expected exception + * condition that also triggers relinking (often it is faster to rely on an + * infrequent but expected {@link ClassCastException} than on an always + * evaluated {@code instanceof} guard). While the linker must produce an + * invocation with parameter types matching those in the call site + * descriptor of the link request, it should not try to match the return + * type expected at the call site except when it can do it with only the + * conversions that lose neither precision nor magnitude, see + * {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)} for + * further explanation. * @throws Exception if the operation fails for whatever reason */ public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingDynamicLinkerExporter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingDynamicLinkerExporter.java new file mode 100644 index 00000000000..64a4eb4aae4 --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingDynamicLinkerExporter.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.dynalink.linker; + +import java.security.Permission; +import java.util.List; +import java.util.ServiceLoader; +import java.util.function.Supplier; +import jdk.internal.dynalink.DynamicLinkerFactory; + +/** + * A class acting as a supplier of guarding dynamic linkers that can be + * automatically loaded by other language runtimes. Language runtimes wishing + * to export their own linkers should subclass this class and implement the + * {@link #get()} method to return a list of exported linkers and declare the + * subclass in + * {@code /META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinkerExporter} + * resource of their distribution (typically, JAR file) so that dynamic linker + * factories can discover them using the {@link ServiceLoader} mechanism. Note + * that instantiating this class is tied to a security check for the + * {@code RuntimePermission("dynalink.exportLinkersAutomatically")} when a + * security manager is present, to ensure that only trusted runtimes can + * automatically export their linkers into other runtimes. + * @see DynamicLinkerFactory#setClassLoader(ClassLoader) + */ +public abstract class GuardingDynamicLinkerExporter implements Supplier> { + /** + * The name of the runtime permission for creating instances of this class. + * Granting this permission to a language runtime allows it to export its + * linkers for automatic loading into other language runtimes. + */ + public static final String AUTOLOAD_PERMISSION_NAME = "dynalink.exportLinkersAutomatically"; + + private static final Permission AUTOLOAD_PERMISSION = new RuntimePermission(AUTOLOAD_PERMISSION_NAME); + + /** + * Creates a new linker exporter. If there is a security manager installed + * checks for the + * {@code RuntimePermission("dynalink.exportLinkersAutomatically")} runtime + * permission. This ensures only language runtimes granted this permission + * will be allowed to export their linkers for automatic loading. + * @throws SecurityException if the necessary runtime permission is not + * granted. + */ + protected GuardingDynamicLinkerExporter() { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(AUTOLOAD_PERMISSION); + } + } +} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java index d2791835530..8b807781f32 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java @@ -83,30 +83,65 @@ package jdk.internal.dynalink.linker; -import jdk.internal.dynalink.support.TypeUtilities; +import java.lang.invoke.MethodHandles; +import java.util.function.Supplier; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.beans.BeansLinker; +import jdk.internal.dynalink.linker.support.TypeUtilities; /** - * Optional interface that can be implemented by {@link GuardingDynamicLinker} implementations to provide - * language-runtime specific implicit type conversion capabilities. Note that if you implement this interface, you will - * very likely want to implement {@link ConversionComparator} interface too, as your additional language-specific - * conversions, in absence of a strategy for prioritizing these conversions, will cause more ambiguity in selecting the - * correct overload when trying to link to an overloaded POJO method. + * Optional interface that can be implemented by {@link GuardingDynamicLinker} + * implementations to provide language-specific type conversion capabilities. + * Note that if you implement this interface, you will very likely want to + * implement {@link ConversionComparator} interface too, as your additional + * language-specific conversions, in absence of a strategy for prioritizing + * these conversions, will cause more ambiguity for {@link BeansLinker} in + * selecting the correct overload when trying to link to an overloaded Java + * method. */ public interface GuardingTypeConverterFactory { /** - * Returns a guarded type conversion that receives an Object of the specified source type and returns an Object - * converted to the specified target type. The type of the invocation is targetType(sourceType), while the type of - * the guard is boolean(sourceType). Note that this will never be invoked for type conversions allowed by the JLS - * 5.3 "Method Invocation Conversion", see {@link TypeUtilities#isMethodInvocationConvertible(Class, Class)} for - * details. An implementation can assume it is never requested to produce a converter for these conversions. + * Returns a guarded type conversion that receives a value of the specified + * source type and returns a value converted to the specified target type. + * Value types can be either primitives or reference types, including + * interfaces, so you can even provide converters for converting your + * language's objects to Java interfaces and classes by generating adapters + * for them. + *

      + * The type of the invocation is {@code targetType(sourceType)}, while the + * type of the guard is {@code boolean(sourceType)}. You are allowed to + * return unconditional invocations (with no guard) if the source type is + * specific to your runtime and your runtime only. + *

      Note that this method will never be invoked for type conversions + * allowed by the JLS 5.3 "Method Invocation Conversion", see + * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class)} for + * details. An implementation can assume it is never requested to produce a + * converter for these conversions. + *

      Dynalink is at liberty to either cache some of the returned converters + * or to repeatedly request the converter factory to create the same + * conversion. * * @param sourceType source type * @param targetType the target type. - * @return a guarded type conversion that contains a guarded invocation that can take an object (if it passes guard) - * and return another object that is its representation coerced into the target type. In case the factory is certain - * it is unable to handle a conversion, it can return null. In case the factory is certain that it can always handle - * the conversion, it can return an unconditional invocation (one whose guard is null). + * @param lookupSupplier a supplier for retrieving the lookup of the class + * on whose behalf a type converter is requested. When a converter is + * requested as part of linking an {@code invokedynamic} instruction the + * supplier will return the lookup passed to the bootstrap method, otherwise + * it will return the public lookup. A typical case where the lookup might + * be needed is when the converter creates a Java adapter class on the fly + * (e.g. to convert some object from the dynamic language into a Java + * interface for interoperability). Invoking the {@link Supplier#get()} + * method on the passed supplier will be subject to the same security checks + * as {@link CallSiteDescriptor#getLookup()}. An implementation should avoid + * retrieving the lookup if it is not needed so as to avoid the expense of + * {@code AccessController.doPrivileged} call. + * @return a guarded invocation that can take an object (if it passes guard) + * and return another object that is its representation coerced into the + * target type. In case the factory is certain it is unable to handle a + * conversion, it can return null. In case the factory is certain that it + * can always handle the conversion, it can return an unconditional + * invocation (one whose guard is null). * @throws Exception if there was an error during creation of the converter */ - public GuardedTypeConversion convertToType(Class sourceType, Class targetType) throws Exception; + public GuardedInvocation convertToType(Class sourceType, Class targetType, Supplier lookupSupplier) throws Exception; } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/LinkRequest.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/LinkRequest.java index 6ca42c8cf49..25ffc183dba 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/LinkRequest.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/LinkRequest.java @@ -84,11 +84,14 @@ package jdk.internal.dynalink.linker; import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.DynamicLinker; import jdk.internal.dynalink.DynamicLinkerFactory; /** - * Represents a request to link a particular invocation at a particular call site. Instances of these requests are being - * passed to {@link GuardingDynamicLinker}. + * Represents a request to link a particular invocation at a particular call + * site. Instances of these requests will be constructed and passed to all + * {@link GuardingDynamicLinker} objects managed by the {@link DynamicLinker} + * that is trying to link the call site. */ public interface LinkRequest { /** @@ -99,64 +102,34 @@ public interface LinkRequest { public CallSiteDescriptor getCallSiteDescriptor(); /** - * Returns the call site token for the call site being linked. This token is an opaque object that is guaranteed to - * have different identity for different call sites, and is also guaranteed to not become weakly reachable before - * the call site does and to become weakly reachable some time after the call site does. This makes it ideal as a - * candidate for a key in a weak hash map in which a linker might want to keep per-call site linking state (usually - * profiling information). - * - * @return the call site token for the call site being linked. - */ - public Object getCallSiteToken(); - - /** - * Returns the arguments for the invocation being linked. The returned array is a clone; modifications to it won't - * affect the arguments in this request. + * Returns the arguments for the invocation being linked. The returned array + * must be a clone; modifications to it must not affect the arguments in + * this request. * * @return the arguments for the invocation being linked. */ public Object[] getArguments(); /** - * Returns the 0th argument for the invocation being linked; this is typically the receiver object. + * Returns the first argument for the invocation being linked; this is + * typically the receiver object. This is a shorthand for + * {@code getArguments()[0]} that also avoids the cloning of the arguments + * array. * * @return the receiver object. */ public Object getReceiver(); - /** - * Returns the number of times this callsite has been linked/relinked. This can be useful if you want to - * change e.g. exception based relinking to guard based relinking. It's probably not a good idea to keep, - * for example, expensive exception throwing relinkage based on failed type checks/ClassCastException in - * a nested callsite tree where the exception is thrown repeatedly for the common case. There it would be - * much more performant to use exact type guards instead. - * - * @return link count for call site - */ - public int getLinkCount(); - /** * Returns true if the call site is considered unstable, that is, it has been relinked more times than was * specified in {@link DynamicLinkerFactory#setUnstableRelinkThreshold(int)}. Linkers should use this as a * hint to prefer producing linkage that is more stable (its guard fails less frequently), even if that assumption - * causes a less effective version of an operation to be linked. This is just a hint, of course, and linkers are - * free to ignore this property. + * causes a less effective version of an operation to be linked. This is just a hint, though, and linkers are + * allowed to ignore this property. * @return true if the call site is considered unstable. */ public boolean isCallSiteUnstable(); - /** - * Returns a request stripped from runtime context arguments. Some language runtimes will include runtime-specific - * context parameters in their call sites as few arguments between 0th argument "this" and the normal arguments. If - * a linker does not recognize such contexts at all, or does not recognize the call site as one with its own - * context, it can ask for the alternative link request with context parameters and arguments removed, and link - * against it instead. - * - * @return the context-stripped request. If the link request does not have any language runtime specific context - * parameters, the same link request is returned. - */ - public LinkRequest withoutRuntimeContext(); - /** * Returns a request identical to this one with call site descriptor and arguments replaced with the ones specified. * @@ -165,5 +138,5 @@ public interface LinkRequest { * @return a new request identical to this one, except with the call site descriptor and arguments replaced with the * specified ones. */ - public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object[] arguments); + public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object... arguments); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/LinkerServices.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/LinkerServices.java index 46a91b9f43f..deb28735f98 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/LinkerServices.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/LinkerServices.java @@ -89,44 +89,54 @@ import java.lang.invoke.MethodType; import jdk.internal.dynalink.DynamicLinker; import jdk.internal.dynalink.DynamicLinkerFactory; import jdk.internal.dynalink.linker.ConversionComparator.Comparison; -import jdk.internal.dynalink.support.TypeUtilities; +import jdk.internal.dynalink.linker.support.TypeUtilities; /** - * Interface for services provided to {@link GuardingDynamicLinker} instances by the {@link DynamicLinker} that owns - * them. You can think of it as the interface of the {@link DynamicLinker} that faces the {@link GuardingDynamicLinker} - * s. + * Interface for services provided to {@link GuardingDynamicLinker} instances by + * the {@link DynamicLinker} that owns them. */ public interface LinkerServices { /** - * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by - * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of - * parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive, - * wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions, - * it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters - * provided by {@link GuardingTypeConverterFactory} implementations. + * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks + * in method handles produced by all available + * {@link GuardingTypeConverterFactory} implementations, providing for + * language-specific type coercing of parameters. It will apply + * {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive, + * wrapper-to-primitive, primitive-to-wrapper conversions as well as for all + * upcasts. For all other conversions, it'll insert + * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} + * with composite filters provided by {@link GuardingTypeConverterFactory} + * implementations. * * @param handle target method handle * @param fromType the types of source arguments - * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)}, - * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}, and - * {@link MethodHandles#filterReturnValue(MethodHandle, MethodHandle)} with - * {@link GuardingTypeConverterFactory}-produced type converters as filters. + * @return a method handle that is a suitable combination of + * {@link MethodHandle#asType(MethodType)}, + * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}, + * and {@link MethodHandles#filterReturnValue(MethodHandle, MethodHandle)} + * with {@link GuardingTypeConverterFactory}-produced type converters as + * filters. */ public MethodHandle asType(MethodHandle handle, MethodType fromType); /** - * Similar to {@link #asType(MethodHandle, MethodType)} except it only converts the return type of the method handle - * when it can be done using a conversion that loses neither precision nor magnitude, otherwise it leaves it - * unchanged. The idea is that other conversions should not be performed by individual linkers, but instead the - * {@link DynamicLinkerFactory#setPrelinkFilter(jdk.internal.dynalink.GuardedInvocationFilter) pre-link filter of - * the dynamic linker} should implement the strategy of dealing with potentially lossy return type conversions in a - * manner specific to the language runtime. + * Similar to {@link #asType(MethodHandle, MethodType)} except it treats + * return value type conversion specially. It only converts the return type + * of the method handle when it can be done using a conversion that loses + * neither precision nor magnitude, otherwise it leaves it unchanged. These + * are the only return value conversions that should be performed by + * individual language-specific linkers, and + * {@link DynamicLinkerFactory#setPrelinkTransformer(GuardedInvocationTransformer) + * pre-link transformer of the dynamic linker} should implement the strategy + * for dealing with potentially lossy return type conversions in a manner + * specific to the language runtime where the call site is located. * * @param handle target method handle * @param fromType the types of source arguments - * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)}, and - * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with - * {@link GuardingTypeConverterFactory}-produced type converters as filters. + * @return a method handle that is a suitable combination of + * {@link MethodHandle#asType(MethodType)}, and + * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} + * with {@link GuardingTypeConverterFactory}-produced type converters as filters. */ public default MethodHandle asTypeLosslessReturn(final MethodHandle handle, final MethodType fromType) { final Class handleReturnType = handle.type().returnType(); @@ -135,11 +145,13 @@ public interface LinkerServices { } /** - * Given a source and target type, returns a method handle that converts between them. Never returns null; in worst - * case it will return an identity conversion (that might fail for some values at runtime). You rarely need to use - * this method directly; you should mostly rely on {@link #asType(MethodHandle, MethodType)} instead. You really - * only need this method if you have a piece of your program that is written in Java, and you need to reuse existing - * type conversion machinery in a non-invokedynamic context. + * Given a source and target type, returns a method handle that converts + * between them. Never returns null; in worst case it will return an + * identity conversion (that might fail for some values at runtime). You + * rarely need to use this method directly and should mostly rely on + * {@link #asType(MethodHandle, MethodType)} instead. This method is needed + * when you need to reuse existing type conversion machinery outside the + * context of processing a link request. * @param sourceType the type to convert from * @param targetType the type to convert to * @return a method handle performing the conversion. @@ -147,11 +159,13 @@ public interface LinkerServices { public MethodHandle getTypeConverter(Class sourceType, Class targetType); /** - * Returns true if there might exist a conversion between the requested types (either an automatic JVM conversion, - * or one provided by any available {@link GuardingTypeConverterFactory}), or false if there definitely does not - * exist a conversion between the requested types. Note that returning true does not guarantee that the conversion - * will succeed at runtime (notably, if the "from" or "to" types are sufficiently generic), but returning false - * guarantees that it would fail. + * Returns true if there might exist a conversion between the requested + * types (either an automatic JVM conversion, or one provided by any + * available {@link GuardingTypeConverterFactory}), or false if there + * definitely does not exist a conversion between the requested types. Note + * that returning true does not guarantee that the conversion will succeed + * at runtime for all values (especially if the "from" or "to" types are + * sufficiently generic), but returning false guarantees that it would fail. * * @param from the source type for the conversion * @param to the target type for the conversion @@ -160,34 +174,47 @@ public interface LinkerServices { public boolean canConvert(Class from, Class to); /** - * Creates a guarded invocation using the {@link DynamicLinker} that exposes this linker services interface. Linkers - * can typically use them to delegate linking of wrapped objects. + * Creates a guarded invocation delegating back to the {@link DynamicLinker} + * that exposes this linker services object. The dynamic linker will then + * itself delegate the linking to all of its managed + * {@link GuardingDynamicLinker}s including potentially this one if no + * linker responds earlier, so beware of infinite recursion. You'll + * typically craft the link request so that it will be different than the + * one you are currently trying to link. * * @param linkRequest a request for linking the invocation - * @return a guarded invocation linked by the top-level linker (or any of its delegates). Can be null if no - * available linker is able to link the invocation. + * @return a guarded invocation linked by some of the guarding dynamic + * linkers managed by the top-level dynamic linker. Can be null if no + * available linker is able to link the invocation. You will typically use + * the elements of the returned invocation to compose your own invocation. * @throws Exception in case the top-level linker throws an exception */ public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest) throws Exception; /** - * Determines which of the two type conversions from a source type to the two target types is preferred. This is - * used for dynamic overloaded method resolution. If the source type is convertible to exactly one target type with - * a method invocation conversion, it is chosen, otherwise available {@link ConversionComparator}s are consulted. + * Determines which of the two type conversions from a source type to the + * two target types is preferred. This is used for dynamic overloaded method + * resolution. If the source type is convertible to exactly one target type + * with a method invocation conversion, it is chosen, otherwise available + * {@link ConversionComparator}s are consulted. * @param sourceType the source type. * @param targetType1 one potential target type * @param targetType2 another potential target type. - * @return one of Comparison constants that establish which - if any - of the target types is preferable for the - * conversion. + * @return one of Comparison constants that establish which – if any + * – of the target types is preferable for the conversion. */ public Comparison compareConversion(Class sourceType, Class targetType1, Class targetType2); /** - * Modifies the method handle so that any parameters that can receive potentially internal language runtime objects - * will have a filter added on them to prevent them from escaping, potentially by wrapping them. - * It can also potentially add an unwrapping filter to the return value. + * Modifies the method handle so that any parameters that can receive + * potentially internal language runtime objects will have a filter added on + * them to prevent them from escaping, potentially by wrapping them. It can + * also potentially add an unwrapping filter to the return value. Basically + * transforms the method handle using the transformer configured by + * {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer)}. * @param target the target method handle - * @return a method handle with parameters and/or return type potentially filtered for wrapping and unwrapping. + * @return a method handle with parameters and/or return type potentially + * filtered for wrapping and unwrapping. */ public MethodHandle filterInternalObjects(final MethodHandle target); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/MethodHandleTransformer.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/MethodHandleTransformer.java index 9d1efbe1f68..071fab2d3f8 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/MethodHandleTransformer.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/MethodHandleTransformer.java @@ -84,10 +84,15 @@ package jdk.internal.dynalink.linker; import java.lang.invoke.MethodHandle; +import jdk.internal.dynalink.DynamicLinkerFactory; /** * A generic interface describing operations that transform method handles. + * Typical usage is for implementing + * {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer) + * internal objects filters}. */ +@FunctionalInterface public interface MethodHandleTransformer { /** * Transforms a method handle. diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/MethodTypeConversionStrategy.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/MethodTypeConversionStrategy.java index f270c5fc63e..237f27c0dff 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/MethodTypeConversionStrategy.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/MethodTypeConversionStrategy.java @@ -85,10 +85,16 @@ package jdk.internal.dynalink.linker; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; +import jdk.internal.dynalink.DynamicLinkerFactory; /** - * Interface for objects representing a strategy for converting a method handle to a new type. + * Interface for objects representing a strategy for converting a method handle + * to a new type. Typical usage is for customizing a language runtime's handling + * of + * {@link DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy) + * method invocation conversions}. */ +@FunctionalInterface public interface MethodTypeConversionStrategy { /** * Converts a method handle to a new type. diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java index 6c80a2002f6..5395f0d1785 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java @@ -83,11 +83,14 @@ package jdk.internal.dynalink.linker; +import jdk.internal.dynalink.linker.support.CompositeTypeBasedGuardingDynamicLinker; + /** * A guarding dynamic linker that can determine whether it can link the call site solely based on the type of the first - * argument at linking invocation time. (The first argument is usually the receiver class). Most language-specific + * argument at linking invocation time. (The first argument is usually the receiver). Most language-specific * linkers will fall into this category, as they recognize their native objects as Java objects of classes implementing - * a specific language-native interface or superclass. The linker mechanism can optimize the dispatch for these linkers. + * a specific language-native interface or superclass. The linker mechanism can optimize the dispatch for these linkers, + * see {@link CompositeTypeBasedGuardingDynamicLinker}. */ public interface TypeBasedGuardingDynamicLinker extends GuardingDynamicLinker { /** diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AutoDiscovery.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/package-info.java similarity index 68% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AutoDiscovery.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/package-info.java index ba318610c08..b04865d320e 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AutoDiscovery.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,53 +81,37 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; - -import java.util.LinkedList; -import java.util.List; -import java.util.ServiceLoader; -import jdk.internal.dynalink.DynamicLinkerFactory; -import jdk.internal.dynalink.linker.GuardingDynamicLinker; - /** - * Provides methods for automatic discovery of all guarding dynamic linkers listed in the - * /META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker resources of all JAR files for a - * particular class loader. Ordinarily, you will not use this class directly, but you will use a - * {@link DynamicLinkerFactory} instead. + *

      + * Contains interfaces and classes needed by language runtimes to implement + * their own language-specific object models and type conversions. The main + * entry point is the + * {@link jdk.internal.dynalink.linker.GuardingDynamicLinker} interface. It needs to be + * implemented in order to provide linking for the runtime's own object model. + * A language runtime can have more than one guarding dynamic linker + * implementation. When a runtime is configuring Dynalink for itself, it will + * normally set these guarding linkers as the prioritized linkers in its + * {@link jdk.internal.dynalink.DynamicLinkerFactory} (and maybe some of them as fallback + * linkers, for e.g. handling "method not found" and similar errors in a + * language-specific manner if no other linker managed to handle the operation.) + *

      + * A language runtime that wishes to make at least some of its linkers available + * to other language runtimes for interoperability will need to declare the + * class names of those linkers in + * {@code /META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker} file in + * its distribution (typically, JAR file). + *

      + * Most language runtimes will be able to implement their own linking logic by + * implementing {@link jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker} + * instead of {@link jdk.internal.dynalink.linker.GuardingDynamicLinker}; it allows for + * faster type-based linking dispatch. + *

      + * Language runtimes that allow type conversions other than those provided by + * Java will need to have their guarding dynamic linker (or linkers) also + * implement the {@link jdk.internal.dynalink.linker.GuardingTypeConverterFactory} + * interface to provide the logic for these conversions. + *

      + * @since 1.9 */ -public class AutoDiscovery { - - private AutoDiscovery() { - } - - /** - * Discovers all guarding dynamic linkers listed in JAR files of the context class loader of the current thread. - * - * @return a list of available linkers. Can be zero-length list but not null. - */ - public static List loadLinkers() { - return getLinkers(ServiceLoader.load(GuardingDynamicLinker.class)); - } - - /** - * Discovers all guarding dynamic linkers listed in JAR files of the specified class loader. - * - * @param cl the class loader to use - * @return a list of guarding dynamic linkers available through the specified class loader. Can be zero-length list - * but not null. - */ - public static List loadLinkers(final ClassLoader cl) { - return getLinkers(ServiceLoader.load(GuardingDynamicLinker.class, cl)); - } - - /** - * I can't believe there's no Collections API for making a List given an Iterator... - */ - private static List getLinkers(final ServiceLoader loader) { - final List list = new LinkedList<>(); - for(final T linker: loader) { - list.add(linker); - } - return list; - } -} +@jdk.Exported +package jdk.internal.dynalink.linker; diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/package.html b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/package.html deleted file mode 100644 index 4e3991d7614..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/package.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - -

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

      - diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/CompositeGuardingDynamicLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeGuardingDynamicLinker.java similarity index 86% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/CompositeGuardingDynamicLinker.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeGuardingDynamicLinker.java index 0165f7f4518..dea386f77dd 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/CompositeGuardingDynamicLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeGuardingDynamicLinker.java @@ -81,20 +81,21 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink.linker.support; import java.io.Serializable; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardingDynamicLinker; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; /** - * A {@link GuardingDynamicLinker} that delegates sequentially to a list of other guarding dynamic linkers. The first - * value returned from a component linker other than null is returned. If no component linker returns an invocation, - * null is returned. + * A {@link GuardingDynamicLinker} that delegates sequentially to a list of + * other guarding dynamic linkers in its + * {@link #getGuardedInvocation(LinkRequest, LinkerServices)}. */ public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker, Serializable { @@ -106,15 +107,27 @@ public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker, Se * Creates a new composite linker. * * @param linkers a list of component linkers. + * @throws NullPointerException if {@code linkers} or any of its elements + * are null. */ public CompositeGuardingDynamicLinker(final Iterable linkers) { final List l = new LinkedList<>(); for(final GuardingDynamicLinker linker: linkers) { - l.add(linker); + l.add(Objects.requireNonNull(linker)); } this.linkers = l.toArray(new GuardingDynamicLinker[l.size()]); } + /** + * Delegates the call to its component linkers. The first non-null value + * returned from a component linker is returned. If no component linker + * returns a non-null invocation, null is returned. + * @param linkRequest the object describing the request for linking a + * particular invocation + * @param linkerServices linker services + * @return the first non-null return value from a component linker, or null + * if none of the components returned a non-null. + */ @Override public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java similarity index 88% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java index 1518f929363..4897455112c 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java @@ -81,12 +81,13 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink.linker.support; import java.io.Serializable; import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardingDynamicLinker; import jdk.internal.dynalink.linker.LinkRequest; @@ -94,10 +95,12 @@ import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; /** - * A composite type-based guarding dynamic linker. When a receiver of a not yet seen class is encountered, all linkers - * are queried sequentially on their {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} method. The linkers - * returning true are then bound to the class, and next time a receiver of same type is encountered, the linking is - * delegated to those linkers only, speeding up dispatch. + * A composite type-based guarding dynamic linker. When a receiver of a not yet + * seen class is encountered, all linkers are queried sequentially on their + * {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} method. The linkers + * returning true are then bound to the class, and next time a receiver of same + * type is encountered, the linking is delegated to those linkers only, speeding + * up dispatch. */ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker, Serializable { private static final long serialVersionUID = 1L; @@ -149,15 +152,25 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin * Creates a new composite type-based linker. * * @param linkers the component linkers + * @throws NullPointerException if {@code linkers} or any of its elements + * are null. */ public CompositeTypeBasedGuardingDynamicLinker(final Iterable linkers) { final List l = new LinkedList<>(); for(final TypeBasedGuardingDynamicLinker linker: linkers) { - l.add(linker); + l.add(Objects.requireNonNull(linker)); } this.classToLinker = new ClassToLinker(l.toArray(new TypeBasedGuardingDynamicLinker[l.size()])); } + /** + * Returns true if at least one of the composite linkers returns true from + * {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} for the type. + * @param type the type to link + * @return true true if at least one of the composite linkers returns true + * from {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)}, false + * otherwise. + */ @Override public boolean canLinkType(final Class type) { return !classToLinker.get(type).isEmpty(); @@ -180,17 +193,21 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin } /** - * Optimizes a list of type-based linkers. If a group of adjacent linkers in the list all implement - * {@link TypeBasedGuardingDynamicLinker}, they will be replaced with a single instance of + * Optimizes a list of type-based linkers. If a group of adjacent linkers in + * the list all implement {@link TypeBasedGuardingDynamicLinker}, they will + * be replaced with a single instance of * {@link CompositeTypeBasedGuardingDynamicLinker} that contains them. * * @param linkers the list of linkers to optimize * @return the optimized list + * @throws NullPointerException if {@code linkers} or any of its elements + * are null. */ public static List optimize(final Iterable linkers) { final List llinkers = new LinkedList<>(); final List tblinkers = new LinkedList<>(); for(final GuardingDynamicLinker linker: linkers) { + Objects.requireNonNull(linker); if(linker instanceof TypeBasedGuardingDynamicLinker) { tblinkers.add((TypeBasedGuardingDynamicLinker)linker); } else { diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/DefaultInternalObjectFilter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/DefaultInternalObjectFilter.java similarity index 87% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/DefaultInternalObjectFilter.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/DefaultInternalObjectFilter.java index 94378f11586..ef18f513dc8 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/DefaultInternalObjectFilter.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/DefaultInternalObjectFilter.java @@ -81,7 +81,7 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink.linker.support; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -90,10 +90,19 @@ import jdk.internal.dynalink.DynamicLinkerFactory; import jdk.internal.dynalink.linker.MethodHandleTransformer; /** - * Default implementation for a {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer)}. - * Given a method handle of {@code Object(Object)} type for filtering parameter and another one of the same type for - * filtering return values, applies them to passed method handles where their parameter types and/or return value types - * are declared to be {@link Object}. + * Default implementation for a + * {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer)} + * that delegates to a pair of filtering method handles. It takes a method + * handle of {@code Object(Object)} type for filtering parameter values and + * another one of the same type for filtering return values. It applies them as + * parameter and return value filters on method handles passed to its + * {@link #transform(MethodHandle)} method, on those parameters and return values + * that are declared to have type {@link Object}. Also handles + * {@link MethodHandle#isVarargsCollector() method handles that support variable + * arity calls} with a last {@code Object[]} parameter. You can broadly think of + * the parameter filter as being a wrapping method for exposing internal runtime + * objects wrapped into an adapter with some public interface, and the return + * value filter as being its inverse unwrapping method. */ public class DefaultInternalObjectFilter implements MethodHandleTransformer { private static final MethodHandle FILTER_VARARGS = new Lookup(MethodHandles.lookup()).findStatic( @@ -105,9 +114,12 @@ public class DefaultInternalObjectFilter implements MethodHandleTransformer { /** * Creates a new filter. - * @param parameterFilter the filter for method parameters. Must be of type {@code Object(Object)}, or null. - * @param returnFilter the filter for return values. Must be of type {@code Object(Object)}, or null. - * @throws IllegalArgumentException if one or both filters are not of the expected type. + * @param parameterFilter the filter for method parameters. Must be of type + * {@code Object(Object)}, or {@code null}. + * @param returnFilter the filter for return values. Must be of type + * {@code Object(Object)}, or {@code null}. + * @throws IllegalArgumentException if one or both filters are not of the + * expected type. */ public DefaultInternalObjectFilter(final MethodHandle parameterFilter, final MethodHandle returnFilter) { this.parameterFilter = checkHandle(parameterFilter, "parameterFilter"); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/Guards.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/Guards.java similarity index 89% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/Guards.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/Guards.java index 2b0256eea07..2eae2dbc9c7 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/Guards.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/Guards.java @@ -81,7 +81,7 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink.linker.support; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -92,10 +92,11 @@ import jdk.internal.dynalink.DynamicLinker; import jdk.internal.dynalink.linker.LinkerServices; /** - * Utility methods for creating typical guards. TODO: introduce reasonable caching of created guards. - * + * Utility methods for creating typical guards for + * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)} + * and for adjusting their method types. */ -public class Guards { +public final class Guards { private static final Logger LOG = Logger .getLogger(Guards.class.getName(), "jdk.internal.dynalink.support.messages"); @@ -184,44 +185,17 @@ public class Guards { return asType(IS_ARRAY, pos, type); } - /** - * Return true if it is safe to strongly reference a class from the referred class loader from a class associated - * with the referring class loader without risking a class loader memory leak. - * - * @param referrerLoader the referrer class loader - * @param referredLoader the referred class loader - * @return true if it is safe to strongly reference the class - */ - public static boolean canReferenceDirectly(final ClassLoader referrerLoader, final ClassLoader referredLoader) { - if(referredLoader == null) { - // Can always refer directly to a system class - return true; - } - if(referrerLoader == null) { - // System classes can't refer directly to any non-system class - return false; - } - // Otherwise, can only refer directly to classes residing in same or - // parent class loader. - - ClassLoader referrer = referrerLoader; - do { - if(referrer == referredLoader) { - return true; - } - referrer = referrer.getParent(); - } while(referrer != null); - return false; - } - private static MethodHandle getClassBoundArgumentTest(final MethodHandle test, final Class clazz, final int pos, final MethodType type) { // Bind the class to the first argument of the test return asType(test.bindTo(clazz), pos, type); } /** - * Takes a guard-test method handle, and adapts it to the requested type, returning a boolean. Only applies - * conversions as per {@link MethodHandle#asType(MethodType)}. + * Takes a method handle intended to be used as a guard, and adapts it to + * the requested type, but returning a boolean. Applies + * {@link MethodHandle#asType(MethodType)} to convert types and uses + * {@link MethodHandles#dropArguments(MethodHandle, int, Class...)} to match + * the requested type arity. * @param test the test method handle * @param type the type to adapt the method handle to * @return the adapted method handle @@ -231,8 +205,12 @@ public class Guards { } /** - * Takes a guard-test method handle, and adapts it to the requested type, returning a boolean. Applies the passed - * {@link LinkerServices} object's {@link LinkerServices#asType(MethodHandle, MethodType)}. + * Takes a method handle intended to be used as a guard, and adapts it to + * the requested type, but returning a boolean. Applies + * {@link LinkerServices#asType(MethodHandle, MethodType)} to convert types + * and uses + * {@link MethodHandles#dropArguments(MethodHandle, int, Class...)} to match + * the requested type arity. * @param linkerServices the linker services to use for type conversions * @param test the test method handle * @param type the type to adapt the method handle to diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/Lookup.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/Lookup.java similarity index 80% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/Lookup.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/Lookup.java index a04b62be7e7..26df87fe514 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/Lookup.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/Lookup.java @@ -81,7 +81,7 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink.linker.support; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -91,14 +91,17 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; /** - * A wrapper around MethodHandles.Lookup that masks checked exceptions in those cases when you're looking up methods - * within your own codebase (therefore it is an error if they are not present). + * A wrapper around {@link java.lang.invoke.MethodHandles.Lookup} that masks + * checked exceptions. It is useful in those cases when you're looking up + * methods within your own codebase (therefore it is an error if they are not + * present). */ -public class Lookup { +public final class Lookup { private final MethodHandles.Lookup lookup; /** - * Creates a new instance, bound to an instance of {@link java.lang.invoke.MethodHandles.Lookup}. + * Creates a new instance, bound to an instance of + * {@link java.lang.invoke.MethodHandles.Lookup}. * * @param lookup the {@link java.lang.invoke.MethodHandles.Lookup} it delegates to. */ @@ -112,23 +115,27 @@ public class Lookup { public static final Lookup PUBLIC = new Lookup(MethodHandles.publicLookup()); /** - * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered - * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, + * converting any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError}. * * @param m the method to unreflect * @return the unreflected method handle. + * @throws IllegalAccessError if the method is inaccessible. */ public MethodHandle unreflect(final Method m) { return unreflect(lookup, m); } /** - * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered - * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, + * converting any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError}. * * @param lookup the lookup used to unreflect * @param m the method to unreflect * @return the unreflected method handle. + * @throws IllegalAccessError if the method is inaccessible. */ public static MethodHandle unreflect(final MethodHandles.Lookup lookup, final Method m) { try { @@ -141,11 +148,12 @@ public class Lookup { } /** - * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, converting any encountered - * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, + * converting any encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. * * @param f the field for which a getter is unreflected * @return the unreflected field getter handle. + * @throws IllegalAccessError if the getter is inaccessible. */ public MethodHandle unreflectGetter(final Field f) { try { @@ -158,9 +166,10 @@ public class Lookup { } /** - * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findGetter(Class, String, Class)}, converting any - * encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and {@link NoSuchFieldException} - * into a {@link NoSuchFieldError}. + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findGetter(Class, String, Class)}, + * converting any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError} and {@link NoSuchFieldException} into a + * {@link NoSuchFieldError}. * * @param refc the class declaring the field * @param name the name of the field @@ -186,11 +195,14 @@ public class Lookup { } /** - * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter(Field)}, converting any encountered - * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter(Field)}, + * converting any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError}. * * @param f the field for which a setter is unreflected * @return the unreflected field setter handle. + * @throws IllegalAccessError if the field is inaccessible. + * @throws NoSuchFieldError if the field does not exist. */ public MethodHandle unreflectSetter(final Field f) { try { @@ -203,23 +215,27 @@ public class Lookup { } /** - * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, converting any - * encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, + * converting any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError}. * * @param c the constructor to unreflect * @return the unreflected constructor handle. + * @throws IllegalAccessError if the constructor is inaccessible. */ public MethodHandle unreflectConstructor(final Constructor c) { return unreflectConstructor(lookup, c); } /** - * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, converting any - * encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, + * converting any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError}. * * @param lookup the lookup used to unreflect * @param c the constructor to unreflect * @return the unreflected constructor handle. + * @throws IllegalAccessError if the constructor is inaccessible. */ public static MethodHandle unreflectConstructor(final MethodHandles.Lookup lookup, final Constructor c) { try { @@ -232,8 +248,10 @@ public class Lookup { } /** - * Performs a findSpecial on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an - * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findSpecial(Class, String, MethodType, Class)} + * on the underlying lookup. Converts any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError} and + * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. * * @param declaringClass class declaring the method * @param name the name of the method @@ -263,8 +281,10 @@ public class Lookup { } /** - * Performs a findStatic on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an - * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findStatic(Class, String, MethodType)} + * on the underlying lookup. Converts any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError} and + * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. * * @param declaringClass class declaring the method * @param name the name of the method @@ -290,8 +310,10 @@ public class Lookup { } /** - * Performs a findVirtual on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an - * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findVirtual(Class, String, MethodType)} + * on the underlying lookup. Converts any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError} and + * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. * * @param declaringClass class declaring the method * @param name the name of the method @@ -317,8 +339,9 @@ public class Lookup { } /** - * Given a lookup, finds using {@link #findSpecial(Class, String, MethodType)} a method on that lookup's class. - * Useful in classes' code for convenient linking to their own privates. + * Given a lookup, finds using {@link #findSpecial(Class, String, MethodType)} + * a method on that lookup's class. Useful in classes' code for convenient + * linking to their own privates. * @param lookup the lookup for the class * @param name the name of the method * @param rtype the return type of the method @@ -331,9 +354,11 @@ public class Lookup { /** - * Finds using {@link #findSpecial(Class, String, MethodType)} a method on that lookup's class. Useful in classes' - * code for convenient linking to their own privates. It's easier to use than {@code findSpecial} in that you can - * just list the parameter types, and don't have to specify lookup class. + * Finds using {@link #findSpecial(Class, String, MethodType)} a method on + * that lookup's class. Useful in classes' code for convenient linking to + * their own privates. It's also more convenient than {@code findSpecial} + * in that you can just list the parameter types, and don't have to specify + * lookup class. * @param name the name of the method * @param rtype the return type of the method * @param ptypes the parameter types of the method @@ -344,9 +369,11 @@ public class Lookup { } /** - * Given a lookup, finds using {@link #findStatic(Class, String, MethodType)} a method on that lookup's class. - * Useful in classes' code for convenient linking to their own privates. It's easier to use than {@code findStatic} - * in that you can just list the parameter types, and don't have to specify lookup class. + * Given a lookup, finds using {@link #findStatic(Class, String, MethodType)} + * a method on that lookup's class. Useful in classes' code for convenient + * linking to their own privates. It's easier to use than {@code findStatic} + * in that you can just list the parameter types, and don't have to specify + * lookup class. * @param lookup the lookup for the class * @param name the name of the method * @param rtype the return type of the method @@ -358,9 +385,11 @@ public class Lookup { } /** - * Finds using {@link #findStatic(Class, String, MethodType)} a method on that lookup's class. Useful in classes' - * code for convenient linking to their own privates. It's easier to use than {@code findStatic} in that you can - * just list the parameter types, and don't have to specify lookup class. + * Finds using {@link #findStatic(Class, String, MethodType)} a method on + * that lookup's class. Useful in classes' code for convenient linking to + * their own privates. It's easier to use than {@code findStatic} + * in that you can just list the parameter types, and don't have to specify + * lookup class. * @param name the name of the method * @param rtype the return type of the method * @param ptypes the parameter types of the method diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/LinkRequestImpl.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/SimpleLinkRequest.java similarity index 76% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/LinkRequestImpl.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/SimpleLinkRequest.java index a0f427410c8..fe01c7641e6 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/LinkRequestImpl.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/SimpleLinkRequest.java @@ -81,48 +81,46 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink.linker.support; +import java.util.Objects; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.LinkRequest; /** - * Default implementation of the {@link LinkRequest}, representing a link request to a call site that passes no language - * runtime specific native context arguments on the stack. + * Default simple implementation of {@link LinkRequest}. */ -public class LinkRequestImpl implements LinkRequest { +public class SimpleLinkRequest implements LinkRequest { private final CallSiteDescriptor callSiteDescriptor; - private final Object callSiteToken; private final Object[] arguments; private final boolean callSiteUnstable; - private final int linkCount; /** * Creates a new link request. * - * @param callSiteDescriptor the descriptor for the call site being linked - * @param callSiteToken the opaque token for the call site being linked. - * @param linkCount how many times this callsite has been linked/relinked - * @param callSiteUnstable true if the call site being linked is considered unstable - * @param arguments the arguments for the invocation + * @param callSiteDescriptor the descriptor for the call site being linked. + * Must not be null. + * @param callSiteUnstable true if the call site being linked is considered + * unstable. + * @param arguments the arguments for the invocation. Must not be null. + * @throws NullPointerException if either {@code callSiteDescriptor} or + * {@code arguments} is null. */ - public LinkRequestImpl(final CallSiteDescriptor callSiteDescriptor, final Object callSiteToken, final int linkCount, final boolean callSiteUnstable, final Object... arguments) { - this.callSiteDescriptor = callSiteDescriptor; - this.callSiteToken = callSiteToken; - this.linkCount = linkCount; + public SimpleLinkRequest(final CallSiteDescriptor callSiteDescriptor, final boolean callSiteUnstable, final Object... arguments) { + this.callSiteDescriptor = Objects.requireNonNull(callSiteDescriptor); this.callSiteUnstable = callSiteUnstable; - this.arguments = arguments; + this.arguments = arguments.clone(); } @Override public Object[] getArguments() { - return arguments != null ? arguments.clone() : null; + return arguments.clone(); } @Override public Object getReceiver() { - return arguments != null && arguments.length > 0 ? arguments[0] : null; + return arguments.length > 0 ? arguments[0] : null; } @Override @@ -130,28 +128,13 @@ public class LinkRequestImpl implements LinkRequest { return callSiteDescriptor; } - @Override - public Object getCallSiteToken() { - return callSiteToken; - } - @Override public boolean isCallSiteUnstable() { return callSiteUnstable; } @Override - public int getLinkCount() { - return linkCount; - } - - @Override - public LinkRequest withoutRuntimeContext() { - return this; - } - - @Override - public LinkRequest replaceArguments(final CallSiteDescriptor newCallSiteDescriptor, final Object[] newArguments) { - return new LinkRequestImpl(newCallSiteDescriptor, callSiteToken, linkCount, callSiteUnstable, newArguments); + public LinkRequest replaceArguments(final CallSiteDescriptor newCallSiteDescriptor, final Object... newArguments) { + return new SimpleLinkRequest(newCallSiteDescriptor, callSiteUnstable, newArguments); } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/TypeUtilities.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/TypeUtilities.java similarity index 57% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/TypeUtilities.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/TypeUtilities.java index 7fe6e9cf3b4..3ba6dc971ff 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/TypeUtilities.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/TypeUtilities.java @@ -81,21 +81,18 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; +package jdk.internal.dynalink.linker.support; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.Set; +import jdk.internal.dynalink.DynamicLinkerFactory; +import jdk.internal.dynalink.linker.MethodTypeConversionStrategy; /** - * Various static utility methods for testing type relationships. + * Various static utility methods for working with Java types. */ public class TypeUtilities { static final Class OBJECT_CLASS = Object.class; @@ -103,107 +100,13 @@ public class TypeUtilities { private TypeUtilities() { } - /** - * Given two types represented by c1 and c2, returns a type that is their most specific common supertype for - * purposes of lossless conversions. - * - * @param c1 one type - * @param c2 another type - * @return their most common superclass or superinterface for purposes of lossless conversions. If they have several - * unrelated superinterfaces as their most specific common type, or the types themselves are completely - * unrelated interfaces, {@link java.lang.Object} is returned. - */ - public static Class getCommonLosslessConversionType(final Class c1, final Class c2) { - if(c1 == c2) { - return c1; - } else if (c1 == void.class || c2 == void.class) { - return Object.class; - } else if(isConvertibleWithoutLoss(c2, c1)) { - return c1; - } else if(isConvertibleWithoutLoss(c1, c2)) { - return c2; - } else if(c1.isPrimitive() && c2.isPrimitive()) { - if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) { - // byte + char = int - return int.class; - } else if((c1 == short.class && c2 == char.class) || (c1 == char.class && c2 == short.class)) { - // short + char = int - return int.class; - } else if((c1 == int.class && c2 == float.class) || (c1 == float.class && c2 == int.class)) { - // int + float = double - return double.class; - } - } - // For all other cases. This will handle long + (float|double) = Number case as well as boolean + anything = Object case too. - return getMostSpecificCommonTypeUnequalNonprimitives(c1, c2); - } - - private static Class getMostSpecificCommonTypeUnequalNonprimitives(final Class c1, final Class c2) { - final Class npc1 = c1.isPrimitive() ? getWrapperType(c1) : c1; - final Class npc2 = c2.isPrimitive() ? getWrapperType(c2) : c2; - final Set> a1 = getAssignables(npc1, npc2); - final Set> a2 = getAssignables(npc2, npc1); - a1.retainAll(a2); - if(a1.isEmpty()) { - // Can happen when at least one of the arguments is an interface, - // as they don't have Object at the root of their hierarchy. - return Object.class; - } - // Gather maximally specific elements. Yes, there can be more than one - // thank to interfaces. I.e., if you call this method for String.class - // and Number.class, you'll have Comparable, Serializable, and Object - // as maximal elements. - final List> max = new ArrayList<>(); - outer: for(final Class clazz: a1) { - for(final Iterator> maxiter = max.iterator(); maxiter.hasNext();) { - final Class maxClazz = maxiter.next(); - if(isSubtype(maxClazz, clazz)) { - // It can't be maximal, if there's already a more specific - // maximal than it. - continue outer; - } - if(isSubtype(clazz, maxClazz)) { - // If it's more specific than a currently maximal element, - // that currently maximal is no longer a maximal. - maxiter.remove(); - } - } - // If we get here, no current maximal is more specific than the - // current class, so it is considered maximal as well - max.add(clazz); - } - if(max.size() > 1) { - return Object.class; - } - return max.get(0); - } - - private static Set> getAssignables(final Class c1, final Class c2) { - final Set> s = new HashSet<>(); - collectAssignables(c1, c2, s); - return s; - } - - private static void collectAssignables(final Class c1, final Class c2, final Set> s) { - if(c1.isAssignableFrom(c2)) { - s.add(c1); - } - final Class sc = c1.getSuperclass(); - if(sc != null) { - collectAssignables(sc, c2, s); - } - final Class[] itf = c1.getInterfaces(); - for(int i = 0; i < itf.length; ++i) { - collectAssignables(itf[i], c2, s); - } - } - private static final Map, Class> WRAPPER_TYPES = createWrapperTypes(); private static final Map, Class> PRIMITIVE_TYPES = invertMap(WRAPPER_TYPES); private static final Map> PRIMITIVE_TYPES_BY_NAME = createClassNameMapping(WRAPPER_TYPES.keySet()); private static Map, Class> createWrapperTypes() { final Map, Class> wrapperTypes = new IdentityHashMap<>(8); + wrapperTypes.put(Void.TYPE, Void.class); wrapperTypes.put(Boolean.TYPE, Boolean.class); wrapperTypes.put(Byte.TYPE, Byte.class); wrapperTypes.put(Character.TYPE, Character.class); @@ -249,23 +152,32 @@ public class TypeUtilities { if(targetType.isPrimitive()) { return isProperPrimitiveSubtype(sourceType, targetType); } - // Boxing + widening reference conversion - assert WRAPPER_TYPES.get(sourceType) != null : sourceType.getName(); - return targetType.isAssignableFrom(WRAPPER_TYPES.get(sourceType)); + return isBoxingAndWideningReferenceConversion(sourceType, targetType); } if(targetType.isPrimitive()) { - final Class unboxedCallSiteType = PRIMITIVE_TYPES.get(sourceType); + final Class unboxedCallSiteType = getPrimitiveType(sourceType); return unboxedCallSiteType != null && (unboxedCallSiteType == targetType || isProperPrimitiveSubtype(unboxedCallSiteType, targetType)); } return false; } + private static boolean isBoxingAndWideningReferenceConversion(final Class sourceType, final Class targetType) { + final Class wrapperType = getWrapperType(sourceType); + assert wrapperType != null : sourceType.getName(); + return targetType.isAssignableFrom(wrapperType); + } + /** - * Determines whether a type can be converted to another without losing any precision. As a special case, - * void is considered convertible only to Object and void, while anything can be converted to void. This - * is because a target type of void means we don't care about the value, so the conversion is always - * permissible. + * Determines whether a type can be converted to another without losing any + * precision. As a special case, void is considered convertible only to void + * and {@link Object} (either as {@code null} or as a custom value set in + * {@link DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy)}). + * Somewhat unintuitively, we consider anything to be convertible to void + * even though converting to void causes the ultimate loss of data. On the + * other hand, conversion to void essentially means that the value is of no + * interest and should be discarded, thus there's no expectation of + * preserving any precision. * * @param sourceType the source type * @param targetType the target type @@ -284,9 +196,7 @@ public class TypeUtilities { if(targetType.isPrimitive()) { return isProperPrimitiveLosslessSubtype(sourceType, targetType); } - // Boxing + widening reference conversion - assert WRAPPER_TYPES.get(sourceType) != null : sourceType.getName(); - return targetType.isAssignableFrom(WRAPPER_TYPES.get(sourceType)); + return isBoxingAndWideningReferenceConversion(sourceType, targetType); } // Can't convert from any non-primitive type to any primitive type without data loss because of null. // Also, can't convert non-assignable reference types. @@ -294,51 +204,11 @@ public class TypeUtilities { } /** - * Determines whether one type can be potentially converted to another type at runtime. Allows a conversion between - * any subtype and supertype in either direction, and also allows a conversion between any two primitive types, as - * well as between any primitive type and any reference type that can hold a boxed primitive. - * - * @param callSiteType the parameter type at the call site - * @param methodType the parameter type in the method declaration - * @return true if callSiteType is potentially convertible to the methodType. - */ - public static boolean isPotentiallyConvertible(final Class callSiteType, final Class methodType) { - // Widening or narrowing reference conversion - if(areAssignable(callSiteType, methodType)) { - return true; - } - if(callSiteType.isPrimitive()) { - // Allow any conversion among primitives, as well as from any - // primitive to any type that can receive a boxed primitive. - // TODO: narrow this a bit, i.e. allow, say, boolean to Character? - // MethodHandles.convertArguments() allows it, so we might need to - // too. - return methodType.isPrimitive() || isAssignableFromBoxedPrimitive(methodType); - } - if(methodType.isPrimitive()) { - // Allow conversion from any reference type that can contain a - // boxed primitive to any primitive. - // TODO: narrow this a bit too? - return isAssignableFromBoxedPrimitive(callSiteType); - } - return false; - } - - /** - * Returns true if either of the types is assignable from the other. - * @param c1 one of the types - * @param c2 another one of the types - * @return true if either c1 is assignable from c2 or c2 is assignable from c1. - */ - public static boolean areAssignable(final Class c1, final Class c2) { - return c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1); - } - - /** - * Determines whether one type is a subtype of another type, as per JLS 4.10 "Subtyping". Note: this is not strict - * or proper subtype, therefore true is also returned for identical types; to be completely precise, it allows - * identity conversion (JLS 5.1.1), widening primitive conversion (JLS 5.1.2) and widening reference conversion (JLS - * 5.1.5). + * Determines whether one type is a subtype of another type, as per JLS + * 4.10 "Subtyping". Note: this is not strict or proper subtype, therefore + * true is also returned for identical types; to be completely precise, it + * allows identity conversion (JLS 5.1.1), widening primitive conversion + * (JLS 5.1.2) and widening reference conversion (JLS 5.1.5). * * @param subType the supposed subtype * @param superType the supposed supertype of the subtype @@ -432,82 +302,31 @@ public class TypeUtilities { return false; } - private static final Map, Class> WRAPPER_TO_PRIMITIVE_TYPES = createWrapperToPrimitiveTypes(); - - private static Map, Class> createWrapperToPrimitiveTypes() { - final Map, Class> classes = new IdentityHashMap<>(); - classes.put(Void.class, Void.TYPE); - classes.put(Boolean.class, Boolean.TYPE); - classes.put(Byte.class, Byte.TYPE); - classes.put(Character.class, Character.TYPE); - classes.put(Short.class, Short.TYPE); - classes.put(Integer.class, Integer.TYPE); - classes.put(Long.class, Long.TYPE); - classes.put(Float.class, Float.TYPE); - classes.put(Double.class, Double.TYPE); - return classes; - } - - private static final Set> PRIMITIVE_WRAPPER_TYPES = createPrimitiveWrapperTypes(); - - private static Set> createPrimitiveWrapperTypes() { - final Map, Class> classes = new IdentityHashMap<>(); - addClassHierarchy(classes, Boolean.class); - addClassHierarchy(classes, Byte.class); - addClassHierarchy(classes, Character.class); - addClassHierarchy(classes, Short.class); - addClassHierarchy(classes, Integer.class); - addClassHierarchy(classes, Long.class); - addClassHierarchy(classes, Float.class); - addClassHierarchy(classes, Double.class); - return classes.keySet(); - } - - private static void addClassHierarchy(final Map, Class> map, final Class clazz) { - if(clazz == null) { - return; - } - map.put(clazz, clazz); - addClassHierarchy(map, clazz.getSuperclass()); - for(final Class itf: clazz.getInterfaces()) { - addClassHierarchy(map, itf); - } - } - /** - * Returns true if the class can be assigned from any boxed primitive. - * - * @param clazz the class - * @return true if the class can be assigned from any boxed primitive. Basically, it is true if the class is any - * primitive wrapper class, or a superclass or superinterface of any primitive wrapper class. - */ - private static boolean isAssignableFromBoxedPrimitive(final Class clazz) { - return PRIMITIVE_WRAPPER_TYPES.contains(clazz); - } - - /** - * Given a name of a primitive type (except "void"), returns the class representing it. I.e. when invoked with - * "int", returns {@link Integer#TYPE}. + * Given a name of a primitive type returns the class representing it. I.e. + * when invoked with "int", returns {@link Integer#TYPE}. * @param name the name of the primitive type - * @return the class representing the primitive type, or null if the name does not correspond to a primitive type - * or is "void". + * @return the class representing the primitive type, or null if the name + * does not correspond to a primitive type. */ public static Class getPrimitiveTypeByName(final String name) { return PRIMITIVE_TYPES_BY_NAME.get(name); } /** - * When passed a class representing a wrapper for a primitive type, returns the class representing the corresponding - * primitive type. I.e. calling it with {@code Integer.class} will return {@code Integer.TYPE}. If passed a class - * that is not a wrapper for primitive type, returns null. - * @param wrapperType the class object representing a wrapper for a primitive type - * @return the class object representing the primitive type, or null if the passed class is not a primitive wrapper. + * When passed a class representing a wrapper for a primitive type, returns + * the class representing the corresponding primitive type. I.e. calling it + * with {@code Integer.class} will return {@code Integer.TYPE}. If passed a + * class that is not a wrapper for primitive type, returns null. + * @param wrapperType the class object representing a wrapper for a + * primitive type. + * @return the class object representing the primitive type, or null if the + * passed class is not a primitive wrapper. */ public static Class getPrimitiveType(final Class wrapperType) { - return WRAPPER_TO_PRIMITIVE_TYPES.get(wrapperType); + return PRIMITIVE_TYPES.get(wrapperType); } - /** * When passed a class representing a primitive type, returns the class representing the corresponding * wrapper type. I.e. calling it with {@code int.class} will return {@code Integer.class}. If passed a class diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NamedDynCallSiteDescriptor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/package-info.java similarity index 78% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NamedDynCallSiteDescriptor.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/package-info.java index 817df52a899..5c8db9d34de 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NamedDynCallSiteDescriptor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * license: */ /* - Copyright 2009-2013 Attila Szegedi + Copyright 2015 Attila Szegedi Licensed under both the Apache License, Version 2.0 (the "Apache License") and the BSD License (the "BSD License"), with licensee being free to @@ -81,37 +81,13 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; - -import java.lang.invoke.MethodType; -import jdk.internal.dynalink.CallSiteDescriptor; - -class NamedDynCallSiteDescriptor extends UnnamedDynCallSiteDescriptor { - private final String name; - - NamedDynCallSiteDescriptor(final String op, final String name, final MethodType methodType) { - super(op, methodType); - this.name = name; - } - - @Override - public int getNameTokenCount() { - return 3; - } - - @Override - public String getNameToken(final int i) { - switch(i) { - case 0: return "dyn"; - case 1: return getOp(); - case 2: return name; - default: throw new IndexOutOfBoundsException(String.valueOf(i)); - } - } - - @Override - public CallSiteDescriptor changeMethodType(final MethodType newMethodType) { - return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new NamedDynCallSiteDescriptor(getOp(), name, - newMethodType)); - } -} +/** + *

      Contains classes that make it more convenient for language runtimes to + * implement their own language-specific object models and type conversions + * by providing basic implementations of some classes as well as various + * utilities. + *

      + * @since 1.9 + */ +@jdk.Exported +package jdk.internal.dynalink.linker.support; diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java new file mode 100644 index 00000000000..807a10287bd --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + *

      + * Dynalink is a library for dynamic linking high-level operations on objects. + * These operations include "read a property", + * "write a property", "invoke a function" and so on. Dynalink is primarily + * useful for implementing programming languages where at least some expressions + * have dynamic types (that is, types that can not be decided statically), and + * the operations on dynamic types are expressed as + * {@link java.lang.invoke.CallSite call sites}. These call sites will be + * linked to appropriate target {@link java.lang.invoke.MethodHandle method handles} + * at run time based on actual types of the values the expressions evaluated to. + * These can change between invocations, necessitating relinking the call site + * multiple times to accommodate new types; Dynalink handles all that and more. + *

      + * Dynalink supports implementation of programming languages with object models + * that differ (even radically) from the JVM's class-based model and have their + * custom type conversions. + *

      + * Dynalink is closely related to, and relies on, the {@link java.lang.invoke} + * package. + *

      + * + * While {@link java.lang.invoke} provides a low level API for dynamic linking + * of {@code invokedynamic} call sites, it does not provide a way to express + * higher level operations on objects, nor methods that implement them. These + * operations are the usual ones in object-oriented environments: property + * access, access of elements of collections, invocation of methods and + * constructors (potentially with multiple dispatch, e.g. link- and run-time + * equivalents of Java overloaded method resolution). These are all functions + * that are normally desired in a language on the JVM. If a language is + * statically typed and its type system matches that of the JVM, it can + * accomplish this with use of the usual invocation, field access, etc. + * instructions (e.g. {@code invokevirtual}, {@code getfield}). However, if the + * language is dynamic (hence, types of some expressions are not known until + * evaluated at run time), or its object model or type system don't match + * closely that of the JVM, then it should use {@code invokedynamic} call sites + * instead and let Dynalink manage them. + *

      Example

      + * Dynalink is probably best explained by an example showing its use. Let's + * suppose you have a program in a language where you don't have to declare the + * type of an object and you want to access a property on it: + *
      + * var color = obj.color;
      + * 
      + * If you generated a Java class to represent the above one-line program, its + * bytecode would look something like this: + *
      + * aload 2 // load "obj" on stack
      + * invokedynamic "GET_PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
      + * astore 3 // store the return value into local variable "color"
      + * 
      + * In order to link the {@code invokedynamic} instruction, we need a bootstrap + * method. A minimalist bootstrap method with Dynalink could look like this: + *
      + * import java.lang.invoke.*;
      + * import jdk.internal.dynalink.*;
      + * import jdk.internal.dynalink.support.*;
      + *
      + * class MyLanguageRuntime {
      + *     private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker();
      + *
      + *     public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
      + *         return dynamicLinker.link(
      + *             new SimpleRelinkableCallSite(
      + *                 new CallSiteDescriptor(lookup, parseOperation(name), type)));
      + *     }
      + *
      + *     private static Operation parseOperation(String name) {
      + *         ...
      + *     }
      + * }
      + * 
      + * There are several objects of significance in the above code snippet: + *
        + *
      • {@link jdk.internal.dynalink.DynamicLinker} is the main object in Dynalink, it + * coordinates the linking of call sites to method handles that implement the + * operations named in them. It is configured and created using a + * {@link jdk.internal.dynalink.DynamicLinkerFactory}.
      • + *
      • When the bootstrap method is invoked, it needs to create a + * {@link java.lang.invoke.CallSite} object. In Dynalink, these call sites need + * to additionally implement the {@link jdk.internal.dynalink.RelinkableCallSite} + * interface. "Relinkable" here alludes to the fact that if the call site + * encounters objects of different types at run time, its target will be changed + * to a method handle that can perform the operation on the newly encountered + * type. {@link jdk.internal.dynalink.support.SimpleRelinkableCallSite} and + * {@link jdk.internal.dynalink.support.ChainedCallSite} (not used in the above example) + * are two implementations already provided by the library.
      • + *
      • Dynalink uses {@link jdk.internal.dynalink.CallSiteDescriptor} objects to + * preserve the parameters to the bootstrap method: the lookup and the method type, + * as it will need them whenever it needs to relink a call site.
      • + *
      • Dynalink uses {@link jdk.internal.dynalink.Operation} objects to express + * dynamic operations. It does not prescribe how would you encode the operations + * in your call site, though. That is why in the above example the + * {@code parseOperation} function is left empty, and you would be expected to + * provide the code to parse the string {@code "GET_PROPERTY:color"} + * in the call site's name into a named property getter operation object as + * {@code new NamedOperation(StandardOperation.GET_PROPERTY), "color")}. + *
      + *

      What can you already do with the above setup? {@code DynamicLinkerFactory} + * by default creates a {@code DynamicLinker} that can link Java objects with the + * usual Java semantics. If you have these three simple classes: + *

      + * public class A {
      + *     public String color;
      + *     public A(String color) { this.color = color; }
      + * }
      + *
      + * public class B {
      + *     private String color;
      + *     public B(String color) { this.color = color; }
      + *     public String getColor() { return color; }
      + * }
      + *
      + * public class C {
      + *     private int color;
      + *     public C(int color) { this.color = color; }
      + *     public int getColor() { return color; }
      + * }
      + * 
      + * and you somehow create their instances and pass them to your call site in your + * programming language: + *
      + * for each(var obj in [new A("red"), new B("green"), new C(0x0000ff)]) {
      + *     print(obj.color);
      + * }
      + * 
      + * then on first invocation, Dynalink will link the {@code .color} getter + * operation to a field getter for {@code A.color}, on second invocation it will + * relink it to {@code B.getColor()} returning a {@code String}, and finally on + * third invocation it will relink it to {@code C.getColor()} returning an {@code int}. + * The {@code SimpleRelinkableCallSite} we used above only remembers the linkage + * for the last encountered type (it implements what is known as a monomorphic + * inline cache). Another already provided implementation, + * {@link jdk.internal.dynalink.support.ChainedCallSite} will remember linkages for + * several different types (it is a polymorphic inline cache) and is + * probably a better choice in serious applications. + *

      Dynalink and bytecode creation

      + * {@code CallSite} objects are usually created as part of bootstrapping + * {@code invokedynamic} instructions in bytecode. Hence, Dynalink is typically + * used as part of language runtimes that compile programs into Java + * {@code .class} bytecode format. Dynalink does not address the aspects of + * either creating bytecode classes or loading them into the JVM. That said, + * Dynalink can also be used without bytecode compilation (e.g. in language + * interpreters) by creating {@code CallSite} objects explicitly and associating + * them with representations of dynamic operations in the interpreted program + * (e.g. a typical representation would be some node objects in a syntax tree). + *

      Available operations

      + * Dynalink defines several standard operations in its + * {@link jdk.internal.dynalink.StandardOperation} class. The linker for Java + * objects can link all of these operations, and you are encouraged to at + * minimum support and use these operations in your language too. To associate + * a fixed name with an operation, you can use + * {@link jdk.internal.dynalink.NamedOperation} as in the above example where + * {@code StandardOperation.GET_PROPERTY} was combined with the name + * {@code "color"} in a {@code NamedOperation} to form a property getter for the + * property named "color". + *

      Composite operations

      + * Some languages might not have separate namespaces on objects for + * properties, elements, and methods, and a source language construct might + * address two or three of them. Dynalink supports specifying composite + * operations for this purpose using the + * {@link jdk.internal.dynalink.CompositeOperation} class. + *

      Language-specific linkers

      + * Languages that define their own object model different than the JVM + * class-based model and/or use their own type conversions will need to create + * their own language-specific linkers. See the {@link jdk.internal.dynalink.linker} + * package and specifically the {@link jdk.internal.dynalink.linker.GuardingDynamicLinker} + * interface to get started. + *

      Dynalink and Java objects

      + * The {@code DynamicLinker} objects created by {@code DynamicLinkerFactory} by + * default contain an internal instance of + * {@code BeansLinker}, which is a language-specific linker + * that implements the usual Java semantics for all of the above operations and + * can link any Java object that no other language-specific linker has managed + * to link. This way, all language runtimes have built-in interoperability with + * ordinary Java objects. See {@link jdk.internal.dynalink.beans.BeansLinker} for details + * on how it links the various operations. + *

      Cross-language interoperability

      + * A {@code DynamicLinkerFactory} can be configured with a + * {@link jdk.internal.dynalink.DynamicLinkerFactory#setClassLoader(ClassLoader) class + * loader}. It will try to instantiate all + * {@link jdk.internal.dynalink.linker.GuardingDynamicLinkerExporter} classes visible to + * that class loader and compose the linkers they provide into the + * {@code DynamicLinker} it creates. This allows for interoperability between + * languages: if you have two language runtimes A and B deployed in your JVM and + * they export their linkers through the above mechanism, language runtime A + * will have a language-specific linker instance from B and vice versa inside + * their {@code DynamicLinker} objects. This means that if an object from + * language runtime B gets passed to code from language runtime A, the linker + * from B will get a chance to link the call site in A when it encounters the + * object from B. + */ +@jdk.Exported +package jdk.internal.dynalink; diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package.html b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package.html deleted file mode 100644 index 588823ac8c3..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - -

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

      -

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

      - diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java index f4c462d53c9..f0967d93f00 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java @@ -83,20 +83,31 @@ package jdk.internal.dynalink.support; +import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MutableCallSite; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.RelinkableCallSite; +import jdk.internal.dynalink.linker.GuardedInvocation; /** - * A basic implementation of the {@link RelinkableCallSite} as a {@link MutableCallSite} subclass. + * A basic implementation of the {@link RelinkableCallSite} as a + * {@link MutableCallSite}. It carries a {@link CallSiteDescriptor} passed in + * the constructor and provides the correct implementation of the + * {@link #initialize(MethodHandle)} method. Subclasses must provide + * {@link #relink(GuardedInvocation, MethodHandle)} and + * {@link #resetAndRelink(GuardedInvocation, MethodHandle)} + * methods. */ public abstract class AbstractRelinkableCallSite extends MutableCallSite implements RelinkableCallSite { private final CallSiteDescriptor descriptor; /** - * Creates a new relinkable call site. - * @param descriptor the descriptor for this call site + * Creates a new abstract relinkable call site. + * @param descriptor the descriptor for this call site that will be returned + * from {@link #getDescriptor()}. The call site's {@link CallSite#type()} + * will be equal to descriptor's {@link CallSiteDescriptor#getMethodType()}. + * @throws NullPointerException if {@code descriptor} is null. */ protected AbstractRelinkableCallSite(final CallSiteDescriptor descriptor) { super(descriptor.getMethodType()); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/BottomGuardingDynamicLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/BottomGuardingDynamicLinker.java deleted file mode 100644 index cb407e1aa1f..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/BottomGuardingDynamicLinker.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink.support; - -import jdk.internal.dynalink.linker.GuardedInvocation; -import jdk.internal.dynalink.linker.LinkRequest; -import jdk.internal.dynalink.linker.LinkerServices; -import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; - -/** - * A linker that can't link any call site. Only used internally by {@link CompositeTypeBasedGuardingDynamicLinker}. Can - * be used by other language runtimes if they need it though. - */ -public class BottomGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker { - - /** - * The sole instance of this stateless linker. - */ - public static final BottomGuardingDynamicLinker INSTANCE = new BottomGuardingDynamicLinker(); - - private BottomGuardingDynamicLinker() { - } - - @Override - public boolean canLinkType(final Class type) { - return false; - } - - @Override - public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) { - return null; - } -} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java deleted file mode 100644 index 7d136cab94e..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink.support; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; -import java.lang.ref.Reference; -import java.lang.ref.WeakReference; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.StringTokenizer; -import java.util.WeakHashMap; -import jdk.internal.dynalink.CallSiteDescriptor; - -/** - * Usable as a default factory for call site descriptor implementations. It is weakly canonicalizing, meaning - * it will return the same immutable call site descriptor for identical inputs, i.e. repeated requests for a - * descriptor signifying public lookup for {@code "dyn:getProp:color"} of type {@code Object(Object)} will - * return the same object as long as a previously created, at least softly reachable one exists. It also uses - * several different implementations of the {@link CallSiteDescriptor} internally, and chooses the most - * space-efficient one based on the input. - */ -public class CallSiteDescriptorFactory { - private static final WeakHashMap> publicDescs = - new WeakHashMap<>(); - - - private CallSiteDescriptorFactory() { - } - - /** - * Creates a new call site descriptor instance. The actual underlying class of the instance is dependent on the - * passed arguments to be space efficient; i.e. if you only use the public lookup, you'll get back an - * implementation that doesn't waste space on storing the lookup object. - * @param lookup the lookup that determines access rights at the call site. If your language runtime doesn't have - * equivalents of Java access concepts, just use {@link MethodHandles#publicLookup()}. Must not be null. - * @param name the name of the method at the call site. Must not be null. - * @param methodType the type of the method at the call site. Must not be null. - * @return a call site descriptor representing the input. Note that although the method name is "create", it will - * in fact return a weakly-referenced canonical instance. - */ - public static CallSiteDescriptor create(final Lookup lookup, final String name, final MethodType methodType) { - Objects.requireNonNull(name); - Objects.requireNonNull(methodType); - Objects.requireNonNull(lookup); - final String[] tokenizedName = tokenizeName(name); - if(isPublicLookup(lookup)) { - return getCanonicalPublicDescriptor(createPublicCallSiteDescriptor(tokenizedName, methodType)); - } - return new LookupCallSiteDescriptor(tokenizedName, methodType, lookup); - } - - static CallSiteDescriptor getCanonicalPublicDescriptor(final CallSiteDescriptor desc) { - synchronized(publicDescs) { - final Reference ref = publicDescs.get(desc); - if(ref != null) { - final CallSiteDescriptor canonical = ref.get(); - if(canonical != null) { - return canonical; - } - } - publicDescs.put(desc, createReference(desc)); - } - return desc; - } - - /** - * Override this to use a different kind of references for the cache - * @param desc desc - * @return reference - */ - protected static Reference createReference(final CallSiteDescriptor desc) { - return new WeakReference<>(desc); - } - - private static CallSiteDescriptor createPublicCallSiteDescriptor(final String[] tokenizedName, final MethodType methodType) { - final int l = tokenizedName.length; - if(l > 0 && tokenizedName[0] == "dyn") { - if(l == 2) { - return new UnnamedDynCallSiteDescriptor(tokenizedName[1], methodType); - } if (l == 3) { - return new NamedDynCallSiteDescriptor(tokenizedName[1], tokenizedName[2], methodType); - } - } - return new DefaultCallSiteDescriptor(tokenizedName, methodType); - } - - private static boolean isPublicLookup(final Lookup lookup) { - return lookup == MethodHandles.publicLookup(); - } - - /** - * Tokenizes the composite name along colons, as well as {@link NameCodec#decode(String) demangles} and interns - * the tokens. The first two tokens are not demangled as they are supposed to be the naming scheme and the name of - * the operation which can be expected to consist of just alphabetical characters. - * @param name the composite name consisting of colon-separated, possibly mangled tokens. - * @return an array of tokens - */ - public static String[] tokenizeName(final String name) { - final StringTokenizer tok = new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER); - final String[] tokens = new String[tok.countTokens()]; - for(int i = 0; i < tokens.length; ++i) { - String token = tok.nextToken(); - if(i > 1) { - token = NameCodec.decode(token); - } - tokens[i] = token.intern(); - } - return tokens; - } - - /** - * Tokenizes a composite operation name along pipe characters. I.e. if you have a "dyn:getElem|getProp|getMethod" - * operation, returns a list of ["getElem", "getProp", "getMethod"]. The tokens are not interned. - * @param desc the call site descriptor with the operation - * @return a list of tokens - */ - public static List tokenizeOperators(final CallSiteDescriptor desc) { - final String ops = desc.getNameToken(CallSiteDescriptor.OPERATOR); - final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER); - final int count = tok.countTokens(); - if(count == 1) { - return Collections.singletonList(ops); - } - final String[] tokens = new String[count]; - for(int i = 0; i < count; ++i) { - tokens[i] = tok.nextToken(); - } - return Arrays.asList(tokens); - } - - /** - * Returns a new call site descriptor that is identical to the passed one, except that it has some parameter types - * removed from its method type. - * @param desc the original call site descriptor - * @param start index of the first parameter to remove - * @param end index of the first parameter to not remove - * @return a new call site descriptor with modified method type - */ - public static CallSiteDescriptor dropParameterTypes(final CallSiteDescriptor desc, final int start, final int end) { - return desc.changeMethodType(desc.getMethodType().dropParameterTypes(start, end)); - } - - /** - * Returns a new call site descriptor that is identical to the passed one, except that it has a single parameter - * type changed in its method type. - * @param desc the original call site descriptor - * @param num index of the parameter to change - * @param nptype the new parameter type - * @return a new call site descriptor with modified method type - */ - public static CallSiteDescriptor changeParameterType(final CallSiteDescriptor desc, final int num, final Class nptype) { - return desc.changeMethodType(desc.getMethodType().changeParameterType(num, nptype)); - } - - /** - * Returns a new call site descriptor that is identical to the passed one, except that it has the return type - * changed in its method type. - * @param desc the original call site descriptor - * @param nrtype the new return type - * @return a new call site descriptor with modified method type - */ - public static CallSiteDescriptor changeReturnType(final CallSiteDescriptor desc, final Class nrtype) { - return desc.changeMethodType(desc.getMethodType().changeReturnType(nrtype)); - } - - /** - * Returns a new call site descriptor that is identical to the passed one, except that it has additional parameter - * types inserted into its method type. - * @param desc the original call site descriptor - * @param num index at which the new parameters are inserted - * @param ptypesToInsert the new types to insert - * @return a new call site descriptor with modified method type - */ - public static CallSiteDescriptor insertParameterTypes(final CallSiteDescriptor desc, final int num, final Class... ptypesToInsert) { - return desc.changeMethodType(desc.getMethodType().insertParameterTypes(num, ptypesToInsert)); - } - - /** - * Returns a new call site descriptor that is identical to the passed one, except that it has additional parameter - * types inserted into its method type. - * @param desc the original call site descriptor - * @param num index at which the new parameters are inserted - * @param ptypesToInsert the new types to insert - * @return a new call site descriptor with modified method type - */ - public static CallSiteDescriptor insertParameterTypes(final CallSiteDescriptor desc, final int num, final List> ptypesToInsert) { - return desc.changeMethodType(desc.getMethodType().insertParameterTypes(num, ptypesToInsert)); - } -} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/ChainedCallSite.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/ChainedCallSite.java similarity index 80% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/ChainedCallSite.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/ChainedCallSite.java index 2653e179c89..80306a6e06e 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/ChainedCallSite.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/ChainedCallSite.java @@ -81,26 +81,33 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink; +package jdk.internal.dynalink.support; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; +import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.GuardedInvocation; -import jdk.internal.dynalink.support.AbstractRelinkableCallSite; -import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.linker.support.Lookup; /** - * A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method - * handles can be chained, cascading from one to the other through - * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. When this call site has to link a new - * method handle and the length of the chain is already at the maximum, it will throw away the oldest method handle. - * Switchpoint-invalidated handles in the chain are removed eagerly (on each linking request, and whenever a - * switchpoint-invalidated method handle is traversed during invocation). There is currently no profiling - * attached to the handles in the chain, so they are never reordered based on usage; the most recently linked method - * handle is always at the start of the chain. + * A relinkable call site that implements a polymorphic inline caching strategy. + * It remembers up to 8 {@link GuardedInvocation}s it was linked with, and on + * each relink request builds a cascading chain of method handles of one + * invocation falling back to the next one. The number of remembered invocations + * can be customized by overriding {@link #getMaxChainLength()} in a subclass. + * When this call site is relinked with a new invocation and the length of the + * chain is already at the maximum, it will throw away the oldest invocation. + * Invocations with invalidated switch points and ones for which their + * invalidating exception triggered are removed eagerly from the chain. The + * invocations are never reordered; the most recently linked method handle is + * always at the start of the chain and the least recently linked at its end. + * The call site can be safely relinked on more than one thread concurrently. + * Race conditions in linking are resolved by throwing away the + * {@link GuardedInvocation} produced on the losing thread without incorporating + * it into the chain, so it can lead to repeated linking for the same arguments. */ public class ChainedCallSite extends AbstractRelinkableCallSite { private static final MethodHandle PRUNE_CATCHES; @@ -130,22 +137,24 @@ public class ChainedCallSite extends AbstractRelinkableCallSite { } /** - * The maximum number of method handles in the chain. Defaults to 8. You can override it in a subclass if you need - * to change the value. If your override returns a value less than 1, the code will break. - * @return the maximum number of method handles in the chain. + * The maximum number of method handles in the chain. Defaults to 8. You can + * override it in a subclass if you need to change the value. + * @return the maximum number of method handles in the chain. The return + * value is checked, and if your override returns a value less than 1, a + * {@link RuntimeException} will be thrown. */ protected int getMaxChainLength() { return 8; } @Override - public void relink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) { - relinkInternal(guardedInvocation, fallback, false, false); + public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) { + relinkInternal(guardedInvocation, relinkAndInvoke, false, false); } @Override - public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) { - relinkInternal(guardedInvocation, fallback, true, false); + public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) { + relinkInternal(guardedInvocation, relinkAndInvoke, true, false); } private MethodHandle relinkInternal(final GuardedInvocation invocation, final MethodHandle relink, final boolean reset, final boolean removeCatches) { @@ -175,7 +184,7 @@ public class ChainedCallSite extends AbstractRelinkableCallSite { // adding any new invocations to it. if(invocation != null) { // Remove oldest entry if we're at max length - if(newInvocations.size() == getMaxChainLength()) { + if(newInvocations.size() == checkMaxChainLength(getMaxChainLength())) { newInvocations.removeFirst(); } newInvocations.addLast(invocation); @@ -206,15 +215,22 @@ public class ChainedCallSite extends AbstractRelinkableCallSite { return target; } + private static int checkMaxChainLength(final int maxChainLength) { + if (maxChainLength > 0) { + return maxChainLength; + } + throw new RuntimeException("getMaxChainLength() returned a non-positive value"); + + } /** * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that * chain. - * @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink). + * @param relinkAndInvoke the ultimate fallback for the chain passed from the dynamic linker. * @return a method handle for prune-and-invoke */ - private MethodHandle makePruneAndInvokeMethod(final MethodHandle relink, final MethodHandle prune) { + private MethodHandle makePruneAndInvokeMethod(final MethodHandle relinkAndInvoke, final MethodHandle prune) { // Bind prune to (this, relink) - final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relink); + final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relinkAndInvoke); // Make it ignore all incoming arguments final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList()); // Invoke prune, then invoke the call site target with original arguments diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/DefaultCallSiteDescriptor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/DefaultCallSiteDescriptor.java deleted file mode 100644 index 17cb0c80438..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/DefaultCallSiteDescriptor.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink.support; - -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; -import jdk.internal.dynalink.CallSiteDescriptor; - -/** - * A default, fairly light implementation of a call site descriptor used for describing non-standard operations. It does - * not store {@link Lookup} objects but always returns the public lookup from its {@link #getLookup()} method. If you - * need to support non-public lookup, you can use {@link LookupCallSiteDescriptor}. - */ -class DefaultCallSiteDescriptor extends AbstractCallSiteDescriptor { - - private final String[] tokenizedName; - private final MethodType methodType; - - DefaultCallSiteDescriptor(final String[] tokenizedName, final MethodType methodType) { - this.tokenizedName = tokenizedName; - this.methodType = methodType; - } - - @Override - public int getNameTokenCount() { - return tokenizedName.length; - } - - @Override - public String getNameToken(final int i) { - try { - return tokenizedName[i]; - } catch(final ArrayIndexOutOfBoundsException e) { - throw new IllegalArgumentException(e.getMessage()); - } - } - - String[] getTokenizedName() { - return tokenizedName; - } - - @Override - public MethodType getMethodType() { - return methodType; - } - - @Override - public CallSiteDescriptor changeMethodType(final MethodType newMethodType) { - return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new DefaultCallSiteDescriptor(tokenizedName, - newMethodType)); - } -} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/LookupCallSiteDescriptor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/LookupCallSiteDescriptor.java deleted file mode 100644 index 7e24033eec6..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/LookupCallSiteDescriptor.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink.support; - -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; -import jdk.internal.dynalink.CallSiteDescriptor; - -/** - * A call site descriptor that stores a specific {@link Lookup}. It does not, however, store static bootstrap arguments. - */ -class LookupCallSiteDescriptor extends DefaultCallSiteDescriptor { - private final Lookup lookup; - - /** - * Create a new call site descriptor from explicit information. - * @param tokenizedName the name of the method - * @param methodType the method type - * @param lookup the lookup - */ - LookupCallSiteDescriptor(final String[] tokenizedName, final MethodType methodType, final Lookup lookup) { - super(tokenizedName, methodType); - this.lookup = lookup; - } - - @Override - public Lookup getLookup() { - return lookup; - } - - @Override - public CallSiteDescriptor changeMethodType(final MethodType newMethodType) { - return new LookupCallSiteDescriptor(getTokenizedName(), newMethodType, lookup); - } -} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NameCodec.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NameCodec.java index 179531f5ea8..d3b8ad75dc0 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NameCodec.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NameCodec.java @@ -83,24 +83,15 @@ package jdk.internal.dynalink.support; -import jdk.internal.dynalink.CallSiteDescriptor; /** * Implements the name mangling and demangling as specified by John Rose's - * "Symbolic Freedom in the - * VM" article. It is recommended that implementers of languages on the JVM uniformly adopt this for symbolic - * interoperability between languages. Normally, you would mangle the names as you're generating bytecode, and then - * demangle them when you're creating {@link CallSiteDescriptor} objects. Note that you are expected to mangle - * individual tokens, and not the whole name at the call site, i.e. the colon character normally separating the tokens - * is never mangled. I.e. you wouldn't mangle {@code dyn:getProp:color} into {@code dyn\!getProp\!color}, but you would - * mangle {@code dyn:getProp:color$} into {@code dyn:getProp:\=color\%} (only mangling the individual token containing - * the symbol {@code color$}). {@link CallSiteDescriptorFactory#tokenizeName(String)} (and by implication, all call site - * descriptors it creates) will automatically perform demangling on the passed names. If you use this factory, or you - * have your own way of creating call site descriptors, but you still delegate to this method of the default factory - * (it is recommended that you do), then you have demangling handled for you already, and only need to ensure that you - * mangle the names when you're emitting them in the bytecode. + * "Symbolic Freedom in the VM" article. Normally, you would + * mangle the names in the call sites as you're generating bytecode, and then + * demangle them when you receive them in bootstrap methods. */ -public class NameCodec { +public final class NameCodec { private static final char ESCAPE_CHAR = '\\'; private static final char EMPTY_ESCAPE = '='; private static final String EMPTY_NAME = new String(new char[] { ESCAPE_CHAR, EMPTY_ESCAPE }); @@ -175,7 +166,7 @@ public class NameCodec { * @return the demangled form of the symbolic name. */ public static String decode(final String name) { - if(name.charAt(0) != ESCAPE_CHAR) { + if(name.isEmpty() || name.charAt(0) != ESCAPE_CHAR) { return name; } final int l = name.length(); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java deleted file mode 100644 index 528bed7aa2a..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink.support; - -import jdk.internal.dynalink.CallSiteDescriptor; -import jdk.internal.dynalink.linker.LinkRequest; - -/** - * A link request implementation for call sites that pass language runtime specific context arguments on the stack. The - * context specific arguments should be the first "n" arguments. - */ -public class RuntimeContextLinkRequestImpl extends LinkRequestImpl { - - private final int runtimeContextArgCount; - private LinkRequestImpl contextStrippedRequest; - - /** - * Creates a new link request. - * - * @param callSiteDescriptor the descriptor for the call site being linked - * @param callSiteToken the opaque token for the call site being linked. - * @param arguments the arguments for the invocation - * @param linkCount number of times callsite has been linked/relinked - * @param callSiteUnstable true if the call site being linked is considered unstable - * @param runtimeContextArgCount the number of the leading arguments on the stack that represent the language - * runtime specific context arguments. - * @throws IllegalArgumentException if runtimeContextArgCount is less than 1. - */ - public RuntimeContextLinkRequestImpl(final CallSiteDescriptor callSiteDescriptor, final Object callSiteToken, - final int linkCount, final boolean callSiteUnstable, final Object[] arguments, final int runtimeContextArgCount) { - super(callSiteDescriptor, callSiteToken, linkCount, callSiteUnstable, arguments); - if(runtimeContextArgCount < 1) { - throw new IllegalArgumentException("runtimeContextArgCount < 1"); - } - this.runtimeContextArgCount = runtimeContextArgCount; - } - - @Override - public LinkRequest withoutRuntimeContext() { - if(contextStrippedRequest == null) { - contextStrippedRequest = - new LinkRequestImpl(CallSiteDescriptorFactory.dropParameterTypes(getCallSiteDescriptor(), 1, - runtimeContextArgCount + 1), getCallSiteToken(), getLinkCount(), isCallSiteUnstable(), getTruncatedArguments()); - } - return contextStrippedRequest; - } - - @Override - public LinkRequest replaceArguments(final CallSiteDescriptor callSiteDescriptor, final Object[] arguments) { - return new RuntimeContextLinkRequestImpl(callSiteDescriptor, getCallSiteToken(), getLinkCount(), isCallSiteUnstable(), arguments, - runtimeContextArgCount); - } - - private Object[] getTruncatedArguments() { - final Object[] args = getArguments(); - final Object[] newargs = new Object[args.length - runtimeContextArgCount]; - newargs[0] = args[0]; // "this" remains at the 0th position - System.arraycopy(args, runtimeContextArgCount + 1, newargs, 1, newargs.length - 1); - return newargs; - } -} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/MonomorphicCallSite.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/SimpleRelinkableCallSite.java similarity index 87% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/MonomorphicCallSite.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/SimpleRelinkableCallSite.java index b49265820b8..7e5a1a78e45 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/MonomorphicCallSite.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/SimpleRelinkableCallSite.java @@ -81,33 +81,35 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink; +package jdk.internal.dynalink.support; import java.lang.invoke.MethodHandle; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.DynamicLinker; import jdk.internal.dynalink.linker.GuardedInvocation; -import jdk.internal.dynalink.support.AbstractRelinkableCallSite; /** - * A relinkable call site that implements monomorphic inline caching strategy. After it linked a method, it will keep it - * until either its guard evaluates to false, or its switchpoint is invalidated, at which time it will throw away the - * previous linkage, and trigger relinking with its associated {@link DynamicLinker}. + * A relinkable call site that implements monomorphic inline caching strategy, + * only being linked to a single {@link GuardedInvocation}. If that invocation + * is invalidated, it will throw it away and ask its associated + * {@link DynamicLinker} to relink it. */ -public class MonomorphicCallSite extends AbstractRelinkableCallSite { +public class SimpleRelinkableCallSite extends AbstractRelinkableCallSite { /** * Creates a new call site with monomorphic inline caching strategy. * @param descriptor the descriptor for this call site */ - public MonomorphicCallSite(final CallSiteDescriptor descriptor) { + public SimpleRelinkableCallSite(final CallSiteDescriptor descriptor) { super(descriptor); } @Override - public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relink) { - setTarget(guardedInvocation.compose(relink)); + public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) { + setTarget(guardedInvocation.compose(relinkAndInvoke)); } @Override - public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relink) { - relink(guardedInvocation, relink); + public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) { + relink(guardedInvocation, relinkAndInvoke); } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/UnnamedDynCallSiteDescriptor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/UnnamedDynCallSiteDescriptor.java deleted file mode 100644 index 89a0677e91f..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/UnnamedDynCallSiteDescriptor.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink.support; - -import java.lang.invoke.MethodType; -import jdk.internal.dynalink.CallSiteDescriptor; - -class UnnamedDynCallSiteDescriptor extends AbstractCallSiteDescriptor { - private final MethodType methodType; - private final String op; - - UnnamedDynCallSiteDescriptor(final String op, final MethodType methodType) { - this.op = op; - this.methodType = methodType; - } - - @Override - public int getNameTokenCount() { - return 2; - } - - String getOp() { - return op; - } - - @Override - public String getNameToken(final int i) { - switch(i) { - case 0: return "dyn"; - case 1: return op; - default: throw new IndexOutOfBoundsException(String.valueOf(i)); - } - } - - @Override - public MethodType getMethodType() { - return methodType; - } - - @Override - public CallSiteDescriptor changeMethodType(final MethodType newMethodType) { - return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new UnnamedDynCallSiteDescriptor(op, - newMethodType)); - } -} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/DefaultPrelinkFilter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/package-info.java similarity index 85% rename from nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/DefaultPrelinkFilter.java rename to nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/package-info.java index ad9679f6643..83772efd7a3 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/DefaultPrelinkFilter.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,19 +81,11 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jdk.internal.dynalink.support; - -import jdk.internal.dynalink.GuardedInvocationFilter; -import jdk.internal.dynalink.linker.GuardedInvocation; -import jdk.internal.dynalink.linker.LinkRequest; -import jdk.internal.dynalink.linker.LinkerServices; - /** - * Default filter for guarded invocation pre link filtering + *

      Contains classes that make using Dynalink more convenient by providing + * basic implementations of some classes as well as various utilities. + *

      + * @since 1.9 */ -public class DefaultPrelinkFilter implements GuardedInvocationFilter { - @Override - public GuardedInvocation filter(final GuardedInvocation inv, final LinkRequest request, final LinkerServices linkerServices) { - return inv.asType(linkerServices, request.getCallSiteDescriptor().getMethodType()); - } -} +@jdk.Exported +package jdk.internal.dynalink.support; diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/package.html b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/package.html deleted file mode 100644 index 7bf9efcdc21..00000000000 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/package.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - -

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

      - diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java index d1cadc83cef..bcb6b35fdbd 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -683,9 +683,9 @@ final class CodeGenerator extends NodeOperatorVisitorOBJECT*/, index); - method.visitInvokeDynamicInsn(dynGetOperation(isMethod, true), signature, LINKERBOOTSTRAP, flags); + method.visitInvokeDynamicInsn(EMPTY_NAME, signature, LINKERBOOTSTRAP, flags | dynGetOperation(isMethod, true)); pushType(resultType); if (result.isBoolean()) { @@ -2331,7 +2334,9 @@ public class MethodEmitter { final Type receiver = popType(Type.OBJECT); assert receiver.isObject(); - method.visitInvokeDynamicInsn("dyn:setElem|setProp", methodDescriptor(void.class, receiver.getTypeClass(), index.getTypeClass(), value.getTypeClass()), LINKERBOOTSTRAP, flags); + method.visitInvokeDynamicInsn(EMPTY_NAME, + methodDescriptor(void.class, receiver.getTypeClass(), index.getTypeClass(), value.getTypeClass()), + LINKERBOOTSTRAP, flags | NashornCallSiteDescriptor.SET_ELEMENT); } /** @@ -2501,16 +2506,16 @@ public class MethodEmitter { } } - private static String dynGetOperation(final boolean isMethod, final boolean isIndex) { + private static int dynGetOperation(final boolean isMethod, final boolean isIndex) { if (isMethod) { - return isIndex ? "dyn:getMethod|getElem|getProp" : "dyn:getMethod|getProp|getElem"; + return isIndex ? NashornCallSiteDescriptor.GET_METHOD_ELEMENT : NashornCallSiteDescriptor.GET_METHOD_PROPERTY; } else { - return isIndex ? "dyn:getElem|getProp|getMethod" : "dyn:getProp|getElem|getMethod"; + return isIndex ? NashornCallSiteDescriptor.GET_ELEMENT : NashornCallSiteDescriptor.GET_PROPERTY; } } - private static String dynSetOperation(final boolean isIndex) { - return isIndex ? "dyn:setElem|setProp" : "dyn:setProp|setElem"; + private static int dynSetOperation(final boolean isIndex) { + return isIndex ? NashornCallSiteDescriptor.SET_ELEMENT : NashornCallSiteDescriptor.SET_PROPERTY; } private Type emitLocalVariableConversion(final LocalVariableConversion conversion, final boolean onlySymbolLiveValue) { diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionCall.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionCall.java index 22bf37d17ae..98533bcaded 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionCall.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionCall.java @@ -25,14 +25,16 @@ package jdk.nashorn.internal.ir; +import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; + /** * Interface used by AccessNodes, IndexNodes and IdentNodes to signal that when evaluated, their value will be treated * as a function and immediately invoked, e.g. {@code foo()}, {@code foo.bar()} or {@code foo[bar]()}. Used to customize * the priority of composite dynamic operations when emitting {@code INVOKEDYNAMIC} instructions that implement them, * namely prioritize {@code getMethod} over {@code getElem} or {@code getProp}. An access or ident node with isFunction - * set to true will be emitted as {@code dyn:getMethod|getProp|getElem} while one with it set to false will be emitted - * as {@code dyn:getProp|getElem|getMethod}. Similarly, an index node with isFunction set to true will be emitted as - * {@code dyn:getMethod|getElem|getProp} while the one set to false will be emitted as {@code dyn:getElem|getProp|getMethod}. + * set to true will be emitted as {@link NashornCallSiteDescriptor#GET_METHOD_PROPERTY} while one with it set to false will be emitted + * as {@link NashornCallSiteDescriptor#GET_PROPERTY}. Similarly, an index node with isFunction set to true will be emitted as + * {@link NashornCallSiteDescriptor#GET_METHOD_ELEMENT} while the one set to false will be emitted as {@link NashornCallSiteDescriptor#GET_ELEMENT}. */ public interface FunctionCall { /** diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java index 9b4f014aa24..3319409e932 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java @@ -39,6 +39,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import jdk.internal.dynalink.support.NameCodec; import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.Handle; import jdk.internal.org.objectweb.asm.Label; @@ -48,6 +49,7 @@ import jdk.internal.org.objectweb.asm.signature.SignatureReader; import jdk.internal.org.objectweb.asm.util.Printer; import jdk.internal.org.objectweb.asm.util.TraceSignatureVisitor; import jdk.nashorn.internal.runtime.ScriptEnvironment; +import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; /** @@ -55,6 +57,7 @@ import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; * Also supports dot formats if --print-code has arguments */ public final class NashornTextifier extends Printer { + private static final String BOOTSTRAP_CLASS_NAME = Bootstrap.class.getName().replace('.', '/'); private String currentClassName; private Iterator