--- a/.hgtags-top-repo Mon Dec 21 17:47:21 2015 +0100
+++ b/.hgtags-top-repo Wed Jul 05 21:09:54 2017 +0200
@@ -340,3 +340,4 @@
12a6fb4f070f8ca8fbca219ab9abf5da8908b317 jdk-9+95
5582a79892596169ebddb3e2c2aa44939e4e3f40 jdk-9+96
75c3897541ecb52ee16d001ea605b12971df7303 jdk-9+97
+48987460c7d49a29013963ee44d090194396bb61 jdk-9+98
--- a/README Mon Dec 21 17:47:21 2015 +0100
+++ b/README Wed Jul 05 21:09:54 2017 +0200
@@ -6,7 +6,7 @@
The root repository can be obtained with something like:
hg clone http://hg.openjdk.java.net/jdk9/jdk9 openjdk9
-
+
You can run the get_source.sh script located in the root repository to get
the other needed repositories:
cd openjdk9 && sh ./get_source.sh
@@ -17,7 +17,7 @@
See http://openjdk.java.net/ for more information about OpenJDK.
Simple Build Instructions:
-
+
0. Get the necessary system software/packages installed on your system, see
http://hg.openjdk.java.net/jdk9/jdk9/raw-file/tip/README-builds.html
@@ -28,10 +28,10 @@
2. Configure the build:
bash ./configure
-
+
3. Build the OpenJDK:
make all
- The resulting JDK image should be found in build/*/images/j2sdk-image
+ The resulting JDK image should be found in build/*/images/jdk
where make is GNU make 3.81 or newer, /usr/bin/make on Linux usually
is 3.81 or newer. Note that on Solaris, GNU make is called "gmake".
--- a/README-builds.html Mon Dec 21 17:47:21 2015 +0100
+++ b/README-builds.html Wed Jul 05 21:09:54 2017 +0200
@@ -250,9 +250,7 @@
</ul></li>
<li><p><strong>Mac OS X</strong></p>
-<p>Install <a href="https://developer.apple.com/xcode/">XCode 4.5.2</a> and also
-install the "Command line tools" found under the preferences pane
-"Downloads"</p></li>
+<p>Install <a href="https://developer.apple.com/xcode/">XCode 6.3</a></p></li>
</ul>
<p><a name="linux"></a></p>
@@ -279,39 +277,67 @@
<h5>Studio Compilers</h5>
<p>At a minimum, the <a href="http://www.oracle.com/
-technetwork/server-storage/solarisstudio/downloads/index.htm">Studio 12 Update 1 Compilers</a> (containing
-version 5.10 of the C and C++ compilers) is required, including specific
+technetwork/server-storage/solarisstudio/downloads/index.htm">Studio 12 Update 4 Compilers</a> (containing
+version 5.13 of the C and C++ compilers) is required, including specific
patches.</p>
-<p>The Solaris SPARC patch list is:</p>
+<p>The Solaris Studio installation should contain at least these packages:</p>
-<ul>
-<li>118683-05: SunOS 5.10: Patch for profiling libraries and assembler</li>
-<li>119963-21: SunOS 5.10: Shared library patch for C++</li>
-<li>120753-08: SunOS 5.10: Microtasking libraries (libmtsk) patch</li>
-<li>128228-09: Sun Studio 12 Update 1: Patch for Sun C++ Compiler</li>
-<li>141860-03: Sun Studio 12 Update 1: Patch for Compiler Common patch for Sun C
-C++ F77 F95</li>
-<li>141861-05: Sun Studio 12 Update 1: Patch for Sun C Compiler</li>
-<li>142371-01: Sun Studio 12.1 Update 1: Patch for dbx</li>
-<li>143384-02: Sun Studio 12 Update 1: Patch for debuginfo handling</li>
-<li>143385-02: Sun Studio 12 Update 1: Patch for Compiler Common patch for Sun C
-C++ F77 F95</li>
-<li>142369-01: Sun Studio 12.1: Patch for Performance Analyzer Tools</li>
-</ul>
+<blockquote>
+ <p><table border="1">
+ <thead>
+ <tr>
+ <td><strong>Package</strong></td>
+ <td><strong>Version</strong></td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>developer/solarisstudio-124/backend</td>
+ <td>12.4-1.0.6.0</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/c++</td>
+ <td>12.4-1.0.10.0</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/cc</td>
+ <td>12.4-1.0.4.0</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/library/c++-libs</td>
+ <td>12.4-1.0.10.0</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/library/math-libs</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/library/studio-gccrt</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/studio-common</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/studio-ja</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/studio-legal</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/studio-zhCN</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ </tbody>
+ </table></p>
+</blockquote>
-<p>The Solaris X86 patch list is:</p>
-
-<ul>
-<li>119961-07: SunOS 5.10_x86, x64, Patch for profiling libraries and assembler</li>
-<li>119964-21: SunOS 5.10_x86: Shared library patch for C++_x86</li>
-<li>120754-08: SunOS 5.10_x86: Microtasking libraries (libmtsk) patch</li>
-<li>141858-06: Sun Studio 12 Update 1_x86: Sun Compiler Common patch for x86
-backend</li>
-<li>128229-09: Sun Studio 12 Update 1_x86: Patch for C++ Compiler</li>
-<li>142363-05: Sun Studio 12 Update 1_x86: Patch for C Compiler</li>
-<li>142368-01: Sun Studio 12.1_x86: Patch for Performance Analyzer Tools</li>
-</ul>
+<p>In particular backend 12.4-1.0.6.0 contains a critical patch for the sparc
+version.</p>
<p>Place the <code>bin</code> directory in <code>PATH</code>.</p>
@@ -1144,10 +1170,6 @@
<p>With Linux, it was just a matter of picking a stable distribution that is a
good representative for Linux in general.</p>
-<p><strong>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.</strong></p>
-
<p>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
@@ -1176,7 +1198,7 @@
<tr>
<td>Linux X86 (32-bit) and X64 (64-bit)</td>
<td>Oracle Enterprise Linux 6.4</td>
- <td>gcc 4.8.2 </td>
+ <td>gcc 4.9.2 </td>
<td>JDK 8</td>
<td>2 or more</td>
<td>1 GB</td>
@@ -1184,8 +1206,8 @@
</tr>
<tr>
<td>Solaris SPARCV9 (64-bit)</td>
- <td>Solaris 10 Update 10</td>
- <td>Studio 12 Update 3 + patches</td>
+ <td>Solaris 11 Update 1</td>
+ <td>Studio 12 Update 4 + patches</td>
<td>JDK 8</td>
<td>4 or more</td>
<td>4 GB</td>
@@ -1193,8 +1215,8 @@
</tr>
<tr>
<td>Solaris X64 (64-bit)</td>
- <td>Solaris 10 Update 10</td>
- <td>Studio 12 Update 3 + patches</td>
+ <td>Solaris 11 Update 1</td>
+ <td>Studio 12 Update 4 + patches</td>
<td>JDK 8</td>
<td>4 or more</td>
<td>4 GB</td>
@@ -1221,7 +1243,7 @@
<tr>
<td>Mac OS X X64 (64-bit)</td>
<td>Mac OS X 10.9 "Mavericks"</td>
- <td>XCode 5.1.1 or newer</td>
+ <td>Xcode 6.3 or newer</td>
<td>JDK 8</td>
<td>2 or more</td>
<td>4 GB</td>
--- a/README-builds.md Mon Dec 21 17:47:21 2015 +0100
+++ b/README-builds.md Wed Jul 05 21:09:54 2017 +0200
@@ -215,9 +215,7 @@
* **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"
+ Install [XCode 6.3](https://developer.apple.com/xcode/)
<a name="linux"></a>
#### Linux
@@ -239,36 +237,66 @@
<a name="studio"></a>
##### Studio Compilers
-At a minimum, the [Studio 12 Update 1 Compilers](http://www.oracle.com/
+At a minimum, the [Studio 12 Update 4 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
+version 5.13 of the C and C++ compilers) is required, including specific
patches.
-The Solaris SPARC patch list is:
+The Solaris Studio installation should contain at least these packages:
- * 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
+> <table border="1">
+ <thead>
+ <tr>
+ <td>**Package**</td>
+ <td>**Version**</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>developer/solarisstudio-124/backend</td>
+ <td>12.4-1.0.6.0</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/c++</td>
+ <td>12.4-1.0.10.0</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/cc</td>
+ <td>12.4-1.0.4.0</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/library/c++-libs</td>
+ <td>12.4-1.0.10.0</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/library/math-libs</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/library/studio-gccrt</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/studio-common</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/studio-ja</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/studio-legal</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ <tr>
+ <td>developer/solarisstudio-124/studio-zhCN</td>
+ <td>12.4-1.0.0.1</td>
+ </tr>
+ </tbody>
+ </table>
-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
+In particular backend 12.4-1.0.6.0 contains a critical patch for the sparc
+version.
Place the `bin` directory in `PATH`.
@@ -1044,10 +1072,6 @@
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
@@ -1075,7 +1099,7 @@
<tr>
<td>Linux X86 (32-bit) and X64 (64-bit)</td>
<td>Oracle Enterprise Linux 6.4</td>
- <td>gcc 4.8.2 </td>
+ <td>gcc 4.9.2 </td>
<td>JDK 8</td>
<td>2 or more</td>
<td>1 GB</td>
@@ -1083,8 +1107,8 @@
</tr>
<tr>
<td>Solaris SPARCV9 (64-bit)</td>
- <td>Solaris 10 Update 10</td>
- <td>Studio 12 Update 3 + patches</td>
+ <td>Solaris 11 Update 1</td>
+ <td>Studio 12 Update 4 + patches</td>
<td>JDK 8</td>
<td>4 or more</td>
<td>4 GB</td>
@@ -1092,8 +1116,8 @@
</tr>
<tr>
<td>Solaris X64 (64-bit)</td>
- <td>Solaris 10 Update 10</td>
- <td>Studio 12 Update 3 + patches</td>
+ <td>Solaris 11 Update 1</td>
+ <td>Studio 12 Update 4 + patches</td>
<td>JDK 8</td>
<td>4 or more</td>
<td>4 GB</td>
@@ -1120,7 +1144,7 @@
<tr>
<td>Mac OS X X64 (64-bit)</td>
<td>Mac OS X 10.9 "Mavericks"</td>
- <td>XCode 5.1.1 or newer</td>
+ <td>Xcode 6.3 or newer</td>
<td>JDK 8</td>
<td>2 or more</td>
<td>4 GB</td>
--- a/common/autoconf/build-performance.m4 Mon Dec 21 17:47:21 2015 +0100
+++ b/common/autoconf/build-performance.m4 Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+# 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
@@ -149,6 +149,19 @@
AC_SUBST(JOBS)
])
+AC_DEFUN_ONCE([BPERF_SETUP_TEST_JOBS],
+[
+ # The number of test jobs will be chosen automatically if TEST_JOBS is 0
+ AC_ARG_WITH(test-jobs, [AS_HELP_STRING([--with-test-jobs],
+ [number of parallel tests jobs to run @<:@based on build jobs@:>@])])
+ if test "x$with_test_jobs" = x; then
+ TEST_JOBS=0
+ else
+ TEST_JOBS=$with_test_jobs
+ fi
+ AC_SUBST(TEST_JOBS)
+])
+
AC_DEFUN([BPERF_SETUP_CCACHE],
[
AC_ARG_ENABLE([ccache],
--- a/common/autoconf/configure.ac Mon Dec 21 17:47:21 2015 +0100
+++ b/common/autoconf/configure.ac Wed Jul 05 21:09:54 2017 +0200
@@ -44,6 +44,7 @@
m4_include([build-performance.m4])
m4_include([flags.m4])
m4_include([help.m4])
+m4_include([hotspot.m4])
m4_include([jdk-options.m4])
m4_include([jdk-version.m4])
m4_include([libraries.m4])
@@ -94,9 +95,10 @@
# These are needed to be able to create a configuration name (and thus the output directory)
JDKOPT_SETUP_JDK_VARIANT
-JDKOPT_SETUP_JVM_INTERPRETER
-JDKOPT_SETUP_JVM_VARIANTS
+HOTSPOT_SETUP_JVM_INTERPRETER
+HOTSPOT_SETUP_JVM_VARIANTS
JDKOPT_SETUP_DEBUG_LEVEL
+HOTSPOT_SETUP_DEBUG_LEVEL
# With basic setup done, call the custom early hook.
CUSTOM_EARLY_HOOK
@@ -132,6 +134,7 @@
# We need build & target for this.
JDKOPT_SETUP_JDK_OPTIONS
+HOTSPOT_SETUP_HOTSPOT_OPTIONS
JDKVER_SETUP_JDK_VERSION_NUMBERS
###############################################################################
@@ -220,7 +223,7 @@
#
###############################################################################
-JDKOPT_SETUP_BUILD_TWEAKS
+HOTSPOT_SETUP_BUILD_TWEAKS
JDKOPT_DETECT_INTREE_EC
###############################################################################
@@ -233,6 +236,7 @@
BPERF_SETUP_BUILD_CORES
BPERF_SETUP_BUILD_MEMORY
BPERF_SETUP_BUILD_JOBS
+BPERF_SETUP_TEST_JOBS
# Setup arguments for the boot jdk (after cores and memory have been setup)
BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS
--- a/common/autoconf/flags.m4 Mon Dec 21 17:47:21 2015 +0100
+++ b/common/autoconf/flags.m4 Wed Jul 05 21:09:54 2017 +0200
@@ -120,13 +120,17 @@
AC_DEFUN_ONCE([FLAGS_SETUP_INIT_FLAGS],
[
- # Option used to tell the compiler whether to create 32- or 64-bit executables
+ # COMPILER_TARGET_BITS_FLAG : option for selecting 32- or 64-bit output
+ # COMPILER_COMMAND_FILE_FLAG : option for passing a command file to the compiler
if test "x$TOOLCHAIN_TYPE" = xxlc; then
COMPILER_TARGET_BITS_FLAG="-q"
+ COMPILER_COMMAND_FILE_FLAG="-f"
else
COMPILER_TARGET_BITS_FLAG="-m"
+ COMPILER_COMMAND_FILE_FLAG="@"
fi
AC_SUBST(COMPILER_TARGET_BITS_FLAG)
+ AC_SUBST(COMPILER_COMMAND_FILE_FLAG)
# FIXME: figure out if we should select AR flags depending on OS or toolchain.
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
@@ -226,37 +230,38 @@
else
SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG"
fi
- SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker @loader_path/.'
+ SET_EXECUTABLE_ORIGIN='-Wl,-rpath,@loader_path/.'
SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/[$]1'
+ SET_SHARED_LIBRARY_NAME='-Wl,-install_name,@rpath/[$]1'
SET_SHARED_LIBRARY_MAPFILE=''
else
# Default works for linux, might work on other platforms as well.
SHARED_LIBRARY_FLAGS='-shared'
- SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker \$$$$ORIGIN[$]1'
- SET_SHARED_LIBRARY_ORIGIN="-Xlinker -z -Xlinker origin $SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-Xlinker -soname=[$]1'
- SET_SHARED_LIBRARY_MAPFILE='-Xlinker -version-script=[$]1'
+ SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$$$ORIGIN[$]1'
+ SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
+ SET_SHARED_LIBRARY_NAME='-Wl,-soname=[$]1'
+ SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=[$]1'
fi
elif test "x$TOOLCHAIN_TYPE" = xclang; then
- PICFLAG=''
C_FLAG_REORDER=''
CXX_FLAG_REORDER=''
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
# Linking is different on MacOSX
+ PICFLAG=''
SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG"
- SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker @loader_path/.'
+ SET_EXECUTABLE_ORIGIN='-Wl,-rpath,@loader_path/.'
SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/[$]1'
+ SET_SHARED_LIBRARY_NAME='-Wl,-install_name,@rpath/[$]1'
SET_SHARED_LIBRARY_MAPFILE=''
else
# Default works for linux, might work on other platforms as well.
+ PICFLAG='-fPIC'
SHARED_LIBRARY_FLAGS='-shared'
- SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker \$$$$ORIGIN[$]1'
- SET_SHARED_LIBRARY_ORIGIN="-Xlinker -z -Xlinker origin $SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-Xlinker -soname=[$]1'
- SET_SHARED_LIBRARY_MAPFILE='-Xlinker -version-script=[$]1'
+ SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$$$ORIGIN[$]1'
+ SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
+ SET_SHARED_LIBRARY_NAME='-Wl,-soname=[$]1'
+ SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=[$]1'
fi
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
PICFLAG="-KPIC"
@@ -265,7 +270,7 @@
SHARED_LIBRARY_FLAGS="-G"
SET_EXECUTABLE_ORIGIN='-R\$$$$ORIGIN[$]1'
SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME=''
+ SET_SHARED_LIBRARY_NAME='-h [$]1'
SET_SHARED_LIBRARY_MAPFILE='-M[$]1'
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
PICFLAG="-qpic=large"
@@ -280,7 +285,7 @@
PICFLAG=""
C_FLAG_REORDER=''
CXX_FLAG_REORDER=''
- SHARED_LIBRARY_FLAGS="-LD"
+ SHARED_LIBRARY_FLAGS="-dll"
SET_EXECUTABLE_ORIGIN=''
SET_SHARED_LIBRARY_ORIGIN=''
SET_SHARED_LIBRARY_NAME=''
@@ -293,6 +298,7 @@
AC_SUBST(SET_SHARED_LIBRARY_ORIGIN)
AC_SUBST(SET_SHARED_LIBRARY_NAME)
AC_SUBST(SET_SHARED_LIBRARY_MAPFILE)
+ AC_SUBST(SHARED_LIBRARY_FLAGS)
if test "x$OPENJDK_TARGET_OS" = xsolaris; then
CFLAGS_JDK="${CFLAGS_JDK} -D__solaris__"
@@ -573,6 +579,25 @@
CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing"
;;
esac
+ elif test "x$TOOLCHAIN_TYPE" = xclang; then
+ if test "x$OPENJDK_TARGET_OS" = xlinux; then
+ if test "x$OPENJDK_TARGET_CPU" = xx86; then
+ # Force compatibility with i586 on 32 bit intel platforms.
+ COMMON_CCXXFLAGS="${COMMON_CCXXFLAGS} -march=i586"
+ fi
+ COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \
+ -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE"
+ case $OPENJDK_TARGET_CPU_ARCH in
+ ppc )
+ # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing
+ CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing"
+ ;;
+ * )
+ COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer"
+ CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing"
+ ;;
+ esac
+ fi
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK -DTRACING -DMACRO_MEMSYS_OPS -DBREAKPTS"
if test "x$OPENJDK_TARGET_CPU_ARCH" = xx86; then
@@ -748,17 +773,17 @@
# If this is a --hash-style=gnu system, use --hash-style=both, why?
# We have previously set HAS_GNU_HASH if this is the case
if test -n "$HAS_GNU_HASH"; then
- LDFLAGS_JDK="${LDFLAGS_JDK} -Xlinker --hash-style=both"
+ LDFLAGS_JDK="${LDFLAGS_JDK} -Wl,--hash-style=both"
fi
if test "x$OPENJDK_TARGET_OS" = xlinux; then
# And since we now know that the linker is gnu, then add -z defs, to forbid
# undefined symbols in object files.
- LDFLAGS_JDK="${LDFLAGS_JDK} -Xlinker -z -Xlinker defs"
+ LDFLAGS_JDK="${LDFLAGS_JDK} -Wl,-z,defs"
case $DEBUG_LEVEL in
release )
# tell linker to optimize libraries.
# Should this be supplied to the OSS linker as well?
- LDFLAGS_JDK="${LDFLAGS_JDK} -Xlinker -O1"
+ LDFLAGS_JDK="${LDFLAGS_JDK} -Wl,-O1"
;;
slowdebug )
if test "x$HAS_LINKER_NOW" = "xtrue"; then
@@ -785,7 +810,7 @@
esac
fi
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- LDFLAGS_JDK="$LDFLAGS_JDK -z defs -xildoff -ztext"
+ LDFLAGS_JDK="$LDFLAGS_JDK -Wl,-z,defs -xildoff -ztext"
LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK -norunpath -xnolib"
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
LDFLAGS_JDK="${LDFLAGS_JDK} -brtl -bnolibpath -bexpall -bernotok"
@@ -803,17 +828,19 @@
fi
LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE} /STACK:$LDFLAGS_STACK_SIZE"
elif test "x$OPENJDK_TARGET_OS" = xlinux; then
- LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Xlinker --allow-shlib-undefined"
+ LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Wl,--allow-shlib-undefined"
fi
# Customize LDFLAGS for libs
LDFLAGS_JDKLIB="${LDFLAGS_JDK}"
+ LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
- LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -dll -libpath:${OUTPUT_ROOT}/support/modules_libs/java.base"
+ LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \
+ -libpath:${OUTPUT_ROOT}/support/modules_libs/java.base"
JDKLIB_LIBS=""
else
- LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS} \
+ LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \
-L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}"
# On some platforms (mac) the linker warns about non existing -L dirs.
--- a/common/autoconf/generated-configure.sh Mon Dec 21 17:47:21 2015 +0100
+++ b/common/autoconf/generated-configure.sh Wed Jul 05 21:09:54 2017 +0200
@@ -646,11 +646,11 @@
JAVA_FLAGS_JAVAC
JAVA_FLAGS_BIG
JAVA_FLAGS
+TEST_JOBS
JOBS
MEMORY_SIZE
NUM_CORES
ENABLE_INTREE_EC
-SALIB_NAME
HOTSPOT_MAKE_ARGS
LIBZIP_CAN_USE_MMAP
LIBDL
@@ -729,6 +729,7 @@
CFLAGS_DEBUG_SYMBOLS
CXX_FLAG_DEPS
C_FLAG_DEPS
+SHARED_LIBRARY_FLAGS
SET_SHARED_LIBRARY_MAPFILE
SET_SHARED_LIBRARY_NAME
SET_SHARED_LIBRARY_ORIGIN
@@ -742,6 +743,7 @@
CC_OUT_OPTION
STRIPFLAGS
ARFLAGS
+COMPILER_COMMAND_FILE_FLAG
COMPILER_TARGET_BITS_FLAG
JT_HOME
JTREGEXE
@@ -753,6 +755,7 @@
HOTSPOT_RC
HOTSPOT_MT
BUILD_AS
+BUILD_LDCXX
BUILD_LD
BUILD_AR
BUILD_NM
@@ -799,6 +802,7 @@
PROPER_COMPILER_CC
TOOLCHAIN_PATH_CC
POTENTIAL_CC
+TOOLCHAIN_VERSION
VS_LIB
VS_INCLUDE
VS_PATH
@@ -857,11 +861,11 @@
PRODUCT_SUFFIX
PRODUCT_NAME
LAUNCHER_NAME
+TEST_IN_BUILD
COPYRIGHT_YEAR
COMPRESS_JARS
UNLIMITED_CRYPTO
CACERTS_FILE
-TEST_IN_BUILD
BUILD_HEADLESS
SUPPORT_HEADFUL
SUPPORT_HEADLESS
@@ -910,7 +914,6 @@
JVM_VARIANT_CORE
JVM_VARIANT_ZEROSHARK
JVM_VARIANT_ZERO
-JVM_VARIANT_KERNEL
JVM_VARIANT_MINIMAL1
JVM_VARIANT_CLIENT
JVM_VARIANT_SERVER
@@ -1073,10 +1076,10 @@
with_output_sync
with_default_make_target
enable_headful
-enable_hotspot_test_in_build
with_cacerts_file
enable_unlimited_crypto
with_copyright_year
+enable_hotspot_test_in_build
with_milestone
with_update_version
with_user_release_suffix
@@ -1142,6 +1145,7 @@
with_num_cores
with_memory_size
with_jobs
+with_test_jobs
with_boot_jdk_jvmargs
with_sjavac_server_java
enable_sjavac
@@ -1883,10 +1887,10 @@
--with-debug-level=fastdebug) [disabled]
--disable-headful disable building headful support (graphical UI
support) [enabled]
+ --enable-unlimited-crypto
+ Enable unlimited crypto policy [disabled]
--enable-hotspot-test-in-build
run the Queens test after Hotspot build [disabled]
- --enable-unlimited-crypto
- Enable unlimited crypto policy [disabled]
--enable-static-build enable static library build [disabled]
--disable-warnings-as-errors
do not consider native warnings to be an error
@@ -1923,8 +1927,7 @@
--with-jdk-variant JDK variant to build (normal) [normal]
--with-jvm-interpreter JVM interpreter to build (template, cpp) [template]
--with-jvm-variants JVM variants (separated by commas) to build (server,
- client, minimal1, kernel, zero, zeroshark, core)
- [server]
+ client, minimal1, zero, zeroshark, core) [server]
--with-debug-level set the debug level (release, fastdebug, slowdebug,
optimized (HotSpot build only)) [release]
--with-devkit use this devkit for compilers, tools and resources
@@ -2061,6 +2064,8 @@
--with-memory-size=1024 [probed]
--with-jobs number of parallel jobs to let make run [calculated
based on cores and memory]
+ --with-test-jobs number of parallel tests jobs to run [based on build
+ jobs]
--with-boot-jdk-jvmargs specify JVM arguments to be passed to all java
invocations of boot JDK, overriding the default
values, e.g --with-boot-jdk-jvmargs="-Xmx8G
@@ -3747,7 +3752,7 @@
#
-# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+# 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
@@ -3785,6 +3790,8 @@
+
+
################################################################################
#
# Optionally enable distributed compilation of native code using icecc/icecream
@@ -3939,7 +3946,11 @@
automatically build the freetype library into '<freetype_src>/lib64' for 64-bit
builds or into '<freetype_src>/lib32' for 32-bit builds.
Afterwards you can always use '--with-freetype-include=<freetype_src>/include'
-and '--with-freetype-lib=<freetype_src>/lib32|64' for other builds."
+and '--with-freetype-lib=<freetype_src>/lib32|64' for other builds.
+
+Alternatively you can unpack the sources like this to use the default directory:
+
+tar --one-top-level=$HOME/freetype --strip-components=1 -xzf freetype-2.5.3.tar.gz"
;;
esac
}
@@ -4037,13 +4048,80 @@
# questions.
#
-
-
-
-
-
-
-
+###############################################################################
+# Check which interpreter of the JVM we want to build.
+# Currently we have:
+# template: Template interpreter (the default)
+# cpp : C++ interpreter
+
+
+###############################################################################
+# Check which variants of the JVM that we want to build.
+# Currently we have:
+# server: normal interpreter and a C2 or tiered C1/C2 compiler
+# client: normal interpreter and C1 (no C2 compiler) (only 32-bit platforms)
+# minimal1: reduced form of client with optional VM services and features stripped out
+# zero: no machine code interpreter, no compiler
+# zeroshark: zero interpreter and shark/llvm compiler backend
+# core: interpreter only, no compiler (only works on some platforms)
+
+
+
+###############################################################################
+# Setup legacy vars/targets and new vars to deal with different debug levels.
+#
+# release: no debug information, all optimizations, no asserts.
+# optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'.
+# fastdebug: debug information (-g), all optimizations, all asserts
+# slowdebug: debug information (-g), no optimizations, all asserts
+#
+
+
+
+
+
+
+#
+# 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.
+#
+
+###############################################################################
+# Check which variant of the JDK that we want to build.
+# Currently we have:
+# normal: standard edition
+# but the custom make system may add other variants
+#
+# Effectively the JDK variant gives a name to a specific set of
+# modules to compile into the JDK.
+
+
+###############################################################################
+# Set the debug level
+# release: no debug information, all optimizations, no asserts.
+# optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'.
+# fastdebug: debug information (-g), all optimizations, all asserts
+# slowdebug: debug information (-g), no optimizations, all asserts
###############################################################################
@@ -4054,8 +4132,6 @@
-
-
###############################################################################
#
# Enable or disable the elliptic curve crypto implementation
@@ -4064,7 +4140,6 @@
-
################################################################################
#
# Gcov coverage data for hotspot
@@ -4078,8 +4153,6 @@
#
-
-
#
# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -4728,7 +4801,7 @@
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1449850507
+DATE_WHEN_GENERATED=1450277321
###############################################################################
#
@@ -15607,17 +15680,6 @@
# These are needed to be able to create a configuration name (and thus the output directory)
- ###############################################################################
- #
- # Check which variant of the JDK that we want to build.
- # Currently we have:
- # normal: standard edition
- # but the custom make system may add other variants
- #
- # Effectively the JDK variant gives a name to a specific set of
- # modules to compile into the JDK. In the future, these modules
- # might even be Jigsaw modules.
- #
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of the JDK to build" >&5
$as_echo_n "checking which variant of the JDK to build... " >&6; }
@@ -15639,14 +15701,6 @@
$as_echo "$JDK_VARIANT" >&6; }
-###############################################################################
-#
-# Check which interpreter of the JVM we want to build.
-# Currently we have:
-# template: Template interpreter (the default)
-# cpp : C++ interpreter
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which interpreter of the JVM to build" >&5
-$as_echo_n "checking which interpreter of the JVM to build... " >&6; }
# Check whether --with-jvm-interpreter was given.
if test "${with_jvm_interpreter+set}" = set; then :
@@ -15654,35 +15708,23 @@
fi
-if test "x$with_jvm_interpreter" = x; then
- with_jvm_interpreter="template"
-fi
-
-JVM_INTERPRETER="$with_jvm_interpreter"
-
-if test "x$JVM_INTERPRETER" != xtemplate && test "x$JVM_INTERPRETER" != xcpp; then
- as_fn_error $? "The available JVM interpreters are: template, cpp" "$LINENO" 5
-fi
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_jvm_interpreter" >&5
-$as_echo "$with_jvm_interpreter" >&6; }
-
-
-
- ###############################################################################
- #
- # Check which variants of the JVM that we want to build.
- # Currently we have:
- # server: normal interpreter and a tiered C1/C2 compiler
- # client: normal interpreter and C1 (no C2 compiler) (only 32-bit platforms)
- # minimal1: reduced form of client with optional VM services and features stripped out
- # kernel: kernel footprint JVM that passes the TCK without major performance problems,
- # ie normal interpreter and C1, only the serial GC, kernel jvmti etc
- # zero: no machine code interpreter, no compiler
- # zeroshark: zero interpreter and shark/llvm compiler backend
-# core: interpreter only, no compiler (only works on some platforms)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking which interpreter of the JVM to build" >&5
+$as_echo_n "checking which interpreter of the JVM to build... " >&6; }
+ if test "x$with_jvm_interpreter" = x; then
+ JVM_INTERPRETER="template"
+ else
+ JVM_INTERPRETER="$with_jvm_interpreter"
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JVM_INTERPRETER" >&5
+$as_echo "$JVM_INTERPRETER" >&6; }
+
+ if test "x$JVM_INTERPRETER" != xtemplate && test "x$JVM_INTERPRETER" != xcpp; then
+ as_fn_error $? "The available JVM interpreters are: template, cpp" "$LINENO" 5
+ fi
+
+
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which variants of the JVM to build" >&5
$as_echo_n "checking which variants of the JVM to build... " >&6; }
@@ -15697,10 +15739,10 @@
fi
JVM_VARIANTS=",$with_jvm_variants,"
- TEST_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,//' -e 's/client,//' -e 's/minimal1,//' -e 's/kernel,//' -e 's/zero,//' -e 's/zeroshark,//' -e 's/core,//'`
+ TEST_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,//' -e 's/client,//' -e 's/minimal1,//' -e 's/zero,//' -e 's/zeroshark,//' -e 's/core,//'`
if test "x$TEST_VARIANTS" != "x,"; then
- as_fn_error $? "The available JVM variants are: server, client, minimal1, kernel, zero, zeroshark, core" "$LINENO" 5
+ as_fn_error $? "The available JVM variants are: server, client, minimal1, zero, zeroshark, core" "$LINENO" 5
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_jvm_variants" >&5
$as_echo "$with_jvm_variants" >&6; }
@@ -15708,7 +15750,6 @@
JVM_VARIANT_SERVER=`$ECHO "$JVM_VARIANTS" | $SED -e '/,server,/!s/.*/false/g' -e '/,server,/s/.*/true/g'`
JVM_VARIANT_CLIENT=`$ECHO "$JVM_VARIANTS" | $SED -e '/,client,/!s/.*/false/g' -e '/,client,/s/.*/true/g'`
JVM_VARIANT_MINIMAL1=`$ECHO "$JVM_VARIANTS" | $SED -e '/,minimal1,/!s/.*/false/g' -e '/,minimal1,/s/.*/true/g'`
- JVM_VARIANT_KERNEL=`$ECHO "$JVM_VARIANTS" | $SED -e '/,kernel,/!s/.*/false/g' -e '/,kernel,/s/.*/true/g'`
JVM_VARIANT_ZERO=`$ECHO "$JVM_VARIANTS" | $SED -e '/,zero,/!s/.*/false/g' -e '/,zero,/s/.*/true/g'`
JVM_VARIANT_ZEROSHARK=`$ECHO "$JVM_VARIANTS" | $SED -e '/,zeroshark,/!s/.*/false/g' -e '/,zeroshark,/s/.*/true/g'`
JVM_VARIANT_CORE=`$ECHO "$JVM_VARIANTS" | $SED -e '/,core,/!s/.*/false/g' -e '/,core,/s/.*/true/g'`
@@ -15718,11 +15759,6 @@
as_fn_error $? "You cannot build a client JVM for a 64-bit machine." "$LINENO" 5
fi
fi
- if test "x$JVM_VARIANT_KERNEL" = xtrue; then
- if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
- as_fn_error $? "You cannot build a kernel JVM for a 64-bit machine." "$LINENO" 5
- fi
- fi
if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then
if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
as_fn_error $? "You cannot build a minimal JVM for a 64-bit machine." "$LINENO" 5
@@ -15731,13 +15767,16 @@
# Replace the commas with AND for use in the build directory name.
ANDED_JVM_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/^,//' -e 's/,$//' -e 's/,/AND/g'`
- COUNT_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,/1/' -e 's/client,/1/' -e 's/minimal1,/1/' -e 's/kernel,/1/' -e 's/zero,/1/' -e 's/zeroshark,/1/' -e 's/core,/1/'`
+ COUNT_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,/1/' -e 's/client,/1/' -e 's/minimal1,/1/' -e 's/zero,/1/' -e 's/zeroshark,/1/' -e 's/core,/1/'`
if test "x$COUNT_VARIANTS" != "x,1"; then
BUILDING_MULTIPLE_JVM_VARIANTS=yes
else
BUILDING_MULTIPLE_JVM_VARIANTS=no
fi
+ if test "x$JVM_VARIANT_ZERO" = xtrue && test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = xyes; then
+ as_fn_error $? "You cannot build multiple variants with zero." "$LINENO" 5
+ fi
@@ -15769,14 +15808,6 @@
- ###############################################################################
- #
- # Set the debug level
- # release: no debug information, all optimizations, no asserts.
- # optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'.
- # fastdebug: debug information (-g), all optimizations, all asserts
- # slowdebug: debug information (-g), no optimizations, all asserts
- #
DEBUG_LEVEL="release"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which debug level to use" >&5
$as_echo_n "checking which debug level to use... " >&6; }
@@ -15813,11 +15844,6 @@
fi
- ###############################################################################
- #
- # Setup legacy vars/targets and new vars to deal with different debug levels.
- #
-
case $DEBUG_LEVEL in
release )
VARIANT="OPT"
@@ -15887,10 +15913,6 @@
HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}minimal1 "
fi
- if test "x$JVM_VARIANT_KERNEL" = xtrue; then
- HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}kernel "
- fi
-
if test "x$JVM_VARIANT_ZERO" = xtrue; then
HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}zero "
fi
@@ -23122,12 +23144,8 @@
# We need build & target for this.
-
- ###############################################################################
- #
# Should we build a JDK/JVM with headful support (ie a graphical ui)?
# We always build headless support.
- #
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking headful support" >&5
$as_echo_n "checking headful support... " >&6; }
# Check whether --enable-headful was given.
@@ -23159,25 +23177,7 @@
- # Control wether Hotspot runs Queens test after build.
- # Check whether --enable-hotspot-test-in-build was given.
-if test "${enable_hotspot_test_in_build+set}" = set; then :
- enableval=$enable_hotspot_test_in_build;
-else
- enable_hotspot_test_in_build=no
-fi
-
- if test "x$enable_hotspot_test_in_build" = "xyes"; then
- TEST_IN_BUILD=true
- else
- TEST_IN_BUILD=false
- fi
-
-
- ###############################################################################
- #
# Choose cacerts source file
- #
# Check whether --with-cacerts-file was given.
if test "${with_cacerts_file+set}" = set; then :
@@ -23189,10 +23189,7 @@
fi
- ###############################################################################
- #
# Enable or disable unlimited crypto
- #
# Check whether --enable-unlimited-crypto was given.
if test "${enable_unlimited_crypto+set}" = set; then :
enableval=$enable_unlimited_crypto;
@@ -23207,10 +23204,7 @@
fi
- ###############################################################################
- #
# Compress jars
- #
COMPRESS_JARS=false
@@ -23232,6 +23226,22 @@
+ # Control wether Hotspot runs Queens test after build.
+ # Check whether --enable-hotspot-test-in-build was given.
+if test "${enable_hotspot_test_in_build+set}" = set; then :
+ enableval=$enable_hotspot_test_in_build;
+else
+ enable_hotspot_test_in_build=no
+fi
+
+ if test "x$enable_hotspot_test_in_build" = "xyes"; then
+ TEST_IN_BUILD=true
+ else
+ TEST_IN_BUILD=false
+ fi
+
+
+
# Warn user that old version arguments are deprecated.
@@ -31432,7 +31442,11 @@
# The microsoft toolchain also requires INCLUDE and LIB to be set.
export INCLUDE="$VS_INCLUDE"
export LIB="$VS_LIB"
- fi
+ else
+ # Currently we do not define this for other toolchains. This might change as the need arise.
+ TOOLCHAIN_VERSION=
+ fi
+
# For solaris we really need solaris tools, and not the GNU equivalent.
# The build tools on Solaris reside in /usr/ccs (C Compilation System),
@@ -45214,6 +45228,7 @@
BUILD_AS="$BUILD_CC -c"
# Just like for the target compiler, use the compiler as linker
BUILD_LD="$BUILD_CC"
+ BUILD_LDCXX="$BUILD_CXX"
PATH="$OLDPATH"
else
@@ -45222,6 +45237,7 @@
BUILD_CC="$CC"
BUILD_CXX="$CXX"
BUILD_LD="$LD"
+ BUILD_LDCXX="$LDCXX"
BUILD_NM="$NM"
BUILD_AS="$AS"
BUILD_SYSROOT_CFLAGS="$SYSROOT_CFLAGS"
@@ -45239,6 +45255,7 @@
+
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
# For hotspot, we need these in Windows mixed path,
# so rewrite them all. Need added .exe suffix.
@@ -45398,7 +45415,7 @@
# "-z relro" supported in GNU binutils 2.17 and later
- LINKER_RELRO_FLAG="-Xlinker -z -Xlinker relro"
+ LINKER_RELRO_FLAG="-Wl,-z,relro"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if linker supports \"$LINKER_RELRO_FLAG\"" >&5
$as_echo_n "checking if linker supports \"$LINKER_RELRO_FLAG\"... " >&6; }
@@ -45448,7 +45465,7 @@
# "-z now" supported in GNU binutils 2.11 and later
- LINKER_NOW_FLAG="-Xlinker -z -Xlinker now"
+ LINKER_NOW_FLAG="-Wl,-z,now"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if linker supports \"$LINKER_NOW_FLAG\"" >&5
$as_echo_n "checking if linker supports \"$LINKER_NOW_FLAG\"... " >&6; }
@@ -45506,7 +45523,7 @@
$as_echo_n "checking for broken SuSE 'ld' which only understands anonymous version tags in executables... " >&6; }
$ECHO "SUNWprivate_1.1 { local: *; };" > version-script.map
$ECHO "int main() { }" > main.c
- if $CXX -Xlinker -version-script=version-script.map main.c 2>&5 >&5; then
+ if $CXX -Wl,-version-script=version-script.map main.c 2>&5 >&5; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
USING_BROKEN_SUSE_LD=no
@@ -45905,12 +45922,16 @@
- # Option used to tell the compiler whether to create 32- or 64-bit executables
+ # COMPILER_TARGET_BITS_FLAG : option for selecting 32- or 64-bit output
+ # COMPILER_COMMAND_FILE_FLAG : option for passing a command file to the compiler
if test "x$TOOLCHAIN_TYPE" = xxlc; then
COMPILER_TARGET_BITS_FLAG="-q"
+ COMPILER_COMMAND_FILE_FLAG="-f"
else
COMPILER_TARGET_BITS_FLAG="-m"
- fi
+ COMPILER_COMMAND_FILE_FLAG="@"
+ fi
+
# FIXME: figure out if we should select AR flags depending on OS or toolchain.
@@ -46646,37 +46667,38 @@
else
SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG"
fi
- SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker @loader_path/.'
+ SET_EXECUTABLE_ORIGIN='-Wl,-rpath,@loader_path/.'
SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/$1'
+ SET_SHARED_LIBRARY_NAME='-Wl,-install_name,@rpath/$1'
SET_SHARED_LIBRARY_MAPFILE=''
else
# Default works for linux, might work on other platforms as well.
SHARED_LIBRARY_FLAGS='-shared'
- SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker \$$$$ORIGIN$1'
- SET_SHARED_LIBRARY_ORIGIN="-Xlinker -z -Xlinker origin $SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-Xlinker -soname=$1'
- SET_SHARED_LIBRARY_MAPFILE='-Xlinker -version-script=$1'
+ SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$$$ORIGIN$1'
+ SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
+ SET_SHARED_LIBRARY_NAME='-Wl,-soname=$1'
+ SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=$1'
fi
elif test "x$TOOLCHAIN_TYPE" = xclang; then
- PICFLAG=''
C_FLAG_REORDER=''
CXX_FLAG_REORDER=''
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
# Linking is different on MacOSX
+ PICFLAG=''
SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG"
- SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker @loader_path/.'
+ SET_EXECUTABLE_ORIGIN='-Wl,-rpath,@loader_path/.'
SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/$1'
+ SET_SHARED_LIBRARY_NAME='-Wl,-install_name,@rpath/$1'
SET_SHARED_LIBRARY_MAPFILE=''
else
# Default works for linux, might work on other platforms as well.
+ PICFLAG='-fPIC'
SHARED_LIBRARY_FLAGS='-shared'
- SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker \$$$$ORIGIN$1'
- SET_SHARED_LIBRARY_ORIGIN="-Xlinker -z -Xlinker origin $SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-Xlinker -soname=$1'
- SET_SHARED_LIBRARY_MAPFILE='-Xlinker -version-script=$1'
+ SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$$$ORIGIN$1'
+ SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
+ SET_SHARED_LIBRARY_NAME='-Wl,-soname=$1'
+ SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=$1'
fi
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
PICFLAG="-KPIC"
@@ -46685,7 +46707,7 @@
SHARED_LIBRARY_FLAGS="-G"
SET_EXECUTABLE_ORIGIN='-R\$$$$ORIGIN$1'
SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME=''
+ SET_SHARED_LIBRARY_NAME='-h $1'
SET_SHARED_LIBRARY_MAPFILE='-M$1'
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
PICFLAG="-qpic=large"
@@ -46700,7 +46722,7 @@
PICFLAG=""
C_FLAG_REORDER=''
CXX_FLAG_REORDER=''
- SHARED_LIBRARY_FLAGS="-LD"
+ SHARED_LIBRARY_FLAGS="-dll"
SET_EXECUTABLE_ORIGIN=''
SET_SHARED_LIBRARY_ORIGIN=''
SET_SHARED_LIBRARY_NAME=''
@@ -46714,6 +46736,7 @@
+
if test "x$OPENJDK_TARGET_OS" = xsolaris; then
CFLAGS_JDK="${CFLAGS_JDK} -D__solaris__"
CXXFLAGS_JDK="${CXXFLAGS_JDK} -D__solaris__"
@@ -47022,6 +47045,25 @@
CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing"
;;
esac
+ elif test "x$TOOLCHAIN_TYPE" = xclang; then
+ if test "x$OPENJDK_TARGET_OS" = xlinux; then
+ if test "x$OPENJDK_TARGET_CPU" = xx86; then
+ # Force compatibility with i586 on 32 bit intel platforms.
+ COMMON_CCXXFLAGS="${COMMON_CCXXFLAGS} -march=i586"
+ fi
+ COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \
+ -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE"
+ case $OPENJDK_TARGET_CPU_ARCH in
+ ppc )
+ # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing
+ CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing"
+ ;;
+ * )
+ COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer"
+ CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing"
+ ;;
+ esac
+ fi
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS $COMMON_CCXXFLAGS_JDK -DTRACING -DMACRO_MEMSYS_OPS -DBREAKPTS"
if test "x$OPENJDK_TARGET_CPU_ARCH" = xx86; then
@@ -47197,17 +47239,17 @@
# If this is a --hash-style=gnu system, use --hash-style=both, why?
# We have previously set HAS_GNU_HASH if this is the case
if test -n "$HAS_GNU_HASH"; then
- LDFLAGS_JDK="${LDFLAGS_JDK} -Xlinker --hash-style=both"
+ LDFLAGS_JDK="${LDFLAGS_JDK} -Wl,--hash-style=both"
fi
if test "x$OPENJDK_TARGET_OS" = xlinux; then
# And since we now know that the linker is gnu, then add -z defs, to forbid
# undefined symbols in object files.
- LDFLAGS_JDK="${LDFLAGS_JDK} -Xlinker -z -Xlinker defs"
+ LDFLAGS_JDK="${LDFLAGS_JDK} -Wl,-z,defs"
case $DEBUG_LEVEL in
release )
# tell linker to optimize libraries.
# Should this be supplied to the OSS linker as well?
- LDFLAGS_JDK="${LDFLAGS_JDK} -Xlinker -O1"
+ LDFLAGS_JDK="${LDFLAGS_JDK} -Wl,-O1"
;;
slowdebug )
if test "x$HAS_LINKER_NOW" = "xtrue"; then
@@ -47234,7 +47276,7 @@
esac
fi
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- LDFLAGS_JDK="$LDFLAGS_JDK -z defs -xildoff -ztext"
+ LDFLAGS_JDK="$LDFLAGS_JDK -Wl,-z,defs -xildoff -ztext"
LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK -norunpath -xnolib"
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
LDFLAGS_JDK="${LDFLAGS_JDK} -brtl -bnolibpath -bexpall -bernotok"
@@ -47252,17 +47294,19 @@
fi
LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE} /STACK:$LDFLAGS_STACK_SIZE"
elif test "x$OPENJDK_TARGET_OS" = xlinux; then
- LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Xlinker --allow-shlib-undefined"
+ LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Wl,--allow-shlib-undefined"
fi
# Customize LDFLAGS for libs
LDFLAGS_JDKLIB="${LDFLAGS_JDK}"
+ LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
- LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -dll -libpath:${OUTPUT_ROOT}/support/modules_libs/java.base"
+ LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \
+ -libpath:${OUTPUT_ROOT}/support/modules_libs/java.base"
JDKLIB_LIBS=""
else
- LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS} \
+ LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \
-L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}"
# On some platforms (mac) the linker warns about non existing -L dirs.
@@ -47657,8 +47701,21 @@
# Check whether --with-native-debug-symbols was given.
if test "${with_native_debug_symbols+set}" = set; then :
withval=$with_native_debug_symbols;
-else
- with_native_debug_symbols="zipped"
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ if test "x$withval" = xexternal || test "x$withval" = xzipped; then
+ as_fn_error $? "AIX only supports the parameters 'none' and 'internal' for --with-native-debug-symbols" "$LINENO" 5
+ fi
+ fi
+
+else
+
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ # AIX doesn't support 'zipped' so use 'internal' as default
+ with_native_debug_symbols="internal"
+ else
+ with_native_debug_symbols="zipped"
+ fi
+
fi
NATIVE_DEBUG_SYMBOLS=$with_native_debug_symbols
@@ -53467,6 +53524,1485 @@
fi
fi
+ if test "x$FOUND_FREETYPE" != xyes; then
+ FREETYPE_BASE_DIR="$HOME/freetype"
+
+ windows_path="$FREETYPE_BASE_DIR"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ unix_path=`$CYGPATH -u "$windows_path"`
+ FREETYPE_BASE_DIR="$unix_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+ FREETYPE_BASE_DIR="$unix_path"
+ fi
+
+ if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
+
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include"
+ POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib64"
+ METHOD="well-known location"
+
+ # Let's start with an optimistic view of the world :-)
+ FOUND_FREETYPE=yes
+
+ # First look for the canonical freetype main include file ft2build.h.
+ if ! test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then
+ # Oh no! Let's try in the freetype2 directory. This is needed at least at Mac OS X Yosemite.
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH/freetype2"
+ if ! test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then
+ # Fail.
+ FOUND_FREETYPE=no
+ fi
+ fi
+
+ if test "x$FOUND_FREETYPE" = xyes; then
+ # Include file found, let's continue the sanity check.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&5
+$as_echo "$as_me: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&6;}
+
+ # Reset to default value
+ FREETYPE_BASE_NAME=freetype
+ FREETYPE_LIB_NAME="${LIBRARY_PREFIX}${FREETYPE_BASE_NAME}${SHARED_LIBRARY_SUFFIX}"
+ if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then
+ if test "x$OPENJDK_TARGET_OS" = xmacosx \
+ && test -s "$POTENTIAL_FREETYPE_LIB_PATH/${LIBRARY_PREFIX}freetype.6${SHARED_LIBRARY_SUFFIX}"; then
+ # On Mac OS X Yosemite, the symlink from libfreetype.dylib to libfreetype.6.dylib disappeared. Check
+ # for the .6 version explicitly.
+ FREETYPE_BASE_NAME=freetype.6
+ FREETYPE_LIB_NAME="${LIBRARY_PREFIX}${FREETYPE_BASE_NAME}${SHARED_LIBRARY_SUFFIX}"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Compensating for missing symlink by using version 6 explicitly" >&5
+$as_echo "$as_me: Compensating for missing symlink by using version 6 explicitly" >&6;}
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&5
+$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&6;}
+ FOUND_FREETYPE=no
+ fi
+ else
+ if test "x$OPENJDK_TARGET_OS" = xwindows; then
+ # On Windows, we will need both .lib and .dll file.
+ if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib. Ignoring location." >&5
+$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib. Ignoring location." >&6;}
+ FOUND_FREETYPE=no
+ fi
+ elif test "x$OPENJDK_TARGET_OS" = xsolaris \
+ && test -s "$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR/$FREETYPE_LIB_NAME"; then
+ # Found lib in isa dir, use that instead.
+ POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead" >&5
+$as_echo "$as_me: Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead" >&6;}
+ fi
+ fi
+ fi
+
+ if test "x$FOUND_FREETYPE" = xyes; then
+
+ # Only process if variable expands to non-empty
+
+ if test "x$POTENTIAL_FREETYPE_INCLUDE_PATH" != x; then
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+ # Input might be given as Windows format, start by converting to
+ # unix format.
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ new_path=`$CYGPATH -u "$path"`
+
+ # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+ # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+ # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+ # "foo.exe" is OK but "foo" is an error.
+ #
+ # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # It is also a way to make sure we got the proper file name for the real test later on.
+ test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+ if test "x$test_shortpath" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_INCLUDE_PATH" "$LINENO" 5
+ fi
+
+ # Call helper function which possibly converts this using DOS-style short mode.
+ # If so, the updated path is stored in $new_path.
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+ path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+ if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+ # Going to short mode and back again did indeed matter. Since short mode is
+ # case insensitive, let's make it lowercase to improve readability.
+ shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Now convert it back to Unix-style (cygpath)
+ input_path=`$CYGPATH -u "$shortmode_path"`
+ new_path="$input_path"
+ fi
+ fi
+
+ test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+ if test "x$test_cygdrive_prefix" = x; then
+ # As a simple fix, exclude /usr/bin since it's not a real path.
+ if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+ # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+ # a path prefixed by /cygdrive for fixpath to work.
+ new_path="$CYGWIN_ROOT_PATH$input_path"
+ fi
+ fi
+
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;}
+ fi
+
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ has_colon=`$ECHO $path | $GREP ^.:`
+ new_path="$path"
+ if test "x$has_colon" = x; then
+ # Not in mixed or Windows style, start by that.
+ new_path=`cmd //c echo $path`
+ fi
+
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ fi
+
+
+ windows_path="$new_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ unix_path=`$CYGPATH -u "$windows_path"`
+ new_path="$unix_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+ new_path="$unix_path"
+ fi
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;}
+ fi
+
+ # Save the first 10 bytes of this path to the storage, so fixpath can work.
+ all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+ else
+ # We're on a unix platform. Hooray! :)
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ has_space=`$ECHO "$path" | $GREP " "`
+ if test "x$has_space" != x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+ fi
+
+ # Use eval to expand a potential ~
+ eval path="$path"
+ if test ! -f "$path" && test ! -d "$path"; then
+ as_fn_error $? "The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
+ fi
+
+ if test -d "$path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`"
+ else
+ dir="`$DIRNAME "$path"`"
+ base="`$BASENAME "$path"`"
+ POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$dir"; $THEPWDCMD -L`/$base"
+ fi
+ fi
+ fi
+
+
+ # Only process if variable expands to non-empty
+
+ if test "x$POTENTIAL_FREETYPE_LIB_PATH" != x; then
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+ # Input might be given as Windows format, start by converting to
+ # unix format.
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ new_path=`$CYGPATH -u "$path"`
+
+ # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+ # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+ # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+ # "foo.exe" is OK but "foo" is an error.
+ #
+ # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # It is also a way to make sure we got the proper file name for the real test later on.
+ test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+ if test "x$test_shortpath" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_LIB_PATH" "$LINENO" 5
+ fi
+
+ # Call helper function which possibly converts this using DOS-style short mode.
+ # If so, the updated path is stored in $new_path.
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+ path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+ if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+ # Going to short mode and back again did indeed matter. Since short mode is
+ # case insensitive, let's make it lowercase to improve readability.
+ shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Now convert it back to Unix-style (cygpath)
+ input_path=`$CYGPATH -u "$shortmode_path"`
+ new_path="$input_path"
+ fi
+ fi
+
+ test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+ if test "x$test_cygdrive_prefix" = x; then
+ # As a simple fix, exclude /usr/bin since it's not a real path.
+ if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+ # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+ # a path prefixed by /cygdrive for fixpath to work.
+ new_path="$CYGWIN_ROOT_PATH$input_path"
+ fi
+ fi
+
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;}
+ fi
+
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ has_colon=`$ECHO $path | $GREP ^.:`
+ new_path="$path"
+ if test "x$has_colon" = x; then
+ # Not in mixed or Windows style, start by that.
+ new_path=`cmd //c echo $path`
+ fi
+
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ fi
+
+
+ windows_path="$new_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ unix_path=`$CYGPATH -u "$windows_path"`
+ new_path="$unix_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+ new_path="$unix_path"
+ fi
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;}
+ fi
+
+ # Save the first 10 bytes of this path to the storage, so fixpath can work.
+ all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+ else
+ # We're on a unix platform. Hooray! :)
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ has_space=`$ECHO "$path" | $GREP " "`
+ if test "x$has_space" != x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+ fi
+
+ # Use eval to expand a potential ~
+ eval path="$path"
+ if test ! -f "$path" && test ! -d "$path"; then
+ as_fn_error $? "The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
+ fi
+
+ if test -d "$path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="`cd "$path"; $THEPWDCMD -L`"
+ else
+ dir="`$DIRNAME "$path"`"
+ base="`$BASENAME "$path"`"
+ POTENTIAL_FREETYPE_LIB_PATH="`cd "$dir"; $THEPWDCMD -L`/$base"
+ fi
+ fi
+ fi
+
+
+ FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype includes" >&5
+$as_echo_n "checking for freetype includes... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_INCLUDE_PATH" >&5
+$as_echo "$FREETYPE_INCLUDE_PATH" >&6; }
+ FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype libraries" >&5
+$as_echo_n "checking for freetype libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_LIB_PATH" >&5
+$as_echo "$FREETYPE_LIB_PATH" >&6; }
+ fi
+
+ else
+
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include"
+ POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib32"
+ METHOD="well-known location"
+
+ # Let's start with an optimistic view of the world :-)
+ FOUND_FREETYPE=yes
+
+ # First look for the canonical freetype main include file ft2build.h.
+ if ! test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then
+ # Oh no! Let's try in the freetype2 directory. This is needed at least at Mac OS X Yosemite.
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH/freetype2"
+ if ! test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then
+ # Fail.
+ FOUND_FREETYPE=no
+ fi
+ fi
+
+ if test "x$FOUND_FREETYPE" = xyes; then
+ # Include file found, let's continue the sanity check.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&5
+$as_echo "$as_me: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&6;}
+
+ # Reset to default value
+ FREETYPE_BASE_NAME=freetype
+ FREETYPE_LIB_NAME="${LIBRARY_PREFIX}${FREETYPE_BASE_NAME}${SHARED_LIBRARY_SUFFIX}"
+ if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then
+ if test "x$OPENJDK_TARGET_OS" = xmacosx \
+ && test -s "$POTENTIAL_FREETYPE_LIB_PATH/${LIBRARY_PREFIX}freetype.6${SHARED_LIBRARY_SUFFIX}"; then
+ # On Mac OS X Yosemite, the symlink from libfreetype.dylib to libfreetype.6.dylib disappeared. Check
+ # for the .6 version explicitly.
+ FREETYPE_BASE_NAME=freetype.6
+ FREETYPE_LIB_NAME="${LIBRARY_PREFIX}${FREETYPE_BASE_NAME}${SHARED_LIBRARY_SUFFIX}"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Compensating for missing symlink by using version 6 explicitly" >&5
+$as_echo "$as_me: Compensating for missing symlink by using version 6 explicitly" >&6;}
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&5
+$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&6;}
+ FOUND_FREETYPE=no
+ fi
+ else
+ if test "x$OPENJDK_TARGET_OS" = xwindows; then
+ # On Windows, we will need both .lib and .dll file.
+ if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib. Ignoring location." >&5
+$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib. Ignoring location." >&6;}
+ FOUND_FREETYPE=no
+ fi
+ elif test "x$OPENJDK_TARGET_OS" = xsolaris \
+ && test -s "$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR/$FREETYPE_LIB_NAME"; then
+ # Found lib in isa dir, use that instead.
+ POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead" >&5
+$as_echo "$as_me: Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead" >&6;}
+ fi
+ fi
+ fi
+
+ if test "x$FOUND_FREETYPE" = xyes; then
+
+ # Only process if variable expands to non-empty
+
+ if test "x$POTENTIAL_FREETYPE_INCLUDE_PATH" != x; then
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+ # Input might be given as Windows format, start by converting to
+ # unix format.
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ new_path=`$CYGPATH -u "$path"`
+
+ # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+ # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+ # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+ # "foo.exe" is OK but "foo" is an error.
+ #
+ # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # It is also a way to make sure we got the proper file name for the real test later on.
+ test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+ if test "x$test_shortpath" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_INCLUDE_PATH" "$LINENO" 5
+ fi
+
+ # Call helper function which possibly converts this using DOS-style short mode.
+ # If so, the updated path is stored in $new_path.
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+ path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+ if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+ # Going to short mode and back again did indeed matter. Since short mode is
+ # case insensitive, let's make it lowercase to improve readability.
+ shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Now convert it back to Unix-style (cygpath)
+ input_path=`$CYGPATH -u "$shortmode_path"`
+ new_path="$input_path"
+ fi
+ fi
+
+ test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+ if test "x$test_cygdrive_prefix" = x; then
+ # As a simple fix, exclude /usr/bin since it's not a real path.
+ if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+ # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+ # a path prefixed by /cygdrive for fixpath to work.
+ new_path="$CYGWIN_ROOT_PATH$input_path"
+ fi
+ fi
+
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;}
+ fi
+
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ has_colon=`$ECHO $path | $GREP ^.:`
+ new_path="$path"
+ if test "x$has_colon" = x; then
+ # Not in mixed or Windows style, start by that.
+ new_path=`cmd //c echo $path`
+ fi
+
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ fi
+
+
+ windows_path="$new_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ unix_path=`$CYGPATH -u "$windows_path"`
+ new_path="$unix_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+ new_path="$unix_path"
+ fi
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;}
+ fi
+
+ # Save the first 10 bytes of this path to the storage, so fixpath can work.
+ all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+ else
+ # We're on a unix platform. Hooray! :)
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ has_space=`$ECHO "$path" | $GREP " "`
+ if test "x$has_space" != x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+ fi
+
+ # Use eval to expand a potential ~
+ eval path="$path"
+ if test ! -f "$path" && test ! -d "$path"; then
+ as_fn_error $? "The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
+ fi
+
+ if test -d "$path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`"
+ else
+ dir="`$DIRNAME "$path"`"
+ base="`$BASENAME "$path"`"
+ POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$dir"; $THEPWDCMD -L`/$base"
+ fi
+ fi
+ fi
+
+
+ # Only process if variable expands to non-empty
+
+ if test "x$POTENTIAL_FREETYPE_LIB_PATH" != x; then
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+ # Input might be given as Windows format, start by converting to
+ # unix format.
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ new_path=`$CYGPATH -u "$path"`
+
+ # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+ # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+ # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+ # "foo.exe" is OK but "foo" is an error.
+ #
+ # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # It is also a way to make sure we got the proper file name for the real test later on.
+ test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+ if test "x$test_shortpath" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_LIB_PATH" "$LINENO" 5
+ fi
+
+ # Call helper function which possibly converts this using DOS-style short mode.
+ # If so, the updated path is stored in $new_path.
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+ path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+ if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+ # Going to short mode and back again did indeed matter. Since short mode is
+ # case insensitive, let's make it lowercase to improve readability.
+ shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Now convert it back to Unix-style (cygpath)
+ input_path=`$CYGPATH -u "$shortmode_path"`
+ new_path="$input_path"
+ fi
+ fi
+
+ test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+ if test "x$test_cygdrive_prefix" = x; then
+ # As a simple fix, exclude /usr/bin since it's not a real path.
+ if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+ # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+ # a path prefixed by /cygdrive for fixpath to work.
+ new_path="$CYGWIN_ROOT_PATH$input_path"
+ fi
+ fi
+
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;}
+ fi
+
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ has_colon=`$ECHO $path | $GREP ^.:`
+ new_path="$path"
+ if test "x$has_colon" = x; then
+ # Not in mixed or Windows style, start by that.
+ new_path=`cmd //c echo $path`
+ fi
+
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ fi
+
+
+ windows_path="$new_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ unix_path=`$CYGPATH -u "$windows_path"`
+ new_path="$unix_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+ new_path="$unix_path"
+ fi
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;}
+ fi
+
+ # Save the first 10 bytes of this path to the storage, so fixpath can work.
+ all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+ else
+ # We're on a unix platform. Hooray! :)
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ has_space=`$ECHO "$path" | $GREP " "`
+ if test "x$has_space" != x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+ fi
+
+ # Use eval to expand a potential ~
+ eval path="$path"
+ if test ! -f "$path" && test ! -d "$path"; then
+ as_fn_error $? "The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
+ fi
+
+ if test -d "$path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="`cd "$path"; $THEPWDCMD -L`"
+ else
+ dir="`$DIRNAME "$path"`"
+ base="`$BASENAME "$path"`"
+ POTENTIAL_FREETYPE_LIB_PATH="`cd "$dir"; $THEPWDCMD -L`/$base"
+ fi
+ fi
+ fi
+
+
+ FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype includes" >&5
+$as_echo_n "checking for freetype includes... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_INCLUDE_PATH" >&5
+$as_echo "$FREETYPE_INCLUDE_PATH" >&6; }
+ FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype libraries" >&5
+$as_echo_n "checking for freetype libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_LIB_PATH" >&5
+$as_echo "$FREETYPE_LIB_PATH" >&6; }
+ fi
+
+ fi
+ if test "x$FOUND_FREETYPE" != xyes && test -d $FREETYPE_BASE_DIR \
+ && test -s "$FREETYPE_BASE_DIR/builds/windows/vc2010/freetype.vcxproj" && test "x$MSBUILD" != x; then
+ # Source is available, as a last resort try to build freetype in default location
+
+ FREETYPE_SRC_PATH="$FREETYPE_BASE_DIR"
+ BUILD_FREETYPE=yes
+
+ # Check if the freetype sources are acessible..
+ if ! test -d $FREETYPE_SRC_PATH; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-freetype-src specified, but can not find path \"$FREETYPE_SRC_PATH\" - ignoring --with-freetype-src" >&5
+$as_echo "$as_me: WARNING: --with-freetype-src specified, but can not find path \"$FREETYPE_SRC_PATH\" - ignoring --with-freetype-src" >&2;}
+ BUILD_FREETYPE=no
+ fi
+ # ..and contain a vc2010 project file
+ vcxproj_path="$FREETYPE_SRC_PATH/builds/windows/vc2010/freetype.vcxproj"
+ if test "x$BUILD_FREETYPE" = xyes && ! test -s $vcxproj_path; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can not find project file $vcxproj_path (you may try a newer freetype version) - ignoring --with-freetype-src" >&5
+$as_echo "$as_me: WARNING: Can not find project file $vcxproj_path (you may try a newer freetype version) - ignoring --with-freetype-src" >&2;}
+ BUILD_FREETYPE=no
+ fi
+ # Now check if configure found a version of 'msbuild.exe'
+ if test "x$BUILD_FREETYPE" = xyes && test "x$MSBUILD" == x ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can not find an msbuild.exe executable (you may try to install .NET 4.0) - ignoring --with-freetype-src" >&5
+$as_echo "$as_me: WARNING: Can not find an msbuild.exe executable (you may try to install .NET 4.0) - ignoring --with-freetype-src" >&2;}
+ BUILD_FREETYPE=no
+ fi
+
+ # Ready to go..
+ if test "x$BUILD_FREETYPE" = xyes; then
+ # msbuild requires trailing slashes for output directories
+ freetype_lib_path="$FREETYPE_SRC_PATH/lib$OPENJDK_TARGET_CPU_BITS/"
+ freetype_lib_path_unix="$freetype_lib_path"
+ freetype_obj_path="$FREETYPE_SRC_PATH/obj$OPENJDK_TARGET_CPU_BITS/"
+
+ unix_path="$vcxproj_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ windows_path=`$CYGPATH -m "$unix_path"`
+ vcxproj_path="$windows_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ windows_path=`cmd //c echo $unix_path`
+ vcxproj_path="$windows_path"
+ fi
+
+
+ unix_path="$freetype_lib_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ windows_path=`$CYGPATH -m "$unix_path"`
+ freetype_lib_path="$windows_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ windows_path=`cmd //c echo $unix_path`
+ freetype_lib_path="$windows_path"
+ fi
+
+
+ unix_path="$freetype_obj_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ windows_path=`$CYGPATH -m "$unix_path"`
+ freetype_obj_path="$windows_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ windows_path=`cmd //c echo $unix_path`
+ freetype_obj_path="$windows_path"
+ fi
+
+ if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
+ freetype_platform=x64
+ else
+ freetype_platform=win32
+ fi
+
+ # The original freetype project file is for VS 2010 (i.e. 'v100'),
+ # so we have to adapt the toolset if building with any other toolsed (i.e. SDK).
+ # Currently 'PLATFORM_TOOLSET' is set in 'TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT'/
+ # 'TOOLCHAIN_CHECK_POSSIBLE_WIN_SDK_ROOT' in toolchain_windows.m4
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Trying to compile freetype sources with PlatformToolset=$PLATFORM_TOOLSET to $freetype_lib_path_unix ..." >&5
+$as_echo "$as_me: Trying to compile freetype sources with PlatformToolset=$PLATFORM_TOOLSET to $freetype_lib_path_unix ..." >&6;}
+
+ # First we try to build the freetype.dll
+ $ECHO -e "@echo off\n"\
+ "$MSBUILD $vcxproj_path "\
+ "/p:PlatformToolset=$PLATFORM_TOOLSET "\
+ "/p:Configuration=\"Release Multithreaded\" "\
+ "/p:Platform=$freetype_platform "\
+ "/p:ConfigurationType=DynamicLibrary "\
+ "/p:TargetName=freetype "\
+ "/p:OutDir=\"$freetype_lib_path\" "\
+ "/p:IntDir=\"$freetype_obj_path\" > freetype.log" > freetype.bat
+ cmd /c freetype.bat
+
+ if test -s "$freetype_lib_path_unix/freetype.dll"; then
+ # If that succeeds we also build freetype.lib
+ $ECHO -e "@echo off\n"\
+ "$MSBUILD $vcxproj_path "\
+ "/p:PlatformToolset=$PLATFORM_TOOLSET "\
+ "/p:Configuration=\"Release Multithreaded\" "\
+ "/p:Platform=$freetype_platform "\
+ "/p:ConfigurationType=StaticLibrary "\
+ "/p:TargetName=freetype "\
+ "/p:OutDir=\"$freetype_lib_path\" "\
+ "/p:IntDir=\"$freetype_obj_path\" >> freetype.log" > freetype.bat
+ cmd /c freetype.bat
+
+ if test -s "$freetype_lib_path_unix/freetype.lib"; then
+ # Once we build both, lib and dll, set freetype lib and include path appropriately
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_SRC_PATH/include"
+ POTENTIAL_FREETYPE_LIB_PATH="$freetype_lib_path_unix"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Compiling freetype sources succeeded! (see freetype.log for build results)" >&5
+$as_echo "$as_me: Compiling freetype sources succeeded! (see freetype.log for build results)" >&6;}
+ else
+ BUILD_FREETYPE=no
+ fi
+ else
+ BUILD_FREETYPE=no
+ fi
+ fi
+
+ if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
+
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include"
+ POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib64"
+ METHOD="well-known location"
+
+ # Let's start with an optimistic view of the world :-)
+ FOUND_FREETYPE=yes
+
+ # First look for the canonical freetype main include file ft2build.h.
+ if ! test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then
+ # Oh no! Let's try in the freetype2 directory. This is needed at least at Mac OS X Yosemite.
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH/freetype2"
+ if ! test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then
+ # Fail.
+ FOUND_FREETYPE=no
+ fi
+ fi
+
+ if test "x$FOUND_FREETYPE" = xyes; then
+ # Include file found, let's continue the sanity check.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&5
+$as_echo "$as_me: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&6;}
+
+ # Reset to default value
+ FREETYPE_BASE_NAME=freetype
+ FREETYPE_LIB_NAME="${LIBRARY_PREFIX}${FREETYPE_BASE_NAME}${SHARED_LIBRARY_SUFFIX}"
+ if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then
+ if test "x$OPENJDK_TARGET_OS" = xmacosx \
+ && test -s "$POTENTIAL_FREETYPE_LIB_PATH/${LIBRARY_PREFIX}freetype.6${SHARED_LIBRARY_SUFFIX}"; then
+ # On Mac OS X Yosemite, the symlink from libfreetype.dylib to libfreetype.6.dylib disappeared. Check
+ # for the .6 version explicitly.
+ FREETYPE_BASE_NAME=freetype.6
+ FREETYPE_LIB_NAME="${LIBRARY_PREFIX}${FREETYPE_BASE_NAME}${SHARED_LIBRARY_SUFFIX}"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Compensating for missing symlink by using version 6 explicitly" >&5
+$as_echo "$as_me: Compensating for missing symlink by using version 6 explicitly" >&6;}
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&5
+$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&6;}
+ FOUND_FREETYPE=no
+ fi
+ else
+ if test "x$OPENJDK_TARGET_OS" = xwindows; then
+ # On Windows, we will need both .lib and .dll file.
+ if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib. Ignoring location." >&5
+$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib. Ignoring location." >&6;}
+ FOUND_FREETYPE=no
+ fi
+ elif test "x$OPENJDK_TARGET_OS" = xsolaris \
+ && test -s "$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR/$FREETYPE_LIB_NAME"; then
+ # Found lib in isa dir, use that instead.
+ POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead" >&5
+$as_echo "$as_me: Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead" >&6;}
+ fi
+ fi
+ fi
+
+ if test "x$FOUND_FREETYPE" = xyes; then
+
+ # Only process if variable expands to non-empty
+
+ if test "x$POTENTIAL_FREETYPE_INCLUDE_PATH" != x; then
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+ # Input might be given as Windows format, start by converting to
+ # unix format.
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ new_path=`$CYGPATH -u "$path"`
+
+ # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+ # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+ # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+ # "foo.exe" is OK but "foo" is an error.
+ #
+ # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # It is also a way to make sure we got the proper file name for the real test later on.
+ test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+ if test "x$test_shortpath" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_INCLUDE_PATH" "$LINENO" 5
+ fi
+
+ # Call helper function which possibly converts this using DOS-style short mode.
+ # If so, the updated path is stored in $new_path.
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+ path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+ if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+ # Going to short mode and back again did indeed matter. Since short mode is
+ # case insensitive, let's make it lowercase to improve readability.
+ shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Now convert it back to Unix-style (cygpath)
+ input_path=`$CYGPATH -u "$shortmode_path"`
+ new_path="$input_path"
+ fi
+ fi
+
+ test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+ if test "x$test_cygdrive_prefix" = x; then
+ # As a simple fix, exclude /usr/bin since it's not a real path.
+ if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+ # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+ # a path prefixed by /cygdrive for fixpath to work.
+ new_path="$CYGWIN_ROOT_PATH$input_path"
+ fi
+ fi
+
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;}
+ fi
+
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ has_colon=`$ECHO $path | $GREP ^.:`
+ new_path="$path"
+ if test "x$has_colon" = x; then
+ # Not in mixed or Windows style, start by that.
+ new_path=`cmd //c echo $path`
+ fi
+
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ fi
+
+
+ windows_path="$new_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ unix_path=`$CYGPATH -u "$windows_path"`
+ new_path="$unix_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+ new_path="$unix_path"
+ fi
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;}
+ fi
+
+ # Save the first 10 bytes of this path to the storage, so fixpath can work.
+ all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+ else
+ # We're on a unix platform. Hooray! :)
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ has_space=`$ECHO "$path" | $GREP " "`
+ if test "x$has_space" != x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+ fi
+
+ # Use eval to expand a potential ~
+ eval path="$path"
+ if test ! -f "$path" && test ! -d "$path"; then
+ as_fn_error $? "The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
+ fi
+
+ if test -d "$path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`"
+ else
+ dir="`$DIRNAME "$path"`"
+ base="`$BASENAME "$path"`"
+ POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$dir"; $THEPWDCMD -L`/$base"
+ fi
+ fi
+ fi
+
+
+ # Only process if variable expands to non-empty
+
+ if test "x$POTENTIAL_FREETYPE_LIB_PATH" != x; then
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+ # Input might be given as Windows format, start by converting to
+ # unix format.
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ new_path=`$CYGPATH -u "$path"`
+
+ # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+ # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+ # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+ # "foo.exe" is OK but "foo" is an error.
+ #
+ # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # It is also a way to make sure we got the proper file name for the real test later on.
+ test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+ if test "x$test_shortpath" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_LIB_PATH" "$LINENO" 5
+ fi
+
+ # Call helper function which possibly converts this using DOS-style short mode.
+ # If so, the updated path is stored in $new_path.
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+ path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+ if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+ # Going to short mode and back again did indeed matter. Since short mode is
+ # case insensitive, let's make it lowercase to improve readability.
+ shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Now convert it back to Unix-style (cygpath)
+ input_path=`$CYGPATH -u "$shortmode_path"`
+ new_path="$input_path"
+ fi
+ fi
+
+ test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+ if test "x$test_cygdrive_prefix" = x; then
+ # As a simple fix, exclude /usr/bin since it's not a real path.
+ if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+ # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+ # a path prefixed by /cygdrive for fixpath to work.
+ new_path="$CYGWIN_ROOT_PATH$input_path"
+ fi
+ fi
+
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;}
+ fi
+
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ has_colon=`$ECHO $path | $GREP ^.:`
+ new_path="$path"
+ if test "x$has_colon" = x; then
+ # Not in mixed or Windows style, start by that.
+ new_path=`cmd //c echo $path`
+ fi
+
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ fi
+
+
+ windows_path="$new_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ unix_path=`$CYGPATH -u "$windows_path"`
+ new_path="$unix_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+ new_path="$unix_path"
+ fi
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;}
+ fi
+
+ # Save the first 10 bytes of this path to the storage, so fixpath can work.
+ all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+ else
+ # We're on a unix platform. Hooray! :)
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ has_space=`$ECHO "$path" | $GREP " "`
+ if test "x$has_space" != x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+ fi
+
+ # Use eval to expand a potential ~
+ eval path="$path"
+ if test ! -f "$path" && test ! -d "$path"; then
+ as_fn_error $? "The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
+ fi
+
+ if test -d "$path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="`cd "$path"; $THEPWDCMD -L`"
+ else
+ dir="`$DIRNAME "$path"`"
+ base="`$BASENAME "$path"`"
+ POTENTIAL_FREETYPE_LIB_PATH="`cd "$dir"; $THEPWDCMD -L`/$base"
+ fi
+ fi
+ fi
+
+
+ FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype includes" >&5
+$as_echo_n "checking for freetype includes... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_INCLUDE_PATH" >&5
+$as_echo "$FREETYPE_INCLUDE_PATH" >&6; }
+ FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype libraries" >&5
+$as_echo_n "checking for freetype libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_LIB_PATH" >&5
+$as_echo "$FREETYPE_LIB_PATH" >&6; }
+ fi
+
+ else
+
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include"
+ POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib32"
+ METHOD="well-known location"
+
+ # Let's start with an optimistic view of the world :-)
+ FOUND_FREETYPE=yes
+
+ # First look for the canonical freetype main include file ft2build.h.
+ if ! test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then
+ # Oh no! Let's try in the freetype2 directory. This is needed at least at Mac OS X Yosemite.
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH/freetype2"
+ if ! test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then
+ # Fail.
+ FOUND_FREETYPE=no
+ fi
+ fi
+
+ if test "x$FOUND_FREETYPE" = xyes; then
+ # Include file found, let's continue the sanity check.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&5
+$as_echo "$as_me: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&6;}
+
+ # Reset to default value
+ FREETYPE_BASE_NAME=freetype
+ FREETYPE_LIB_NAME="${LIBRARY_PREFIX}${FREETYPE_BASE_NAME}${SHARED_LIBRARY_SUFFIX}"
+ if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then
+ if test "x$OPENJDK_TARGET_OS" = xmacosx \
+ && test -s "$POTENTIAL_FREETYPE_LIB_PATH/${LIBRARY_PREFIX}freetype.6${SHARED_LIBRARY_SUFFIX}"; then
+ # On Mac OS X Yosemite, the symlink from libfreetype.dylib to libfreetype.6.dylib disappeared. Check
+ # for the .6 version explicitly.
+ FREETYPE_BASE_NAME=freetype.6
+ FREETYPE_LIB_NAME="${LIBRARY_PREFIX}${FREETYPE_BASE_NAME}${SHARED_LIBRARY_SUFFIX}"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Compensating for missing symlink by using version 6 explicitly" >&5
+$as_echo "$as_me: Compensating for missing symlink by using version 6 explicitly" >&6;}
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&5
+$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&6;}
+ FOUND_FREETYPE=no
+ fi
+ else
+ if test "x$OPENJDK_TARGET_OS" = xwindows; then
+ # On Windows, we will need both .lib and .dll file.
+ if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib. Ignoring location." >&5
+$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib. Ignoring location." >&6;}
+ FOUND_FREETYPE=no
+ fi
+ elif test "x$OPENJDK_TARGET_OS" = xsolaris \
+ && test -s "$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR/$FREETYPE_LIB_NAME"; then
+ # Found lib in isa dir, use that instead.
+ POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead" >&5
+$as_echo "$as_me: Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead" >&6;}
+ fi
+ fi
+ fi
+
+ if test "x$FOUND_FREETYPE" = xyes; then
+
+ # Only process if variable expands to non-empty
+
+ if test "x$POTENTIAL_FREETYPE_INCLUDE_PATH" != x; then
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+ # Input might be given as Windows format, start by converting to
+ # unix format.
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ new_path=`$CYGPATH -u "$path"`
+
+ # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+ # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+ # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+ # "foo.exe" is OK but "foo" is an error.
+ #
+ # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # It is also a way to make sure we got the proper file name for the real test later on.
+ test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+ if test "x$test_shortpath" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_INCLUDE_PATH" "$LINENO" 5
+ fi
+
+ # Call helper function which possibly converts this using DOS-style short mode.
+ # If so, the updated path is stored in $new_path.
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+ path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+ if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+ # Going to short mode and back again did indeed matter. Since short mode is
+ # case insensitive, let's make it lowercase to improve readability.
+ shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Now convert it back to Unix-style (cygpath)
+ input_path=`$CYGPATH -u "$shortmode_path"`
+ new_path="$input_path"
+ fi
+ fi
+
+ test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+ if test "x$test_cygdrive_prefix" = x; then
+ # As a simple fix, exclude /usr/bin since it's not a real path.
+ if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+ # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+ # a path prefixed by /cygdrive for fixpath to work.
+ new_path="$CYGWIN_ROOT_PATH$input_path"
+ fi
+ fi
+
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;}
+ fi
+
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ has_colon=`$ECHO $path | $GREP ^.:`
+ new_path="$path"
+ if test "x$has_colon" = x; then
+ # Not in mixed or Windows style, start by that.
+ new_path=`cmd //c echo $path`
+ fi
+
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ fi
+
+
+ windows_path="$new_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ unix_path=`$CYGPATH -u "$windows_path"`
+ new_path="$unix_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+ new_path="$unix_path"
+ fi
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;}
+ fi
+
+ # Save the first 10 bytes of this path to the storage, so fixpath can work.
+ all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+ else
+ # We're on a unix platform. Hooray! :)
+ path="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ has_space=`$ECHO "$path" | $GREP " "`
+ if test "x$has_space" != x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+ fi
+
+ # Use eval to expand a potential ~
+ eval path="$path"
+ if test ! -f "$path" && test ! -d "$path"; then
+ as_fn_error $? "The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
+ fi
+
+ if test -d "$path"; then
+ POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`"
+ else
+ dir="`$DIRNAME "$path"`"
+ base="`$BASENAME "$path"`"
+ POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$dir"; $THEPWDCMD -L`/$base"
+ fi
+ fi
+ fi
+
+
+ # Only process if variable expands to non-empty
+
+ if test "x$POTENTIAL_FREETYPE_LIB_PATH" != x; then
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+ # Input might be given as Windows format, start by converting to
+ # unix format.
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ new_path=`$CYGPATH -u "$path"`
+
+ # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+ # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+ # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+ # "foo.exe" is OK but "foo" is an error.
+ #
+ # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # It is also a way to make sure we got the proper file name for the real test later on.
+ test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+ if test "x$test_shortpath" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_LIB_PATH" "$LINENO" 5
+ fi
+
+ # Call helper function which possibly converts this using DOS-style short mode.
+ # If so, the updated path is stored in $new_path.
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+ path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+ if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+ # Going to short mode and back again did indeed matter. Since short mode is
+ # case insensitive, let's make it lowercase to improve readability.
+ shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Now convert it back to Unix-style (cygpath)
+ input_path=`$CYGPATH -u "$shortmode_path"`
+ new_path="$input_path"
+ fi
+ fi
+
+ test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+ if test "x$test_cygdrive_prefix" = x; then
+ # As a simple fix, exclude /usr/bin since it's not a real path.
+ if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+ # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+ # a path prefixed by /cygdrive for fixpath to work.
+ new_path="$CYGWIN_ROOT_PATH$input_path"
+ fi
+ fi
+
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;}
+ fi
+
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ has_colon=`$ECHO $path | $GREP ^.:`
+ new_path="$path"
+ if test "x$has_colon" = x; then
+ # Not in mixed or Windows style, start by that.
+ new_path=`cmd //c echo $path`
+ fi
+
+
+ input_path="$new_path"
+ # Check if we need to convert this using DOS-style short mode. If the path
+ # contains just simple characters, use it. Otherwise (spaces, weird characters),
+ # take no chances and rewrite it.
+ # Note: m4 eats our [], so we need to use [ and ] instead.
+ has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+ if test "x$has_forbidden_chars" != x; then
+ # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+ new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ fi
+
+
+ windows_path="$new_path"
+ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+ unix_path=`$CYGPATH -u "$windows_path"`
+ new_path="$unix_path"
+ elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+ unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+ new_path="$unix_path"
+ fi
+
+ if test "x$path" != "x$new_path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="$new_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;}
+ fi
+
+ # Save the first 10 bytes of this path to the storage, so fixpath can work.
+ all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+ else
+ # We're on a unix platform. Hooray! :)
+ path="$POTENTIAL_FREETYPE_LIB_PATH"
+ has_space=`$ECHO "$path" | $GREP " "`
+ if test "x$has_space" != x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
+ as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+ fi
+
+ # Use eval to expand a potential ~
+ eval path="$path"
+ if test ! -f "$path" && test ! -d "$path"; then
+ as_fn_error $? "The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
+ fi
+
+ if test -d "$path"; then
+ POTENTIAL_FREETYPE_LIB_PATH="`cd "$path"; $THEPWDCMD -L`"
+ else
+ dir="`$DIRNAME "$path"`"
+ base="`$BASENAME "$path"`"
+ POTENTIAL_FREETYPE_LIB_PATH="`cd "$dir"; $THEPWDCMD -L`/$base"
+ fi
+ fi
+ fi
+
+
+ FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype includes" >&5
+$as_echo_n "checking for freetype includes... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_INCLUDE_PATH" >&5
+$as_echo "$FREETYPE_INCLUDE_PATH" >&6; }
+ FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype libraries" >&5
+$as_echo_n "checking for freetype libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_LIB_PATH" >&5
+$as_echo "$FREETYPE_LIB_PATH" >&6; }
+ fi
+
+ fi
+ fi
+ fi
else
FREETYPE_BASE_DIR="$SYSROOT/usr"
@@ -57085,13 +58621,6 @@
HOTSPOT_MAKE_ARGS="$HOTSPOT_TARGET"
- # The name of the Service Agent jar.
- SALIB_NAME="${LIBRARY_PREFIX}saproc${SHARED_LIBRARY_SUFFIX}"
- if test "x$OPENJDK_TARGET_OS" = "xwindows"; then
- SALIB_NAME="${LIBRARY_PREFIX}sawindbg${SHARED_LIBRARY_SUFFIX}"
- fi
-
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if elliptic curve crypto implementation is present" >&5
$as_echo_n "checking if elliptic curve crypto implementation is present... " >&6; }
@@ -57253,6 +58782,21 @@
+ # The number of test jobs will be chosen automatically if TEST_JOBS is 0
+
+# Check whether --with-test-jobs was given.
+if test "${with_test_jobs+set}" = set; then :
+ withval=$with_test_jobs;
+fi
+
+ if test "x$with_test_jobs" = x; then
+ TEST_JOBS=0
+ else
+ TEST_JOBS=$with_test_jobs
+ fi
+
+
+
# Setup arguments for the boot jdk (after cores and memory have been setup)
##############################################################################
--- a/common/autoconf/help.m4 Mon Dec 21 17:47:21 2015 +0100
+++ b/common/autoconf/help.m4 Wed Jul 05 21:09:54 2017 +0200
@@ -86,7 +86,11 @@
automatically build the freetype library into '<freetype_src>/lib64' for 64-bit
builds or into '<freetype_src>/lib32' for 32-bit builds.
Afterwards you can always use '--with-freetype-include=<freetype_src>/include'
-and '--with-freetype-lib=<freetype_src>/lib[32|64]' for other builds."
+and '--with-freetype-lib=<freetype_src>/lib[32|64]' for other builds.
+
+Alternatively you can unpack the sources like this to use the default directory:
+
+tar --one-top-level=$HOME/freetype --strip-components=1 -xzf freetype-2.5.3.tar.gz"
;;
esac
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/common/autoconf/hotspot.m4 Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,268 @@
+#
+# 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.
+#
+
+###############################################################################
+# Check which interpreter of the JVM we want to build.
+# Currently we have:
+# template: Template interpreter (the default)
+# cpp : C++ interpreter
+AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_INTERPRETER],
+[
+ AC_ARG_WITH([jvm-interpreter], [AS_HELP_STRING([--with-jvm-interpreter],
+ [JVM interpreter to build (template, cpp) @<:@template@:>@])])
+
+ AC_MSG_CHECKING([which interpreter of the JVM to build])
+ if test "x$with_jvm_interpreter" = x; then
+ JVM_INTERPRETER="template"
+ else
+ JVM_INTERPRETER="$with_jvm_interpreter"
+ fi
+ AC_MSG_RESULT([$JVM_INTERPRETER])
+
+ if test "x$JVM_INTERPRETER" != xtemplate && test "x$JVM_INTERPRETER" != xcpp; then
+ AC_MSG_ERROR([The available JVM interpreters are: template, cpp])
+ fi
+
+ AC_SUBST(JVM_INTERPRETER)
+])
+
+###############################################################################
+# Check which variants of the JVM that we want to build.
+# Currently we have:
+# server: normal interpreter and a C2 or tiered C1/C2 compiler
+# client: normal interpreter and C1 (no C2 compiler) (only 32-bit platforms)
+# minimal1: reduced form of client with optional VM services and features stripped out
+# zero: no machine code interpreter, no compiler
+# zeroshark: zero interpreter and shark/llvm compiler backend
+# core: interpreter only, no compiler (only works on some platforms)
+AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_VARIANTS],
+[
+ AC_MSG_CHECKING([which variants of the JVM to build])
+ AC_ARG_WITH([jvm-variants], [AS_HELP_STRING([--with-jvm-variants],
+ [JVM variants (separated by commas) to build (server, client, minimal1, zero, zeroshark, core) @<:@server@:>@])])
+
+ if test "x$with_jvm_variants" = x; then
+ with_jvm_variants="server"
+ fi
+
+ JVM_VARIANTS=",$with_jvm_variants,"
+ TEST_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,//' -e 's/client,//' -e 's/minimal1,//' -e 's/zero,//' -e 's/zeroshark,//' -e 's/core,//'`
+
+ if test "x$TEST_VARIANTS" != "x,"; then
+ AC_MSG_ERROR([The available JVM variants are: server, client, minimal1, zero, zeroshark, core])
+ fi
+ AC_MSG_RESULT([$with_jvm_variants])
+
+ JVM_VARIANT_SERVER=`$ECHO "$JVM_VARIANTS" | $SED -e '/,server,/!s/.*/false/g' -e '/,server,/s/.*/true/g'`
+ JVM_VARIANT_CLIENT=`$ECHO "$JVM_VARIANTS" | $SED -e '/,client,/!s/.*/false/g' -e '/,client,/s/.*/true/g'`
+ JVM_VARIANT_MINIMAL1=`$ECHO "$JVM_VARIANTS" | $SED -e '/,minimal1,/!s/.*/false/g' -e '/,minimal1,/s/.*/true/g'`
+ JVM_VARIANT_ZERO=`$ECHO "$JVM_VARIANTS" | $SED -e '/,zero,/!s/.*/false/g' -e '/,zero,/s/.*/true/g'`
+ JVM_VARIANT_ZEROSHARK=`$ECHO "$JVM_VARIANTS" | $SED -e '/,zeroshark,/!s/.*/false/g' -e '/,zeroshark,/s/.*/true/g'`
+ JVM_VARIANT_CORE=`$ECHO "$JVM_VARIANTS" | $SED -e '/,core,/!s/.*/false/g' -e '/,core,/s/.*/true/g'`
+
+ if test "x$JVM_VARIANT_CLIENT" = xtrue; then
+ if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
+ AC_MSG_ERROR([You cannot build a client JVM for a 64-bit machine.])
+ fi
+ fi
+ if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then
+ if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
+ AC_MSG_ERROR([You cannot build a minimal JVM for a 64-bit machine.])
+ fi
+ fi
+
+ # Replace the commas with AND for use in the build directory name.
+ ANDED_JVM_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/^,//' -e 's/,$//' -e 's/,/AND/g'`
+ COUNT_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,/1/' -e 's/client,/1/' -e 's/minimal1,/1/' -e 's/zero,/1/' -e 's/zeroshark,/1/' -e 's/core,/1/'`
+ if test "x$COUNT_VARIANTS" != "x,1"; then
+ BUILDING_MULTIPLE_JVM_VARIANTS=yes
+ else
+ BUILDING_MULTIPLE_JVM_VARIANTS=no
+ fi
+
+ if test "x$JVM_VARIANT_ZERO" = xtrue && test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = xyes; then
+ AC_MSG_ERROR([You cannot build multiple variants with zero.])
+ fi
+
+ AC_SUBST(JVM_VARIANTS)
+ AC_SUBST(JVM_VARIANT_SERVER)
+ AC_SUBST(JVM_VARIANT_CLIENT)
+ AC_SUBST(JVM_VARIANT_MINIMAL1)
+ AC_SUBST(JVM_VARIANT_ZERO)
+ AC_SUBST(JVM_VARIANT_ZEROSHARK)
+ AC_SUBST(JVM_VARIANT_CORE)
+
+ INCLUDE_SA=true
+ if test "x$JVM_VARIANT_ZERO" = xtrue ; then
+ INCLUDE_SA=false
+ fi
+ if test "x$JVM_VARIANT_ZEROSHARK" = xtrue ; then
+ INCLUDE_SA=false
+ fi
+ if test "x$OPENJDK_TARGET_OS" = xaix ; then
+ INCLUDE_SA=false
+ fi
+ if test "x$OPENJDK_TARGET_CPU" = xaarch64; then
+ INCLUDE_SA=false
+ fi
+ AC_SUBST(INCLUDE_SA)
+
+ if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then
+ MACOSX_UNIVERSAL="true"
+ fi
+
+ AC_SUBST(MACOSX_UNIVERSAL)
+])
+
+
+###############################################################################
+# Setup legacy vars/targets and new vars to deal with different debug levels.
+#
+# release: no debug information, all optimizations, no asserts.
+# optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'.
+# fastdebug: debug information (-g), all optimizations, all asserts
+# slowdebug: debug information (-g), no optimizations, all asserts
+#
+AC_DEFUN_ONCE([HOTSPOT_SETUP_DEBUG_LEVEL],
+[
+ case $DEBUG_LEVEL in
+ release )
+ VARIANT="OPT"
+ FASTDEBUG="false"
+ DEBUG_CLASSFILES="false"
+ BUILD_VARIANT_RELEASE=""
+ HOTSPOT_DEBUG_LEVEL="product"
+ HOTSPOT_EXPORT="product"
+ ;;
+ fastdebug )
+ VARIANT="DBG"
+ FASTDEBUG="true"
+ DEBUG_CLASSFILES="true"
+ BUILD_VARIANT_RELEASE="-fastdebug"
+ HOTSPOT_DEBUG_LEVEL="fastdebug"
+ HOTSPOT_EXPORT="fastdebug"
+ ;;
+ slowdebug )
+ VARIANT="DBG"
+ FASTDEBUG="false"
+ DEBUG_CLASSFILES="true"
+ BUILD_VARIANT_RELEASE="-debug"
+ HOTSPOT_DEBUG_LEVEL="debug"
+ HOTSPOT_EXPORT="debug"
+ ;;
+ optimized )
+ VARIANT="OPT"
+ FASTDEBUG="false"
+ DEBUG_CLASSFILES="false"
+ BUILD_VARIANT_RELEASE="-optimized"
+ HOTSPOT_DEBUG_LEVEL="optimized"
+ HOTSPOT_EXPORT="optimized"
+ ;;
+ esac
+
+ # The debug level 'optimized' is a little special because it is currently only
+ # applicable to the HotSpot build where it means to build a completely
+ # optimized version of the VM without any debugging code (like for the
+ # 'release' debug level which is called 'product' in the HotSpot build) but
+ # with the exception that it can contain additional code which is otherwise
+ # protected by '#ifndef PRODUCT' macros. These 'optimized' builds are used to
+ # test new and/or experimental features which are not intended for customer
+ # shipment. Because these new features need to be tested and benchmarked in
+ # real world scenarios, we want to build the containing JDK at the 'release'
+ # debug level.
+ if test "x$DEBUG_LEVEL" = xoptimized; then
+ DEBUG_LEVEL="release"
+ fi
+
+ #####
+ # Generate the legacy makefile targets for hotspot.
+ # The hotspot api for selecting the build artifacts, really, needs to be improved.
+ # JDK-7195896 will fix this on the hotspot side by using the JVM_VARIANT_* variables to
+ # determine what needs to be built. All we will need to set here is all_product, all_fastdebug etc
+ # But until then ...
+ HOTSPOT_TARGET=""
+
+ if test "x$JVM_VARIANT_SERVER" = xtrue; then
+ HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL} "
+ fi
+
+ if test "x$JVM_VARIANT_CLIENT" = xtrue; then
+ HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}1 "
+ fi
+
+ if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then
+ HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}minimal1 "
+ fi
+
+ if test "x$JVM_VARIANT_ZERO" = xtrue; then
+ HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}zero "
+ fi
+
+ if test "x$JVM_VARIANT_ZEROSHARK" = xtrue; then
+ HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}shark "
+ fi
+
+ if test "x$JVM_VARIANT_CORE" = xtrue; then
+ HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}core "
+ fi
+
+ HOTSPOT_TARGET="$HOTSPOT_TARGET docs export_$HOTSPOT_EXPORT"
+
+ # On Macosx universal binaries are produced, but they only contain
+ # 64 bit intel. This invalidates control of which jvms are built
+ # from configure, but only server is valid anyway. Fix this
+ # when hotspot makefiles are rewritten.
+ if test "x$MACOSX_UNIVERSAL" = xtrue; then
+ HOTSPOT_TARGET=universal_${HOTSPOT_EXPORT}
+ fi
+
+ #####
+
+ AC_SUBST(DEBUG_LEVEL)
+ AC_SUBST(VARIANT)
+ AC_SUBST(FASTDEBUG)
+ AC_SUBST(DEBUG_CLASSFILES)
+ AC_SUBST(BUILD_VARIANT_RELEASE)
+])
+
+AC_DEFUN_ONCE([HOTSPOT_SETUP_HOTSPOT_OPTIONS],
+[
+ # Control wether Hotspot runs Queens test after build.
+ AC_ARG_ENABLE([hotspot-test-in-build], [AS_HELP_STRING([--enable-hotspot-test-in-build],
+ [run the Queens test after Hotspot build @<:@disabled@:>@])],,
+ [enable_hotspot_test_in_build=no])
+ if test "x$enable_hotspot_test_in_build" = "xyes"; then
+ TEST_IN_BUILD=true
+ else
+ TEST_IN_BUILD=false
+ fi
+ AC_SUBST(TEST_IN_BUILD)
+])
+
+AC_DEFUN_ONCE([HOTSPOT_SETUP_BUILD_TWEAKS],
+[
+ HOTSPOT_MAKE_ARGS="$HOTSPOT_TARGET"
+ AC_SUBST(HOTSPOT_MAKE_ARGS)
+])
--- a/common/autoconf/jdk-options.m4 Mon Dec 21 17:47:21 2015 +0100
+++ b/common/autoconf/jdk-options.m4 Wed Jul 05 21:09:54 2017 +0200
@@ -23,19 +23,16 @@
# questions.
#
+###############################################################################
+# Check which variant of the JDK that we want to build.
+# Currently we have:
+# normal: standard edition
+# but the custom make system may add other variants
+#
+# Effectively the JDK variant gives a name to a specific set of
+# modules to compile into the JDK.
AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_VARIANT],
[
- ###############################################################################
- #
- # Check which variant of the JDK that we want to build.
- # Currently we have:
- # normal: standard edition
- # but the custom make system may add other variants
- #
- # Effectively the JDK variant gives a name to a specific set of
- # modules to compile into the JDK. In the future, these modules
- # might even be Jigsaw modules.
- #
AC_MSG_CHECKING([which variant of the JDK to build])
AC_ARG_WITH([jdk-variant], [AS_HELP_STRING([--with-jdk-variant],
[JDK variant to build (normal) @<:@normal@:>@])])
@@ -51,138 +48,14 @@
AC_MSG_RESULT([$JDK_VARIANT])
])
-AC_DEFUN_ONCE([JDKOPT_SETUP_JVM_INTERPRETER],
-[
###############################################################################
-#
-# Check which interpreter of the JVM we want to build.
-# Currently we have:
-# template: Template interpreter (the default)
-# cpp : C++ interpreter
-AC_MSG_CHECKING([which interpreter of the JVM to build])
-AC_ARG_WITH([jvm-interpreter], [AS_HELP_STRING([--with-jvm-interpreter],
- [JVM interpreter to build (template, cpp) @<:@template@:>@])])
-
-if test "x$with_jvm_interpreter" = x; then
- with_jvm_interpreter="template"
-fi
-
-JVM_INTERPRETER="$with_jvm_interpreter"
-
-if test "x$JVM_INTERPRETER" != xtemplate && test "x$JVM_INTERPRETER" != xcpp; then
- AC_MSG_ERROR([The available JVM interpreters are: template, cpp])
-fi
-
-AC_SUBST(JVM_INTERPRETER)
-
-AC_MSG_RESULT([$with_jvm_interpreter])
-])
-
-AC_DEFUN_ONCE([JDKOPT_SETUP_JVM_VARIANTS],
-[
-
- ###############################################################################
- #
- # Check which variants of the JVM that we want to build.
- # Currently we have:
- # server: normal interpreter and a tiered C1/C2 compiler
- # client: normal interpreter and C1 (no C2 compiler) (only 32-bit platforms)
- # minimal1: reduced form of client with optional VM services and features stripped out
- # kernel: kernel footprint JVM that passes the TCK without major performance problems,
- # ie normal interpreter and C1, only the serial GC, kernel jvmti etc
- # zero: no machine code interpreter, no compiler
- # zeroshark: zero interpreter and shark/llvm compiler backend
-# core: interpreter only, no compiler (only works on some platforms)
- AC_MSG_CHECKING([which variants of the JVM to build])
- AC_ARG_WITH([jvm-variants], [AS_HELP_STRING([--with-jvm-variants],
- [JVM variants (separated by commas) to build (server, client, minimal1, kernel, zero, zeroshark, core) @<:@server@:>@])])
-
- if test "x$with_jvm_variants" = x; then
- with_jvm_variants="server"
- fi
-
- JVM_VARIANTS=",$with_jvm_variants,"
- TEST_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,//' -e 's/client,//' -e 's/minimal1,//' -e 's/kernel,//' -e 's/zero,//' -e 's/zeroshark,//' -e 's/core,//'`
-
- if test "x$TEST_VARIANTS" != "x,"; then
- AC_MSG_ERROR([The available JVM variants are: server, client, minimal1, kernel, zero, zeroshark, core])
- fi
- AC_MSG_RESULT([$with_jvm_variants])
-
- JVM_VARIANT_SERVER=`$ECHO "$JVM_VARIANTS" | $SED -e '/,server,/!s/.*/false/g' -e '/,server,/s/.*/true/g'`
- JVM_VARIANT_CLIENT=`$ECHO "$JVM_VARIANTS" | $SED -e '/,client,/!s/.*/false/g' -e '/,client,/s/.*/true/g'`
- JVM_VARIANT_MINIMAL1=`$ECHO "$JVM_VARIANTS" | $SED -e '/,minimal1,/!s/.*/false/g' -e '/,minimal1,/s/.*/true/g'`
- JVM_VARIANT_KERNEL=`$ECHO "$JVM_VARIANTS" | $SED -e '/,kernel,/!s/.*/false/g' -e '/,kernel,/s/.*/true/g'`
- JVM_VARIANT_ZERO=`$ECHO "$JVM_VARIANTS" | $SED -e '/,zero,/!s/.*/false/g' -e '/,zero,/s/.*/true/g'`
- JVM_VARIANT_ZEROSHARK=`$ECHO "$JVM_VARIANTS" | $SED -e '/,zeroshark,/!s/.*/false/g' -e '/,zeroshark,/s/.*/true/g'`
- JVM_VARIANT_CORE=`$ECHO "$JVM_VARIANTS" | $SED -e '/,core,/!s/.*/false/g' -e '/,core,/s/.*/true/g'`
-
- if test "x$JVM_VARIANT_CLIENT" = xtrue; then
- if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
- AC_MSG_ERROR([You cannot build a client JVM for a 64-bit machine.])
- fi
- fi
- if test "x$JVM_VARIANT_KERNEL" = xtrue; then
- if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
- AC_MSG_ERROR([You cannot build a kernel JVM for a 64-bit machine.])
- fi
- fi
- if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then
- if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
- AC_MSG_ERROR([You cannot build a minimal JVM for a 64-bit machine.])
- fi
- fi
-
- # Replace the commas with AND for use in the build directory name.
- ANDED_JVM_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/^,//' -e 's/,$//' -e 's/,/AND/g'`
- COUNT_VARIANTS=`$ECHO "$JVM_VARIANTS" | $SED -e 's/server,/1/' -e 's/client,/1/' -e 's/minimal1,/1/' -e 's/kernel,/1/' -e 's/zero,/1/' -e 's/zeroshark,/1/' -e 's/core,/1/'`
- if test "x$COUNT_VARIANTS" != "x,1"; then
- BUILDING_MULTIPLE_JVM_VARIANTS=yes
- else
- BUILDING_MULTIPLE_JVM_VARIANTS=no
- fi
-
- AC_SUBST(JVM_VARIANTS)
- AC_SUBST(JVM_VARIANT_SERVER)
- AC_SUBST(JVM_VARIANT_CLIENT)
- AC_SUBST(JVM_VARIANT_MINIMAL1)
- AC_SUBST(JVM_VARIANT_KERNEL)
- AC_SUBST(JVM_VARIANT_ZERO)
- AC_SUBST(JVM_VARIANT_ZEROSHARK)
- AC_SUBST(JVM_VARIANT_CORE)
-
- INCLUDE_SA=true
- if test "x$JVM_VARIANT_ZERO" = xtrue ; then
- INCLUDE_SA=false
- fi
- if test "x$JVM_VARIANT_ZEROSHARK" = xtrue ; then
- INCLUDE_SA=false
- fi
- if test "x$OPENJDK_TARGET_OS" = xaix ; then
- INCLUDE_SA=false
- fi
- if test "x$OPENJDK_TARGET_CPU" = xaarch64; then
- INCLUDE_SA=false
- fi
- AC_SUBST(INCLUDE_SA)
-
- if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then
- MACOSX_UNIVERSAL="true"
- fi
-
- AC_SUBST(MACOSX_UNIVERSAL)
-])
-
+# Set the debug level
+# release: no debug information, all optimizations, no asserts.
+# optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'.
+# fastdebug: debug information (-g), all optimizations, all asserts
+# slowdebug: debug information (-g), no optimizations, all asserts
AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL],
[
- ###############################################################################
- #
- # Set the debug level
- # release: no debug information, all optimizations, no asserts.
- # optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'.
- # fastdebug: debug information (-g), all optimizations, all asserts
- # slowdebug: debug information (-g), no optimizations, all asserts
- #
DEBUG_LEVEL="release"
AC_MSG_CHECKING([which debug level to use])
AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug],
@@ -208,118 +81,8 @@
test "x$DEBUG_LEVEL" != xslowdebug; then
AC_MSG_ERROR([Allowed debug levels are: release, fastdebug and slowdebug])
fi
-
-
- ###############################################################################
- #
- # Setup legacy vars/targets and new vars to deal with different debug levels.
- #
-
- case $DEBUG_LEVEL in
- release )
- VARIANT="OPT"
- FASTDEBUG="false"
- DEBUG_CLASSFILES="false"
- BUILD_VARIANT_RELEASE=""
- HOTSPOT_DEBUG_LEVEL="product"
- HOTSPOT_EXPORT="product"
- ;;
- fastdebug )
- VARIANT="DBG"
- FASTDEBUG="true"
- DEBUG_CLASSFILES="true"
- BUILD_VARIANT_RELEASE="-fastdebug"
- HOTSPOT_DEBUG_LEVEL="fastdebug"
- HOTSPOT_EXPORT="fastdebug"
- ;;
- slowdebug )
- VARIANT="DBG"
- FASTDEBUG="false"
- DEBUG_CLASSFILES="true"
- BUILD_VARIANT_RELEASE="-debug"
- HOTSPOT_DEBUG_LEVEL="debug"
- HOTSPOT_EXPORT="debug"
- ;;
- optimized )
- VARIANT="OPT"
- FASTDEBUG="false"
- DEBUG_CLASSFILES="false"
- BUILD_VARIANT_RELEASE="-optimized"
- HOTSPOT_DEBUG_LEVEL="optimized"
- HOTSPOT_EXPORT="optimized"
- ;;
- esac
-
- # The debug level 'optimized' is a little special because it is currently only
- # applicable to the HotSpot build where it means to build a completely
- # optimized version of the VM without any debugging code (like for the
- # 'release' debug level which is called 'product' in the HotSpot build) but
- # with the exception that it can contain additional code which is otherwise
- # protected by '#ifndef PRODUCT' macros. These 'optimized' builds are used to
- # test new and/or experimental features which are not intended for customer
- # shipment. Because these new features need to be tested and benchmarked in
- # real world scenarios, we want to build the containing JDK at the 'release'
- # debug level.
- if test "x$DEBUG_LEVEL" = xoptimized; then
- DEBUG_LEVEL="release"
- fi
-
- #####
- # Generate the legacy makefile targets for hotspot.
- # The hotspot api for selecting the build artifacts, really, needs to be improved.
- # JDK-7195896 will fix this on the hotspot side by using the JVM_VARIANT_* variables to
- # determine what needs to be built. All we will need to set here is all_product, all_fastdebug etc
- # But until then ...
- HOTSPOT_TARGET=""
-
- if test "x$JVM_VARIANT_SERVER" = xtrue; then
- HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL} "
- fi
-
- if test "x$JVM_VARIANT_CLIENT" = xtrue; then
- HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}1 "
- fi
-
- if test "x$JVM_VARIANT_MINIMAL1" = xtrue; then
- HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}minimal1 "
- fi
-
- if test "x$JVM_VARIANT_KERNEL" = xtrue; then
- HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}kernel "
- fi
-
- if test "x$JVM_VARIANT_ZERO" = xtrue; then
- HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}zero "
- fi
-
- if test "x$JVM_VARIANT_ZEROSHARK" = xtrue; then
- HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}shark "
- fi
-
- if test "x$JVM_VARIANT_CORE" = xtrue; then
- HOTSPOT_TARGET="$HOTSPOT_TARGET${HOTSPOT_DEBUG_LEVEL}core "
- fi
-
- HOTSPOT_TARGET="$HOTSPOT_TARGET docs export_$HOTSPOT_EXPORT"
-
- # On Macosx universal binaries are produced, but they only contain
- # 64 bit intel. This invalidates control of which jvms are built
- # from configure, but only server is valid anyway. Fix this
- # when hotspot makefiles are rewritten.
- if test "x$MACOSX_UNIVERSAL" = xtrue; then
- HOTSPOT_TARGET=universal_${HOTSPOT_EXPORT}
- fi
-
- #####
-
- AC_SUBST(DEBUG_LEVEL)
- AC_SUBST(VARIANT)
- AC_SUBST(FASTDEBUG)
- AC_SUBST(DEBUG_CLASSFILES)
- AC_SUBST(BUILD_VARIANT_RELEASE)
])
-
###############################################################################
#
# Should we build only OpenJDK even if closed sources are present?
@@ -367,12 +130,8 @@
AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS],
[
-
- ###############################################################################
- #
# Should we build a JDK/JVM with headful support (ie a graphical ui)?
# We always build headless support.
- #
AC_MSG_CHECKING([headful support])
AC_ARG_ENABLE([headful], [AS_HELP_STRING([--disable-headful],
[disable building headful support (graphical UI support) @<:@enabled@:>@])],
@@ -398,21 +157,7 @@
AC_SUBST(SUPPORT_HEADFUL)
AC_SUBST(BUILD_HEADLESS)
- # Control wether Hotspot runs Queens test after build.
- AC_ARG_ENABLE([hotspot-test-in-build], [AS_HELP_STRING([--enable-hotspot-test-in-build],
- [run the Queens test after Hotspot build @<:@disabled@:>@])],,
- [enable_hotspot_test_in_build=no])
- if test "x$enable_hotspot_test_in_build" = "xyes"; then
- TEST_IN_BUILD=true
- else
- TEST_IN_BUILD=false
- fi
- AC_SUBST(TEST_IN_BUILD)
-
- ###############################################################################
- #
# Choose cacerts source file
- #
AC_ARG_WITH(cacerts-file, [AS_HELP_STRING([--with-cacerts-file],
[specify alternative cacerts file])])
if test "x$with_cacerts_file" != x; then
@@ -420,10 +165,7 @@
fi
AC_SUBST(CACERTS_FILE)
- ###############################################################################
- #
# Enable or disable unlimited crypto
- #
AC_ARG_ENABLE(unlimited-crypto, [AS_HELP_STRING([--enable-unlimited-crypto],
[Enable unlimited crypto policy @<:@disabled@:>@])],,
[enable_unlimited_crypto=no])
@@ -434,10 +176,7 @@
fi
AC_SUBST(UNLIMITED_CRYPTO)
- ###############################################################################
- #
# Compress jars
- #
COMPRESS_JARS=false
AC_SUBST(COMPRESS_JARS)
@@ -455,19 +194,6 @@
AC_SUBST(COPYRIGHT_YEAR)
])
-AC_DEFUN_ONCE([JDKOPT_SETUP_BUILD_TWEAKS],
-[
- HOTSPOT_MAKE_ARGS="$HOTSPOT_TARGET"
- AC_SUBST(HOTSPOT_MAKE_ARGS)
-
- # The name of the Service Agent jar.
- SALIB_NAME="${LIBRARY_PREFIX}saproc${SHARED_LIBRARY_SUFFIX}"
- if test "x$OPENJDK_TARGET_OS" = "xwindows"; then
- SALIB_NAME="${LIBRARY_PREFIX}sawindbg${SHARED_LIBRARY_SUFFIX}"
- fi
- AC_SUBST(SALIB_NAME)
-])
-
###############################################################################
#
# Enable or disable the elliptic curve crypto implementation
@@ -487,7 +213,6 @@
AC_SUBST(ENABLE_INTREE_EC)
])
-
AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
[
#
@@ -498,8 +223,21 @@
AC_ARG_WITH([native-debug-symbols],
[AS_HELP_STRING([--with-native-debug-symbols],
[set the native debug symbol configuration (none, internal, external, zipped) @<:@zipped@:>@])],
- [],
- [with_native_debug_symbols="zipped"])
+ [
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ if test "x$withval" = xexternal || test "x$withval" = xzipped; then
+ AC_MSG_ERROR([AIX only supports the parameters 'none' and 'internal' for --with-native-debug-symbols])
+ fi
+ fi
+ ],
+ [
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ # AIX doesn't support 'zipped' so use 'internal' as default
+ with_native_debug_symbols="internal"
+ else
+ with_native_debug_symbols="zipped"
+ fi
+ ])
NATIVE_DEBUG_SYMBOLS=$with_native_debug_symbols
AC_MSG_RESULT([$NATIVE_DEBUG_SYMBOLS])
@@ -632,5 +370,3 @@
AC_SUBST(STATIC_BUILD)
])
-
-
--- a/common/autoconf/lib-freetype.m4 Mon Dec 21 17:47:21 2015 +0100
+++ b/common/autoconf/lib-freetype.m4 Wed Jul 05 21:09:54 2017 +0200
@@ -321,6 +321,25 @@
BASIC_WINDOWS_REWRITE_AS_UNIX_PATH(FREETYPE_BASE_DIR)
LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location])
fi
+ if test "x$FOUND_FREETYPE" != xyes; then
+ FREETYPE_BASE_DIR="$HOME/freetype"
+ BASIC_WINDOWS_REWRITE_AS_UNIX_PATH(FREETYPE_BASE_DIR)
+ if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
+ LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib64], [well-known location])
+ else
+ LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib32], [well-known location])
+ fi
+ if test "x$FOUND_FREETYPE" != xyes && test -d $FREETYPE_BASE_DIR \
+ && test -s "$FREETYPE_BASE_DIR/builds/windows/vc2010/freetype.vcxproj" && test "x$MSBUILD" != x; then
+ # Source is available, as a last resort try to build freetype in default location
+ LIB_BUILD_FREETYPE($FREETYPE_BASE_DIR)
+ if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
+ LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib64], [well-known location])
+ else
+ LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib32], [well-known location])
+ fi
+ fi
+ fi
else
FREETYPE_BASE_DIR="$SYSROOT/usr"
LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location])
--- a/common/autoconf/spec.gmk.in Mon Dec 21 17:47:21 2015 +0100
+++ b/common/autoconf/spec.gmk.in Wed Jul 05 21:09:54 2017 +0200
@@ -204,13 +204,12 @@
# These are the libjvms that we want to build.
# The java launcher uses the default.
-# The others can be selected by specifying -client -server -minimal1 -kernel -zero or -zeroshark
+# The others can be selected by specifying -client -server -minimal1 -zero or -zeroshark
# on the java launcher command line.
JVM_VARIANTS:=@JVM_VARIANTS@
JVM_VARIANT_SERVER:=@JVM_VARIANT_SERVER@
JVM_VARIANT_CLIENT:=@JVM_VARIANT_CLIENT@
JVM_VARIANT_MINIMAL1:=@JVM_VARIANT_MINIMAL1@
-JVM_VARIANT_KERNEL:=@JVM_VARIANT_KERNEL@
JVM_VARIANT_ZERO:=@JVM_VARIANT_ZERO@
JVM_VARIANT_ZEROSHARK:=@JVM_VARIANT_ZEROSHARK@
JVM_VARIANT_CORE:=@JVM_VARIANT_CORE@
@@ -270,6 +269,7 @@
# Number of parallel jobs to use for compilation
JOBS?=@JOBS@
+TEST_JOBS?=@TEST_JOBS@
# Default make target
DEFAULT_MAKE_TARGET:=@DEFAULT_MAKE_TARGET@
@@ -280,6 +280,8 @@
CUPS_CFLAGS:=@CUPS_CFLAGS@
ALSA_LIBS:=@ALSA_LIBS@
ALSA_CFLAGS:=@ALSA_CFLAGS@
+LIBFFI_LIBS:=@LIBFFI_LIBS@
+LIBFFI_CFLAGS:=@LIBFFI_CFLAGS@
PACKAGE_PATH=@PACKAGE_PATH@
@@ -300,11 +302,15 @@
# Toolchain type: gcc, clang, solstudio, lxc, microsoft...
TOOLCHAIN_TYPE:=@TOOLCHAIN_TYPE@
+TOOLCHAIN_VERSION := @TOOLCHAIN_VERSION@
# Option used to tell the compiler whether to create 32- or 64-bit executables
COMPILER_TARGET_BITS_FLAG:=@COMPILER_TARGET_BITS_FLAG@
COMPILER_SUPPORTS_TARGET_BITS_FLAG=@COMPILER_SUPPORTS_TARGET_BITS_FLAG@
+# Option used to pass a command file to the compiler
+COMPILER_COMMAND_FILE_FLAG:=@COMPILER_COMMAND_FILE_FLAG@
+
CC_OUT_OPTION:=@CC_OUT_OPTION@
EXE_OUT_OPTION:=@EXE_OUT_OPTION@
LD_OUT_OPTION:=@LD_OUT_OPTION@
@@ -388,6 +394,7 @@
BUILD_CC:=@FIXPATH@ @BUILD_ICECC@ @BUILD_CC@
BUILD_CXX:=@FIXPATH@ @BUILD_ICECC@ @BUILD_CXX@
BUILD_LD:=@FIXPATH@ @BUILD_LD@
+BUILD_LDCXX:=@FIXPATH@ @BUILD_LDCXX@
BUILD_AS:=@FIXPATH@ @BUILD_AS@
BUILD_AR:=@FIXPATH@ @BUILD_AR@
BUILD_NM:=@FIXPATH@ @BUILD_NM@
@@ -433,6 +440,8 @@
# (Note absence of := assignment, because we do not want to evaluate the macro body here)
SET_SHARED_LIBRARY_NAME=@SET_SHARED_LIBRARY_NAME@
+SHARED_LIBRARY_FLAGS=@SHARED_LIBRARY_FLAGS@
+
# Set origin using the linker, ie use the relative path to the dependent library to find the dependees.
# (Note absence of := assignment, because we do not want to evaluate the macro body here)
SET_SHARED_LIBRARY_ORIGIN=@SET_SHARED_LIBRARY_ORIGIN@
@@ -650,9 +659,6 @@
# Misc
#
-# Name of Service Agent library
-SALIB_NAME=@SALIB_NAME@
-
INCLUDE_SA=@INCLUDE_SA@
OS_VERSION_MAJOR:=@OS_VERSION_MAJOR@
--- a/common/autoconf/toolchain.m4 Mon Dec 21 17:47:21 2015 +0100
+++ b/common/autoconf/toolchain.m4 Wed Jul 05 21:09:54 2017 +0200
@@ -216,7 +216,11 @@
# The microsoft toolchain also requires INCLUDE and LIB to be set.
export INCLUDE="$VS_INCLUDE"
export LIB="$VS_LIB"
+ else
+ # Currently we do not define this for other toolchains. This might change as the need arise.
+ TOOLCHAIN_VERSION=
fi
+ AC_SUBST(TOOLCHAIN_VERSION)
# For solaris we really need solaris tools, and not the GNU equivalent.
# The build tools on Solaris reside in /usr/ccs (C Compilation System),
@@ -731,6 +735,7 @@
BUILD_AS="$BUILD_CC -c"
# Just like for the target compiler, use the compiler as linker
BUILD_LD="$BUILD_CC"
+ BUILD_LDCXX="$BUILD_CXX"
PATH="$OLDPATH"
else
@@ -739,6 +744,7 @@
BUILD_CC="$CC"
BUILD_CXX="$CXX"
BUILD_LD="$LD"
+ BUILD_LDCXX="$LDCXX"
BUILD_NM="$NM"
BUILD_AS="$AS"
BUILD_SYSROOT_CFLAGS="$SYSROOT_CFLAGS"
@@ -749,6 +755,7 @@
AC_SUBST(BUILD_CC)
AC_SUBST(BUILD_CXX)
AC_SUBST(BUILD_LD)
+ AC_SUBST(BUILD_LDCXX)
AC_SUBST(BUILD_NM)
AC_SUBST(BUILD_AS)
AC_SUBST(BUILD_SYSROOT_CFLAGS)
@@ -822,13 +829,13 @@
[HAS_CFLAG_OPTIMIZE_DEBUG=false])
# "-z relro" supported in GNU binutils 2.17 and later
- LINKER_RELRO_FLAG="-Xlinker -z -Xlinker relro"
+ LINKER_RELRO_FLAG="-Wl,-z,relro"
FLAGS_LINKER_CHECK_ARGUMENTS([$LINKER_RELRO_FLAG],
[HAS_LINKER_RELRO=true],
[HAS_LINKER_RELRO=false])
# "-z now" supported in GNU binutils 2.11 and later
- LINKER_NOW_FLAG="-Xlinker -z -Xlinker now"
+ LINKER_NOW_FLAG="-Wl,-z,now"
FLAGS_LINKER_CHECK_ARGUMENTS([$LINKER_NOW_FLAG],
[HAS_LINKER_NOW=true],
[HAS_LINKER_NOW=false])
@@ -841,7 +848,7 @@
AC_MSG_CHECKING([for broken SuSE 'ld' which only understands anonymous version tags in executables])
$ECHO "SUNWprivate_1.1 { local: *; };" > version-script.map
$ECHO "int main() { }" > main.c
- if $CXX -Xlinker -version-script=version-script.map main.c 2>&AS_MESSAGE_LOG_FD >&AS_MESSAGE_LOG_FD; then
+ if $CXX -Wl,-version-script=version-script.map main.c 2>&AS_MESSAGE_LOG_FD >&AS_MESSAGE_LOG_FD; then
AC_MSG_RESULT(no)
USING_BROKEN_SUSE_LD=no
else
--- a/common/bin/compare.sh Mon Dec 21 17:47:21 2015 +0100
+++ b/common/bin/compare.sh Wed Jul 05 21:09:54 2017 +0200
@@ -37,13 +37,18 @@
if [ "$OPENJDK_TARGET_OS" = "macosx" ]; then
FULLDUMP_CMD="$OTOOL -v -V -h -X -d"
LDD_CMD="$OTOOL -L"
- DIS_CMD="$OTOOL -v -t"
+ DIS_CMD="$OTOOL -v -V -t"
STAT_PRINT_SIZE="-f %z"
elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then
FULLDUMP_CMD="$DUMPBIN -all"
LDD_CMD="$DUMPBIN -dependants | $GREP .dll"
DIS_CMD="$DUMPBIN -disasm:nobytes"
STAT_PRINT_SIZE="-c %s"
+elif [ "$OPENJDK_TARGET_OS" = "aix" ]; then
+ FULLDUMP_CMD="dump -h -r -t -n -X64"
+ LDD_CMD="$LDD"
+ DIS_CMD="$OBJDUMP -d"
+ STAT_PRINT_SIZE="-c %s"
else
FULLDUMP_CMD="$READELF -a"
LDD_CMD="$LDD"
@@ -730,6 +735,9 @@
# Some symbols get seemingly random 15 character prefixes. Filter them out.
$NM -a $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other
$NM -a $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this
+ elif [ "$OPENJDK_TARGET_OS" = "aix" ]; then
+ $OBJDUMP -T $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other
+ $OBJDUMP -T $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this
else
$NM -a $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other
$NM -a $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this
@@ -796,14 +804,21 @@
DEP_MSG=" - "
fi
+ # Some linux compilers add a unique Build ID
+ if [ "$OPENJDK_TARGET_OS" = "linux" ]; then
+ BUILD_ID_FILTER="$SED -r 's/(Build ID:) [0-9a-f]{40}/\1/'"
+ else
+ BUILD_ID_FILTER="$CAT"
+ fi
+
# Compare fulldump output
if [ -n "$FULLDUMP_CMD" ] && [ -z "$SKIP_FULLDUMP_DIFF" ]; then
if [ -z "$FULLDUMP_DIFF_FILTER" ]; then
FULLDUMP_DIFF_FILTER="$CAT"
fi
- $FULLDUMP_CMD $OTHER_FILE | eval "$FULLDUMP_DIFF_FILTER" \
+ $FULLDUMP_CMD $OTHER_FILE | eval "$BUILD_ID_FILTER" | eval "$FULLDUMP_DIFF_FILTER" \
> $WORK_FILE_BASE.fulldump.other 2>&1
- $FULLDUMP_CMD $THIS_FILE | eval "$FULLDUMP_DIFF_FILTER" \
+ $FULLDUMP_CMD $THIS_FILE | eval "$BUILD_ID_FILTER" | eval "$FULLDUMP_DIFF_FILTER" \
> $WORK_FILE_BASE.fulldump.this 2>&1
LC_ALL=C $DIFF $WORK_FILE_BASE.fulldump.other $WORK_FILE_BASE.fulldump.this \
--- a/common/bin/compare_exceptions.sh.incl Mon Dec 21 17:47:21 2015 +0100
+++ b/common/bin/compare_exceptions.sh.incl Wed Jul 05 21:09:54 2017 +0200
@@ -57,14 +57,18 @@
./demo/jvmti/mtrace/lib/libmtrace.so
./demo/jvmti/versionCheck/lib/libversionCheck.so
./demo/jvmti/waiters/lib/libwaiters.so
+./lib/i386/client/libjsig.so
./lib/i386/client/libjvm.so
./lib/i386/libattach.so
./lib/i386/libdt_socket.so
./lib/i386/libinstrument.so
./lib/i386/libjsdt.so
+./lib/i386/libjsig.so
./lib/i386/libmanagement.so
+./lib/i386/libnet.so
./lib/i386/libnpt.so
./lib/i386/libverify.so
+./lib/i386/server/libjsig.so
./lib/i386/server/libjvm.so
./bin/appletviewer
./bin/idlj
@@ -105,6 +109,17 @@
./bin/xjc
"
+# Issue with __FILE__ usage in generated header files prevent clean fulldump diff of
+# server jvm with old hotspot build.
+KNOWN_FULLDUMP_DIFF="
+./lib/i386/server/libjvm.so
+"
+KNOWN_DIS_DIFF="
+./lib/i386/server/libjvm.so
+"
+DIS_DIFF_FILTER="$SED \
+ -e 's/\(:\t\)\([0-9a-z]\{2,2\} \)\{1,7\}/\1<hex>/g' \
+ -e 's/0x[0-9a-z]\{2,9\}/<hex>/g'"
fi
if [ "$OPENJDK_TARGET_OS" = "linux" ] && [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; then
@@ -135,6 +150,7 @@
./lib/amd64/libjsdt.so
./lib/amd64/libjsig.so
./lib/amd64/libmanagement.so
+./lib/amd64/libnet.so
./lib/amd64/libnpt.so
./lib/amd64/libsaproc.so
./lib/amd64/libverify.so
@@ -179,6 +195,12 @@
./bin/xjc
"
+# Issue with __FILE__ usage in generated header files prevent clean fulldump diff of
+# server jvm with old hotspot build.
+KNOWN_FULLDUMP_DIFF="
+./lib/amd64/server/libjvm.so
+"
+
fi
if [ "$OPENJDK_TARGET_OS" = "solaris" ] && [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; then
@@ -299,14 +321,13 @@
# Filter random C++ symbol strings.
# Some numbers differ randomly.
-# Can't use space in these expressions as the shell will mess with them.
DIS_DIFF_FILTER="$SED \
- -e 's/\.[a-zA-Z0-9_\$]\{15,15\}/<SYM>/g' \
- -e 's/\([0-9a-f][0-9a-f].\)\{2,8\}[0-9a-f][0-9a-f]/<NUMS>/g' \
- -e 's/\(0x\)[0-9a-f]*\([,(>]\)/\1<HEX>\2/g' \
- -e 's/\(0x\)[0-9a-f]*$/\1<HEX>/g' \
- -e 's/\(\#.\)[0-9a-f]*\(.<\)/\1<HEX>\2/g' \
- -e 's/[\.A-Za-z0-9%]\{16,16\}$/<BIN>/g'"
+ -e 's/\.[a-zA-Z0-9_\$]\{15\}/<SYM>/g' \
+ -e 's/\(\# \)[0-9a-f]*\( <\)/\1<HEX>\2/g' \
+ -e 's/0x[0-9a-f]*$/<HEX>/g' \
+ -e 's/0x[0-9a-f]*\([,(>]\)/<HEX>\1/g' \
+ -e 's/: [0-9a-f][0-9a-f]\( [0-9a-f][0-9a-f]\)\{2,10\}/: <NUMS>/g' \
+ -e 's/ [\.A-Za-z0-9%@]\{16\}$/ <BIN>/g'"
fi
@@ -425,18 +446,23 @@
./bin/xjc
"
-# Filter random C++ symbol strings.
# Some numbers differ randomly.
DIS_DIFF_FILTER="$SED \
- -e 's/\$[a-zA-Z0-9_\$]\{15,15\}/<SYM>/g' \
- -e 's/[0-9a-f][0-9a-f].[0-9a-f][0-9a-f].[0-9a-f][0-9a-f].[0-9a-f][0-9a-f]/<NUMS>/g' \
- -e 's/\(%g1,.0x\)[0-9a-f]*\(,.%g1\)/\1<HEX>\2/g' \
- -e 's/\(!.\)[0-9a-f]*\(.<SUNWprivate_1.1+0x\)[0-9a-f]*/\1<NUM>\2<HEX>/g' \
- -e 's/\!.[0-9a-f]\{1,4\} <_DYNAMIC+0x[0-9a-f]\{1,4\}>/<DYNAMIC>/g'"
+ -e 's/\$[a-zA-Z0-9_\$]\{15\}/<SYM>/g' \
+ -e 's/: [0-9a-f][0-9a-f]\( [0-9a-f][0-9a-f]\)\{2,10\}/: <NUMS>/g' \
+ -e 's/, [0-9a-fx\-]\{1,8\}/, <CONST>/g' \
+ -e 's/call [0-9a-f]\{7\}/call <ADDR>/g' \
+ -e 's/0x[0-9a-f]\{1,8\}/<HEX>/g' \
+ -e 's/\! [0-9a-f]\{1,8\} /! <ADDR> /g'"
-# Some xor instructions end up with different args in the lib but not in the object files.
-ACCEPTED_DIS_DIFF="
-./demo/jvmti/waiters/lib/libwaiters.so
+# libjvm.so
+# __FILE__ macro usage in debug.hpp causes differences between old and new
+# hotspot builds in ad_sparc.o and ad_sparc_clone.o. The .o files compare
+# equal when stripped, but at link time differences appear. Removing
+# __FILE__ from ShouldNotCallThis() and ShouldNotReachHere() removes
+# the differences.
+KNOWN_DIS_DIFF="
+./lib/sparcv9/server/libjvm.so
"
SKIP_FULLDUMP_DIFF="true"
@@ -634,11 +660,12 @@
SORT_SYMBOLS="
./Contents/Home/lib/libsaproc.dylib
./lib/libsaproc.dylib
+./lib/libjsig.dylib
"
ACCEPTED_SMALL_SIZE_DIFF="$ACCEPTED_BIN_DIFF"
-DIS_DIFF_FILTER="$SED \
- -e 's/0x[0-9a-f]\{4,16\}/<HEXSTR>/g'"
+DIS_DIFF_FILTER="LANG=C $SED \
+ -e 's/0x[0-9a-f]\{3,16\}/<HEXSTR>/g' -e 's/^[0-9a-f]\{12,20\}/<ADDR>/'"
fi
--- a/common/conf/jib-profiles.js Mon Dec 21 17:47:21 2015 +0100
+++ b/common/conf/jib-profiles.js Wed Jul 05 21:09:54 2017 +0200
@@ -357,8 +357,8 @@
var devkit_platform_revisions = {
linux_x64: "gcc4.9.2-OEL6.4+1.0",
macosx_x64: "Xcode6.3-MacOSX10.9+1.0",
- solaris_x64: "SS12u3-Solaris10u10+1.0",
- solaris_sparcv9: "SS12u3-Solaris10u10+1.0",
+ solaris_x64: "SS12u4-Solaris11u1+1.0",
+ solaris_sparcv9: "SS12u4-Solaris11u1+1.0",
windows_x64: "VS2013SP4+1.0"
};
--- a/corba/.hgtags Mon Dec 21 17:47:21 2015 +0100
+++ b/corba/.hgtags Wed Jul 05 21:09:54 2017 +0200
@@ -340,3 +340,4 @@
fd038e8a16eec80d0d6b337d74a582790ed4b3ee jdk-9+95
feb1bd85d7990dcf5584ca9e53104269c01db006 jdk-9+96
10a482b863582376d4ca229090334b23b05159fc jdk-9+97
+ea285530245cf4e0edf0479121a41347d3030eba jdk-9+98
--- a/hotspot/.hgtags Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/.hgtags Wed Jul 05 21:09:54 2017 +0200
@@ -500,3 +500,4 @@
0c79cf3cdf0904fc4a630b91b32904491e1ae430 jdk-9+95
a94bb7203596dd632486f1e3655fa5f70541dc08 jdk-9+96
de592ea5f7ba0f8a8c5afc03bd169f7690c72b6f jdk-9+97
+e5b1a23be1e105417ba1c4c576ab373eb3fa2c2b jdk-9+98
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Wed Jul 05 21:09:54 2017 +0200
@@ -1446,7 +1446,7 @@
if (type.equals("threads")) {
Threads threads = VM.getVM().getThreads();
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
- Address base = thread.getBaseOfStackPointer();
+ Address base = thread.getStackBase();
Address end = thread.getLastJavaSP();
if (end == null) continue;
if (end.lessThan(base)) {
@@ -1454,11 +1454,13 @@
base = end;
end = tmp;
}
- out.println("Searching " + base + " " + end);
+ //out.println("Searching " + base + " " + end);
while (base != null && base.lessThan(end)) {
Address val = base.getAddressAt(0);
if (AddressOps.equal(val, value)) {
- out.println(base);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ thread.printThreadIDOn(new PrintStream(bos));
+ out.println("found on the stack of thread " + bos.toString() + " at " + base);
}
base = base.addOffsetTo(stride);
}
@@ -1601,6 +1603,8 @@
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
out.println("Thread " + bos.toString() + " Address " + thread.getAddress());
+ thread.printInfoOn(out);
+ out.println(" ");
if (!all) return;
}
}
@@ -1618,6 +1622,8 @@
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
thread.printThreadIDOn(out);
out.println(" " + thread.getThreadName());
+ thread.printInfoOn(out);
+ out.println("\n...");
}
}
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Wed Jul 05 21:09:54 2017 +0200
@@ -416,7 +416,7 @@
} else {
tty.println("No Java frames present");
}
- tty.println("Base of Stack: " + getBaseOfStackPointer());
+ tty.println("Base of Stack: " + getStackBase());
tty.println("Last_Java_SP: " + getLastJavaSP());
tty.println("Last_Java_FP: " + getLastJavaFP());
tty.println("Last_Java_PC: " + getLastJavaPC());
--- a/hotspot/make/aix/makefiles/xlc.make Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/make/aix/makefiles/xlc.make Wed Jul 05 21:09:54 2017 +0200
@@ -74,6 +74,9 @@
CFLAGS += -qnortti
CFLAGS += -qnoeh
+# for compiler-level tls
+CFLAGS += -qtls=default
+
CFLAGS += -D_REENTRANT
# no xlc counterpart for -fcheck-new
# CFLAGS += -fcheck-new
--- a/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -71,7 +71,7 @@
-DSOLARIS_11_B159_OR_LATER
SA_CFLAGS := $(CFLAGS_JDKLIB) $(COMMON_CFLAGS)
SA_CXXFLAGS := $(CXXFLAGS_JDKLIB) $(COMMON_CFLAGS)
- SA_LDFLAGS := $(subst -z defs,, $(LDFLAGS_JDKLIB)) \
+ SA_LDFLAGS := $(subst -Wl$(COMMA)-z$(COMMA)defs,, $(LDFLAGS_JDKLIB)) \
-mt $(LDFLAGS_CXX_JDK)
SA_LIBS := -ldl -ldemangle -lthread -lc
--- a/hotspot/make/linux/makefiles/gcc.make Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/make/linux/makefiles/gcc.make Wed Jul 05 21:09:54 2017 +0200
@@ -260,6 +260,13 @@
OPT_CFLAGS = $(OPT_CFLAGS/$(OPT_CFLAGS_DEFAULT)) $(OPT_EXTRAS)
+# Variable tracking size limit exceeded for VMStructs::init()
+ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "1"
+ # GCC >= 4.3
+ # Gcc 4.1.2 does not support this flag, nor does it have problems compiling the file.
+ OPT_CFLAGS/vmStructs.o += -fno-var-tracking-assignments
+endif
+
# The gcc compiler segv's on ia64 when compiling bytecodeInterpreter.cpp
# if we use expensive-optimizations
ifeq ($(BUILDARCH), ia64)
--- a/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -39,7 +39,6 @@
#include "prims/jvmtiThreadState.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
@@ -259,20 +258,3 @@
return entry_point;
}
-
-
-void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) {
-
- // This code is sort of the equivalent of C2IAdapter::setup_stack_frame back in
- // the days we had adapter frames. When we deoptimize a situation where a
- // compiled caller calls a compiled caller will have registers it expects
- // to survive the call to the callee. If we deoptimize the callee the only
- // way we can restore these registers is to have the oldest interpreter
- // frame that we create restore these values. That is what this routine
- // will accomplish.
-
- // At the moment we have modified c2 to not have any callee save registers
- // so this problem does not exist and this routine is just a place holder.
-
- assert(f->is_interpreted_frame(), "must be interpreted");
-}
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -41,6 +41,7 @@
#include "runtime/icache.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/sharedRuntime.hpp"
+#include "runtime/thread.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1CollectedHeap.inline.hpp"
@@ -4653,3 +4654,23 @@
BIND(DONE);
sub(result, result, len); // Return index where we stopped
}
+
+// get_thread() can be called anywhere inside generated code so we
+// need to save whatever non-callee save context might get clobbered
+// by the call to JavaThread::aarch64_get_thread_helper() or, indeed,
+// the call setup code.
+//
+// aarch64_get_thread_helper() clobbers only r0, r1, and flags.
+//
+void MacroAssembler::get_thread(Register dst) {
+ RegSet saved_regs = RegSet::range(r0, r1) + lr - dst;
+ push(saved_regs, sp);
+
+ mov(lr, CAST_FROM_FN_PTR(address, JavaThread::aarch64_get_thread_helper));
+ blrt(lr, 1, 0, 1);
+ if (dst != c_rarg0) {
+ mov(dst, c_rarg0);
+ }
+
+ pop(saved_regs, sp);
+}
--- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1973,7 +1973,7 @@
// c_rarg4 - input length
//
// Output:
- // rax - input length
+ // x0 - input length
//
address generate_cipherBlockChaining_decryptAESCrypt() {
assert(UseAES, "need AES instructions and misaligned SSE support");
@@ -2035,7 +2035,7 @@
__ br(Assembler::EQ, L_rounds_52);
__ aesd(v0, v17); __ aesimc(v0, v0);
- __ aesd(v0, v17); __ aesimc(v0, v0);
+ __ aesd(v0, v18); __ aesimc(v0, v0);
__ BIND(L_rounds_52);
__ aesd(v0, v19); __ aesimc(v0, v0);
__ aesd(v0, v20); __ aesimc(v0, v0);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,1925 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Red Hat Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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/macroAssembler.hpp"
+#include "interpreter/bytecodeHistogram.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterGenerator.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/interp_masm.hpp"
+#include "interpreter/templateTable.hpp"
+#include "interpreter/bytecodeTracer.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/methodData.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "prims/jvmtiThreadState.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/synchronizer.hpp"
+#include "runtime/timer.hpp"
+#include "runtime/vframeArray.hpp"
+#include "utilities/debug.hpp"
+#include <sys/types.h>
+
+#ifndef PRODUCT
+#include "oops/method.hpp"
+#endif // !PRODUCT
+
+#ifdef BUILTIN_SIM
+#include "../../../../../../simulator/simulator.hpp"
+#endif
+
+#define __ _masm->
+
+#ifndef CC_INTERP
+
+//-----------------------------------------------------------------------------
+
+extern "C" void entry(CodeBuffer*);
+
+//-----------------------------------------------------------------------------
+
+address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
+ address entry = __ pc();
+
+#ifdef ASSERT
+ {
+ Label L;
+ __ ldr(rscratch1, Address(rfp,
+ frame::interpreter_frame_monitor_block_top_offset *
+ wordSize));
+ __ mov(rscratch2, sp);
+ __ cmp(rscratch1, rscratch2); // maximal rsp for current rfp (stack
+ // grows negative)
+ __ br(Assembler::HS, L); // check if frame is complete
+ __ stop ("interpreter frame not set up");
+ __ bind(L);
+ }
+#endif // ASSERT
+ // Restore bcp under the assumption that the current frame is still
+ // interpreted
+ __ restore_bcp();
+
+ // expression stack must be empty before entering the VM if an
+ // exception happened
+ __ empty_expression_stack();
+ // throw exception
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_StackOverflowError));
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(
+ const char* name) {
+ address entry = __ pc();
+ // expression stack must be empty before entering the VM if an
+ // exception happened
+ __ empty_expression_stack();
+ // setup parameters
+ // ??? convention: expect aberrant index in register r1
+ __ movw(c_rarg2, r1);
+ __ mov(c_rarg1, (address)name);
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::
+ throw_ArrayIndexOutOfBoundsException),
+ c_rarg1, c_rarg2);
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
+ address entry = __ pc();
+
+ // object is at TOS
+ __ pop(c_rarg1);
+
+ // expression stack must be empty before entering the VM if an
+ // exception happened
+ __ empty_expression_stack();
+
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::
+ throw_ClassCastException),
+ c_rarg1);
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_exception_handler_common(
+ const char* name, const char* message, bool pass_oop) {
+ assert(!pass_oop || message == NULL, "either oop or message but not both");
+ address entry = __ pc();
+ if (pass_oop) {
+ // object is at TOS
+ __ pop(c_rarg2);
+ }
+ // expression stack must be empty before entering the VM if an
+ // exception happened
+ __ empty_expression_stack();
+ // setup parameters
+ __ lea(c_rarg1, Address((address)name));
+ if (pass_oop) {
+ __ call_VM(r0, CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::
+ create_klass_exception),
+ c_rarg1, c_rarg2);
+ } else {
+ // kind of lame ExternalAddress can't take NULL because
+ // external_word_Relocation will assert.
+ if (message != NULL) {
+ __ lea(c_rarg2, Address((address)message));
+ } else {
+ __ mov(c_rarg2, NULL_WORD);
+ }
+ __ call_VM(r0,
+ CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception),
+ c_rarg1, c_rarg2);
+ }
+ // throw exception
+ __ b(address(Interpreter::throw_exception_entry()));
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
+ address entry = __ pc();
+ // NULL last_sp until next java call
+ __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
+ __ dispatch_next(state);
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
+ address entry = __ pc();
+
+ // Restore stack bottom in case i2c adjusted stack
+ __ ldr(esp, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
+ // and NULL it as marker that esp is now tos until next java call
+ __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
+ __ restore_bcp();
+ __ restore_locals();
+ __ restore_constant_pool_cache();
+ __ get_method(rmethod);
+
+ // Pop N words from the stack
+ __ get_cache_and_index_at_bcp(r1, r2, 1, index_size);
+ __ ldr(r1, Address(r1, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
+ __ andr(r1, r1, ConstantPoolCacheEntry::parameter_size_mask);
+
+ __ add(esp, esp, r1, Assembler::LSL, 3);
+
+ // Restore machine SP
+ __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
+ __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset()));
+ __ add(rscratch1, rscratch1, frame::interpreter_frame_monitor_size() + 2);
+ __ ldr(rscratch2,
+ Address(rfp, frame::interpreter_frame_initial_sp_offset * wordSize));
+ __ sub(rscratch1, rscratch2, rscratch1, ext::uxtw, 3);
+ __ andr(sp, rscratch1, -16);
+
+#ifndef PRODUCT
+ // tell the simulator that the method has been reentered
+ if (NotifySimulator) {
+ __ notify(Assembler::method_reentry);
+ }
+#endif
+ __ get_dispatch();
+ __ dispatch_next(state, step);
+
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state,
+ int step) {
+ address entry = __ pc();
+ __ restore_bcp();
+ __ restore_locals();
+ __ restore_constant_pool_cache();
+ __ get_method(rmethod);
+
+ // handle exceptions
+ {
+ Label L;
+ __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset()));
+ __ cbz(rscratch1, L);
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_pending_exception));
+ __ should_not_reach_here();
+ __ bind(L);
+ }
+
+ __ get_dispatch();
+
+ // Calculate stack limit
+ __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
+ __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset()));
+ __ add(rscratch1, rscratch1, frame::interpreter_frame_monitor_size() + 2);
+ __ ldr(rscratch2,
+ Address(rfp, frame::interpreter_frame_initial_sp_offset * wordSize));
+ __ sub(rscratch1, rscratch2, rscratch1, ext::uxtx, 3);
+ __ andr(sp, rscratch1, -16);
+
+ // Restore expression stack pointer
+ __ ldr(esp, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
+ // NULL last_sp until next java call
+ __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
+
+ __ dispatch_next(state, step);
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_result_handler_for(
+ BasicType type) {
+ address entry = __ pc();
+ switch (type) {
+ case T_BOOLEAN: __ uxtb(r0, r0); break;
+ case T_CHAR : __ uxth(r0, r0); break;
+ case T_BYTE : __ sxtb(r0, r0); break;
+ case T_SHORT : __ sxth(r0, r0); break;
+ case T_INT : __ uxtw(r0, r0); break; // FIXME: We almost certainly don't need this
+ case T_LONG : /* nothing to do */ break;
+ case T_VOID : /* nothing to do */ break;
+ case T_FLOAT : /* nothing to do */ break;
+ case T_DOUBLE : /* nothing to do */ break;
+ case T_OBJECT :
+ // retrieve result from frame
+ __ ldr(r0, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize));
+ // and verify it
+ __ verify_oop(r0);
+ break;
+ default : ShouldNotReachHere();
+ }
+ __ ret(lr); // return from result handler
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_safept_entry_for(
+ TosState state,
+ address runtime_entry) {
+ address entry = __ pc();
+ __ push(state);
+ __ call_VM(noreg, runtime_entry);
+ __ membar(Assembler::AnyAny);
+ __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos));
+ return entry;
+}
+
+// Helpers for commoning out cases in the various type of method entries.
+//
+
+
+// increment invocation count & check for overflow
+//
+// Note: checking for negative value instead of overflow
+// so we have a 'sticky' overflow test
+//
+// rmethod: method
+//
+void InterpreterGenerator::generate_counter_incr(
+ Label* overflow,
+ Label* profile_method,
+ Label* profile_method_continue) {
+ Label done;
+ // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not.
+ if (TieredCompilation) {
+ int increment = InvocationCounter::count_increment;
+ Label no_mdo;
+ if (ProfileInterpreter) {
+ // Are we profiling?
+ __ ldr(r0, Address(rmethod, Method::method_data_offset()));
+ __ cbz(r0, no_mdo);
+ // Increment counter in the MDO
+ const Address mdo_invocation_counter(r0, in_bytes(MethodData::invocation_counter_offset()) +
+ in_bytes(InvocationCounter::counter_offset()));
+ const Address mask(r0, in_bytes(MethodData::invoke_mask_offset()));
+ __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rscratch1, rscratch2, false, Assembler::EQ, overflow);
+ __ b(done);
+ }
+ __ bind(no_mdo);
+ // Increment counter in MethodCounters
+ const Address invocation_counter(rscratch2,
+ MethodCounters::invocation_counter_offset() +
+ InvocationCounter::counter_offset());
+ __ get_method_counters(rmethod, rscratch2, done);
+ const Address mask(rscratch2, in_bytes(MethodCounters::invoke_mask_offset()));
+ __ increment_mask_and_jump(invocation_counter, increment, mask, rscratch1, r1, false, Assembler::EQ, overflow);
+ __ bind(done);
+ } else { // not TieredCompilation
+ const Address backedge_counter(rscratch2,
+ MethodCounters::backedge_counter_offset() +
+ InvocationCounter::counter_offset());
+ const Address invocation_counter(rscratch2,
+ MethodCounters::invocation_counter_offset() +
+ InvocationCounter::counter_offset());
+
+ __ get_method_counters(rmethod, rscratch2, done);
+
+ if (ProfileInterpreter) { // %%% Merge this into MethodData*
+ __ ldrw(r1, Address(rscratch2, MethodCounters::interpreter_invocation_counter_offset()));
+ __ addw(r1, r1, 1);
+ __ strw(r1, Address(rscratch2, MethodCounters::interpreter_invocation_counter_offset()));
+ }
+ // Update standard invocation counters
+ __ ldrw(r1, invocation_counter);
+ __ ldrw(r0, backedge_counter);
+
+ __ addw(r1, r1, InvocationCounter::count_increment);
+ __ andw(r0, r0, InvocationCounter::count_mask_value);
+
+ __ strw(r1, invocation_counter);
+ __ addw(r0, r0, r1); // add both counters
+
+ // profile_method is non-null only for interpreted method so
+ // profile_method != NULL == !native_call
+
+ if (ProfileInterpreter && profile_method != NULL) {
+ // Test to see if we should create a method data oop
+ __ ldr(rscratch2, Address(rmethod, Method::method_counters_offset()));
+ __ ldrw(rscratch2, Address(rscratch2, in_bytes(MethodCounters::interpreter_profile_limit_offset())));
+ __ cmpw(r0, rscratch2);
+ __ br(Assembler::LT, *profile_method_continue);
+
+ // if no method data exists, go to profile_method
+ __ test_method_data_pointer(r0, *profile_method);
+ }
+
+ {
+ __ ldr(rscratch2, Address(rmethod, Method::method_counters_offset()));
+ __ ldrw(rscratch2, Address(rscratch2, in_bytes(MethodCounters::interpreter_invocation_limit_offset())));
+ __ cmpw(r0, rscratch2);
+ __ br(Assembler::HS, *overflow);
+ }
+ __ bind(done);
+ }
+}
+
+void InterpreterGenerator::generate_counter_overflow(Label* do_continue) {
+
+ // Asm interpreter on entry
+ // On return (i.e. jump to entry_point) [ back to invocation of interpreter ]
+ // Everything as it was on entry
+
+ // InterpreterRuntime::frequency_counter_overflow takes two
+ // arguments, the first (thread) is passed by call_VM, the second
+ // indicates if the counter overflow occurs at a backwards branch
+ // (NULL bcp). We pass zero for it. The call returns the address
+ // of the verified entry point for the method or NULL if the
+ // compilation did not complete (either went background or bailed
+ // out).
+ __ mov(c_rarg1, 0);
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::frequency_counter_overflow),
+ c_rarg1);
+
+ __ b(*do_continue);
+}
+
+// See if we've got enough room on the stack for locals plus overhead.
+// The expression stack grows down incrementally, so the normal guard
+// page mechanism will work for that.
+//
+// NOTE: Since the additional locals are also always pushed (wasn't
+// obvious in generate_method_entry) so the guard should work for them
+// too.
+//
+// Args:
+// r3: number of additional locals this frame needs (what we must check)
+// rmethod: Method*
+//
+// Kills:
+// r0
+void InterpreterGenerator::generate_stack_overflow_check(void) {
+
+ // monitor entry size: see picture of stack set
+ // (generate_method_entry) and frame_amd64.hpp
+ const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
+
+ // total overhead size: entry_size + (saved rbp through expr stack
+ // bottom). be sure to change this if you add/subtract anything
+ // to/from the overhead area
+ const int overhead_size =
+ -(frame::interpreter_frame_initial_sp_offset * wordSize) + entry_size;
+
+ const int page_size = os::vm_page_size();
+
+ Label after_frame_check;
+
+ // see if the frame is greater than one page in size. If so,
+ // then we need to verify there is enough stack space remaining
+ // for the additional locals.
+ //
+ // Note that we use SUBS rather than CMP here because the immediate
+ // field of this instruction may overflow. SUBS can cope with this
+ // because it is a macro that will expand to some number of MOV
+ // instructions and a register operation.
+ __ subs(rscratch1, r3, (page_size - overhead_size) / Interpreter::stackElementSize);
+ __ br(Assembler::LS, after_frame_check);
+
+ // compute rsp as if this were going to be the last frame on
+ // the stack before the red zone
+
+ const Address stack_base(rthread, Thread::stack_base_offset());
+ const Address stack_size(rthread, Thread::stack_size_offset());
+
+ // locals + overhead, in bytes
+ __ mov(r0, overhead_size);
+ __ add(r0, r0, r3, Assembler::LSL, Interpreter::logStackElementSize); // 2 slots per parameter.
+
+ __ ldr(rscratch1, stack_base);
+ __ ldr(rscratch2, stack_size);
+
+#ifdef ASSERT
+ Label stack_base_okay, stack_size_okay;
+ // verify that thread stack base is non-zero
+ __ cbnz(rscratch1, stack_base_okay);
+ __ stop("stack base is zero");
+ __ bind(stack_base_okay);
+ // verify that thread stack size is non-zero
+ __ cbnz(rscratch2, stack_size_okay);
+ __ stop("stack size is zero");
+ __ bind(stack_size_okay);
+#endif
+
+ // Add stack base to locals and subtract stack size
+ __ sub(rscratch1, rscratch1, rscratch2); // Stack limit
+ __ add(r0, r0, rscratch1);
+
+ // Use the maximum number of pages we might bang.
+ const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages :
+ (StackRedPages+StackYellowPages);
+
+ // add in the red and yellow zone sizes
+ __ add(r0, r0, max_pages * page_size * 2);
+
+ // check against the current stack bottom
+ __ cmp(sp, r0);
+ __ br(Assembler::HI, after_frame_check);
+
+ // Remove the incoming args, peeling the machine SP back to where it
+ // was in the caller. This is not strictly necessary, but unless we
+ // do so the stack frame may have a garbage FP; this ensures a
+ // correct call stack that we can always unwind. The ANDR should be
+ // unnecessary because the sender SP in r13 is always aligned, but
+ // it doesn't hurt.
+ __ andr(sp, r13, -16);
+
+ // Note: the restored frame is not necessarily interpreted.
+ // Use the shared runtime version of the StackOverflowError.
+ assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "stub not yet generated");
+ __ far_jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry()));
+
+ // all done with frame size check
+ __ bind(after_frame_check);
+}
+
+// Allocate monitor and lock method (asm interpreter)
+//
+// Args:
+// rmethod: Method*
+// rlocals: locals
+//
+// Kills:
+// r0
+// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs)
+// rscratch1, rscratch2 (scratch regs)
+void TemplateInterpreterGenerator::lock_method() {
+ // synchronize method
+ const Address access_flags(rmethod, Method::access_flags_offset());
+ const Address monitor_block_top(
+ rfp,
+ frame::interpreter_frame_monitor_block_top_offset * wordSize);
+ const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
+
+#ifdef ASSERT
+ {
+ Label L;
+ __ ldrw(r0, access_flags);
+ __ tst(r0, JVM_ACC_SYNCHRONIZED);
+ __ br(Assembler::NE, L);
+ __ stop("method doesn't need synchronization");
+ __ bind(L);
+ }
+#endif // ASSERT
+
+ // get synchronization object
+ {
+ const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+ Label done;
+ __ ldrw(r0, access_flags);
+ __ tst(r0, JVM_ACC_STATIC);
+ // get receiver (assume this is frequent case)
+ __ ldr(r0, Address(rlocals, Interpreter::local_offset_in_bytes(0)));
+ __ br(Assembler::EQ, done);
+ __ ldr(r0, Address(rmethod, Method::const_offset()));
+ __ ldr(r0, Address(r0, ConstMethod::constants_offset()));
+ __ ldr(r0, Address(r0,
+ ConstantPool::pool_holder_offset_in_bytes()));
+ __ ldr(r0, Address(r0, mirror_offset));
+
+#ifdef ASSERT
+ {
+ Label L;
+ __ cbnz(r0, L);
+ __ stop("synchronization object is NULL");
+ __ bind(L);
+ }
+#endif // ASSERT
+
+ __ bind(done);
+ }
+
+ // add space for monitor & lock
+ __ sub(sp, sp, entry_size); // add space for a monitor entry
+ __ sub(esp, esp, entry_size);
+ __ mov(rscratch1, esp);
+ __ str(rscratch1, monitor_block_top); // set new monitor block top
+ // store object
+ __ str(r0, Address(esp, BasicObjectLock::obj_offset_in_bytes()));
+ __ mov(c_rarg1, esp); // object address
+ __ lock_object(c_rarg1);
+}
+
+// Generate a fixed interpreter frame. This is identical setup for
+// interpreted methods and for native methods hence the shared code.
+//
+// Args:
+// lr: return address
+// rmethod: Method*
+// rlocals: pointer to locals
+// rcpool: cp cache
+// stack_pointer: previous sp
+void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
+ // initialize fixed part of activation frame
+ if (native_call) {
+ __ sub(esp, sp, 12 * wordSize);
+ __ mov(rbcp, zr);
+ __ stp(esp, zr, Address(__ pre(sp, -12 * wordSize)));
+ // add 2 zero-initialized slots for native calls
+ __ stp(zr, zr, Address(sp, 10 * wordSize));
+ } else {
+ __ sub(esp, sp, 10 * wordSize);
+ __ ldr(rscratch1, Address(rmethod, Method::const_offset())); // get ConstMethod
+ __ add(rbcp, rscratch1, in_bytes(ConstMethod::codes_offset())); // get codebase
+ __ stp(esp, rbcp, Address(__ pre(sp, -10 * wordSize)));
+ }
+
+ if (ProfileInterpreter) {
+ Label method_data_continue;
+ __ ldr(rscratch1, Address(rmethod, Method::method_data_offset()));
+ __ cbz(rscratch1, method_data_continue);
+ __ lea(rscratch1, Address(rscratch1, in_bytes(MethodData::data_offset())));
+ __ bind(method_data_continue);
+ __ stp(rscratch1, rmethod, Address(sp, 4 * wordSize)); // save Method* and mdp (method data pointer)
+ } else {
+ __ stp(zr, rmethod, Address(sp, 4 * wordSize)); // save Method* (no mdp)
+ }
+
+ __ ldr(rcpool, Address(rmethod, Method::const_offset()));
+ __ ldr(rcpool, Address(rcpool, ConstMethod::constants_offset()));
+ __ ldr(rcpool, Address(rcpool, ConstantPool::cache_offset_in_bytes()));
+ __ stp(rlocals, rcpool, Address(sp, 2 * wordSize));
+
+ __ stp(rfp, lr, Address(sp, 8 * wordSize));
+ __ lea(rfp, Address(sp, 8 * wordSize));
+
+ // set sender sp
+ // leave last_sp as null
+ __ stp(zr, r13, Address(sp, 6 * wordSize));
+
+ // Move SP out of the way
+ if (! native_call) {
+ __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
+ __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset()));
+ __ add(rscratch1, rscratch1, frame::interpreter_frame_monitor_size() + 2);
+ __ sub(rscratch1, sp, rscratch1, ext::uxtw, 3);
+ __ andr(sp, rscratch1, -16);
+ }
+}
+
+// End of helpers
+
+// Various method entries
+//------------------------------------------------------------------------------------------------------------------------
+//
+//
+
+// Method entry for java.lang.ref.Reference.get.
+address InterpreterGenerator::generate_Reference_get_entry(void) {
+#if INCLUDE_ALL_GCS
+ // Code: _aload_0, _getfield, _areturn
+ // parameter size = 1
+ //
+ // The code that gets generated by this routine is split into 2 parts:
+ // 1. The "intrinsified" code for G1 (or any SATB based GC),
+ // 2. The slow path - which is an expansion of the regular method entry.
+ //
+ // Notes:-
+ // * In the G1 code we do not check whether we need to block for
+ // a safepoint. If G1 is enabled then we must execute the specialized
+ // code for Reference.get (except when the Reference object is null)
+ // so that we can log the value in the referent field with an SATB
+ // update buffer.
+ // If the code for the getfield template is modified so that the
+ // G1 pre-barrier code is executed when the current method is
+ // Reference.get() then going through the normal method entry
+ // will be fine.
+ // * The G1 code can, however, check the receiver object (the instance
+ // of java.lang.Reference) and jump to the slow path if null. If the
+ // Reference object is null then we obviously cannot fetch the referent
+ // and so we don't need to call the G1 pre-barrier. Thus we can use the
+ // regular method entry code to generate the NPE.
+ //
+ // This code is based on generate_accessor_enty.
+ //
+ // rmethod: Method*
+ // r13: senderSP must preserve for slow path, set SP to it on fast path
+
+ 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;
+ const Register local_0 = c_rarg0;
+ // Check if local 0 != NULL
+ // If the receiver is null then it is OK to jump to the slow path.
+ __ ldr(local_0, Address(esp, 0));
+ __ cbz(local_0, slow_path);
+
+
+ // Load the value of the referent field.
+ const Address field_address(local_0, referent_offset);
+ __ load_heap_oop(local_0, field_address);
+
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer.
+ __ enter(); // g1_write may call runtime
+ __ g1_write_barrier_pre(noreg /* obj */,
+ local_0 /* pre_val */,
+ rthread /* thread */,
+ rscratch2 /* tmp */,
+ true /* tosca_live */,
+ true /* expand_call */);
+ __ leave();
+ // areturn
+ __ andr(sp, r13, -16); // done with stack
+ __ ret(lr);
+
+ // generate a vanilla interpreter entry as the slow path
+ __ bind(slow_path);
+ __ 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_accessor_entry();
+}
+
+/**
+ * Method entry for static native methods:
+ * int java.util.zip.CRC32.update(int crc, int b)
+ */
+address InterpreterGenerator::generate_CRC32_update_entry() {
+ if (UseCRC32Intrinsics) {
+ address entry = __ pc();
+
+ // rmethod: Method*
+ // r13: senderSP must preserved for slow path
+ // esp: args
+
+ Label slow_path;
+ // If we need a safepoint check, generate full interpreter entry.
+ ExternalAddress state(SafepointSynchronize::address_of_state());
+ unsigned long offset;
+ __ adrp(rscratch1, ExternalAddress(SafepointSynchronize::address_of_state()), offset);
+ __ ldrw(rscratch1, Address(rscratch1, offset));
+ assert(SafepointSynchronize::_not_synchronized == 0, "rewrite this code");
+ __ cbnz(rscratch1, slow_path);
+
+ // We don't generate local frame and don't align stack because
+ // we call stub code and there is no safepoint on this path.
+
+ // Load parameters
+ const Register crc = c_rarg0; // crc
+ const Register val = c_rarg1; // source java byte value
+ const Register tbl = c_rarg2; // scratch
+
+ // Arguments are reversed on java expression stack
+ __ ldrw(val, Address(esp, 0)); // byte value
+ __ ldrw(crc, Address(esp, wordSize)); // Initial CRC
+
+ __ adrp(tbl, ExternalAddress(StubRoutines::crc_table_addr()), offset);
+ __ add(tbl, tbl, offset);
+
+ __ ornw(crc, zr, crc); // ~crc
+ __ update_byte_crc32(crc, val, tbl);
+ __ ornw(crc, zr, crc); // ~crc
+
+ // result in c_rarg0
+
+ __ andr(sp, r13, -16);
+ __ ret(lr);
+
+ // 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;
+}
+
+/**
+ * Method entry for static native methods:
+ * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len)
+ * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len)
+ */
+address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
+ if (UseCRC32Intrinsics) {
+ address entry = __ pc();
+
+ // rmethod,: Method*
+ // r13: senderSP must preserved for slow path
+
+ Label slow_path;
+ // If we need a safepoint check, generate full interpreter entry.
+ ExternalAddress state(SafepointSynchronize::address_of_state());
+ unsigned long offset;
+ __ adrp(rscratch1, ExternalAddress(SafepointSynchronize::address_of_state()), offset);
+ __ ldrw(rscratch1, Address(rscratch1, offset));
+ assert(SafepointSynchronize::_not_synchronized == 0, "rewrite this code");
+ __ cbnz(rscratch1, slow_path);
+
+ // We don't generate local frame and don't align stack because
+ // we call stub code and there is no safepoint on this path.
+
+ // Load parameters
+ const Register crc = c_rarg0; // crc
+ const Register buf = c_rarg1; // source java byte array address
+ const Register len = c_rarg2; // length
+ const Register off = len; // offset (never overlaps with 'len')
+
+ // Arguments are reversed on java expression stack
+ // Calculate address of start element
+ if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) {
+ __ ldr(buf, Address(esp, 2*wordSize)); // long buf
+ __ ldrw(off, Address(esp, wordSize)); // offset
+ __ add(buf, buf, off); // + offset
+ __ ldrw(crc, Address(esp, 4*wordSize)); // Initial CRC
+ } else {
+ __ ldr(buf, Address(esp, 2*wordSize)); // byte[] array
+ __ add(buf, buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // + header size
+ __ ldrw(off, Address(esp, wordSize)); // offset
+ __ add(buf, buf, off); // + offset
+ __ ldrw(crc, Address(esp, 3*wordSize)); // Initial CRC
+ }
+ // Can now load 'len' since we're finished with 'off'
+ __ ldrw(len, Address(esp, 0x0)); // Length
+
+ __ andr(sp, r13, -16); // Restore the caller's SP
+
+ // We are frameless so we can just jump to the stub.
+ __ b(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32()));
+
+ // 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 InterpreterGenerator::bang_stack_shadow_pages(bool native_call) {
+ // Bang each page in the shadow zone. We can't assume it's been done for
+ // an interpreter frame with greater than a page of locals, so each page
+ // needs to be checked. Only true for non-native.
+ if (UseStackBanging) {
+ const int start_page = native_call ? StackShadowPages : 1;
+ const int page_size = os::vm_page_size();
+ for (int pages = start_page; pages <= StackShadowPages ; pages++) {
+ __ sub(rscratch2, sp, pages*page_size);
+ __ str(zr, Address(rscratch2));
+ }
+ }
+}
+
+
+// Interpreter stub for calling a native method. (asm interpreter)
+// This sets up a somewhat different looking stack for calling the
+// native method than the typical interpreter frame setup.
+address InterpreterGenerator::generate_native_entry(bool synchronized) {
+ // determine code generation flags
+ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
+
+ // r1: Method*
+ // rscratch1: sender sp
+
+ address entry_point = __ pc();
+
+ const Address constMethod (rmethod, Method::const_offset());
+ const Address access_flags (rmethod, Method::access_flags_offset());
+ const Address size_of_parameters(r2, ConstMethod::
+ size_of_parameters_offset());
+
+ // get parameter size (always needed)
+ __ ldr(r2, constMethod);
+ __ load_unsigned_short(r2, size_of_parameters);
+
+ // native calls don't need the stack size check since they have no
+ // expression stack and the arguments are already on the stack and
+ // we only add a handful of words to the stack
+
+ // rmethod: Method*
+ // r2: size of parameters
+ // rscratch1: sender sp
+
+ // for natives the size of locals is zero
+
+ // compute beginning of parameters (rlocals)
+ __ add(rlocals, esp, r2, ext::uxtx, 3);
+ __ add(rlocals, rlocals, -wordSize);
+
+ // Pull SP back to minimum size: this avoids holes in the stack
+ __ andr(sp, esp, -16);
+
+ // initialize fixed part of activation frame
+ generate_fixed_frame(true);
+#ifndef PRODUCT
+ // tell the simulator that a method has been entered
+ if (NotifySimulator) {
+ __ notify(Assembler::method_entry);
+ }
+#endif
+
+ // make sure method is native & not abstract
+#ifdef ASSERT
+ __ ldrw(r0, access_flags);
+ {
+ Label L;
+ __ tst(r0, JVM_ACC_NATIVE);
+ __ br(Assembler::NE, L);
+ __ stop("tried to execute non-native method as native");
+ __ bind(L);
+ }
+ {
+ Label L;
+ __ tst(r0, JVM_ACC_ABSTRACT);
+ __ br(Assembler::EQ, L);
+ __ stop("tried to execute abstract method in interpreter");
+ __ bind(L);
+ }
+#endif
+
+ // Since at this point in the method invocation the exception
+ // handler would try to exit the monitor of synchronized methods
+ // which hasn't been entered yet, we set the thread local variable
+ // _do_not_unlock_if_synchronized to true. The remove_activation
+ // will check this flag.
+
+ const Address do_not_unlock_if_synchronized(rthread,
+ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
+ __ mov(rscratch2, true);
+ __ strb(rscratch2, do_not_unlock_if_synchronized);
+
+ // increment invocation count & check for overflow
+ Label invocation_counter_overflow;
+ if (inc_counter) {
+ generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
+ }
+
+ Label continue_after_compile;
+ __ bind(continue_after_compile);
+
+ bang_stack_shadow_pages(true);
+
+ // reset the _do_not_unlock_if_synchronized flag
+ __ strb(zr, do_not_unlock_if_synchronized);
+
+ // check for synchronized methods
+ // Must happen AFTER invocation_counter check and stack overflow check,
+ // so method is not locked if overflows.
+ if (synchronized) {
+ lock_method();
+ } else {
+ // no synchronization necessary
+#ifdef ASSERT
+ {
+ Label L;
+ __ ldrw(r0, access_flags);
+ __ tst(r0, JVM_ACC_SYNCHRONIZED);
+ __ br(Assembler::EQ, L);
+ __ stop("method needs synchronization");
+ __ bind(L);
+ }
+#endif
+ }
+
+ // start execution
+#ifdef ASSERT
+ {
+ Label L;
+ const Address monitor_block_top(rfp,
+ frame::interpreter_frame_monitor_block_top_offset * wordSize);
+ __ ldr(rscratch1, monitor_block_top);
+ __ cmp(esp, rscratch1);
+ __ br(Assembler::EQ, L);
+ __ stop("broken stack frame setup in interpreter");
+ __ bind(L);
+ }
+#endif
+
+ // jvmti support
+ __ notify_method_entry();
+
+ // work registers
+ const Register t = r17;
+ const Register result_handler = r19;
+
+ // allocate space for parameters
+ __ ldr(t, Address(rmethod, Method::const_offset()));
+ __ load_unsigned_short(t, Address(t, ConstMethod::size_of_parameters_offset()));
+
+ __ sub(rscratch1, esp, t, ext::uxtx, Interpreter::logStackElementSize);
+ __ andr(sp, rscratch1, -16);
+ __ mov(esp, rscratch1);
+
+ // get signature handler
+ {
+ Label L;
+ __ ldr(t, Address(rmethod, Method::signature_handler_offset()));
+ __ cbnz(t, L);
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::prepare_native_call),
+ rmethod);
+ __ ldr(t, Address(rmethod, Method::signature_handler_offset()));
+ __ bind(L);
+ }
+
+ // call signature handler
+ assert(InterpreterRuntime::SignatureHandlerGenerator::from() == rlocals,
+ "adjust this code");
+ assert(InterpreterRuntime::SignatureHandlerGenerator::to() == sp,
+ "adjust this code");
+ assert(InterpreterRuntime::SignatureHandlerGenerator::temp() == rscratch1,
+ "adjust this code");
+
+ // The generated handlers do not touch rmethod (the method).
+ // However, large signatures cannot be cached and are generated
+ // each time here. The slow-path generator can do a GC on return,
+ // so we must reload it after the call.
+ __ blr(t);
+ __ get_method(rmethod); // slow path can do a GC, reload rmethod
+
+
+ // result handler is in r0
+ // set result handler
+ __ mov(result_handler, r0);
+ // pass mirror handle if static call
+ {
+ Label L;
+ const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+ __ ldrw(t, Address(rmethod, Method::access_flags_offset()));
+ __ tst(t, JVM_ACC_STATIC);
+ __ br(Assembler::EQ, L);
+ // get mirror
+ __ ldr(t, Address(rmethod, Method::const_offset()));
+ __ ldr(t, Address(t, ConstMethod::constants_offset()));
+ __ ldr(t, Address(t, ConstantPool::pool_holder_offset_in_bytes()));
+ __ ldr(t, Address(t, mirror_offset));
+ // copy mirror into activation frame
+ __ str(t, Address(rfp, frame::interpreter_frame_oop_temp_offset * wordSize));
+ // pass handle to mirror
+ __ add(c_rarg1, rfp, frame::interpreter_frame_oop_temp_offset * wordSize);
+ __ bind(L);
+ }
+
+ // get native function entry point in r10
+ {
+ Label L;
+ __ ldr(r10, Address(rmethod, Method::native_function_offset()));
+ address unsatisfied = (SharedRuntime::native_method_throw_unsatisfied_link_error_entry());
+ __ mov(rscratch2, unsatisfied);
+ __ ldr(rscratch2, rscratch2);
+ __ cmp(r10, rscratch2);
+ __ br(Assembler::NE, L);
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::prepare_native_call),
+ rmethod);
+ __ get_method(rmethod);
+ __ ldr(r10, Address(rmethod, Method::native_function_offset()));
+ __ bind(L);
+ }
+
+ // pass JNIEnv
+ __ add(c_rarg0, rthread, in_bytes(JavaThread::jni_environment_offset()));
+
+ // It is enough that the pc() points into the right code
+ // segment. It does not have to be the correct return pc.
+ __ set_last_Java_frame(esp, rfp, (address)NULL, rscratch1);
+
+ // change thread state
+#ifdef ASSERT
+ {
+ Label L;
+ __ ldrw(t, Address(rthread, JavaThread::thread_state_offset()));
+ __ cmp(t, _thread_in_Java);
+ __ br(Assembler::EQ, L);
+ __ stop("Wrong thread state in native stub");
+ __ bind(L);
+ }
+#endif
+
+ // Change state to native
+ __ mov(rscratch1, _thread_in_native);
+ __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
+ __ stlrw(rscratch1, rscratch2);
+
+ // Call the native method.
+ __ blrt(r10, rscratch1);
+ __ maybe_isb();
+ __ get_method(rmethod);
+ // result potentially in r0 or v0
+
+ // make room for the pushes we're about to do
+ __ sub(rscratch1, esp, 4 * wordSize);
+ __ andr(sp, rscratch1, -16);
+
+ // NOTE: The order of these pushes is known to frame::interpreter_frame_result
+ // in order to extract the result of a method call. If the order of these
+ // pushes change or anything else is added to the stack then the code in
+ // interpreter_frame_result must also change.
+ __ push(dtos);
+ __ push(ltos);
+
+ // change thread state
+ __ mov(rscratch1, _thread_in_native_trans);
+ __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
+ __ stlrw(rscratch1, rscratch2);
+
+ if (os::is_MP()) {
+ if (UseMembar) {
+ // Force this write out before the read below
+ __ dsb(Assembler::SY);
+ } else {
+ // 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
+ // due to cache line collision.
+ __ serialize_memory(rthread, rscratch2);
+ }
+ }
+
+ // check for safepoint operation in progress and/or pending suspend requests
+ {
+ Label Continue;
+ {
+ unsigned long offset;
+ __ adrp(rscratch2, SafepointSynchronize::address_of_state(), offset);
+ __ ldrw(rscratch2, Address(rscratch2, offset));
+ }
+ assert(SafepointSynchronize::_not_synchronized == 0,
+ "SafepointSynchronize::_not_synchronized");
+ Label L;
+ __ cbnz(rscratch2, L);
+ __ ldrw(rscratch2, Address(rthread, JavaThread::suspend_flags_offset()));
+ __ cbz(rscratch2, 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. So we do a runtime call by
+ // hand.
+ //
+ __ mov(c_rarg0, rthread);
+ __ mov(rscratch2, CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans));
+ __ blrt(rscratch2, 1, 0, 0);
+ __ maybe_isb();
+ __ get_method(rmethod);
+ __ reinit_heapbase();
+ __ bind(Continue);
+ }
+
+ // change thread state
+ __ mov(rscratch1, _thread_in_Java);
+ __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
+ __ stlrw(rscratch1, rscratch2);
+
+ // reset_last_Java_frame
+ __ reset_last_Java_frame(true, true);
+
+ // reset handle block
+ __ ldr(t, Address(rthread, JavaThread::active_handles_offset()));
+ __ str(zr, Address(t, JNIHandleBlock::top_offset_in_bytes()));
+
+ // If result is an oop unbox and store it in frame where gc will see it
+ // and result handler will pick it up
+
+ {
+ Label no_oop, store_result;
+ __ adr(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT)));
+ __ cmp(t, result_handler);
+ __ br(Assembler::NE, no_oop);
+ // retrieve result
+ __ pop(ltos);
+ __ cbz(r0, store_result);
+ __ ldr(r0, Address(r0, 0));
+ __ bind(store_result);
+ __ str(r0, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize));
+ // keep stack depth as expected by pushing oop which will eventually be discarded
+ __ push(ltos);
+ __ bind(no_oop);
+ }
+
+ {
+ Label no_reguard;
+ __ lea(rscratch1, Address(rthread, in_bytes(JavaThread::stack_guard_state_offset())));
+ __ ldrb(rscratch1, Address(rscratch1));
+ __ cmp(rscratch1, JavaThread::stack_guard_yellow_disabled);
+ __ br(Assembler::NE, no_reguard);
+
+ __ pusha(); // XXX only save smashed registers
+ __ mov(c_rarg0, rthread);
+ __ mov(rscratch2, CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages));
+ __ blrt(rscratch2, 0, 0, 0);
+ __ popa(); // XXX only restore smashed registers
+ __ bind(no_reguard);
+ }
+
+ // The method register is junk from after the thread_in_native transition
+ // until here. Also can't call_VM until the bcp has been
+ // restored. Need bcp for throwing exception below so get it now.
+ __ get_method(rmethod);
+
+ // restore bcp to have legal interpreter frame, i.e., bci == 0 <=>
+ // rbcp == code_base()
+ __ ldr(rbcp, Address(rmethod, Method::const_offset())); // get ConstMethod*
+ __ add(rbcp, rbcp, in_bytes(ConstMethod::codes_offset())); // get codebase
+ // handle exceptions (exception handling will handle unlocking!)
+ {
+ Label L;
+ __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset()));
+ __ cbz(rscratch1, L);
+ // Note: At some point we may want to unify this with the code
+ // used in call_VM_base(); i.e., we should use the
+ // StubRoutines::forward_exception code. For now this doesn't work
+ // here because the rsp is not correctly set at this point.
+ __ MacroAssembler::call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_pending_exception));
+ __ should_not_reach_here();
+ __ bind(L);
+ }
+
+ // do unlocking if necessary
+ {
+ Label L;
+ __ ldrw(t, Address(rmethod, Method::access_flags_offset()));
+ __ tst(t, JVM_ACC_SYNCHRONIZED);
+ __ br(Assembler::EQ, L);
+ // the code below should be shared with interpreter macro
+ // assembler implementation
+ {
+ Label unlock;
+ // BasicObjectLock will be first in list, since this is a
+ // synchronized method. However, need to check that the object
+ // has not been unlocked by an explicit monitorexit bytecode.
+
+ // monitor expect in c_rarg1 for slow unlock path
+ __ lea (c_rarg1, Address(rfp, // address of first monitor
+ (intptr_t)(frame::interpreter_frame_initial_sp_offset *
+ wordSize - sizeof(BasicObjectLock))));
+
+ __ ldr(t, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()));
+ __ cbnz(t, unlock);
+
+ // Entry already unlocked, need to throw exception
+ __ MacroAssembler::call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_illegal_monitor_state_exception));
+ __ should_not_reach_here();
+
+ __ bind(unlock);
+ __ unlock_object(c_rarg1);
+ }
+ __ bind(L);
+ }
+
+ // jvmti support
+ // Note: This must happen _after_ handling/throwing any exceptions since
+ // the exception handler code notifies the runtime of method exits
+ // too. If this happens before, method entry/exit notifications are
+ // not properly paired (was bug - gri 11/22/99).
+ __ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI);
+
+ // restore potential result in r0:d0, call result handler to
+ // restore potential result in ST0 & handle result
+
+ __ pop(ltos);
+ __ pop(dtos);
+
+ __ blr(result_handler);
+
+ // remove activation
+ __ ldr(esp, Address(rfp,
+ frame::interpreter_frame_sender_sp_offset *
+ wordSize)); // get sender sp
+ // remove frame anchor
+ __ leave();
+
+ // resture sender sp
+ __ mov(sp, esp);
+
+ __ ret(lr);
+
+ if (inc_counter) {
+ // Handle overflow of counter and compile method
+ __ bind(invocation_counter_overflow);
+ generate_counter_overflow(&continue_after_compile);
+ }
+
+ return entry_point;
+}
+
+//
+// Generic interpreted method entry to (asm) interpreter
+//
+address InterpreterGenerator::generate_normal_entry(bool synchronized) {
+ // determine code generation flags
+ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
+
+ // rscratch1: sender sp
+ address entry_point = __ pc();
+
+ const Address constMethod(rmethod, Method::const_offset());
+ const Address access_flags(rmethod, Method::access_flags_offset());
+ const Address size_of_parameters(r3,
+ ConstMethod::size_of_parameters_offset());
+ const Address size_of_locals(r3, ConstMethod::size_of_locals_offset());
+
+ // get parameter size (always needed)
+ // need to load the const method first
+ __ ldr(r3, constMethod);
+ __ load_unsigned_short(r2, size_of_parameters);
+
+ // r2: size of parameters
+
+ __ load_unsigned_short(r3, size_of_locals); // get size of locals in words
+ __ sub(r3, r3, r2); // r3 = no. of additional locals
+
+ // see if we've got enough room on the stack for locals plus overhead.
+ generate_stack_overflow_check();
+
+ // compute beginning of parameters (rlocals)
+ __ add(rlocals, esp, r2, ext::uxtx, 3);
+ __ sub(rlocals, rlocals, wordSize);
+
+ // Make room for locals
+ __ sub(rscratch1, esp, r3, ext::uxtx, 3);
+ __ andr(sp, rscratch1, -16);
+
+ // r3 - # of additional locals
+ // allocate space for locals
+ // explicitly initialize locals
+ {
+ Label exit, loop;
+ __ ands(zr, r3, r3);
+ __ br(Assembler::LE, exit); // do nothing if r3 <= 0
+ __ bind(loop);
+ __ str(zr, Address(__ post(rscratch1, wordSize)));
+ __ sub(r3, r3, 1); // until everything initialized
+ __ cbnz(r3, loop);
+ __ bind(exit);
+ }
+
+ // And the base dispatch table
+ __ get_dispatch();
+
+ // initialize fixed part of activation frame
+ generate_fixed_frame(false);
+#ifndef PRODUCT
+ // tell the simulator that a method has been entered
+ if (NotifySimulator) {
+ __ notify(Assembler::method_entry);
+ }
+#endif
+ // make sure method is not native & not abstract
+#ifdef ASSERT
+ __ ldrw(r0, access_flags);
+ {
+ Label L;
+ __ tst(r0, JVM_ACC_NATIVE);
+ __ br(Assembler::EQ, L);
+ __ stop("tried to execute native method as non-native");
+ __ bind(L);
+ }
+ {
+ Label L;
+ __ tst(r0, JVM_ACC_ABSTRACT);
+ __ br(Assembler::EQ, L);
+ __ stop("tried to execute abstract method in interpreter");
+ __ bind(L);
+ }
+#endif
+
+ // Since at this point in the method invocation the exception
+ // handler would try to exit the monitor of synchronized methods
+ // which hasn't been entered yet, we set the thread local variable
+ // _do_not_unlock_if_synchronized to true. The remove_activation
+ // will check this flag.
+
+ const Address do_not_unlock_if_synchronized(rthread,
+ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
+ __ mov(rscratch2, true);
+ __ strb(rscratch2, do_not_unlock_if_synchronized);
+
+ // increment invocation count & check for overflow
+ Label invocation_counter_overflow;
+ Label profile_method;
+ Label profile_method_continue;
+ if (inc_counter) {
+ generate_counter_incr(&invocation_counter_overflow,
+ &profile_method,
+ &profile_method_continue);
+ if (ProfileInterpreter) {
+ __ bind(profile_method_continue);
+ }
+ }
+
+ Label continue_after_compile;
+ __ bind(continue_after_compile);
+
+ bang_stack_shadow_pages(false);
+
+ // reset the _do_not_unlock_if_synchronized flag
+ __ strb(zr, do_not_unlock_if_synchronized);
+
+ // check for synchronized methods
+ // Must happen AFTER invocation_counter check and stack overflow check,
+ // so method is not locked if overflows.
+ if (synchronized) {
+ // Allocate monitor and lock method
+ lock_method();
+ } else {
+ // no synchronization necessary
+#ifdef ASSERT
+ {
+ Label L;
+ __ ldrw(r0, access_flags);
+ __ tst(r0, JVM_ACC_SYNCHRONIZED);
+ __ br(Assembler::EQ, L);
+ __ stop("method needs synchronization");
+ __ bind(L);
+ }
+#endif
+ }
+
+ // start execution
+#ifdef ASSERT
+ {
+ Label L;
+ const Address monitor_block_top (rfp,
+ frame::interpreter_frame_monitor_block_top_offset * wordSize);
+ __ ldr(rscratch1, monitor_block_top);
+ __ cmp(esp, rscratch1);
+ __ br(Assembler::EQ, L);
+ __ stop("broken stack frame setup in interpreter");
+ __ bind(L);
+ }
+#endif
+
+ // jvmti support
+ __ notify_method_entry();
+
+ __ dispatch_next(vtos);
+
+ // invocation counter overflow
+ if (inc_counter) {
+ if (ProfileInterpreter) {
+ // We have decided to profile this method in the interpreter
+ __ bind(profile_method);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
+ __ set_method_data_pointer_for_bcp();
+ // don't think we need this
+ __ get_method(r1);
+ __ b(profile_method_continue);
+ }
+ // Handle overflow of counter and compile method
+ __ bind(invocation_counter_overflow);
+ generate_counter_overflow(&continue_after_compile);
+ }
+
+ return entry_point;
+}
+
+//-----------------------------------------------------------------------------
+// Exceptions
+
+void TemplateInterpreterGenerator::generate_throw_exception() {
+ // Entry point in previous activation (i.e., if the caller was
+ // interpreted)
+ Interpreter::_rethrow_exception_entry = __ pc();
+ // Restore sp to interpreter_frame_last_sp even though we are going
+ // to empty the expression stack for the exception processing.
+ __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
+ // r0: exception
+ // r3: return address/pc that threw exception
+ __ restore_bcp(); // rbcp points to call/send
+ __ restore_locals();
+ __ restore_constant_pool_cache();
+ __ reinit_heapbase(); // restore rheapbase as heapbase.
+ __ get_dispatch();
+
+#ifndef PRODUCT
+ // tell the simulator that the caller method has been reentered
+ if (NotifySimulator) {
+ __ get_method(rmethod);
+ __ notify(Assembler::method_reentry);
+ }
+#endif
+ // Entry point for exceptions thrown within interpreter code
+ Interpreter::_throw_exception_entry = __ pc();
+ // If we came here via a NullPointerException on the receiver of a
+ // method, rmethod may be corrupt.
+ __ get_method(rmethod);
+ // expression stack is undefined here
+ // r0: exception
+ // rbcp: exception bcp
+ __ verify_oop(r0);
+ __ mov(c_rarg1, r0);
+
+ // expression stack must be empty before entering the VM in case of
+ // an exception
+ __ empty_expression_stack();
+ // find exception handler address and preserve exception oop
+ __ call_VM(r3,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::exception_handler_for_exception),
+ c_rarg1);
+
+ // Calculate stack limit
+ __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
+ __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset()));
+ __ add(rscratch1, rscratch1, frame::interpreter_frame_monitor_size() + 4);
+ __ ldr(rscratch2,
+ Address(rfp, frame::interpreter_frame_initial_sp_offset * wordSize));
+ __ sub(rscratch1, rscratch2, rscratch1, ext::uxtx, 3);
+ __ andr(sp, rscratch1, -16);
+
+ // r0: exception handler entry point
+ // r3: preserved exception oop
+ // rbcp: bcp for exception handler
+ __ push_ptr(r3); // push exception which is now the only value on the stack
+ __ br(r0); // jump to exception handler (may be _remove_activation_entry!)
+
+ // If the exception is not handled in the current frame the frame is
+ // removed and the exception is rethrown (i.e. exception
+ // continuation is _rethrow_exception).
+ //
+ // Note: At this point the bci is still the bxi for the instruction
+ // which caused the exception and the expression stack is
+ // empty. Thus, for any VM calls at this point, GC will find a legal
+ // oop map (with empty expression stack).
+
+ //
+ // JVMTI PopFrame support
+ //
+
+ Interpreter::_remove_activation_preserving_args_entry = __ pc();
+ __ empty_expression_stack();
+ // Set the popframe_processing bit in pending_popframe_condition
+ // indicating that we are currently handling popframe, so that
+ // call_VMs that may happen later do not trigger new popframe
+ // handling cycles.
+ __ ldrw(r3, Address(rthread, JavaThread::popframe_condition_offset()));
+ __ orr(r3, r3, JavaThread::popframe_processing_bit);
+ __ strw(r3, Address(rthread, JavaThread::popframe_condition_offset()));
+
+ {
+ // Check to see whether we are returning to a deoptimized frame.
+ // (The PopFrame call ensures that the caller of the popped frame is
+ // either interpreted or compiled and deoptimizes it if compiled.)
+ // In this case, we can't call dispatch_next() after the frame is
+ // popped, but instead must save the incoming arguments and restore
+ // them after deoptimization has occurred.
+ //
+ // Note that we don't compare the return PC against the
+ // deoptimization blob's unpack entry because of the presence of
+ // adapter frames in C2.
+ Label caller_not_deoptimized;
+ __ ldr(c_rarg1, Address(rfp, frame::return_addr_offset * wordSize));
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::interpreter_contains), c_rarg1);
+ __ cbnz(r0, caller_not_deoptimized);
+
+ // Compute size of arguments for saving when returning to
+ // deoptimized caller
+ __ get_method(r0);
+ __ ldr(r0, Address(r0, Method::const_offset()));
+ __ load_unsigned_short(r0, Address(r0, in_bytes(ConstMethod::
+ size_of_parameters_offset())));
+ __ lsl(r0, r0, Interpreter::logStackElementSize);
+ __ restore_locals(); // XXX do we need this?
+ __ sub(rlocals, rlocals, r0);
+ __ add(rlocals, rlocals, wordSize);
+ // Save these arguments
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
+ Deoptimization::
+ popframe_preserve_args),
+ rthread, r0, rlocals);
+
+ __ remove_activation(vtos,
+ /* throw_monitor_exception */ false,
+ /* install_monitor_exception */ false,
+ /* notify_jvmdi */ false);
+
+ // Inform deoptimization that it is responsible for restoring
+ // these arguments
+ __ mov(rscratch1, JavaThread::popframe_force_deopt_reexecution_bit);
+ __ strw(rscratch1, Address(rthread, JavaThread::popframe_condition_offset()));
+
+ // Continue in deoptimization handler
+ __ ret(lr);
+
+ __ bind(caller_not_deoptimized);
+ }
+
+ __ remove_activation(vtos,
+ /* throw_monitor_exception */ false,
+ /* install_monitor_exception */ false,
+ /* notify_jvmdi */ false);
+
+ // Restore the last_sp and null it out
+ __ ldr(esp, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
+ __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
+
+ __ restore_bcp();
+ __ restore_locals();
+ __ restore_constant_pool_cache();
+ __ get_method(rmethod);
+
+ // The method data pointer was incremented already during
+ // call profiling. We have to restore the mdp for the current bcp.
+ if (ProfileInterpreter) {
+ __ set_method_data_pointer_for_bcp();
+ }
+
+ // Clear the popframe condition flag
+ __ strw(zr, Address(rthread, JavaThread::popframe_condition_offset()));
+ assert(JavaThread::popframe_inactive == 0, "fix popframe_inactive");
+
+#if INCLUDE_JVMTI
+ {
+ Label L_done;
+
+ __ ldrb(rscratch1, Address(rbcp, 0));
+ __ cmpw(r1, Bytecodes::_invokestatic);
+ __ br(Assembler::EQ, L_done);
+
+ // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
+ // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
+
+ __ ldr(c_rarg0, Address(rlocals, 0));
+ __ call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), c_rarg0, rmethod, rbcp);
+
+ __ cbz(r0, L_done);
+
+ __ str(r0, Address(esp, 0));
+ __ bind(L_done);
+ }
+#endif // INCLUDE_JVMTI
+
+ // Restore machine SP
+ __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
+ __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset()));
+ __ add(rscratch1, rscratch1, frame::interpreter_frame_monitor_size() + 4);
+ __ ldr(rscratch2,
+ Address(rfp, frame::interpreter_frame_initial_sp_offset * wordSize));
+ __ sub(rscratch1, rscratch2, rscratch1, ext::uxtw, 3);
+ __ andr(sp, rscratch1, -16);
+
+ __ dispatch_next(vtos);
+ // end of PopFrame support
+
+ Interpreter::_remove_activation_entry = __ pc();
+
+ // preserve exception over this code sequence
+ __ pop_ptr(r0);
+ __ str(r0, Address(rthread, JavaThread::vm_result_offset()));
+ // remove the activation (without doing throws on illegalMonitorExceptions)
+ __ remove_activation(vtos, false, true, false);
+ // restore exception
+ // restore exception
+ __ get_vm_result(r0, rthread);
+
+ // In between activations - previous activation type unknown yet
+ // compute continuation point - the continuation point expects the
+ // following registers set up:
+ //
+ // r0: exception
+ // lr: return address/pc that threw exception
+ // rsp: expression stack of caller
+ // rfp: fp of caller
+ // FIXME: There's no point saving LR here because VM calls don't trash it
+ __ stp(r0, lr, Address(__ pre(sp, -2 * wordSize))); // save exception & return address
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
+ SharedRuntime::exception_handler_for_return_address),
+ rthread, lr);
+ __ mov(r1, r0); // save exception handler
+ __ ldp(r0, lr, Address(__ post(sp, 2 * wordSize))); // restore exception & return address
+ // We might be returning to a deopt handler that expects r3 to
+ // contain the exception pc
+ __ mov(r3, lr);
+ // Note that an "issuing PC" is actually the next PC after the call
+ __ br(r1); // jump to exception
+ // handler of caller
+}
+
+
+//
+// JVMTI ForceEarlyReturn support
+//
+address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
+ address entry = __ pc();
+
+ __ restore_bcp();
+ __ restore_locals();
+ __ empty_expression_stack();
+ __ load_earlyret_value(state);
+
+ __ ldr(rscratch1, Address(rthread, JavaThread::jvmti_thread_state_offset()));
+ Address cond_addr(rscratch1, JvmtiThreadState::earlyret_state_offset());
+
+ // Clear the earlyret state
+ assert(JvmtiThreadState::earlyret_inactive == 0, "should be");
+ __ str(zr, cond_addr);
+
+ __ remove_activation(state,
+ false, /* throw_monitor_exception */
+ false, /* install_monitor_exception */
+ true); /* notify_jvmdi */
+ __ ret(lr);
+
+ return entry;
+} // end of ForceEarlyReturn support
+
+
+
+//-----------------------------------------------------------------------------
+// Helper for vtos entry point generation
+
+void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
+ address& bep,
+ address& cep,
+ address& sep,
+ address& aep,
+ address& iep,
+ address& lep,
+ address& fep,
+ address& dep,
+ address& vep) {
+ assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
+ Label L;
+ aep = __ pc(); __ push_ptr(); __ b(L);
+ fep = __ pc(); __ push_f(); __ b(L);
+ dep = __ pc(); __ push_d(); __ b(L);
+ lep = __ pc(); __ push_l(); __ b(L);
+ bep = cep = sep =
+ iep = __ pc(); __ push_i();
+ vep = __ pc();
+ __ bind(L);
+ generate_and_dispatch(t);
+}
+
+//-----------------------------------------------------------------------------
+// Generation of individual instructions
+
+// helpers for generate_and_dispatch
+
+
+InterpreterGenerator::InterpreterGenerator(StubQueue* code)
+ : TemplateInterpreterGenerator(code) {
+ generate_all(); // down here so it can be "virtual"
+}
+
+//-----------------------------------------------------------------------------
+
+// Non-product code
+#ifndef PRODUCT
+address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
+ address entry = __ pc();
+
+ __ push(lr);
+ __ push(state);
+ __ push(RegSet::range(r0, r15), sp);
+ __ mov(c_rarg2, r0); // Pass itos
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode),
+ c_rarg1, c_rarg2, c_rarg3);
+ __ pop(RegSet::range(r0, r15), sp);
+ __ pop(state);
+ __ pop(lr);
+ __ ret(lr); // return from result handler
+
+ return entry;
+}
+
+void TemplateInterpreterGenerator::count_bytecode() {
+ Register rscratch3 = r0;
+ __ push(rscratch1);
+ __ push(rscratch2);
+ __ push(rscratch3);
+ Label L;
+ __ mov(rscratch2, (address) &BytecodeCounter::_counter_value);
+ __ bind(L);
+ __ ldxr(rscratch1, rscratch2);
+ __ add(rscratch1, rscratch1, 1);
+ __ stxr(rscratch3, rscratch1, rscratch2);
+ __ cbnzw(rscratch3, L);
+ __ pop(rscratch3);
+ __ pop(rscratch2);
+ __ pop(rscratch1);
+}
+
+void TemplateInterpreterGenerator::histogram_bytecode(Template* t) { ; }
+
+void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) { ; }
+
+
+void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
+ // Call a little run-time stub to avoid blow-up for each bytecode.
+ // The run-time runtime saves the right registers, depending on
+ // the tosca in-state for the given template.
+
+ assert(Interpreter::trace_code(t->tos_in()) != NULL,
+ "entry must have been generated");
+ __ bl(Interpreter::trace_code(t->tos_in()));
+ __ reinit_heapbase();
+}
+
+
+void TemplateInterpreterGenerator::stop_interpreter_at() {
+ Label L;
+ __ push(rscratch1);
+ __ mov(rscratch1, (address) &BytecodeCounter::_counter_value);
+ __ ldr(rscratch1, Address(rscratch1));
+ __ mov(rscratch2, StopInterpreterAt);
+ __ cmpw(rscratch1, rscratch2);
+ __ br(Assembler::NE, L);
+ __ brk(0);
+ __ bind(L);
+ __ pop(rscratch1);
+}
+
+#ifdef BUILTIN_SIM
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+extern "C" {
+ static int PAGESIZE = getpagesize();
+ int is_mapped_address(u_int64_t address)
+ {
+ address = (address & ~((u_int64_t)PAGESIZE - 1));
+ if (msync((void *)address, PAGESIZE, MS_ASYNC) == 0) {
+ return true;
+ }
+ if (errno != ENOMEM) {
+ return true;
+ }
+ return false;
+ }
+
+ void bccheck1(u_int64_t pc, u_int64_t fp, char *method, int *bcidx, int *framesize, char *decode)
+ {
+ if (method != 0) {
+ method[0] = '\0';
+ }
+ if (bcidx != 0) {
+ *bcidx = -2;
+ }
+ if (decode != 0) {
+ decode[0] = 0;
+ }
+
+ if (framesize != 0) {
+ *framesize = -1;
+ }
+
+ if (Interpreter::contains((address)pc)) {
+ AArch64Simulator *sim = AArch64Simulator::get_current(UseSimulatorCache, DisableBCCheck);
+ Method* meth;
+ address bcp;
+ if (fp) {
+#define FRAME_SLOT_METHOD 3
+#define FRAME_SLOT_BCP 7
+ meth = (Method*)sim->getMemory()->loadU64(fp - (FRAME_SLOT_METHOD << 3));
+ bcp = (address)sim->getMemory()->loadU64(fp - (FRAME_SLOT_BCP << 3));
+#undef FRAME_SLOT_METHOD
+#undef FRAME_SLOT_BCP
+ } else {
+ meth = (Method*)sim->getCPUState().xreg(RMETHOD, 0);
+ bcp = (address)sim->getCPUState().xreg(RBCP, 0);
+ }
+ if (meth->is_native()) {
+ return;
+ }
+ if(method && meth->is_method()) {
+ ResourceMark rm;
+ method[0] = 'I';
+ method[1] = ' ';
+ meth->name_and_sig_as_C_string(method + 2, 398);
+ }
+ if (bcidx) {
+ if (meth->contains(bcp)) {
+ *bcidx = meth->bci_from(bcp);
+ } else {
+ *bcidx = -2;
+ }
+ }
+ if (decode) {
+ if (!BytecodeTracer::closure()) {
+ BytecodeTracer::set_closure(BytecodeTracer::std_closure());
+ }
+ stringStream str(decode, 400);
+ BytecodeTracer::trace(meth, bcp, &str);
+ }
+ } else {
+ if (method) {
+ CodeBlob *cb = CodeCache::find_blob((address)pc);
+ if (cb != NULL) {
+ if (cb->is_nmethod()) {
+ ResourceMark rm;
+ nmethod* nm = (nmethod*)cb;
+ method[0] = 'C';
+ method[1] = ' ';
+ nm->method()->name_and_sig_as_C_string(method + 2, 398);
+ } else if (cb->is_adapter_blob()) {
+ strcpy(method, "B adapter blob");
+ } else if (cb->is_runtime_stub()) {
+ strcpy(method, "B runtime stub");
+ } else if (cb->is_exception_stub()) {
+ strcpy(method, "B exception stub");
+ } else if (cb->is_deoptimization_stub()) {
+ strcpy(method, "B deoptimization stub");
+ } else if (cb->is_safepoint_stub()) {
+ strcpy(method, "B safepoint stub");
+ } else if (cb->is_uncommon_trap_stub()) {
+ strcpy(method, "B uncommon trap stub");
+ } else if (cb->contains((address)StubRoutines::call_stub())) {
+ strcpy(method, "B call stub");
+ } else {
+ strcpy(method, "B unknown blob : ");
+ strcat(method, cb->name());
+ }
+ if (framesize != NULL) {
+ *framesize = cb->frame_size();
+ }
+ }
+ }
+ }
+ }
+
+
+ JNIEXPORT void bccheck(u_int64_t pc, u_int64_t fp, char *method, int *bcidx, int *framesize, char *decode)
+ {
+ bccheck1(pc, fp, method, bcidx, framesize, decode);
+ }
+}
+
+#endif // BUILTIN_SIM
+#endif // !PRODUCT
+#endif // ! CC_INTERP
--- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -24,238 +24,12 @@
*/
#include "precompiled.hpp"
-#include "asm/macroAssembler.hpp"
-#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
-#include "interpreter/interpreterGenerator.hpp"
-#include "interpreter/interpreterRuntime.hpp"
-#include "interpreter/interp_masm.hpp"
-#include "interpreter/templateTable.hpp"
-#include "interpreter/bytecodeTracer.hpp"
-#include "oops/arrayOop.hpp"
-#include "oops/methodData.hpp"
-#include "oops/method.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/jvmtiExport.hpp"
-#include "prims/jvmtiThreadState.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/synchronizer.hpp"
-#include "runtime/timer.hpp"
-#include "runtime/vframeArray.hpp"
-#include "utilities/debug.hpp"
-#include <sys/types.h>
-
-#ifndef PRODUCT
+#include "oops/constMethod.hpp"
#include "oops/method.hpp"
-#endif // !PRODUCT
-
-#ifdef BUILTIN_SIM
-#include "../../../../../../simulator/simulator.hpp"
-#endif
-
-#define __ _masm->
-
-#ifndef CC_INTERP
-
-//-----------------------------------------------------------------------------
-
-extern "C" void entry(CodeBuffer*);
-
-//-----------------------------------------------------------------------------
-
-address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
- address entry = __ pc();
-
-#ifdef ASSERT
- {
- Label L;
- __ ldr(rscratch1, Address(rfp,
- frame::interpreter_frame_monitor_block_top_offset *
- wordSize));
- __ mov(rscratch2, sp);
- __ cmp(rscratch1, rscratch2); // maximal rsp for current rfp (stack
- // grows negative)
- __ br(Assembler::HS, L); // check if frame is complete
- __ stop ("interpreter frame not set up");
- __ bind(L);
- }
-#endif // ASSERT
- // Restore bcp under the assumption that the current frame is still
- // interpreted
- __ restore_bcp();
-
- // expression stack must be empty before entering the VM if an
- // exception happened
- __ empty_expression_stack();
- // throw exception
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_StackOverflowError));
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(
- const char* name) {
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an
- // exception happened
- __ empty_expression_stack();
- // setup parameters
- // ??? convention: expect aberrant index in register r1
- __ movw(c_rarg2, r1);
- __ mov(c_rarg1, (address)name);
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::
- throw_ArrayIndexOutOfBoundsException),
- c_rarg1, c_rarg2);
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
- address entry = __ pc();
-
- // object is at TOS
- __ pop(c_rarg1);
-
- // expression stack must be empty before entering the VM if an
- // exception happened
- __ empty_expression_stack();
-
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::
- throw_ClassCastException),
- c_rarg1);
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_exception_handler_common(
- const char* name, const char* message, bool pass_oop) {
- assert(!pass_oop || message == NULL, "either oop or message but not both");
- address entry = __ pc();
- if (pass_oop) {
- // object is at TOS
- __ pop(c_rarg2);
- }
- // expression stack must be empty before entering the VM if an
- // exception happened
- __ empty_expression_stack();
- // setup parameters
- __ lea(c_rarg1, Address((address)name));
- if (pass_oop) {
- __ call_VM(r0, CAST_FROM_FN_PTR(address,
- InterpreterRuntime::
- create_klass_exception),
- c_rarg1, c_rarg2);
- } else {
- // kind of lame ExternalAddress can't take NULL because
- // external_word_Relocation will assert.
- if (message != NULL) {
- __ lea(c_rarg2, Address((address)message));
- } else {
- __ mov(c_rarg2, NULL_WORD);
- }
- __ call_VM(r0,
- CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception),
- c_rarg1, c_rarg2);
- }
- // throw exception
- __ b(address(Interpreter::throw_exception_entry()));
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
- address entry = __ pc();
- // NULL last_sp until next java call
- __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
- __ dispatch_next(state);
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
- address entry = __ pc();
-
- // Restore stack bottom in case i2c adjusted stack
- __ ldr(esp, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
- // and NULL it as marker that esp is now tos until next java call
- __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
- __ restore_bcp();
- __ restore_locals();
- __ restore_constant_pool_cache();
- __ get_method(rmethod);
-
- // Pop N words from the stack
- __ get_cache_and_index_at_bcp(r1, r2, 1, index_size);
- __ ldr(r1, Address(r1, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
- __ andr(r1, r1, ConstantPoolCacheEntry::parameter_size_mask);
-
- __ add(esp, esp, r1, Assembler::LSL, 3);
-
- // Restore machine SP
- __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
- __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset()));
- __ add(rscratch1, rscratch1, frame::interpreter_frame_monitor_size() + 2);
- __ ldr(rscratch2,
- Address(rfp, frame::interpreter_frame_initial_sp_offset * wordSize));
- __ sub(rscratch1, rscratch2, rscratch1, ext::uxtw, 3);
- __ andr(sp, rscratch1, -16);
-
-#ifndef PRODUCT
- // tell the simulator that the method has been reentered
- if (NotifySimulator) {
- __ notify(Assembler::method_reentry);
- }
-#endif
- __ get_dispatch();
- __ dispatch_next(state, step);
-
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state,
- int step) {
- address entry = __ pc();
- __ restore_bcp();
- __ restore_locals();
- __ restore_constant_pool_cache();
- __ get_method(rmethod);
-
- // handle exceptions
- {
- Label L;
- __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset()));
- __ cbz(rscratch1, L);
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_pending_exception));
- __ should_not_reach_here();
- __ bind(L);
- }
-
- __ get_dispatch();
-
- // Calculate stack limit
- __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
- __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset()));
- __ add(rscratch1, rscratch1, frame::interpreter_frame_monitor_size() + 2);
- __ ldr(rscratch2,
- Address(rfp, frame::interpreter_frame_initial_sp_offset * wordSize));
- __ sub(rscratch1, rscratch2, rscratch1, ext::uxtx, 3);
- __ andr(sp, rscratch1, -16);
-
- // Restore expression stack pointer
- __ ldr(esp, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
- // NULL last_sp until next java call
- __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
-
- __ dispatch_next(state, step);
- return entry;
-}
+#include "runtime/frame.inline.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/macros.hpp"
int AbstractInterpreter::BasicType_as_index(BasicType type) {
@@ -279,1195 +53,6 @@
return i;
}
-
-address TemplateInterpreterGenerator::generate_result_handler_for(
- BasicType type) {
- address entry = __ pc();
- switch (type) {
- case T_BOOLEAN: __ uxtb(r0, r0); break;
- case T_CHAR : __ uxth(r0, r0); break;
- case T_BYTE : __ sxtb(r0, r0); break;
- case T_SHORT : __ sxth(r0, r0); break;
- case T_INT : __ uxtw(r0, r0); break; // FIXME: We almost certainly don't need this
- case T_LONG : /* nothing to do */ break;
- case T_VOID : /* nothing to do */ break;
- case T_FLOAT : /* nothing to do */ break;
- case T_DOUBLE : /* nothing to do */ break;
- case T_OBJECT :
- // retrieve result from frame
- __ ldr(r0, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize));
- // and verify it
- __ verify_oop(r0);
- break;
- default : ShouldNotReachHere();
- }
- __ ret(lr); // return from result handler
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_safept_entry_for(
- TosState state,
- address runtime_entry) {
- address entry = __ pc();
- __ push(state);
- __ call_VM(noreg, runtime_entry);
- __ membar(Assembler::AnyAny);
- __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos));
- return entry;
-}
-
-// Helpers for commoning out cases in the various type of method entries.
-//
-
-
-// increment invocation count & check for overflow
-//
-// Note: checking for negative value instead of overflow
-// so we have a 'sticky' overflow test
-//
-// rmethod: method
-//
-void InterpreterGenerator::generate_counter_incr(
- Label* overflow,
- Label* profile_method,
- Label* profile_method_continue) {
- Label done;
- // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not.
- if (TieredCompilation) {
- int increment = InvocationCounter::count_increment;
- Label no_mdo;
- if (ProfileInterpreter) {
- // Are we profiling?
- __ ldr(r0, Address(rmethod, Method::method_data_offset()));
- __ cbz(r0, no_mdo);
- // Increment counter in the MDO
- const Address mdo_invocation_counter(r0, in_bytes(MethodData::invocation_counter_offset()) +
- in_bytes(InvocationCounter::counter_offset()));
- const Address mask(r0, in_bytes(MethodData::invoke_mask_offset()));
- __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rscratch1, rscratch2, false, Assembler::EQ, overflow);
- __ b(done);
- }
- __ bind(no_mdo);
- // Increment counter in MethodCounters
- const Address invocation_counter(rscratch2,
- MethodCounters::invocation_counter_offset() +
- InvocationCounter::counter_offset());
- __ get_method_counters(rmethod, rscratch2, done);
- const Address mask(rscratch2, in_bytes(MethodCounters::invoke_mask_offset()));
- __ increment_mask_and_jump(invocation_counter, increment, mask, rscratch1, r1, false, Assembler::EQ, overflow);
- __ bind(done);
- } else { // not TieredCompilation
- const Address backedge_counter(rscratch2,
- MethodCounters::backedge_counter_offset() +
- InvocationCounter::counter_offset());
- const Address invocation_counter(rscratch2,
- MethodCounters::invocation_counter_offset() +
- InvocationCounter::counter_offset());
-
- __ get_method_counters(rmethod, rscratch2, done);
-
- if (ProfileInterpreter) { // %%% Merge this into MethodData*
- __ ldrw(r1, Address(rscratch2, MethodCounters::interpreter_invocation_counter_offset()));
- __ addw(r1, r1, 1);
- __ strw(r1, Address(rscratch2, MethodCounters::interpreter_invocation_counter_offset()));
- }
- // Update standard invocation counters
- __ ldrw(r1, invocation_counter);
- __ ldrw(r0, backedge_counter);
-
- __ addw(r1, r1, InvocationCounter::count_increment);
- __ andw(r0, r0, InvocationCounter::count_mask_value);
-
- __ strw(r1, invocation_counter);
- __ addw(r0, r0, r1); // add both counters
-
- // profile_method is non-null only for interpreted method so
- // profile_method != NULL == !native_call
-
- if (ProfileInterpreter && profile_method != NULL) {
- // Test to see if we should create a method data oop
- __ ldr(rscratch2, Address(rmethod, Method::method_counters_offset()));
- __ ldrw(rscratch2, Address(rscratch2, in_bytes(MethodCounters::interpreter_profile_limit_offset())));
- __ cmpw(r0, rscratch2);
- __ br(Assembler::LT, *profile_method_continue);
-
- // if no method data exists, go to profile_method
- __ test_method_data_pointer(r0, *profile_method);
- }
-
- {
- __ ldr(rscratch2, Address(rmethod, Method::method_counters_offset()));
- __ ldrw(rscratch2, Address(rscratch2, in_bytes(MethodCounters::interpreter_invocation_limit_offset())));
- __ cmpw(r0, rscratch2);
- __ br(Assembler::HS, *overflow);
- }
- __ bind(done);
- }
-}
-
-void InterpreterGenerator::generate_counter_overflow(Label* do_continue) {
-
- // Asm interpreter on entry
- // On return (i.e. jump to entry_point) [ back to invocation of interpreter ]
- // Everything as it was on entry
-
- // InterpreterRuntime::frequency_counter_overflow takes two
- // arguments, the first (thread) is passed by call_VM, the second
- // indicates if the counter overflow occurs at a backwards branch
- // (NULL bcp). We pass zero for it. The call returns the address
- // of the verified entry point for the method or NULL if the
- // compilation did not complete (either went background or bailed
- // out).
- __ mov(c_rarg1, 0);
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::frequency_counter_overflow),
- c_rarg1);
-
- __ b(*do_continue);
-}
-
-// See if we've got enough room on the stack for locals plus overhead.
-// The expression stack grows down incrementally, so the normal guard
-// page mechanism will work for that.
-//
-// NOTE: Since the additional locals are also always pushed (wasn't
-// obvious in generate_method_entry) so the guard should work for them
-// too.
-//
-// Args:
-// r3: number of additional locals this frame needs (what we must check)
-// rmethod: Method*
-//
-// Kills:
-// r0
-void InterpreterGenerator::generate_stack_overflow_check(void) {
-
- // monitor entry size: see picture of stack set
- // (generate_method_entry) and frame_amd64.hpp
- const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
-
- // total overhead size: entry_size + (saved rbp through expr stack
- // bottom). be sure to change this if you add/subtract anything
- // to/from the overhead area
- const int overhead_size =
- -(frame::interpreter_frame_initial_sp_offset * wordSize) + entry_size;
-
- const int page_size = os::vm_page_size();
-
- Label after_frame_check;
-
- // see if the frame is greater than one page in size. If so,
- // then we need to verify there is enough stack space remaining
- // for the additional locals.
- //
- // Note that we use SUBS rather than CMP here because the immediate
- // field of this instruction may overflow. SUBS can cope with this
- // because it is a macro that will expand to some number of MOV
- // instructions and a register operation.
- __ subs(rscratch1, r3, (page_size - overhead_size) / Interpreter::stackElementSize);
- __ br(Assembler::LS, after_frame_check);
-
- // compute rsp as if this were going to be the last frame on
- // the stack before the red zone
-
- const Address stack_base(rthread, Thread::stack_base_offset());
- const Address stack_size(rthread, Thread::stack_size_offset());
-
- // locals + overhead, in bytes
- __ mov(r0, overhead_size);
- __ add(r0, r0, r3, Assembler::LSL, Interpreter::logStackElementSize); // 2 slots per parameter.
-
- __ ldr(rscratch1, stack_base);
- __ ldr(rscratch2, stack_size);
-
-#ifdef ASSERT
- Label stack_base_okay, stack_size_okay;
- // verify that thread stack base is non-zero
- __ cbnz(rscratch1, stack_base_okay);
- __ stop("stack base is zero");
- __ bind(stack_base_okay);
- // verify that thread stack size is non-zero
- __ cbnz(rscratch2, stack_size_okay);
- __ stop("stack size is zero");
- __ bind(stack_size_okay);
-#endif
-
- // Add stack base to locals and subtract stack size
- __ sub(rscratch1, rscratch1, rscratch2); // Stack limit
- __ add(r0, r0, rscratch1);
-
- // Use the maximum number of pages we might bang.
- const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages :
- (StackRedPages+StackYellowPages);
-
- // add in the red and yellow zone sizes
- __ add(r0, r0, max_pages * page_size * 2);
-
- // check against the current stack bottom
- __ cmp(sp, r0);
- __ br(Assembler::HI, after_frame_check);
-
- // Remove the incoming args, peeling the machine SP back to where it
- // was in the caller. This is not strictly necessary, but unless we
- // do so the stack frame may have a garbage FP; this ensures a
- // correct call stack that we can always unwind. The ANDR should be
- // unnecessary because the sender SP in r13 is always aligned, but
- // it doesn't hurt.
- __ andr(sp, r13, -16);
-
- // Note: the restored frame is not necessarily interpreted.
- // Use the shared runtime version of the StackOverflowError.
- assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "stub not yet generated");
- __ far_jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry()));
-
- // all done with frame size check
- __ bind(after_frame_check);
-}
-
-// Allocate monitor and lock method (asm interpreter)
-//
-// Args:
-// rmethod: Method*
-// rlocals: locals
-//
-// Kills:
-// r0
-// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs)
-// rscratch1, rscratch2 (scratch regs)
-void TemplateInterpreterGenerator::lock_method() {
- // synchronize method
- const Address access_flags(rmethod, Method::access_flags_offset());
- const Address monitor_block_top(
- rfp,
- frame::interpreter_frame_monitor_block_top_offset * wordSize);
- const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
-
-#ifdef ASSERT
- {
- Label L;
- __ ldrw(r0, access_flags);
- __ tst(r0, JVM_ACC_SYNCHRONIZED);
- __ br(Assembler::NE, L);
- __ stop("method doesn't need synchronization");
- __ bind(L);
- }
-#endif // ASSERT
-
- // get synchronization object
- {
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- Label done;
- __ ldrw(r0, access_flags);
- __ tst(r0, JVM_ACC_STATIC);
- // get receiver (assume this is frequent case)
- __ ldr(r0, Address(rlocals, Interpreter::local_offset_in_bytes(0)));
- __ br(Assembler::EQ, done);
- __ ldr(r0, Address(rmethod, Method::const_offset()));
- __ ldr(r0, Address(r0, ConstMethod::constants_offset()));
- __ ldr(r0, Address(r0,
- ConstantPool::pool_holder_offset_in_bytes()));
- __ ldr(r0, Address(r0, mirror_offset));
-
-#ifdef ASSERT
- {
- Label L;
- __ cbnz(r0, L);
- __ stop("synchronization object is NULL");
- __ bind(L);
- }
-#endif // ASSERT
-
- __ bind(done);
- }
-
- // add space for monitor & lock
- __ sub(sp, sp, entry_size); // add space for a monitor entry
- __ sub(esp, esp, entry_size);
- __ mov(rscratch1, esp);
- __ str(rscratch1, monitor_block_top); // set new monitor block top
- // store object
- __ str(r0, Address(esp, BasicObjectLock::obj_offset_in_bytes()));
- __ mov(c_rarg1, esp); // object address
- __ lock_object(c_rarg1);
-}
-
-// Generate a fixed interpreter frame. This is identical setup for
-// interpreted methods and for native methods hence the shared code.
-//
-// Args:
-// lr: return address
-// rmethod: Method*
-// rlocals: pointer to locals
-// rcpool: cp cache
-// stack_pointer: previous sp
-void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
- // initialize fixed part of activation frame
- if (native_call) {
- __ sub(esp, sp, 12 * wordSize);
- __ mov(rbcp, zr);
- __ stp(esp, zr, Address(__ pre(sp, -12 * wordSize)));
- // add 2 zero-initialized slots for native calls
- __ stp(zr, zr, Address(sp, 10 * wordSize));
- } else {
- __ sub(esp, sp, 10 * wordSize);
- __ ldr(rscratch1, Address(rmethod, Method::const_offset())); // get ConstMethod
- __ add(rbcp, rscratch1, in_bytes(ConstMethod::codes_offset())); // get codebase
- __ stp(esp, rbcp, Address(__ pre(sp, -10 * wordSize)));
- }
-
- if (ProfileInterpreter) {
- Label method_data_continue;
- __ ldr(rscratch1, Address(rmethod, Method::method_data_offset()));
- __ cbz(rscratch1, method_data_continue);
- __ lea(rscratch1, Address(rscratch1, in_bytes(MethodData::data_offset())));
- __ bind(method_data_continue);
- __ stp(rscratch1, rmethod, Address(sp, 4 * wordSize)); // save Method* and mdp (method data pointer)
- } else {
- __ stp(zr, rmethod, Address(sp, 4 * wordSize)); // save Method* (no mdp)
- }
-
- __ ldr(rcpool, Address(rmethod, Method::const_offset()));
- __ ldr(rcpool, Address(rcpool, ConstMethod::constants_offset()));
- __ ldr(rcpool, Address(rcpool, ConstantPool::cache_offset_in_bytes()));
- __ stp(rlocals, rcpool, Address(sp, 2 * wordSize));
-
- __ stp(rfp, lr, Address(sp, 8 * wordSize));
- __ lea(rfp, Address(sp, 8 * wordSize));
-
- // set sender sp
- // leave last_sp as null
- __ stp(zr, r13, Address(sp, 6 * wordSize));
-
- // Move SP out of the way
- if (! native_call) {
- __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
- __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset()));
- __ add(rscratch1, rscratch1, frame::interpreter_frame_monitor_size() + 2);
- __ sub(rscratch1, sp, rscratch1, ext::uxtw, 3);
- __ andr(sp, rscratch1, -16);
- }
-}
-
-// End of helpers
-
-// Various method entries
-//------------------------------------------------------------------------------------------------------------------------
-//
-//
-
-// Method entry for java.lang.ref.Reference.get.
-address InterpreterGenerator::generate_Reference_get_entry(void) {
-#if INCLUDE_ALL_GCS
- // Code: _aload_0, _getfield, _areturn
- // parameter size = 1
- //
- // The code that gets generated by this routine is split into 2 parts:
- // 1. The "intrinsified" code for G1 (or any SATB based GC),
- // 2. The slow path - which is an expansion of the regular method entry.
- //
- // Notes:-
- // * In the G1 code we do not check whether we need to block for
- // a safepoint. If G1 is enabled then we must execute the specialized
- // code for Reference.get (except when the Reference object is null)
- // so that we can log the value in the referent field with an SATB
- // update buffer.
- // If the code for the getfield template is modified so that the
- // G1 pre-barrier code is executed when the current method is
- // Reference.get() then going through the normal method entry
- // will be fine.
- // * The G1 code can, however, check the receiver object (the instance
- // of java.lang.Reference) and jump to the slow path if null. If the
- // Reference object is null then we obviously cannot fetch the referent
- // and so we don't need to call the G1 pre-barrier. Thus we can use the
- // regular method entry code to generate the NPE.
- //
- // This code is based on generate_accessor_enty.
- //
- // rmethod: Method*
- // r13: senderSP must preserve for slow path, set SP to it on fast path
-
- 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;
- const Register local_0 = c_rarg0;
- // Check if local 0 != NULL
- // If the receiver is null then it is OK to jump to the slow path.
- __ ldr(local_0, Address(esp, 0));
- __ cbz(local_0, slow_path);
-
-
- // Load the value of the referent field.
- const Address field_address(local_0, referent_offset);
- __ load_heap_oop(local_0, field_address);
-
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer.
- __ enter(); // g1_write may call runtime
- __ g1_write_barrier_pre(noreg /* obj */,
- local_0 /* pre_val */,
- rthread /* thread */,
- rscratch2 /* tmp */,
- true /* tosca_live */,
- true /* expand_call */);
- __ leave();
- // areturn
- __ andr(sp, r13, -16); // done with stack
- __ ret(lr);
-
- // generate a vanilla interpreter entry as the slow path
- __ bind(slow_path);
- __ 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_accessor_entry();
-}
-
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.update(int crc, int b)
- */
-address InterpreterGenerator::generate_CRC32_update_entry() {
- if (UseCRC32Intrinsics) {
- address entry = __ pc();
-
- // rmethod: Method*
- // r13: senderSP must preserved for slow path
- // esp: args
-
- Label slow_path;
- // If we need a safepoint check, generate full interpreter entry.
- ExternalAddress state(SafepointSynchronize::address_of_state());
- unsigned long offset;
- __ adrp(rscratch1, ExternalAddress(SafepointSynchronize::address_of_state()), offset);
- __ ldrw(rscratch1, Address(rscratch1, offset));
- assert(SafepointSynchronize::_not_synchronized == 0, "rewrite this code");
- __ cbnz(rscratch1, slow_path);
-
- // We don't generate local frame and don't align stack because
- // we call stub code and there is no safepoint on this path.
-
- // Load parameters
- const Register crc = c_rarg0; // crc
- const Register val = c_rarg1; // source java byte value
- const Register tbl = c_rarg2; // scratch
-
- // Arguments are reversed on java expression stack
- __ ldrw(val, Address(esp, 0)); // byte value
- __ ldrw(crc, Address(esp, wordSize)); // Initial CRC
-
- __ adrp(tbl, ExternalAddress(StubRoutines::crc_table_addr()), offset);
- __ add(tbl, tbl, offset);
-
- __ ornw(crc, zr, crc); // ~crc
- __ update_byte_crc32(crc, val, tbl);
- __ ornw(crc, zr, crc); // ~crc
-
- // result in c_rarg0
-
- __ andr(sp, r13, -16);
- __ ret(lr);
-
- // 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;
-}
-
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len)
- * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len)
- */
-address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
- if (UseCRC32Intrinsics) {
- address entry = __ pc();
-
- // rmethod,: Method*
- // r13: senderSP must preserved for slow path
-
- Label slow_path;
- // If we need a safepoint check, generate full interpreter entry.
- ExternalAddress state(SafepointSynchronize::address_of_state());
- unsigned long offset;
- __ adrp(rscratch1, ExternalAddress(SafepointSynchronize::address_of_state()), offset);
- __ ldrw(rscratch1, Address(rscratch1, offset));
- assert(SafepointSynchronize::_not_synchronized == 0, "rewrite this code");
- __ cbnz(rscratch1, slow_path);
-
- // We don't generate local frame and don't align stack because
- // we call stub code and there is no safepoint on this path.
-
- // Load parameters
- const Register crc = c_rarg0; // crc
- const Register buf = c_rarg1; // source java byte array address
- const Register len = c_rarg2; // length
- const Register off = len; // offset (never overlaps with 'len')
-
- // Arguments are reversed on java expression stack
- // Calculate address of start element
- if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) {
- __ ldr(buf, Address(esp, 2*wordSize)); // long buf
- __ ldrw(off, Address(esp, wordSize)); // offset
- __ add(buf, buf, off); // + offset
- __ ldrw(crc, Address(esp, 4*wordSize)); // Initial CRC
- } else {
- __ ldr(buf, Address(esp, 2*wordSize)); // byte[] array
- __ add(buf, buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // + header size
- __ ldrw(off, Address(esp, wordSize)); // offset
- __ add(buf, buf, off); // + offset
- __ ldrw(crc, Address(esp, 3*wordSize)); // Initial CRC
- }
- // Can now load 'len' since we're finished with 'off'
- __ ldrw(len, Address(esp, 0x0)); // Length
-
- __ andr(sp, r13, -16); // Restore the caller's SP
-
- // We are frameless so we can just jump to the stub.
- __ b(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32()));
-
- // 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 InterpreterGenerator::bang_stack_shadow_pages(bool native_call) {
- // Bang each page in the shadow zone. We can't assume it's been done for
- // an interpreter frame with greater than a page of locals, so each page
- // needs to be checked. Only true for non-native.
- if (UseStackBanging) {
- const int start_page = native_call ? StackShadowPages : 1;
- const int page_size = os::vm_page_size();
- for (int pages = start_page; pages <= StackShadowPages ; pages++) {
- __ sub(rscratch2, sp, pages*page_size);
- __ str(zr, Address(rscratch2));
- }
- }
-}
-
-
-// Interpreter stub for calling a native method. (asm interpreter)
-// This sets up a somewhat different looking stack for calling the
-// native method than the typical interpreter frame setup.
-address InterpreterGenerator::generate_native_entry(bool synchronized) {
- // determine code generation flags
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // r1: Method*
- // rscratch1: sender sp
-
- address entry_point = __ pc();
-
- const Address constMethod (rmethod, Method::const_offset());
- const Address access_flags (rmethod, Method::access_flags_offset());
- const Address size_of_parameters(r2, ConstMethod::
- size_of_parameters_offset());
-
- // get parameter size (always needed)
- __ ldr(r2, constMethod);
- __ load_unsigned_short(r2, size_of_parameters);
-
- // native calls don't need the stack size check since they have no
- // expression stack and the arguments are already on the stack and
- // we only add a handful of words to the stack
-
- // rmethod: Method*
- // r2: size of parameters
- // rscratch1: sender sp
-
- // for natives the size of locals is zero
-
- // compute beginning of parameters (rlocals)
- __ add(rlocals, esp, r2, ext::uxtx, 3);
- __ add(rlocals, rlocals, -wordSize);
-
- // Pull SP back to minimum size: this avoids holes in the stack
- __ andr(sp, esp, -16);
-
- // initialize fixed part of activation frame
- generate_fixed_frame(true);
-#ifndef PRODUCT
- // tell the simulator that a method has been entered
- if (NotifySimulator) {
- __ notify(Assembler::method_entry);
- }
-#endif
-
- // make sure method is native & not abstract
-#ifdef ASSERT
- __ ldrw(r0, access_flags);
- {
- Label L;
- __ tst(r0, JVM_ACC_NATIVE);
- __ br(Assembler::NE, L);
- __ stop("tried to execute non-native method as native");
- __ bind(L);
- }
- {
- Label L;
- __ tst(r0, JVM_ACC_ABSTRACT);
- __ br(Assembler::EQ, L);
- __ stop("tried to execute abstract method in interpreter");
- __ bind(L);
- }
-#endif
-
- // Since at this point in the method invocation the exception
- // handler would try to exit the monitor of synchronized methods
- // which hasn't been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. The remove_activation
- // will check this flag.
-
- const Address do_not_unlock_if_synchronized(rthread,
- in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
- __ mov(rscratch2, true);
- __ strb(rscratch2, do_not_unlock_if_synchronized);
-
- // increment invocation count & check for overflow
- Label invocation_counter_overflow;
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
- }
-
- Label continue_after_compile;
- __ bind(continue_after_compile);
-
- bang_stack_shadow_pages(true);
-
- // reset the _do_not_unlock_if_synchronized flag
- __ strb(zr, do_not_unlock_if_synchronized);
-
- // check for synchronized methods
- // Must happen AFTER invocation_counter check and stack overflow check,
- // so method is not locked if overflows.
- if (synchronized) {
- lock_method();
- } else {
- // no synchronization necessary
-#ifdef ASSERT
- {
- Label L;
- __ ldrw(r0, access_flags);
- __ tst(r0, JVM_ACC_SYNCHRONIZED);
- __ br(Assembler::EQ, L);
- __ stop("method needs synchronization");
- __ bind(L);
- }
-#endif
- }
-
- // start execution
-#ifdef ASSERT
- {
- Label L;
- const Address monitor_block_top(rfp,
- frame::interpreter_frame_monitor_block_top_offset * wordSize);
- __ ldr(rscratch1, monitor_block_top);
- __ cmp(esp, rscratch1);
- __ br(Assembler::EQ, L);
- __ stop("broken stack frame setup in interpreter");
- __ bind(L);
- }
-#endif
-
- // jvmti support
- __ notify_method_entry();
-
- // work registers
- const Register t = r17;
- const Register result_handler = r19;
-
- // allocate space for parameters
- __ ldr(t, Address(rmethod, Method::const_offset()));
- __ load_unsigned_short(t, Address(t, ConstMethod::size_of_parameters_offset()));
-
- __ sub(rscratch1, esp, t, ext::uxtx, Interpreter::logStackElementSize);
- __ andr(sp, rscratch1, -16);
- __ mov(esp, rscratch1);
-
- // get signature handler
- {
- Label L;
- __ ldr(t, Address(rmethod, Method::signature_handler_offset()));
- __ cbnz(t, L);
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::prepare_native_call),
- rmethod);
- __ ldr(t, Address(rmethod, Method::signature_handler_offset()));
- __ bind(L);
- }
-
- // call signature handler
- assert(InterpreterRuntime::SignatureHandlerGenerator::from() == rlocals,
- "adjust this code");
- assert(InterpreterRuntime::SignatureHandlerGenerator::to() == sp,
- "adjust this code");
- assert(InterpreterRuntime::SignatureHandlerGenerator::temp() == rscratch1,
- "adjust this code");
-
- // The generated handlers do not touch rmethod (the method).
- // However, large signatures cannot be cached and are generated
- // each time here. The slow-path generator can do a GC on return,
- // so we must reload it after the call.
- __ blr(t);
- __ get_method(rmethod); // slow path can do a GC, reload rmethod
-
-
- // result handler is in r0
- // set result handler
- __ mov(result_handler, r0);
- // pass mirror handle if static call
- {
- Label L;
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- __ ldrw(t, Address(rmethod, Method::access_flags_offset()));
- __ tst(t, JVM_ACC_STATIC);
- __ br(Assembler::EQ, L);
- // get mirror
- __ ldr(t, Address(rmethod, Method::const_offset()));
- __ ldr(t, Address(t, ConstMethod::constants_offset()));
- __ ldr(t, Address(t, ConstantPool::pool_holder_offset_in_bytes()));
- __ ldr(t, Address(t, mirror_offset));
- // copy mirror into activation frame
- __ str(t, Address(rfp, frame::interpreter_frame_oop_temp_offset * wordSize));
- // pass handle to mirror
- __ add(c_rarg1, rfp, frame::interpreter_frame_oop_temp_offset * wordSize);
- __ bind(L);
- }
-
- // get native function entry point in r10
- {
- Label L;
- __ ldr(r10, Address(rmethod, Method::native_function_offset()));
- address unsatisfied = (SharedRuntime::native_method_throw_unsatisfied_link_error_entry());
- __ mov(rscratch2, unsatisfied);
- __ ldr(rscratch2, rscratch2);
- __ cmp(r10, rscratch2);
- __ br(Assembler::NE, L);
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::prepare_native_call),
- rmethod);
- __ get_method(rmethod);
- __ ldr(r10, Address(rmethod, Method::native_function_offset()));
- __ bind(L);
- }
-
- // pass JNIEnv
- __ add(c_rarg0, rthread, in_bytes(JavaThread::jni_environment_offset()));
-
- // It is enough that the pc() points into the right code
- // segment. It does not have to be the correct return pc.
- __ set_last_Java_frame(esp, rfp, (address)NULL, rscratch1);
-
- // change thread state
-#ifdef ASSERT
- {
- Label L;
- __ ldrw(t, Address(rthread, JavaThread::thread_state_offset()));
- __ cmp(t, _thread_in_Java);
- __ br(Assembler::EQ, L);
- __ stop("Wrong thread state in native stub");
- __ bind(L);
- }
-#endif
-
- // Change state to native
- __ mov(rscratch1, _thread_in_native);
- __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
- __ stlrw(rscratch1, rscratch2);
-
- // Call the native method.
- __ blrt(r10, rscratch1);
- __ maybe_isb();
- __ get_method(rmethod);
- // result potentially in r0 or v0
-
- // make room for the pushes we're about to do
- __ sub(rscratch1, esp, 4 * wordSize);
- __ andr(sp, rscratch1, -16);
-
- // NOTE: The order of these pushes is known to frame::interpreter_frame_result
- // in order to extract the result of a method call. If the order of these
- // pushes change or anything else is added to the stack then the code in
- // interpreter_frame_result must also change.
- __ push(dtos);
- __ push(ltos);
-
- // change thread state
- __ mov(rscratch1, _thread_in_native_trans);
- __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
- __ stlrw(rscratch1, rscratch2);
-
- if (os::is_MP()) {
- if (UseMembar) {
- // Force this write out before the read below
- __ dsb(Assembler::SY);
- } else {
- // 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
- // due to cache line collision.
- __ serialize_memory(rthread, rscratch2);
- }
- }
-
- // check for safepoint operation in progress and/or pending suspend requests
- {
- Label Continue;
- {
- unsigned long offset;
- __ adrp(rscratch2, SafepointSynchronize::address_of_state(), offset);
- __ ldrw(rscratch2, Address(rscratch2, offset));
- }
- assert(SafepointSynchronize::_not_synchronized == 0,
- "SafepointSynchronize::_not_synchronized");
- Label L;
- __ cbnz(rscratch2, L);
- __ ldrw(rscratch2, Address(rthread, JavaThread::suspend_flags_offset()));
- __ cbz(rscratch2, 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. So we do a runtime call by
- // hand.
- //
- __ mov(c_rarg0, rthread);
- __ mov(rscratch2, CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans));
- __ blrt(rscratch2, 1, 0, 0);
- __ maybe_isb();
- __ get_method(rmethod);
- __ reinit_heapbase();
- __ bind(Continue);
- }
-
- // change thread state
- __ mov(rscratch1, _thread_in_Java);
- __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
- __ stlrw(rscratch1, rscratch2);
-
- // reset_last_Java_frame
- __ reset_last_Java_frame(true, true);
-
- // reset handle block
- __ ldr(t, Address(rthread, JavaThread::active_handles_offset()));
- __ str(zr, Address(t, JNIHandleBlock::top_offset_in_bytes()));
-
- // If result is an oop unbox and store it in frame where gc will see it
- // and result handler will pick it up
-
- {
- Label no_oop, store_result;
- __ adr(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT)));
- __ cmp(t, result_handler);
- __ br(Assembler::NE, no_oop);
- // retrieve result
- __ pop(ltos);
- __ cbz(r0, store_result);
- __ ldr(r0, Address(r0, 0));
- __ bind(store_result);
- __ str(r0, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize));
- // keep stack depth as expected by pushing oop which will eventually be discarded
- __ push(ltos);
- __ bind(no_oop);
- }
-
- {
- Label no_reguard;
- __ lea(rscratch1, Address(rthread, in_bytes(JavaThread::stack_guard_state_offset())));
- __ ldrb(rscratch1, Address(rscratch1));
- __ cmp(rscratch1, JavaThread::stack_guard_yellow_disabled);
- __ br(Assembler::NE, no_reguard);
-
- __ pusha(); // XXX only save smashed registers
- __ mov(c_rarg0, rthread);
- __ mov(rscratch2, CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages));
- __ blrt(rscratch2, 0, 0, 0);
- __ popa(); // XXX only restore smashed registers
- __ bind(no_reguard);
- }
-
- // The method register is junk from after the thread_in_native transition
- // until here. Also can't call_VM until the bcp has been
- // restored. Need bcp for throwing exception below so get it now.
- __ get_method(rmethod);
-
- // restore bcp to have legal interpreter frame, i.e., bci == 0 <=>
- // rbcp == code_base()
- __ ldr(rbcp, Address(rmethod, Method::const_offset())); // get ConstMethod*
- __ add(rbcp, rbcp, in_bytes(ConstMethod::codes_offset())); // get codebase
- // handle exceptions (exception handling will handle unlocking!)
- {
- Label L;
- __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset()));
- __ cbz(rscratch1, L);
- // Note: At some point we may want to unify this with the code
- // used in call_VM_base(); i.e., we should use the
- // StubRoutines::forward_exception code. For now this doesn't work
- // here because the rsp is not correctly set at this point.
- __ MacroAssembler::call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_pending_exception));
- __ should_not_reach_here();
- __ bind(L);
- }
-
- // do unlocking if necessary
- {
- Label L;
- __ ldrw(t, Address(rmethod, Method::access_flags_offset()));
- __ tst(t, JVM_ACC_SYNCHRONIZED);
- __ br(Assembler::EQ, L);
- // the code below should be shared with interpreter macro
- // assembler implementation
- {
- Label unlock;
- // BasicObjectLock will be first in list, since this is a
- // synchronized method. However, need to check that the object
- // has not been unlocked by an explicit monitorexit bytecode.
-
- // monitor expect in c_rarg1 for slow unlock path
- __ lea (c_rarg1, Address(rfp, // address of first monitor
- (intptr_t)(frame::interpreter_frame_initial_sp_offset *
- wordSize - sizeof(BasicObjectLock))));
-
- __ ldr(t, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()));
- __ cbnz(t, unlock);
-
- // Entry already unlocked, need to throw exception
- __ MacroAssembler::call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_illegal_monitor_state_exception));
- __ should_not_reach_here();
-
- __ bind(unlock);
- __ unlock_object(c_rarg1);
- }
- __ bind(L);
- }
-
- // jvmti support
- // Note: This must happen _after_ handling/throwing any exceptions since
- // the exception handler code notifies the runtime of method exits
- // too. If this happens before, method entry/exit notifications are
- // not properly paired (was bug - gri 11/22/99).
- __ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI);
-
- // restore potential result in r0:d0, call result handler to
- // restore potential result in ST0 & handle result
-
- __ pop(ltos);
- __ pop(dtos);
-
- __ blr(result_handler);
-
- // remove activation
- __ ldr(esp, Address(rfp,
- frame::interpreter_frame_sender_sp_offset *
- wordSize)); // get sender sp
- // remove frame anchor
- __ leave();
-
- // resture sender sp
- __ mov(sp, esp);
-
- __ ret(lr);
-
- if (inc_counter) {
- // Handle overflow of counter and compile method
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(&continue_after_compile);
- }
-
- return entry_point;
-}
-
-//
-// Generic interpreted method entry to (asm) interpreter
-//
-address InterpreterGenerator::generate_normal_entry(bool synchronized) {
- // determine code generation flags
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // rscratch1: sender sp
- address entry_point = __ pc();
-
- const Address constMethod(rmethod, Method::const_offset());
- const Address access_flags(rmethod, Method::access_flags_offset());
- const Address size_of_parameters(r3,
- ConstMethod::size_of_parameters_offset());
- const Address size_of_locals(r3, ConstMethod::size_of_locals_offset());
-
- // get parameter size (always needed)
- // need to load the const method first
- __ ldr(r3, constMethod);
- __ load_unsigned_short(r2, size_of_parameters);
-
- // r2: size of parameters
-
- __ load_unsigned_short(r3, size_of_locals); // get size of locals in words
- __ sub(r3, r3, r2); // r3 = no. of additional locals
-
- // see if we've got enough room on the stack for locals plus overhead.
- generate_stack_overflow_check();
-
- // compute beginning of parameters (rlocals)
- __ add(rlocals, esp, r2, ext::uxtx, 3);
- __ sub(rlocals, rlocals, wordSize);
-
- // Make room for locals
- __ sub(rscratch1, esp, r3, ext::uxtx, 3);
- __ andr(sp, rscratch1, -16);
-
- // r3 - # of additional locals
- // allocate space for locals
- // explicitly initialize locals
- {
- Label exit, loop;
- __ ands(zr, r3, r3);
- __ br(Assembler::LE, exit); // do nothing if r3 <= 0
- __ bind(loop);
- __ str(zr, Address(__ post(rscratch1, wordSize)));
- __ sub(r3, r3, 1); // until everything initialized
- __ cbnz(r3, loop);
- __ bind(exit);
- }
-
- // And the base dispatch table
- __ get_dispatch();
-
- // initialize fixed part of activation frame
- generate_fixed_frame(false);
-#ifndef PRODUCT
- // tell the simulator that a method has been entered
- if (NotifySimulator) {
- __ notify(Assembler::method_entry);
- }
-#endif
- // make sure method is not native & not abstract
-#ifdef ASSERT
- __ ldrw(r0, access_flags);
- {
- Label L;
- __ tst(r0, JVM_ACC_NATIVE);
- __ br(Assembler::EQ, L);
- __ stop("tried to execute native method as non-native");
- __ bind(L);
- }
- {
- Label L;
- __ tst(r0, JVM_ACC_ABSTRACT);
- __ br(Assembler::EQ, L);
- __ stop("tried to execute abstract method in interpreter");
- __ bind(L);
- }
-#endif
-
- // Since at this point in the method invocation the exception
- // handler would try to exit the monitor of synchronized methods
- // which hasn't been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. The remove_activation
- // will check this flag.
-
- const Address do_not_unlock_if_synchronized(rthread,
- in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
- __ mov(rscratch2, true);
- __ strb(rscratch2, do_not_unlock_if_synchronized);
-
- // increment invocation count & check for overflow
- Label invocation_counter_overflow;
- Label profile_method;
- Label profile_method_continue;
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow,
- &profile_method,
- &profile_method_continue);
- if (ProfileInterpreter) {
- __ bind(profile_method_continue);
- }
- }
-
- Label continue_after_compile;
- __ bind(continue_after_compile);
-
- bang_stack_shadow_pages(false);
-
- // reset the _do_not_unlock_if_synchronized flag
- __ strb(zr, do_not_unlock_if_synchronized);
-
- // check for synchronized methods
- // Must happen AFTER invocation_counter check and stack overflow check,
- // so method is not locked if overflows.
- if (synchronized) {
- // Allocate monitor and lock method
- lock_method();
- } else {
- // no synchronization necessary
-#ifdef ASSERT
- {
- Label L;
- __ ldrw(r0, access_flags);
- __ tst(r0, JVM_ACC_SYNCHRONIZED);
- __ br(Assembler::EQ, L);
- __ stop("method needs synchronization");
- __ bind(L);
- }
-#endif
- }
-
- // start execution
-#ifdef ASSERT
- {
- Label L;
- const Address monitor_block_top (rfp,
- frame::interpreter_frame_monitor_block_top_offset * wordSize);
- __ ldr(rscratch1, monitor_block_top);
- __ cmp(esp, rscratch1);
- __ br(Assembler::EQ, L);
- __ stop("broken stack frame setup in interpreter");
- __ bind(L);
- }
-#endif
-
- // jvmti support
- __ notify_method_entry();
-
- __ dispatch_next(vtos);
-
- // invocation counter overflow
- if (inc_counter) {
- if (ProfileInterpreter) {
- // We have decided to profile this method in the interpreter
- __ bind(profile_method);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
- __ set_method_data_pointer_for_bcp();
- // don't think we need this
- __ get_method(r1);
- __ b(profile_method_continue);
- }
- // Handle overflow of counter and compile method
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(&continue_after_compile);
- }
-
- return entry_point;
-}
-
// These should never be compiled since the interpreter will prefer
// the compiled version to the intrinsic version.
bool AbstractInterpreter::can_be_compiled(methodHandle m) {
@@ -1593,483 +178,3 @@
*interpreter_frame->interpreter_frame_cache_addr() =
method->constants()->cache();
}
-
-
-//-----------------------------------------------------------------------------
-// Exceptions
-
-void TemplateInterpreterGenerator::generate_throw_exception() {
- // Entry point in previous activation (i.e., if the caller was
- // interpreted)
- Interpreter::_rethrow_exception_entry = __ pc();
- // Restore sp to interpreter_frame_last_sp even though we are going
- // to empty the expression stack for the exception processing.
- __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
- // r0: exception
- // r3: return address/pc that threw exception
- __ restore_bcp(); // rbcp points to call/send
- __ restore_locals();
- __ restore_constant_pool_cache();
- __ reinit_heapbase(); // restore rheapbase as heapbase.
- __ get_dispatch();
-
-#ifndef PRODUCT
- // tell the simulator that the caller method has been reentered
- if (NotifySimulator) {
- __ get_method(rmethod);
- __ notify(Assembler::method_reentry);
- }
-#endif
- // Entry point for exceptions thrown within interpreter code
- Interpreter::_throw_exception_entry = __ pc();
- // If we came here via a NullPointerException on the receiver of a
- // method, rmethod may be corrupt.
- __ get_method(rmethod);
- // expression stack is undefined here
- // r0: exception
- // rbcp: exception bcp
- __ verify_oop(r0);
- __ mov(c_rarg1, r0);
-
- // expression stack must be empty before entering the VM in case of
- // an exception
- __ empty_expression_stack();
- // find exception handler address and preserve exception oop
- __ call_VM(r3,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::exception_handler_for_exception),
- c_rarg1);
-
- // Calculate stack limit
- __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
- __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset()));
- __ add(rscratch1, rscratch1, frame::interpreter_frame_monitor_size() + 4);
- __ ldr(rscratch2,
- Address(rfp, frame::interpreter_frame_initial_sp_offset * wordSize));
- __ sub(rscratch1, rscratch2, rscratch1, ext::uxtx, 3);
- __ andr(sp, rscratch1, -16);
-
- // r0: exception handler entry point
- // r3: preserved exception oop
- // rbcp: bcp for exception handler
- __ push_ptr(r3); // push exception which is now the only value on the stack
- __ br(r0); // jump to exception handler (may be _remove_activation_entry!)
-
- // If the exception is not handled in the current frame the frame is
- // removed and the exception is rethrown (i.e. exception
- // continuation is _rethrow_exception).
- //
- // Note: At this point the bci is still the bxi for the instruction
- // which caused the exception and the expression stack is
- // empty. Thus, for any VM calls at this point, GC will find a legal
- // oop map (with empty expression stack).
-
- //
- // JVMTI PopFrame support
- //
-
- Interpreter::_remove_activation_preserving_args_entry = __ pc();
- __ empty_expression_stack();
- // Set the popframe_processing bit in pending_popframe_condition
- // indicating that we are currently handling popframe, so that
- // call_VMs that may happen later do not trigger new popframe
- // handling cycles.
- __ ldrw(r3, Address(rthread, JavaThread::popframe_condition_offset()));
- __ orr(r3, r3, JavaThread::popframe_processing_bit);
- __ strw(r3, Address(rthread, JavaThread::popframe_condition_offset()));
-
- {
- // Check to see whether we are returning to a deoptimized frame.
- // (The PopFrame call ensures that the caller of the popped frame is
- // either interpreted or compiled and deoptimizes it if compiled.)
- // In this case, we can't call dispatch_next() after the frame is
- // popped, but instead must save the incoming arguments and restore
- // them after deoptimization has occurred.
- //
- // Note that we don't compare the return PC against the
- // deoptimization blob's unpack entry because of the presence of
- // adapter frames in C2.
- Label caller_not_deoptimized;
- __ ldr(c_rarg1, Address(rfp, frame::return_addr_offset * wordSize));
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
- InterpreterRuntime::interpreter_contains), c_rarg1);
- __ cbnz(r0, caller_not_deoptimized);
-
- // Compute size of arguments for saving when returning to
- // deoptimized caller
- __ get_method(r0);
- __ ldr(r0, Address(r0, Method::const_offset()));
- __ load_unsigned_short(r0, Address(r0, in_bytes(ConstMethod::
- size_of_parameters_offset())));
- __ lsl(r0, r0, Interpreter::logStackElementSize);
- __ restore_locals(); // XXX do we need this?
- __ sub(rlocals, rlocals, r0);
- __ add(rlocals, rlocals, wordSize);
- // Save these arguments
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
- Deoptimization::
- popframe_preserve_args),
- rthread, r0, rlocals);
-
- __ remove_activation(vtos,
- /* throw_monitor_exception */ false,
- /* install_monitor_exception */ false,
- /* notify_jvmdi */ false);
-
- // Inform deoptimization that it is responsible for restoring
- // these arguments
- __ mov(rscratch1, JavaThread::popframe_force_deopt_reexecution_bit);
- __ strw(rscratch1, Address(rthread, JavaThread::popframe_condition_offset()));
-
- // Continue in deoptimization handler
- __ ret(lr);
-
- __ bind(caller_not_deoptimized);
- }
-
- __ remove_activation(vtos,
- /* throw_monitor_exception */ false,
- /* install_monitor_exception */ false,
- /* notify_jvmdi */ false);
-
- // Restore the last_sp and null it out
- __ ldr(esp, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
- __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
-
- __ restore_bcp();
- __ restore_locals();
- __ restore_constant_pool_cache();
- __ get_method(rmethod);
-
- // The method data pointer was incremented already during
- // call profiling. We have to restore the mdp for the current bcp.
- if (ProfileInterpreter) {
- __ set_method_data_pointer_for_bcp();
- }
-
- // Clear the popframe condition flag
- __ strw(zr, Address(rthread, JavaThread::popframe_condition_offset()));
- assert(JavaThread::popframe_inactive == 0, "fix popframe_inactive");
-
-#if INCLUDE_JVMTI
- {
- Label L_done;
-
- __ ldrb(rscratch1, Address(rbcp, 0));
- __ cmpw(r1, Bytecodes::_invokestatic);
- __ br(Assembler::EQ, L_done);
-
- // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
- // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
-
- __ ldr(c_rarg0, Address(rlocals, 0));
- __ call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), c_rarg0, rmethod, rbcp);
-
- __ cbz(r0, L_done);
-
- __ str(r0, Address(esp, 0));
- __ bind(L_done);
- }
-#endif // INCLUDE_JVMTI
-
- // Restore machine SP
- __ ldr(rscratch1, Address(rmethod, Method::const_offset()));
- __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset()));
- __ add(rscratch1, rscratch1, frame::interpreter_frame_monitor_size() + 4);
- __ ldr(rscratch2,
- Address(rfp, frame::interpreter_frame_initial_sp_offset * wordSize));
- __ sub(rscratch1, rscratch2, rscratch1, ext::uxtw, 3);
- __ andr(sp, rscratch1, -16);
-
- __ dispatch_next(vtos);
- // end of PopFrame support
-
- Interpreter::_remove_activation_entry = __ pc();
-
- // preserve exception over this code sequence
- __ pop_ptr(r0);
- __ str(r0, Address(rthread, JavaThread::vm_result_offset()));
- // remove the activation (without doing throws on illegalMonitorExceptions)
- __ remove_activation(vtos, false, true, false);
- // restore exception
- // restore exception
- __ get_vm_result(r0, rthread);
-
- // In between activations - previous activation type unknown yet
- // compute continuation point - the continuation point expects the
- // following registers set up:
- //
- // r0: exception
- // lr: return address/pc that threw exception
- // rsp: expression stack of caller
- // rfp: fp of caller
- // FIXME: There's no point saving LR here because VM calls don't trash it
- __ stp(r0, lr, Address(__ pre(sp, -2 * wordSize))); // save exception & return address
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
- SharedRuntime::exception_handler_for_return_address),
- rthread, lr);
- __ mov(r1, r0); // save exception handler
- __ ldp(r0, lr, Address(__ post(sp, 2 * wordSize))); // restore exception & return address
- // We might be returning to a deopt handler that expects r3 to
- // contain the exception pc
- __ mov(r3, lr);
- // Note that an "issuing PC" is actually the next PC after the call
- __ br(r1); // jump to exception
- // handler of caller
-}
-
-
-//
-// JVMTI ForceEarlyReturn support
-//
-address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
- address entry = __ pc();
-
- __ restore_bcp();
- __ restore_locals();
- __ empty_expression_stack();
- __ load_earlyret_value(state);
-
- __ ldr(rscratch1, Address(rthread, JavaThread::jvmti_thread_state_offset()));
- Address cond_addr(rscratch1, JvmtiThreadState::earlyret_state_offset());
-
- // Clear the earlyret state
- assert(JvmtiThreadState::earlyret_inactive == 0, "should be");
- __ str(zr, cond_addr);
-
- __ remove_activation(state,
- false, /* throw_monitor_exception */
- false, /* install_monitor_exception */
- true); /* notify_jvmdi */
- __ ret(lr);
-
- return entry;
-} // end of ForceEarlyReturn support
-
-
-
-//-----------------------------------------------------------------------------
-// Helper for vtos entry point generation
-
-void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
- address& bep,
- address& cep,
- address& sep,
- address& aep,
- address& iep,
- address& lep,
- address& fep,
- address& dep,
- address& vep) {
- assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
- Label L;
- aep = __ pc(); __ push_ptr(); __ b(L);
- fep = __ pc(); __ push_f(); __ b(L);
- dep = __ pc(); __ push_d(); __ b(L);
- lep = __ pc(); __ push_l(); __ b(L);
- bep = cep = sep =
- iep = __ pc(); __ push_i();
- vep = __ pc();
- __ bind(L);
- generate_and_dispatch(t);
-}
-
-//-----------------------------------------------------------------------------
-// Generation of individual instructions
-
-// helpers for generate_and_dispatch
-
-
-InterpreterGenerator::InterpreterGenerator(StubQueue* code)
- : TemplateInterpreterGenerator(code) {
- generate_all(); // down here so it can be "virtual"
-}
-
-//-----------------------------------------------------------------------------
-
-// Non-product code
-#ifndef PRODUCT
-address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
- address entry = __ pc();
-
- __ push(lr);
- __ push(state);
- __ push(RegSet::range(r0, r15), sp);
- __ mov(c_rarg2, r0); // Pass itos
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode),
- c_rarg1, c_rarg2, c_rarg3);
- __ pop(RegSet::range(r0, r15), sp);
- __ pop(state);
- __ pop(lr);
- __ ret(lr); // return from result handler
-
- return entry;
-}
-
-void TemplateInterpreterGenerator::count_bytecode() {
- Register rscratch3 = r0;
- __ push(rscratch1);
- __ push(rscratch2);
- __ push(rscratch3);
- Label L;
- __ mov(rscratch2, (address) &BytecodeCounter::_counter_value);
- __ bind(L);
- __ ldxr(rscratch1, rscratch2);
- __ add(rscratch1, rscratch1, 1);
- __ stxr(rscratch3, rscratch1, rscratch2);
- __ cbnzw(rscratch3, L);
- __ pop(rscratch3);
- __ pop(rscratch2);
- __ pop(rscratch1);
-}
-
-void TemplateInterpreterGenerator::histogram_bytecode(Template* t) { ; }
-
-void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) { ; }
-
-
-void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
- // Call a little run-time stub to avoid blow-up for each bytecode.
- // The run-time runtime saves the right registers, depending on
- // the tosca in-state for the given template.
-
- assert(Interpreter::trace_code(t->tos_in()) != NULL,
- "entry must have been generated");
- __ bl(Interpreter::trace_code(t->tos_in()));
- __ reinit_heapbase();
-}
-
-
-void TemplateInterpreterGenerator::stop_interpreter_at() {
- Label L;
- __ push(rscratch1);
- __ mov(rscratch1, (address) &BytecodeCounter::_counter_value);
- __ ldr(rscratch1, Address(rscratch1));
- __ mov(rscratch2, StopInterpreterAt);
- __ cmpw(rscratch1, rscratch2);
- __ br(Assembler::NE, L);
- __ brk(0);
- __ bind(L);
- __ pop(rscratch1);
-}
-
-#ifdef BUILTIN_SIM
-
-#include <sys/mman.h>
-#include <unistd.h>
-
-extern "C" {
- static int PAGESIZE = getpagesize();
- int is_mapped_address(u_int64_t address)
- {
- address = (address & ~((u_int64_t)PAGESIZE - 1));
- if (msync((void *)address, PAGESIZE, MS_ASYNC) == 0) {
- return true;
- }
- if (errno != ENOMEM) {
- return true;
- }
- return false;
- }
-
- void bccheck1(u_int64_t pc, u_int64_t fp, char *method, int *bcidx, int *framesize, char *decode)
- {
- if (method != 0) {
- method[0] = '\0';
- }
- if (bcidx != 0) {
- *bcidx = -2;
- }
- if (decode != 0) {
- decode[0] = 0;
- }
-
- if (framesize != 0) {
- *framesize = -1;
- }
-
- if (Interpreter::contains((address)pc)) {
- AArch64Simulator *sim = AArch64Simulator::get_current(UseSimulatorCache, DisableBCCheck);
- Method* meth;
- address bcp;
- if (fp) {
-#define FRAME_SLOT_METHOD 3
-#define FRAME_SLOT_BCP 7
- meth = (Method*)sim->getMemory()->loadU64(fp - (FRAME_SLOT_METHOD << 3));
- bcp = (address)sim->getMemory()->loadU64(fp - (FRAME_SLOT_BCP << 3));
-#undef FRAME_SLOT_METHOD
-#undef FRAME_SLOT_BCP
- } else {
- meth = (Method*)sim->getCPUState().xreg(RMETHOD, 0);
- bcp = (address)sim->getCPUState().xreg(RBCP, 0);
- }
- if (meth->is_native()) {
- return;
- }
- if(method && meth->is_method()) {
- ResourceMark rm;
- method[0] = 'I';
- method[1] = ' ';
- meth->name_and_sig_as_C_string(method + 2, 398);
- }
- if (bcidx) {
- if (meth->contains(bcp)) {
- *bcidx = meth->bci_from(bcp);
- } else {
- *bcidx = -2;
- }
- }
- if (decode) {
- if (!BytecodeTracer::closure()) {
- BytecodeTracer::set_closure(BytecodeTracer::std_closure());
- }
- stringStream str(decode, 400);
- BytecodeTracer::trace(meth, bcp, &str);
- }
- } else {
- if (method) {
- CodeBlob *cb = CodeCache::find_blob((address)pc);
- if (cb != NULL) {
- if (cb->is_nmethod()) {
- ResourceMark rm;
- nmethod* nm = (nmethod*)cb;
- method[0] = 'C';
- method[1] = ' ';
- nm->method()->name_and_sig_as_C_string(method + 2, 398);
- } else if (cb->is_adapter_blob()) {
- strcpy(method, "B adapter blob");
- } else if (cb->is_runtime_stub()) {
- strcpy(method, "B runtime stub");
- } else if (cb->is_exception_stub()) {
- strcpy(method, "B exception stub");
- } else if (cb->is_deoptimization_stub()) {
- strcpy(method, "B deoptimization stub");
- } else if (cb->is_safepoint_stub()) {
- strcpy(method, "B safepoint stub");
- } else if (cb->is_uncommon_trap_stub()) {
- strcpy(method, "B uncommon trap stub");
- } else if (cb->contains((address)StubRoutines::call_stub())) {
- strcpy(method, "B call stub");
- } else {
- strcpy(method, "B unknown blob : ");
- strcat(method, cb->name());
- }
- if (framesize != NULL) {
- *framesize = cb->frame_size();
- }
- }
- }
- }
- }
-
-
- JNIEXPORT void bccheck(u_int64_t pc, u_int64_t fp, char *method, int *bcidx, int *framesize, char *decode)
- {
- bccheck1(pc, fp, method, bcidx, framesize, decode);
- }
-}
-
-#endif // BUILTIN_SIM
-#endif // !PRODUCT
-#endif // ! CC_INTERP
--- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -39,7 +39,6 @@
#include "prims/jvmtiThreadState.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
@@ -61,26 +60,6 @@
#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
-int AbstractInterpreter::BasicType_as_index(BasicType type) {
- int i = 0;
- switch (type) {
- case T_BOOLEAN: i = 0; break;
- case T_CHAR : i = 1; break;
- case T_BYTE : i = 2; break;
- case T_SHORT : i = 3; break;
- case T_INT : i = 4; break;
- case T_LONG : i = 5; break;
- case T_VOID : i = 6; break;
- case T_FLOAT : i = 7; break;
- case T_DOUBLE : i = 8; break;
- case T_OBJECT : i = 9; break;
- case T_ARRAY : i = 9; break;
- default : ShouldNotReachHere();
- }
- assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds");
- return i;
-}
-
address AbstractInterpreterGenerator::generate_slow_signature_handler() {
// Slow_signature handler that respects the PPC C calling conventions.
//
@@ -579,18 +558,3 @@
return NULL;
}
-
-void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) {
- // This code is sort of the equivalent of C2IAdapter::setup_stack_frame back in
- // the days we had adapter frames. When we deoptimize a situation where a
- // compiled caller calls a compiled caller will have registers it expects
- // to survive the call to the callee. If we deoptimize the callee the only
- // way we can restore these registers is to have the oldest interpreter
- // frame that we create restore these values. That is what this routine
- // will accomplish.
-
- // At the moment we have modified c2 to not have any callee save registers
- // so this problem does not exist and this routine is just a place holder.
-
- assert(f->is_interpreted_frame(), "must be interpreted");
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,1802 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#ifndef CC_INTERP
+#include "asm/macroAssembler.inline.hpp"
+#include "interpreter/bytecodeHistogram.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterGenerator.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/interp_masm.hpp"
+#include "interpreter/templateTable.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/methodData.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "prims/jvmtiThreadState.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/synchronizer.hpp"
+#include "runtime/timer.hpp"
+#include "runtime/vframeArray.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/macros.hpp"
+
+#undef __
+#define __ _masm->
+
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#else
+#define BLOCK_COMMENT(str) __ block_comment(str)
+#endif
+
+#define BIND(label) __ bind(label); BLOCK_COMMENT(#label ":")
+
+//-----------------------------------------------------------------------------
+
+// Actually we should never reach here since we do stack overflow checks before pushing any frame.
+address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
+ address entry = __ pc();
+ __ unimplemented("generate_StackOverflowError_handler");
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
+ address entry = __ pc();
+ __ empty_expression_stack();
+ __ load_const_optimized(R4_ARG2, (address) name);
+ // Index is in R17_tos.
+ __ mr(R5_ARG3, R17_tos);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException));
+ return entry;
+}
+
+#if 0
+// Call special ClassCastException constructor taking object to cast
+// and target class as arguments.
+address TemplateInterpreterGenerator::generate_ClassCastException_verbose_handler() {
+ address entry = __ pc();
+
+ // Expression stack must be empty before entering the VM if an
+ // exception happened.
+ __ empty_expression_stack();
+
+ // Thread will be loaded to R3_ARG1.
+ // Target class oop is in register R5_ARG3 by convention!
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException_verbose), R17_tos, R5_ARG3);
+ // Above call must not return here since exception pending.
+ DEBUG_ONLY(__ should_not_reach_here();)
+ return entry;
+}
+#endif
+
+address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
+ address entry = __ pc();
+ // Expression stack must be empty before entering the VM if an
+ // exception happened.
+ __ empty_expression_stack();
+
+ // Load exception object.
+ // Thread will be loaded to R3_ARG1.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException), R17_tos);
+#ifdef ASSERT
+ // Above call must not return here since exception pending.
+ __ should_not_reach_here();
+#endif
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
+ address entry = __ pc();
+ //__ untested("generate_exception_handler_common");
+ Register Rexception = R17_tos;
+
+ // Expression stack must be empty before entering the VM if an exception happened.
+ __ empty_expression_stack();
+
+ __ load_const_optimized(R4_ARG2, (address) name, R11_scratch1);
+ if (pass_oop) {
+ __ mr(R5_ARG3, Rexception);
+ __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), false);
+ } else {
+ __ load_const_optimized(R5_ARG3, (address) message, R11_scratch1);
+ __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), false);
+ }
+
+ // Throw exception.
+ __ mr(R3_ARG1, Rexception);
+ __ load_const_optimized(R11_scratch1, Interpreter::throw_exception_entry(), R12_scratch2);
+ __ mtctr(R11_scratch1);
+ __ bctr();
+
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
+ address entry = __ pc();
+ __ unimplemented("generate_continuation_for");
+ return entry;
+}
+
+// This entry is returned to when a call returns to the interpreter.
+// When we arrive here, we expect that the callee stack frame is already popped.
+address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
+ address entry = __ pc();
+
+ // Move the value out of the return register back to the TOS cache of current frame.
+ switch (state) {
+ case ltos:
+ case btos:
+ case ctos:
+ case stos:
+ case atos:
+ case itos: __ mr(R17_tos, R3_RET); break; // RET -> TOS cache
+ case ftos:
+ case dtos: __ fmr(F15_ftos, F1_RET); break; // TOS cache -> GR_FRET
+ case vtos: break; // Nothing to do, this was a void return.
+ default : ShouldNotReachHere();
+ }
+
+ __ restore_interpreter_state(R11_scratch1); // Sets R11_scratch1 = fp.
+ __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1);
+ __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0);
+
+ // Compiled code destroys templateTableBase, reload.
+ __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R12_scratch2);
+
+ if (state == atos) {
+ __ profile_return_type(R3_RET, R11_scratch1, R12_scratch2);
+ }
+
+ const Register cache = R11_scratch1;
+ const Register size = R12_scratch2;
+ __ get_cache_and_index_at_bcp(cache, 1, index_size);
+
+ // Get least significant byte of 64 bit value:
+#if defined(VM_LITTLE_ENDIAN)
+ __ lbz(size, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()), cache);
+#else
+ __ lbz(size, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()) + 7, cache);
+#endif
+ __ sldi(size, size, Interpreter::logStackElementSize);
+ __ add(R15_esp, R15_esp, size);
+ __ dispatch_next(state, step);
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) {
+ address entry = __ pc();
+ // If state != vtos, we're returning from a native method, which put it's result
+ // into the result register. So move the value out of the return register back
+ // to the TOS cache of current frame.
+
+ switch (state) {
+ case ltos:
+ case btos:
+ case ctos:
+ case stos:
+ case atos:
+ case itos: __ mr(R17_tos, R3_RET); break; // GR_RET -> TOS cache
+ case ftos:
+ case dtos: __ fmr(F15_ftos, F1_RET); break; // TOS cache -> GR_FRET
+ case vtos: break; // Nothing to do, this was a void return.
+ default : ShouldNotReachHere();
+ }
+
+ // Load LcpoolCache @@@ should be already set!
+ __ get_constant_pool_cache(R27_constPoolCache);
+
+ // Handle a pending exception, fall through if none.
+ __ check_and_forward_exception(R11_scratch1, R12_scratch2);
+
+ // Start executing bytecodes.
+ __ dispatch_next(state, step);
+
+ return entry;
+}
+
+// A result handler converts the native result into java format.
+// Use the shared code between c++ and template interpreter.
+address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) {
+ return AbstractInterpreterGenerator::generate_result_handler_for(type);
+}
+
+address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) {
+ address entry = __ pc();
+
+ __ push(state);
+ __ call_VM(noreg, runtime_entry);
+ __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos));
+
+ return entry;
+}
+
+// Helpers for commoning out cases in the various type of method entries.
+
+// Increment invocation count & check for overflow.
+//
+// Note: checking for negative value instead of overflow
+// so we have a 'sticky' overflow test.
+//
+void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) {
+ // Note: In tiered we increment either counters in method or in MDO depending if we're profiling or not.
+ Register Rscratch1 = R11_scratch1;
+ Register Rscratch2 = R12_scratch2;
+ Register R3_counters = R3_ARG1;
+ Label done;
+
+ if (TieredCompilation) {
+ const int increment = InvocationCounter::count_increment;
+ const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift;
+ Label no_mdo;
+ if (ProfileInterpreter) {
+ const Register Rmdo = Rscratch1;
+ // If no method data exists, go to profile_continue.
+ __ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method);
+ __ cmpdi(CCR0, Rmdo, 0);
+ __ beq(CCR0, no_mdo);
+
+ // Increment backedge counter in the MDO.
+ const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
+ __ lwz(Rscratch2, mdo_bc_offs, Rmdo);
+ __ addi(Rscratch2, Rscratch2, increment);
+ __ stw(Rscratch2, mdo_bc_offs, Rmdo);
+ __ load_const_optimized(Rscratch1, mask, R0);
+ __ and_(Rscratch1, Rscratch2, Rscratch1);
+ __ bne(CCR0, done);
+ __ b(*overflow);
+ }
+
+ // Increment counter in MethodCounters*.
+ const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
+ __ bind(no_mdo);
+ __ get_method_counters(R19_method, R3_counters, done);
+ __ lwz(Rscratch2, mo_bc_offs, R3_counters);
+ __ addi(Rscratch2, Rscratch2, increment);
+ __ stw(Rscratch2, mo_bc_offs, R3_counters);
+ __ load_const_optimized(Rscratch1, mask, R0);
+ __ and_(Rscratch1, Rscratch2, Rscratch1);
+ __ beq(CCR0, *overflow);
+
+ __ bind(done);
+
+ } else {
+
+ // Update standard invocation counters.
+ Register Rsum_ivc_bec = R4_ARG2;
+ __ get_method_counters(R19_method, R3_counters, done);
+ __ increment_invocation_counter(R3_counters, Rsum_ivc_bec, R12_scratch2);
+ // Increment interpreter invocation counter.
+ if (ProfileInterpreter) { // %%% Merge this into methodDataOop.
+ __ lwz(R12_scratch2, in_bytes(MethodCounters::interpreter_invocation_counter_offset()), R3_counters);
+ __ addi(R12_scratch2, R12_scratch2, 1);
+ __ stw(R12_scratch2, in_bytes(MethodCounters::interpreter_invocation_counter_offset()), R3_counters);
+ }
+ // Check if we must create a method data obj.
+ if (ProfileInterpreter && profile_method != NULL) {
+ const Register profile_limit = Rscratch1;
+ int pl_offs = __ load_const_optimized(profile_limit, &InvocationCounter::InterpreterProfileLimit, R0, true);
+ __ lwz(profile_limit, pl_offs, profile_limit);
+ // Test to see if we should create a method data oop.
+ __ cmpw(CCR0, Rsum_ivc_bec, profile_limit);
+ __ blt(CCR0, *profile_method_continue);
+ // If no method data exists, go to profile_method.
+ __ test_method_data_pointer(*profile_method);
+ }
+ // Finally check for counter overflow.
+ if (overflow) {
+ const Register invocation_limit = Rscratch1;
+ int il_offs = __ load_const_optimized(invocation_limit, &InvocationCounter::InterpreterInvocationLimit, R0, true);
+ __ lwz(invocation_limit, il_offs, invocation_limit);
+ assert(4 == sizeof(InvocationCounter::InterpreterInvocationLimit), "unexpected field size");
+ __ cmpw(CCR0, Rsum_ivc_bec, invocation_limit);
+ __ bge(CCR0, *overflow);
+ }
+
+ __ bind(done);
+ }
+}
+
+// Generate code to initiate compilation on invocation counter overflow.
+void TemplateInterpreterGenerator::generate_counter_overflow(Label& continue_entry) {
+ // Generate code to initiate compilation on the counter overflow.
+
+ // InterpreterRuntime::frequency_counter_overflow takes one arguments,
+ // which indicates if the counter overflow occurs at a backwards branch (NULL bcp)
+ // We pass zero in.
+ // The call returns the address of the verified entry point for the method or NULL
+ // if the compilation did not complete (either went background or bailed out).
+ //
+ // Unlike the C++ interpreter above: Check exceptions!
+ // Assumption: Caller must set the flag "do_not_unlock_if_sychronized" if the monitor of a sync'ed
+ // method has not yet been created. Thus, no unlocking of a non-existing monitor can occur.
+
+ __ li(R4_ARG2, 0);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true);
+
+ // Returns verified_entry_point or NULL.
+ // We ignore it in any case.
+ __ b(continue_entry);
+}
+
+void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rmem_frame_size, Register Rscratch1) {
+ assert_different_registers(Rmem_frame_size, Rscratch1);
+ __ generate_stack_overflow_check_with_compare_and_throw(Rmem_frame_size, Rscratch1);
+}
+
+void TemplateInterpreterGenerator::unlock_method(bool check_exceptions) {
+ __ unlock_object(R26_monitor, check_exceptions);
+}
+
+// Lock the current method, interpreter register window must be set up!
+void TemplateInterpreterGenerator::lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded) {
+ const Register Robj_to_lock = Rscratch2;
+
+ {
+ if (!flags_preloaded) {
+ __ lwz(Rflags, method_(access_flags));
+ }
+
+#ifdef ASSERT
+ // Check if methods needs synchronization.
+ {
+ Label Lok;
+ __ testbitdi(CCR0, R0, Rflags, JVM_ACC_SYNCHRONIZED_BIT);
+ __ btrue(CCR0,Lok);
+ __ stop("method doesn't need synchronization");
+ __ bind(Lok);
+ }
+#endif // ASSERT
+ }
+
+ // Get synchronization object to Rscratch2.
+ {
+ const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+ Label Lstatic;
+ Label Ldone;
+
+ __ testbitdi(CCR0, R0, Rflags, JVM_ACC_STATIC_BIT);
+ __ btrue(CCR0, Lstatic);
+
+ // Non-static case: load receiver obj from stack and we're done.
+ __ ld(Robj_to_lock, R18_locals);
+ __ b(Ldone);
+
+ __ bind(Lstatic); // Static case: Lock the java mirror
+ __ ld(Robj_to_lock, in_bytes(Method::const_offset()), R19_method);
+ __ ld(Robj_to_lock, in_bytes(ConstMethod::constants_offset()), Robj_to_lock);
+ __ ld(Robj_to_lock, ConstantPool::pool_holder_offset_in_bytes(), Robj_to_lock);
+ __ ld(Robj_to_lock, mirror_offset, Robj_to_lock);
+
+ __ bind(Ldone);
+ __ verify_oop(Robj_to_lock);
+ }
+
+ // Got the oop to lock => execute!
+ __ add_monitor_to_stack(true, Rscratch1, R0);
+
+ __ std(Robj_to_lock, BasicObjectLock::obj_offset_in_bytes(), R26_monitor);
+ __ lock_object(R26_monitor, Robj_to_lock);
+}
+
+// Generate a fixed interpreter frame for pure interpreter
+// and I2N native transition frames.
+//
+// Before (stack grows downwards):
+//
+// | ... |
+// |------------- |
+// | java arg0 |
+// | ... |
+// | java argn |
+// | | <- R15_esp
+// | |
+// |--------------|
+// | abi_112 |
+// | | <- R1_SP
+// |==============|
+//
+//
+// After:
+//
+// | ... |
+// | java arg0 |<- R18_locals
+// | ... |
+// | java argn |
+// |--------------|
+// | |
+// | java locals |
+// | |
+// |--------------|
+// | abi_48 |
+// |==============|
+// | |
+// | istate |
+// | |
+// |--------------|
+// | monitor |<- R26_monitor
+// |--------------|
+// | |<- R15_esp
+// | expression |
+// | stack |
+// | |
+// |--------------|
+// | |
+// | abi_112 |<- R1_SP
+// |==============|
+//
+// The top most frame needs an abi space of 112 bytes. This space is needed,
+// since we call to c. The c function may spill their arguments to the caller
+// frame. When we call to java, we don't need these spill slots. In order to save
+// space on the stack, we resize the caller. However, java local reside in
+// the caller frame and the frame has to be increased. The frame_size for the
+// current frame was calculated based on max_stack as size for the expression
+// stack. At the call, just a part of the expression stack might be used.
+// We don't want to waste this space and cut the frame back accordingly.
+// The resulting amount for resizing is calculated as follows:
+// resize = (number_of_locals - number_of_arguments) * slot_size
+// + (R1_SP - R15_esp) + 48
+//
+// The size for the callee frame is calculated:
+// framesize = 112 + max_stack + monitor + state_size
+//
+// maxstack: Max number of slots on the expression stack, loaded from the method.
+// monitor: We statically reserve room for one monitor object.
+// state_size: We save the current state of the interpreter to this area.
+//
+void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call, Register Rsize_of_parameters, Register Rsize_of_locals) {
+ Register parent_frame_resize = R6_ARG4, // Frame will grow by this number of bytes.
+ top_frame_size = R7_ARG5,
+ Rconst_method = R8_ARG6;
+
+ assert_different_registers(Rsize_of_parameters, Rsize_of_locals, parent_frame_resize, top_frame_size);
+
+ __ ld(Rconst_method, method_(const));
+ __ lhz(Rsize_of_parameters /* number of params */,
+ in_bytes(ConstMethod::size_of_parameters_offset()), Rconst_method);
+ if (native_call) {
+ // If we're calling a native method, we reserve space for the worst-case signature
+ // handler varargs vector, which is max(Argument::n_register_parameters, parameter_count+2).
+ // We add two slots to the parameter_count, one for the jni
+ // environment and one for a possible native mirror.
+ Label skip_native_calculate_max_stack;
+ __ addi(top_frame_size, Rsize_of_parameters, 2);
+ __ cmpwi(CCR0, top_frame_size, Argument::n_register_parameters);
+ __ bge(CCR0, skip_native_calculate_max_stack);
+ __ li(top_frame_size, Argument::n_register_parameters);
+ __ bind(skip_native_calculate_max_stack);
+ __ sldi(Rsize_of_parameters, Rsize_of_parameters, Interpreter::logStackElementSize);
+ __ sldi(top_frame_size, top_frame_size, Interpreter::logStackElementSize);
+ __ sub(parent_frame_resize, R1_SP, R15_esp); // <0, off by Interpreter::stackElementSize!
+ assert(Rsize_of_locals == noreg, "Rsize_of_locals not initialized"); // Only relevant value is Rsize_of_parameters.
+ } else {
+ __ lhz(Rsize_of_locals /* number of params */, in_bytes(ConstMethod::size_of_locals_offset()), Rconst_method);
+ __ sldi(Rsize_of_parameters, Rsize_of_parameters, Interpreter::logStackElementSize);
+ __ sldi(Rsize_of_locals, Rsize_of_locals, Interpreter::logStackElementSize);
+ __ lhz(top_frame_size, in_bytes(ConstMethod::max_stack_offset()), Rconst_method);
+ __ sub(R11_scratch1, Rsize_of_locals, Rsize_of_parameters); // >=0
+ __ sub(parent_frame_resize, R1_SP, R15_esp); // <0, off by Interpreter::stackElementSize!
+ __ sldi(top_frame_size, top_frame_size, Interpreter::logStackElementSize);
+ __ add(parent_frame_resize, parent_frame_resize, R11_scratch1);
+ }
+
+ // Compute top frame size.
+ __ addi(top_frame_size, top_frame_size, frame::abi_reg_args_size + frame::ijava_state_size);
+
+ // Cut back area between esp and max_stack.
+ __ addi(parent_frame_resize, parent_frame_resize, frame::abi_minframe_size - Interpreter::stackElementSize);
+
+ __ round_to(top_frame_size, frame::alignment_in_bytes);
+ __ round_to(parent_frame_resize, frame::alignment_in_bytes);
+ // parent_frame_resize = (locals-parameters) - (ESP-SP-ABI48) Rounded to frame alignment size.
+ // Enlarge by locals-parameters (not in case of native_call), shrink by ESP-SP-ABI48.
+
+ {
+ // --------------------------------------------------------------------------
+ // Stack overflow check
+
+ Label cont;
+ __ add(R11_scratch1, parent_frame_resize, top_frame_size);
+ generate_stack_overflow_check(R11_scratch1, R12_scratch2);
+ }
+
+ // Set up interpreter state registers.
+
+ __ add(R18_locals, R15_esp, Rsize_of_parameters);
+ __ ld(R27_constPoolCache, in_bytes(ConstMethod::constants_offset()), Rconst_method);
+ __ ld(R27_constPoolCache, ConstantPool::cache_offset_in_bytes(), R27_constPoolCache);
+
+ // Set method data pointer.
+ if (ProfileInterpreter) {
+ Label zero_continue;
+ __ ld(R28_mdx, method_(method_data));
+ __ cmpdi(CCR0, R28_mdx, 0);
+ __ beq(CCR0, zero_continue);
+ __ addi(R28_mdx, R28_mdx, in_bytes(MethodData::data_offset()));
+ __ bind(zero_continue);
+ }
+
+ if (native_call) {
+ __ li(R14_bcp, 0); // Must initialize.
+ } else {
+ __ add(R14_bcp, in_bytes(ConstMethod::codes_offset()), Rconst_method);
+ }
+
+ // Resize parent frame.
+ __ mflr(R12_scratch2);
+ __ neg(parent_frame_resize, parent_frame_resize);
+ __ resize_frame(parent_frame_resize, R11_scratch1);
+ __ std(R12_scratch2, _abi(lr), R1_SP);
+
+ __ addi(R26_monitor, R1_SP, - frame::ijava_state_size);
+ __ addi(R15_esp, R26_monitor, - Interpreter::stackElementSize);
+
+ // Store values.
+ // R15_esp, R14_bcp, R26_monitor, R28_mdx are saved at java calls
+ // in InterpreterMacroAssembler::call_from_interpreter.
+ __ std(R19_method, _ijava_state_neg(method), R1_SP);
+ __ std(R21_sender_SP, _ijava_state_neg(sender_sp), R1_SP);
+ __ std(R27_constPoolCache, _ijava_state_neg(cpoolCache), R1_SP);
+ __ std(R18_locals, _ijava_state_neg(locals), R1_SP);
+
+ // Note: esp, bcp, monitor, mdx live in registers. Hence, the correct version can only
+ // be found in the frame after save_interpreter_state is done. This is always true
+ // for non-top frames. But when a signal occurs, dumping the top frame can go wrong,
+ // because e.g. frame::interpreter_frame_bcp() will not access the correct value
+ // (Enhanced Stack Trace).
+ // The signal handler does not save the interpreter state into the frame.
+ __ li(R0, 0);
+#ifdef ASSERT
+ // Fill remaining slots with constants.
+ __ load_const_optimized(R11_scratch1, 0x5afe);
+ __ load_const_optimized(R12_scratch2, 0xdead);
+#endif
+ // We have to initialize some frame slots for native calls (accessed by GC).
+ if (native_call) {
+ __ std(R26_monitor, _ijava_state_neg(monitors), R1_SP);
+ __ std(R14_bcp, _ijava_state_neg(bcp), R1_SP);
+ if (ProfileInterpreter) { __ std(R28_mdx, _ijava_state_neg(mdx), R1_SP); }
+ }
+#ifdef ASSERT
+ else {
+ __ std(R12_scratch2, _ijava_state_neg(monitors), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(bcp), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(mdx), R1_SP);
+ }
+ __ std(R11_scratch1, _ijava_state_neg(ijava_reserved), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(esp), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(lresult), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(fresult), R1_SP);
+#endif
+ __ subf(R12_scratch2, top_frame_size, R1_SP);
+ __ std(R0, _ijava_state_neg(oop_tmp), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(top_frame_sp), R1_SP);
+
+ // Push top frame.
+ __ push_frame(top_frame_size, R11_scratch1);
+}
+
+// End of helpers
+
+address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) {
+ if (!TemplateInterpreter::math_entry_available(kind)) {
+ NOT_PRODUCT(__ should_not_reach_here();)
+ return NULL;
+ }
+
+ address entry = __ pc();
+
+ __ lfd(F1_RET, Interpreter::stackElementSize, R15_esp);
+
+ // Pop c2i arguments (if any) off when we return.
+#ifdef ASSERT
+ __ ld(R9_ARG7, 0, R1_SP);
+ __ ld(R10_ARG8, 0, R21_sender_SP);
+ __ cmpd(CCR0, R9_ARG7, R10_ARG8);
+ __ asm_assert_eq("backlink", 0x545);
+#endif // ASSERT
+ __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
+
+ if (kind == Interpreter::java_lang_math_sqrt) {
+ __ fsqrt(F1_RET, F1_RET);
+ } else if (kind == Interpreter::java_lang_math_abs) {
+ __ fabs(F1_RET, F1_RET);
+ } else {
+ ShouldNotReachHere();
+ }
+
+ // And we're done.
+ __ blr();
+
+ __ flush();
+
+ return entry;
+}
+
+// Interpreter stub for calling a native method. (asm interpreter)
+// This sets up a somewhat different looking stack for calling the
+// native method than the typical interpreter frame setup.
+//
+// On entry:
+// R19_method - method
+// R16_thread - JavaThread*
+// R15_esp - intptr_t* sender tos
+//
+// abstract stack (grows up)
+// [ IJava (caller of JNI callee) ] <-- ASP
+// ...
+address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
+
+ address entry = __ pc();
+
+ const bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
+
+ // -----------------------------------------------------------------------------
+ // Allocate a new frame that represents the native callee (i2n frame).
+ // This is not a full-blown interpreter frame, but in particular, the
+ // following registers are valid after this:
+ // - R19_method
+ // - R18_local (points to start of argumuments to native function)
+ //
+ // abstract stack (grows up)
+ // [ IJava (caller of JNI callee) ] <-- ASP
+ // ...
+
+ const Register signature_handler_fd = R11_scratch1;
+ const Register pending_exception = R0;
+ const Register result_handler_addr = R31;
+ const Register native_method_fd = R11_scratch1;
+ const Register access_flags = R22_tmp2;
+ const Register active_handles = R11_scratch1; // R26_monitor saved to state.
+ const Register sync_state = R12_scratch2;
+ const Register sync_state_addr = sync_state; // Address is dead after use.
+ const Register suspend_flags = R11_scratch1;
+
+ //=============================================================================
+ // Allocate new frame and initialize interpreter state.
+
+ Label exception_return;
+ Label exception_return_sync_check;
+ Label stack_overflow_return;
+
+ // Generate new interpreter state and jump to stack_overflow_return in case of
+ // a stack overflow.
+ //generate_compute_interpreter_state(stack_overflow_return);
+
+ Register size_of_parameters = R22_tmp2;
+
+ generate_fixed_frame(true, size_of_parameters, noreg /* unused */);
+
+ //=============================================================================
+ // Increment invocation counter. On overflow, entry to JNI method
+ // will be compiled.
+ Label invocation_counter_overflow, continue_after_compile;
+ if (inc_counter) {
+ if (synchronized) {
+ // Since at this point in the method invocation the exception handler
+ // would try to exit the monitor of synchronized methods which hasn't
+ // been entered yet, we set the thread local variable
+ // _do_not_unlock_if_synchronized to true. If any exception was thrown by
+ // runtime, exception handling i.e. unlock_if_synchronized_method will
+ // check this thread local flag.
+ // This flag has two effects, one is to force an unwind in the topmost
+ // interpreter frame and not perform an unlock while doing so.
+ __ li(R0, 1);
+ __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
+ }
+ generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
+
+ BIND(continue_after_compile);
+ // Reset the _do_not_unlock_if_synchronized flag.
+ if (synchronized) {
+ __ li(R0, 0);
+ __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
+ }
+ }
+
+ // access_flags = method->access_flags();
+ // Load access flags.
+ assert(access_flags->is_nonvolatile(),
+ "access_flags must be in a non-volatile register");
+ // Type check.
+ assert(4 == sizeof(AccessFlags), "unexpected field size");
+ __ lwz(access_flags, method_(access_flags));
+
+ // We don't want to reload R19_method and access_flags after calls
+ // to some helper functions.
+ assert(R19_method->is_nonvolatile(),
+ "R19_method must be a non-volatile register");
+
+ // Check for synchronized methods. Must happen AFTER invocation counter
+ // check, so method is not locked if counter overflows.
+
+ if (synchronized) {
+ lock_method(access_flags, R11_scratch1, R12_scratch2, true);
+
+ // Update monitor in state.
+ __ ld(R11_scratch1, 0, R1_SP);
+ __ std(R26_monitor, _ijava_state_neg(monitors), R11_scratch1);
+ }
+
+ // jvmti/jvmpi support
+ __ notify_method_entry();
+
+ //=============================================================================
+ // Get and call the signature handler.
+
+ __ ld(signature_handler_fd, method_(signature_handler));
+ Label call_signature_handler;
+
+ __ cmpdi(CCR0, signature_handler_fd, 0);
+ __ bne(CCR0, call_signature_handler);
+
+ // Method has never been called. Either generate a specialized
+ // handler or point to the slow one.
+ //
+ // Pass parameter 'false' to avoid exception check in call_VM.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), R19_method, false);
+
+ // Check for an exception while looking up the target method. If we
+ // incurred one, bail.
+ __ ld(pending_exception, thread_(pending_exception));
+ __ cmpdi(CCR0, pending_exception, 0);
+ __ bne(CCR0, exception_return_sync_check); // Has pending exception.
+
+ // Reload signature handler, it may have been created/assigned in the meanwhile.
+ __ ld(signature_handler_fd, method_(signature_handler));
+ __ twi_0(signature_handler_fd); // Order wrt. load of klass mirror and entry point (isync is below).
+
+ BIND(call_signature_handler);
+
+ // Before we call the signature handler we push a new frame to
+ // protect the interpreter frame volatile registers when we return
+ // from jni but before we can get back to Java.
+
+ // First set the frame anchor while the SP/FP registers are
+ // convenient and the slow signature handler can use this same frame
+ // anchor.
+
+ // We have a TOP_IJAVA_FRAME here, which belongs to us.
+ __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R12_scratch2/*tmp*/);
+
+ // Now the interpreter frame (and its call chain) have been
+ // invalidated and flushed. We are now protected against eager
+ // being enabled in native code. Even if it goes eager the
+ // registers will be reloaded as clean and we will invalidate after
+ // the call so no spurious flush should be possible.
+
+ // Call signature handler and pass locals address.
+ //
+ // Our signature handlers copy required arguments to the C stack
+ // (outgoing C args), R3_ARG1 to R10_ARG8, and FARG1 to FARG13.
+ __ mr(R3_ARG1, R18_locals);
+#if !defined(ABI_ELFv2)
+ __ ld(signature_handler_fd, 0, signature_handler_fd);
+#endif
+
+ __ call_stub(signature_handler_fd);
+
+ // Remove the register parameter varargs slots we allocated in
+ // compute_interpreter_state. SP+16 ends up pointing to the ABI
+ // outgoing argument area.
+ //
+ // Not needed on PPC64.
+ //__ add(SP, SP, Argument::n_register_parameters*BytesPerWord);
+
+ assert(result_handler_addr->is_nonvolatile(), "result_handler_addr must be in a non-volatile register");
+ // Save across call to native method.
+ __ mr(result_handler_addr, R3_RET);
+
+ __ isync(); // Acquire signature handler before trying to fetch the native entry point and klass mirror.
+
+ // Set up fixed parameters and call the native method.
+ // If the method is static, get mirror into R4_ARG2.
+ {
+ Label method_is_not_static;
+ // Access_flags is non-volatile and still, no need to restore it.
+
+ // Restore access flags.
+ __ testbitdi(CCR0, R0, access_flags, JVM_ACC_STATIC_BIT);
+ __ bfalse(CCR0, method_is_not_static);
+
+ // constants = method->constants();
+ __ ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method);
+ __ ld(R11_scratch1, in_bytes(ConstMethod::constants_offset()), R11_scratch1);
+ // pool_holder = method->constants()->pool_holder();
+ __ ld(R11_scratch1/*pool_holder*/, ConstantPool::pool_holder_offset_in_bytes(),
+ R11_scratch1/*constants*/);
+
+ const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+
+ // mirror = pool_holder->klass_part()->java_mirror();
+ __ ld(R0/*mirror*/, mirror_offset, R11_scratch1/*pool_holder*/);
+ // state->_native_mirror = mirror;
+
+ __ ld(R11_scratch1, 0, R1_SP);
+ __ std(R0/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1);
+ // R4_ARG2 = &state->_oop_temp;
+ __ addi(R4_ARG2, R11_scratch1, _ijava_state_neg(oop_tmp));
+ BIND(method_is_not_static);
+ }
+
+ // At this point, arguments have been copied off the stack into
+ // their JNI positions. Oops are boxed in-place on the stack, with
+ // handles copied to arguments. The result handler address is in a
+ // register.
+
+ // Pass JNIEnv address as first parameter.
+ __ addir(R3_ARG1, thread_(jni_environment));
+
+ // Load the native_method entry before we change the thread state.
+ __ ld(native_method_fd, method_(native_function));
+
+ //=============================================================================
+ // Transition from _thread_in_Java to _thread_in_native. As soon as
+ // we make this change the safepoint code needs to be certain that
+ // the last Java frame we established is good. The pc in that frame
+ // just needs to be near here not an actual return address.
+
+ // We use release_store_fence to update values like the thread state, where
+ // we don't want the current thread to continue until all our prior memory
+ // accesses (including the new thread state) are visible to other threads.
+ __ li(R0, _thread_in_native);
+ __ release();
+
+ // TODO PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size");
+ __ stw(R0, thread_(thread_state));
+
+ if (UseMembar) {
+ __ fence();
+ }
+
+ //=============================================================================
+ // Call the native method. Argument registers must not have been
+ // overwritten since "__ call_stub(signature_handler);" (except for
+ // ARG1 and ARG2 for static methods).
+ __ call_c(native_method_fd);
+
+ __ li(R0, 0);
+ __ ld(R11_scratch1, 0, R1_SP);
+ __ std(R3_RET, _ijava_state_neg(lresult), R11_scratch1);
+ __ stfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1);
+ __ std(R0/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1); // reset
+
+ // Note: C++ interpreter needs the following here:
+ // The frame_manager_lr field, which we use for setting the last
+ // java frame, gets overwritten by the signature handler. Restore
+ // it now.
+ //__ get_PC_trash_LR(R11_scratch1);
+ //__ std(R11_scratch1, _top_ijava_frame_abi(frame_manager_lr), R1_SP);
+
+ // Because of GC R19_method may no longer be valid.
+
+ // Block, if necessary, before resuming in _thread_in_Java state.
+ // In order for GC to work, don't clear the last_Java_sp until after
+ // blocking.
+
+ //=============================================================================
+ // Switch thread to "native transition" state before reading the
+ // synchronization state. This additional state is necessary
+ // because reading and testing the synchronization state is not
+ // atomic w.r.t. GC, as this scenario demonstrates: Java thread A,
+ // in _thread_in_native state, loads _not_synchronized and is
+ // preempted. VM thread changes sync state to synchronizing and
+ // suspends threads for GC. Thread A is resumed to finish this
+ // native method, but doesn't block here since it didn't see any
+ // synchronization in progress, and escapes.
+
+ // We use release_store_fence to update values like the thread state, where
+ // we don't want the current thread to continue until all our prior memory
+ // accesses (including the new thread state) are visible to other threads.
+ __ li(R0/*thread_state*/, _thread_in_native_trans);
+ __ release();
+ __ stw(R0/*thread_state*/, thread_(thread_state));
+ if (UseMembar) {
+ __ fence();
+ }
+ // Write serialization page so that the 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 due to cache line collision.
+ else {
+ __ serialize_memory(R16_thread, R11_scratch1, R12_scratch2);
+ }
+
+ // Now before we return to java we must look for a current safepoint
+ // (a new safepoint can not start since we entered native_trans).
+ // We must check here because a current safepoint could be modifying
+ // the callers registers right this moment.
+
+ // Acquire isn't strictly necessary here because of the fence, but
+ // sync_state is declared to be volatile, so we do it anyway
+ // (cmp-br-isync on one path, release (same as acquire on PPC64) on the other path).
+ int sync_state_offs = __ load_const_optimized(sync_state_addr, SafepointSynchronize::address_of_state(), /*temp*/R0, true);
+
+ // TODO PPC port assert(4 == SafepointSynchronize::sz_state(), "unexpected field size");
+ __ lwz(sync_state, sync_state_offs, sync_state_addr);
+
+ // TODO PPC port assert(4 == Thread::sz_suspend_flags(), "unexpected field size");
+ __ lwz(suspend_flags, thread_(suspend_flags));
+
+ Label sync_check_done;
+ Label do_safepoint;
+ // No synchronization in progress nor yet synchronized.
+ __ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized);
+ // Not suspended.
+ __ cmpwi(CCR1, suspend_flags, 0);
+
+ __ bne(CCR0, do_safepoint);
+ __ beq(CCR1, sync_check_done);
+ __ bind(do_safepoint);
+ __ isync();
+ // Block. We do the call directly and leave the current
+ // last_Java_frame setup undisturbed. We must save any possible
+ // native result across the call. No oop is present.
+
+ __ mr(R3_ARG1, R16_thread);
+#if defined(ABI_ELFv2)
+ __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
+ relocInfo::none);
+#else
+ __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans),
+ relocInfo::none);
+#endif
+
+ __ bind(sync_check_done);
+
+ //=============================================================================
+ // <<<<<< Back in Interpreter Frame >>>>>
+
+ // We are in thread_in_native_trans here and back in the normal
+ // interpreter frame. We don't have to do anything special about
+ // safepoints and we can switch to Java mode anytime we are ready.
+
+ // Note: frame::interpreter_frame_result has a dependency on how the
+ // method result is saved across the call to post_method_exit. For
+ // native methods it assumes that the non-FPU/non-void result is
+ // saved in _native_lresult and a FPU result in _native_fresult. If
+ // this changes then the interpreter_frame_result implementation
+ // will need to be updated too.
+
+ // On PPC64, we have stored the result directly after the native call.
+
+ //=============================================================================
+ // Back in Java
+
+ // We use release_store_fence to update values like the thread state, where
+ // we don't want the current thread to continue until all our prior memory
+ // accesses (including the new thread state) are visible to other threads.
+ __ li(R0/*thread_state*/, _thread_in_Java);
+ __ release();
+ __ stw(R0/*thread_state*/, thread_(thread_state));
+ if (UseMembar) {
+ __ fence();
+ }
+
+ __ reset_last_Java_frame();
+
+ // Jvmdi/jvmpi support. Whether we've got an exception pending or
+ // not, and whether unlocking throws an exception or not, we notify
+ // on native method exit. If we do have an exception, we'll end up
+ // in the caller's context to handle it, so if we don't do the
+ // notify here, we'll drop it on the floor.
+ __ notify_method_exit(true/*native method*/,
+ ilgl /*illegal state (not used for native methods)*/,
+ InterpreterMacroAssembler::NotifyJVMTI,
+ false /*check_exceptions*/);
+
+ //=============================================================================
+ // Handle exceptions
+
+ if (synchronized) {
+ // Don't check for exceptions since we're still in the i2n frame. Do that
+ // manually afterwards.
+ unlock_method(false);
+ }
+
+ // Reset active handles after returning from native.
+ // thread->active_handles()->clear();
+ __ ld(active_handles, thread_(active_handles));
+ // TODO PPC port assert(4 == JNIHandleBlock::top_size_in_bytes(), "unexpected field size");
+ __ li(R0, 0);
+ __ stw(R0, JNIHandleBlock::top_offset_in_bytes(), active_handles);
+
+ Label exception_return_sync_check_already_unlocked;
+ __ ld(R0/*pending_exception*/, thread_(pending_exception));
+ __ cmpdi(CCR0, R0/*pending_exception*/, 0);
+ __ bne(CCR0, exception_return_sync_check_already_unlocked);
+
+ //-----------------------------------------------------------------------------
+ // No exception pending.
+
+ // Move native method result back into proper registers and return.
+ // Invoke result handler (may unbox/promote).
+ __ ld(R11_scratch1, 0, R1_SP);
+ __ ld(R3_RET, _ijava_state_neg(lresult), R11_scratch1);
+ __ lfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1);
+ __ call_stub(result_handler_addr);
+
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2);
+
+ // Must use the return pc which was loaded from the caller's frame
+ // as the VM uses return-pc-patching for deoptimization.
+ __ mtlr(R0);
+ __ blr();
+
+ //-----------------------------------------------------------------------------
+ // An exception is pending. We call into the runtime only if the
+ // caller was not interpreted. If it was interpreted the
+ // interpreter will do the correct thing. If it isn't interpreted
+ // (call stub/compiled code) we will change our return and continue.
+
+ BIND(exception_return_sync_check);
+
+ if (synchronized) {
+ // Don't check for exceptions since we're still in the i2n frame. Do that
+ // manually afterwards.
+ unlock_method(false);
+ }
+ BIND(exception_return_sync_check_already_unlocked);
+
+ const Register return_pc = R31;
+
+ __ ld(return_pc, 0, R1_SP);
+ __ ld(return_pc, _abi(lr), return_pc);
+
+ // Get the address of the exception handler.
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
+ R16_thread,
+ return_pc /* return pc */);
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, noreg, R11_scratch1, R12_scratch2);
+
+ // Load the PC of the the exception handler into LR.
+ __ mtlr(R3_RET);
+
+ // Load exception into R3_ARG1 and clear pending exception in thread.
+ __ ld(R3_ARG1/*exception*/, thread_(pending_exception));
+ __ li(R4_ARG2, 0);
+ __ std(R4_ARG2, thread_(pending_exception));
+
+ // Load the original return pc into R4_ARG2.
+ __ mr(R4_ARG2/*issuing_pc*/, return_pc);
+
+ // Return to exception handler.
+ __ blr();
+
+ //=============================================================================
+ // Counter overflow.
+
+ if (inc_counter) {
+ // Handle invocation counter overflow.
+ __ bind(invocation_counter_overflow);
+
+ generate_counter_overflow(continue_after_compile);
+ }
+
+ return entry;
+}
+
+// Generic interpreted method entry to (asm) interpreter.
+//
+address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
+ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
+ address entry = __ pc();
+ // Generate the code to allocate the interpreter stack frame.
+ Register Rsize_of_parameters = R4_ARG2, // Written by generate_fixed_frame.
+ Rsize_of_locals = R5_ARG3; // Written by generate_fixed_frame.
+
+ generate_fixed_frame(false, Rsize_of_parameters, Rsize_of_locals);
+
+ // --------------------------------------------------------------------------
+ // Zero out non-parameter locals.
+ // Note: *Always* zero out non-parameter locals as Sparc does. It's not
+ // worth to ask the flag, just do it.
+ Register Rslot_addr = R6_ARG4,
+ Rnum = R7_ARG5;
+ Label Lno_locals, Lzero_loop;
+
+ // Set up the zeroing loop.
+ __ subf(Rnum, Rsize_of_parameters, Rsize_of_locals);
+ __ subf(Rslot_addr, Rsize_of_parameters, R18_locals);
+ __ srdi_(Rnum, Rnum, Interpreter::logStackElementSize);
+ __ beq(CCR0, Lno_locals);
+ __ li(R0, 0);
+ __ mtctr(Rnum);
+
+ // The zero locals loop.
+ __ bind(Lzero_loop);
+ __ std(R0, 0, Rslot_addr);
+ __ addi(Rslot_addr, Rslot_addr, -Interpreter::stackElementSize);
+ __ bdnz(Lzero_loop);
+
+ __ bind(Lno_locals);
+
+ // --------------------------------------------------------------------------
+ // Counter increment and overflow check.
+ Label invocation_counter_overflow,
+ profile_method,
+ profile_method_continue;
+ if (inc_counter || ProfileInterpreter) {
+
+ Register Rdo_not_unlock_if_synchronized_addr = R11_scratch1;
+ if (synchronized) {
+ // Since at this point in the method invocation the exception handler
+ // would try to exit the monitor of synchronized methods which hasn't
+ // been entered yet, we set the thread local variable
+ // _do_not_unlock_if_synchronized to true. If any exception was thrown by
+ // runtime, exception handling i.e. unlock_if_synchronized_method will
+ // check this thread local flag.
+ // This flag has two effects, one is to force an unwind in the topmost
+ // interpreter frame and not perform an unlock while doing so.
+ __ li(R0, 1);
+ __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
+ }
+
+ // Argument and return type profiling.
+ __ profile_parameters_type(R3_ARG1, R4_ARG2, R5_ARG3, R6_ARG4);
+
+ // Increment invocation counter and check for overflow.
+ if (inc_counter) {
+ generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue);
+ }
+
+ __ bind(profile_method_continue);
+
+ // Reset the _do_not_unlock_if_synchronized flag.
+ if (synchronized) {
+ __ li(R0, 0);
+ __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
+ }
+ }
+
+ // --------------------------------------------------------------------------
+ // Locking of synchronized methods. Must happen AFTER invocation_counter
+ // check and stack overflow check, so method is not locked if overflows.
+ if (synchronized) {
+ lock_method(R3_ARG1, R4_ARG2, R5_ARG3);
+ }
+#ifdef ASSERT
+ else {
+ Label Lok;
+ __ lwz(R0, in_bytes(Method::access_flags_offset()), R19_method);
+ __ andi_(R0, R0, JVM_ACC_SYNCHRONIZED);
+ __ asm_assert_eq("method needs synchronization", 0x8521);
+ __ bind(Lok);
+ }
+#endif // ASSERT
+
+ __ verify_thread();
+
+ // --------------------------------------------------------------------------
+ // JVMTI support
+ __ notify_method_entry();
+
+ // --------------------------------------------------------------------------
+ // Start executing instructions.
+ __ dispatch_next(vtos);
+
+ // --------------------------------------------------------------------------
+ // Out of line counter overflow and MDO creation code.
+ if (ProfileInterpreter) {
+ // We have decided to profile this method in the interpreter.
+ __ bind(profile_method);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
+ __ set_method_data_pointer_for_bcp();
+ __ b(profile_method_continue);
+ }
+
+ if (inc_counter) {
+ // Handle invocation counter overflow.
+ __ bind(invocation_counter_overflow);
+ generate_counter_overflow(profile_method_continue);
+ }
+ return entry;
+}
+
+// CRC32 Intrinsics.
+//
+// Contract on scratch and work registers.
+// =======================================
+//
+// On ppc, the register set {R2..R12} is available in the interpreter as scratch/work registers.
+// You should, however, keep in mind that {R3_ARG1..R10_ARG8} is the C-ABI argument register set.
+// You can't rely on these registers across calls.
+//
+// The generators for CRC32_update and for CRC32_updateBytes use the
+// scratch/work register set internally, passing the work registers
+// as arguments to the MacroAssembler emitters as required.
+//
+// R3_ARG1..R6_ARG4 are preset to hold the incoming java arguments.
+// Their contents is not constant but may change according to the requirements
+// of the emitted code.
+//
+// All other registers from the scratch/work register set are used "internally"
+// and contain garbage (i.e. unpredictable values) once blr() is reached.
+// Basically, only R3_RET contains a defined value which is the function result.
+//
+/**
+ * Method entry for static native methods:
+ * int java.util.zip.CRC32.update(int crc, int b)
+ */
+address InterpreterGenerator::generate_CRC32_update_entry() {
+ if (UseCRC32Intrinsics) {
+ address start = __ pc(); // Remember stub start address (is rtn value).
+ Label slow_path;
+
+ // Safepoint check
+ const Register sync_state = R11_scratch1;
+ int sync_state_offs = __ load_const_optimized(sync_state, SafepointSynchronize::address_of_state(), /*temp*/R0, true);
+ __ lwz(sync_state, sync_state_offs, sync_state);
+ __ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized);
+ __ bne(CCR0, slow_path);
+
+ // We don't generate local frame and don't align stack because
+ // we not even call stub code (we generate the code inline)
+ // and there is no safepoint on this path.
+
+ // Load java parameters.
+ // R15_esp is callers operand stack pointer, i.e. it points to the parameters.
+ const Register argP = R15_esp;
+ const Register crc = R3_ARG1; // crc value
+ const Register data = R4_ARG2; // address of java byte value (kernel_crc32 needs address)
+ const Register dataLen = R5_ARG3; // source data len (1 byte). Not used because calling the single-byte emitter.
+ const Register table = R6_ARG4; // address of crc32 table
+ const Register tmp = dataLen; // Reuse unused len register to show we don't actually need a separate tmp here.
+
+ BLOCK_COMMENT("CRC32_update {");
+
+ // Arguments are reversed on java expression stack
+#ifdef VM_LITTLE_ENDIAN
+ __ addi(data, argP, 0+1*wordSize); // (stack) address of byte value. Emitter expects address, not value.
+ // Being passed as an int, the single byte is at offset +0.
+#else
+ __ addi(data, argP, 3+1*wordSize); // (stack) address of byte value. Emitter expects address, not value.
+ // Being passed from java as an int, the single byte is at offset +3.
+#endif
+ __ lwz(crc, 2*wordSize, argP); // Current crc state, zero extend to 64 bit to have a clean register.
+
+ StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
+ __ kernel_crc32_singleByte(crc, data, dataLen, table, tmp);
+
+ // Restore caller sp for c2i case and return.
+ __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
+ __ blr();
+
+ // 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;
+ }
+
+ return NULL;
+}
+
+// CRC32 Intrinsics.
+/**
+ * Method entry for static native methods:
+ * int java.util.zip.CRC32.updateBytes( int crc, byte[] b, int off, int len)
+ * int java.util.zip.CRC32.updateByteBuffer(int crc, long* buf, int off, int len)
+ */
+address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
+ if (UseCRC32Intrinsics) {
+ address start = __ pc(); // Remember stub start address (is rtn value).
+ Label slow_path;
+
+ // Safepoint check
+ const Register sync_state = R11_scratch1;
+ int sync_state_offs = __ load_const_optimized(sync_state, SafepointSynchronize::address_of_state(), /*temp*/R0, true);
+ __ lwz(sync_state, sync_state_offs, sync_state);
+ __ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized);
+ __ bne(CCR0, slow_path);
+
+ // We don't generate local frame and don't align stack because
+ // we not even call stub code (we generate the code inline)
+ // and there is no safepoint on this path.
+
+ // Load parameters.
+ // Z_esp is callers operand stack pointer, i.e. it points to the parameters.
+ const Register argP = R15_esp;
+ const Register crc = R3_ARG1; // crc value
+ const Register data = R4_ARG2; // address of java byte array
+ const Register dataLen = R5_ARG3; // source data len
+ const Register table = R6_ARG4; // address of crc32 table
+
+ const Register t0 = R9; // scratch registers for crc calculation
+ const Register t1 = R10;
+ const Register t2 = R11;
+ const Register t3 = R12;
+
+ const Register tc0 = R2; // registers to hold pre-calculated column addresses
+ const Register tc1 = R7;
+ const Register tc2 = R8;
+ const Register tc3 = table; // table address is reconstructed at the end of kernel_crc32_* emitters
+
+ const Register tmp = t0; // Only used very locally to calculate byte buffer address.
+
+ // Arguments are reversed on java expression stack.
+ // Calculate address of start element.
+ if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) { // Used for "updateByteBuffer direct".
+ BLOCK_COMMENT("CRC32_updateByteBuffer {");
+ // crc @ (SP + 5W) (32bit)
+ // buf @ (SP + 3W) (64bit ptr to long array)
+ // off @ (SP + 2W) (32bit)
+ // dataLen @ (SP + 1W) (32bit)
+ // data = buf + off
+ __ ld( data, 3*wordSize, argP); // start of byte buffer
+ __ lwa( tmp, 2*wordSize, argP); // byte buffer offset
+ __ lwa( dataLen, 1*wordSize, argP); // #bytes to process
+ __ lwz( crc, 5*wordSize, argP); // current crc state
+ __ add( data, data, tmp); // Add byte buffer offset.
+ } else { // Used for "updateBytes update".
+ BLOCK_COMMENT("CRC32_updateBytes {");
+ // crc @ (SP + 4W) (32bit)
+ // buf @ (SP + 3W) (64bit ptr to byte array)
+ // off @ (SP + 2W) (32bit)
+ // dataLen @ (SP + 1W) (32bit)
+ // data = buf + off + base_offset
+ __ ld( data, 3*wordSize, argP); // start of byte buffer
+ __ lwa( tmp, 2*wordSize, argP); // byte buffer offset
+ __ lwa( dataLen, 1*wordSize, argP); // #bytes to process
+ __ add( data, data, tmp); // add byte buffer offset
+ __ lwz( crc, 4*wordSize, argP); // current crc state
+ __ addi(data, data, arrayOopDesc::base_offset_in_bytes(T_BYTE));
+ }
+
+ StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
+
+ // Performance measurements show the 1word and 2word variants to be almost equivalent,
+ // with very light advantages for the 1word variant. We chose the 1word variant for
+ // code compactness.
+ __ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, tc3);
+
+ // Restore caller sp for c2i case and return.
+ __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
+ __ blr();
+
+ // 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;
+ }
+
+ return NULL;
+}
+
+// =============================================================================
+// Exceptions
+
+void TemplateInterpreterGenerator::generate_throw_exception() {
+ Register Rexception = R17_tos,
+ Rcontinuation = R3_RET;
+
+ // --------------------------------------------------------------------------
+ // Entry point if an method returns with a pending exception (rethrow).
+ Interpreter::_rethrow_exception_entry = __ pc();
+ {
+ __ restore_interpreter_state(R11_scratch1); // Sets R11_scratch1 = fp.
+ __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1);
+ __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0);
+
+ // Compiled code destroys templateTableBase, reload.
+ __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1);
+ }
+
+ // Entry point if a interpreted method throws an exception (throw).
+ Interpreter::_throw_exception_entry = __ pc();
+ {
+ __ mr(Rexception, R3_RET);
+
+ __ verify_thread();
+ __ verify_oop(Rexception);
+
+ // Expression stack must be empty before entering the VM in case of an exception.
+ __ empty_expression_stack();
+ // Find exception handler address and preserve exception oop.
+ // Call C routine to find handler and jump to it.
+ __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), Rexception);
+ __ mtctr(Rcontinuation);
+ // Push exception for exception handler bytecodes.
+ __ push_ptr(Rexception);
+
+ // Jump to exception handler (may be remove activation entry!).
+ __ bctr();
+ }
+
+ // If the exception is not handled in the current frame the frame is
+ // removed and the exception is rethrown (i.e. exception
+ // continuation is _rethrow_exception).
+ //
+ // Note: At this point the bci is still the bxi for the instruction
+ // which caused the exception and the expression stack is
+ // empty. Thus, for any VM calls at this point, GC will find a legal
+ // oop map (with empty expression stack).
+
+ // In current activation
+ // tos: exception
+ // bcp: exception bcp
+
+ // --------------------------------------------------------------------------
+ // JVMTI PopFrame support
+
+ Interpreter::_remove_activation_preserving_args_entry = __ pc();
+ {
+ // Set the popframe_processing bit in popframe_condition indicating that we are
+ // currently handling popframe, so that call_VMs that may happen later do not
+ // trigger new popframe handling cycles.
+ __ lwz(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
+ __ ori(R11_scratch1, R11_scratch1, JavaThread::popframe_processing_bit);
+ __ stw(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
+
+ // Empty the expression stack, as in normal exception handling.
+ __ empty_expression_stack();
+ __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, /* install_monitor_exception */ false);
+
+ // Check to see whether we are returning to a deoptimized frame.
+ // (The PopFrame call ensures that the caller of the popped frame is
+ // either interpreted or compiled and deoptimizes it if compiled.)
+ // Note that we don't compare the return PC against the
+ // deoptimization blob's unpack entry because of the presence of
+ // adapter frames in C2.
+ Label Lcaller_not_deoptimized;
+ Register return_pc = R3_ARG1;
+ __ ld(return_pc, 0, R1_SP);
+ __ ld(return_pc, _abi(lr), return_pc);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), return_pc);
+ __ cmpdi(CCR0, R3_RET, 0);
+ __ bne(CCR0, Lcaller_not_deoptimized);
+
+ // The deoptimized case.
+ // In this case, we can't call dispatch_next() after the frame is
+ // popped, but instead must save the incoming arguments and restore
+ // them after deoptimization has occurred.
+ __ ld(R4_ARG2, in_bytes(Method::const_offset()), R19_method);
+ __ lhz(R4_ARG2 /* number of params */, in_bytes(ConstMethod::size_of_parameters_offset()), R4_ARG2);
+ __ slwi(R4_ARG2, R4_ARG2, Interpreter::logStackElementSize);
+ __ addi(R5_ARG3, R18_locals, Interpreter::stackElementSize);
+ __ subf(R5_ARG3, R4_ARG2, R5_ARG3);
+ // Save these arguments.
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), R16_thread, R4_ARG2, R5_ARG3);
+
+ // Inform deoptimization that it is responsible for restoring these arguments.
+ __ load_const_optimized(R11_scratch1, JavaThread::popframe_force_deopt_reexecution_bit);
+ __ stw(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
+
+ // Return from the current method into the deoptimization blob. Will eventually
+ // end up in the deopt interpeter entry, deoptimization prepared everything that
+ // we will reexecute the call that called us.
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*reload return_pc*/ return_pc, R11_scratch1, R12_scratch2);
+ __ mtlr(return_pc);
+ __ blr();
+
+ // The non-deoptimized case.
+ __ bind(Lcaller_not_deoptimized);
+
+ // Clear the popframe condition flag.
+ __ li(R0, 0);
+ __ stw(R0, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
+
+ // Get out of the current method and re-execute the call that called us.
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ noreg, R11_scratch1, R12_scratch2);
+ __ restore_interpreter_state(R11_scratch1);
+ __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1);
+ __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0);
+ if (ProfileInterpreter) {
+ __ set_method_data_pointer_for_bcp();
+ __ ld(R11_scratch1, 0, R1_SP);
+ __ std(R28_mdx, _ijava_state_neg(mdx), R11_scratch1);
+ }
+#if INCLUDE_JVMTI
+ Label L_done;
+
+ __ lbz(R11_scratch1, 0, R14_bcp);
+ __ cmpwi(CCR0, R11_scratch1, Bytecodes::_invokestatic);
+ __ bne(CCR0, L_done);
+
+ // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
+ // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
+ __ ld(R4_ARG2, 0, R18_locals);
+ __ MacroAssembler::call_VM(R4_ARG2, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), R4_ARG2, R19_method, R14_bcp, false);
+ __ restore_interpreter_state(R11_scratch1, /*bcp_and_mdx_only*/ true);
+ __ cmpdi(CCR0, R4_ARG2, 0);
+ __ beq(CCR0, L_done);
+ __ std(R4_ARG2, wordSize, R15_esp);
+ __ bind(L_done);
+#endif // INCLUDE_JVMTI
+ __ dispatch_next(vtos);
+ }
+ // end of JVMTI PopFrame support
+
+ // --------------------------------------------------------------------------
+ // Remove activation exception entry.
+ // This is jumped to if an interpreted method can't handle an exception itself
+ // (we come from the throw/rethrow exception entry above). We're going to call
+ // into the VM to find the exception handler in the caller, pop the current
+ // frame and return the handler we calculated.
+ Interpreter::_remove_activation_entry = __ pc();
+ {
+ __ pop_ptr(Rexception);
+ __ verify_thread();
+ __ verify_oop(Rexception);
+ __ std(Rexception, in_bytes(JavaThread::vm_result_offset()), R16_thread);
+
+ __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, true);
+ __ notify_method_exit(false, vtos, InterpreterMacroAssembler::SkipNotifyJVMTI, false);
+
+ __ get_vm_result(Rexception);
+
+ // We are done with this activation frame; find out where to go next.
+ // The continuation point will be an exception handler, which expects
+ // the following registers set up:
+ //
+ // RET: exception oop
+ // ARG2: Issuing PC (see generate_exception_blob()), only used if the caller is compiled.
+
+ Register return_pc = R31; // Needs to survive the runtime call.
+ __ ld(return_pc, 0, R1_SP);
+ __ ld(return_pc, _abi(lr), return_pc);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, return_pc);
+
+ // Remove the current activation.
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ noreg, R11_scratch1, R12_scratch2);
+
+ __ mr(R4_ARG2, return_pc);
+ __ mtlr(R3_RET);
+ __ mr(R3_RET, Rexception);
+ __ blr();
+ }
+}
+
+// JVMTI ForceEarlyReturn support.
+// Returns "in the middle" of a method with a "fake" return value.
+address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
+
+ Register Rscratch1 = R11_scratch1,
+ Rscratch2 = R12_scratch2;
+
+ address entry = __ pc();
+ __ empty_expression_stack();
+
+ __ load_earlyret_value(state, Rscratch1);
+
+ __ ld(Rscratch1, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread);
+ // Clear the earlyret state.
+ __ li(R0, 0);
+ __ stw(R0, in_bytes(JvmtiThreadState::earlyret_state_offset()), Rscratch1);
+
+ __ remove_activation(state, false, false);
+ // Copied from TemplateTable::_return.
+ // Restoration of lr done by remove_activation.
+ switch (state) {
+ case ltos:
+ case btos:
+ case ctos:
+ case stos:
+ case atos:
+ case itos: __ mr(R3_RET, R17_tos); break;
+ case ftos:
+ case dtos: __ fmr(F1_RET, F15_ftos); break;
+ case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need
+ // to get visible before the reference to the object gets stored anywhere.
+ __ membar(Assembler::StoreStore); break;
+ default : ShouldNotReachHere();
+ }
+ __ blr();
+
+ return entry;
+} // end of ForceEarlyReturn support
+
+//-----------------------------------------------------------------------------
+// Helper for vtos entry point generation
+
+void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
+ address& bep,
+ address& cep,
+ address& sep,
+ address& aep,
+ address& iep,
+ address& lep,
+ address& fep,
+ address& dep,
+ address& vep) {
+ assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
+ Label L;
+
+ aep = __ pc(); __ push_ptr(); __ b(L);
+ fep = __ pc(); __ push_f(); __ b(L);
+ dep = __ pc(); __ push_d(); __ b(L);
+ lep = __ pc(); __ push_l(); __ b(L);
+ __ align(32, 12, 24); // align L
+ bep = cep = sep =
+ iep = __ pc(); __ push_i();
+ vep = __ pc();
+ __ bind(L);
+ generate_and_dispatch(t);
+}
+
+//-----------------------------------------------------------------------------
+// Generation of individual instructions
+
+// helpers for generate_and_dispatch
+
+InterpreterGenerator::InterpreterGenerator(StubQueue* code)
+ : TemplateInterpreterGenerator(code) {
+ generate_all(); // Down here so it can be "virtual".
+}
+
+//-----------------------------------------------------------------------------
+
+// Non-product code
+#ifndef PRODUCT
+address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
+ //__ flush_bundle();
+ address entry = __ pc();
+
+ const char *bname = NULL;
+ uint tsize = 0;
+ switch(state) {
+ case ftos:
+ bname = "trace_code_ftos {";
+ tsize = 2;
+ break;
+ case btos:
+ bname = "trace_code_btos {";
+ tsize = 2;
+ break;
+ case ctos:
+ bname = "trace_code_ctos {";
+ tsize = 2;
+ break;
+ case stos:
+ bname = "trace_code_stos {";
+ tsize = 2;
+ break;
+ case itos:
+ bname = "trace_code_itos {";
+ tsize = 2;
+ break;
+ case ltos:
+ bname = "trace_code_ltos {";
+ tsize = 3;
+ break;
+ case atos:
+ bname = "trace_code_atos {";
+ tsize = 2;
+ break;
+ case vtos:
+ // Note: In case of vtos, the topmost of stack value could be a int or doubl
+ // In case of a double (2 slots) we won't see the 2nd stack value.
+ // Maybe we simply should print the topmost 3 stack slots to cope with the problem.
+ bname = "trace_code_vtos {";
+ tsize = 2;
+
+ break;
+ case dtos:
+ bname = "trace_code_dtos {";
+ tsize = 3;
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ BLOCK_COMMENT(bname);
+
+ // Support short-cut for TraceBytecodesAt.
+ // Don't call into the VM if we don't want to trace to speed up things.
+ Label Lskip_vm_call;
+ if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) {
+ int offs1 = __ load_const_optimized(R11_scratch1, (address) &TraceBytecodesAt, R0, true);
+ int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true);
+ __ ld(R11_scratch1, offs1, R11_scratch1);
+ __ lwa(R12_scratch2, offs2, R12_scratch2);
+ __ cmpd(CCR0, R12_scratch2, R11_scratch1);
+ __ blt(CCR0, Lskip_vm_call);
+ }
+
+ __ push(state);
+ // Load 2 topmost expression stack values.
+ __ ld(R6_ARG4, tsize*Interpreter::stackElementSize, R15_esp);
+ __ ld(R5_ARG3, Interpreter::stackElementSize, R15_esp);
+ __ mflr(R31);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), /* unused */ R4_ARG2, R5_ARG3, R6_ARG4, false);
+ __ mtlr(R31);
+ __ pop(state);
+
+ if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) {
+ __ bind(Lskip_vm_call);
+ }
+ __ blr();
+ BLOCK_COMMENT("} trace_code");
+ return entry;
+}
+
+void TemplateInterpreterGenerator::count_bytecode() {
+ int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeCounter::_counter_value, R12_scratch2, true);
+ __ lwz(R12_scratch2, offs, R11_scratch1);
+ __ addi(R12_scratch2, R12_scratch2, 1);
+ __ stw(R12_scratch2, offs, R11_scratch1);
+}
+
+void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
+ int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeHistogram::_counters[t->bytecode()], R12_scratch2, true);
+ __ lwz(R12_scratch2, offs, R11_scratch1);
+ __ addi(R12_scratch2, R12_scratch2, 1);
+ __ stw(R12_scratch2, offs, R11_scratch1);
+}
+
+void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) {
+ const Register addr = R11_scratch1,
+ tmp = R12_scratch2;
+ // Get index, shift out old bytecode, bring in new bytecode, and store it.
+ // _index = (_index >> log2_number_of_codes) |
+ // (bytecode << log2_number_of_codes);
+ int offs1 = __ load_const_optimized(addr, (address)&BytecodePairHistogram::_index, tmp, true);
+ __ lwz(tmp, offs1, addr);
+ __ srwi(tmp, tmp, BytecodePairHistogram::log2_number_of_codes);
+ __ ori(tmp, tmp, ((int) t->bytecode()) << BytecodePairHistogram::log2_number_of_codes);
+ __ stw(tmp, offs1, addr);
+
+ // Bump bucket contents.
+ // _counters[_index] ++;
+ int offs2 = __ load_const_optimized(addr, (address)&BytecodePairHistogram::_counters, R0, true);
+ __ sldi(tmp, tmp, LogBytesPerInt);
+ __ add(addr, tmp, addr);
+ __ lwz(tmp, offs2, addr);
+ __ addi(tmp, tmp, 1);
+ __ stw(tmp, offs2, addr);
+}
+
+void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
+ // Call a little run-time stub to avoid blow-up for each bytecode.
+ // The run-time runtime saves the right registers, depending on
+ // the tosca in-state for the given template.
+
+ assert(Interpreter::trace_code(t->tos_in()) != NULL,
+ "entry must have been generated");
+
+ // Note: we destroy LR here.
+ __ bl(Interpreter::trace_code(t->tos_in()));
+}
+
+void TemplateInterpreterGenerator::stop_interpreter_at() {
+ Label L;
+ int offs1 = __ load_const_optimized(R11_scratch1, (address) &StopInterpreterAt, R0, true);
+ int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true);
+ __ ld(R11_scratch1, offs1, R11_scratch1);
+ __ lwa(R12_scratch2, offs2, R12_scratch2);
+ __ cmpd(CCR0, R12_scratch2, R11_scratch1);
+ __ bne(CCR0, L);
+ __ illtrap();
+ __ bind(L);
+}
+
+#endif // !PRODUCT
+#endif // !CC_INTERP
--- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013, 2015 SAP AG. All rights reserved.
+ * Copyright (c) 2015 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,1389 +24,38 @@
*/
#include "precompiled.hpp"
-#ifndef CC_INTERP
-#include "asm/macroAssembler.inline.hpp"
-#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
-#include "interpreter/interpreterGenerator.hpp"
-#include "interpreter/interpreterRuntime.hpp"
-#include "interpreter/interp_masm.hpp"
-#include "interpreter/templateTable.hpp"
-#include "oops/arrayOop.hpp"
-#include "oops/methodData.hpp"
+#include "oops/constMethod.hpp"
#include "oops/method.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/jvmtiExport.hpp"
-#include "prims/jvmtiThreadState.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/synchronizer.hpp"
-#include "runtime/timer.hpp"
-#include "runtime/vframeArray.hpp"
#include "utilities/debug.hpp"
#include "utilities/macros.hpp"
-#undef __
-#define __ _masm->
-#ifdef PRODUCT
-#define BLOCK_COMMENT(str) /* nothing */
-#else
-#define BLOCK_COMMENT(str) __ block_comment(str)
-#endif
-
-#define BIND(label) __ bind(label); BLOCK_COMMENT(#label ":")
-
-//-----------------------------------------------------------------------------
-
-// Actually we should never reach here since we do stack overflow checks before pushing any frame.
-address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
- address entry = __ pc();
- __ unimplemented("generate_StackOverflowError_handler");
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
- address entry = __ pc();
- __ empty_expression_stack();
- __ load_const_optimized(R4_ARG2, (address) name);
- // Index is in R17_tos.
- __ mr(R5_ARG3, R17_tos);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException));
- return entry;
-}
-
-#if 0
-// Call special ClassCastException constructor taking object to cast
-// and target class as arguments.
-address TemplateInterpreterGenerator::generate_ClassCastException_verbose_handler() {
- address entry = __ pc();
-
- // Expression stack must be empty before entering the VM if an
- // exception happened.
- __ empty_expression_stack();
-
- // Thread will be loaded to R3_ARG1.
- // Target class oop is in register R5_ARG3 by convention!
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException_verbose), R17_tos, R5_ARG3);
- // Above call must not return here since exception pending.
- DEBUG_ONLY(__ should_not_reach_here();)
- return entry;
-}
-#endif
-
-address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
- address entry = __ pc();
- // Expression stack must be empty before entering the VM if an
- // exception happened.
- __ empty_expression_stack();
-
- // Load exception object.
- // Thread will be loaded to R3_ARG1.
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException), R17_tos);
-#ifdef ASSERT
- // Above call must not return here since exception pending.
- __ should_not_reach_here();
-#endif
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
- address entry = __ pc();
- //__ untested("generate_exception_handler_common");
- Register Rexception = R17_tos;
-
- // Expression stack must be empty before entering the VM if an exception happened.
- __ empty_expression_stack();
-
- __ load_const_optimized(R4_ARG2, (address) name, R11_scratch1);
- if (pass_oop) {
- __ mr(R5_ARG3, Rexception);
- __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), false);
- } else {
- __ load_const_optimized(R5_ARG3, (address) message, R11_scratch1);
- __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), false);
- }
-
- // Throw exception.
- __ mr(R3_ARG1, Rexception);
- __ load_const_optimized(R11_scratch1, Interpreter::throw_exception_entry(), R12_scratch2);
- __ mtctr(R11_scratch1);
- __ bctr();
-
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
- address entry = __ pc();
- __ unimplemented("generate_continuation_for");
- return entry;
-}
-
-// This entry is returned to when a call returns to the interpreter.
-// When we arrive here, we expect that the callee stack frame is already popped.
-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
- address entry = __ pc();
-
- // Move the value out of the return register back to the TOS cache of current frame.
- switch (state) {
- case ltos:
- case btos:
- case ctos:
- case stos:
- case atos:
- case itos: __ mr(R17_tos, R3_RET); break; // RET -> TOS cache
- case ftos:
- case dtos: __ fmr(F15_ftos, F1_RET); break; // TOS cache -> GR_FRET
- case vtos: break; // Nothing to do, this was a void return.
- default : ShouldNotReachHere();
- }
-
- __ restore_interpreter_state(R11_scratch1); // Sets R11_scratch1 = fp.
- __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1);
- __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0);
-
- // Compiled code destroys templateTableBase, reload.
- __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R12_scratch2);
-
- if (state == atos) {
- __ profile_return_type(R3_RET, R11_scratch1, R12_scratch2);
- }
-
- const Register cache = R11_scratch1;
- const Register size = R12_scratch2;
- __ get_cache_and_index_at_bcp(cache, 1, index_size);
-
- // Get least significant byte of 64 bit value:
-#if defined(VM_LITTLE_ENDIAN)
- __ lbz(size, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()), cache);
-#else
- __ lbz(size, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()) + 7, cache);
-#endif
- __ sldi(size, size, Interpreter::logStackElementSize);
- __ add(R15_esp, R15_esp, size);
- __ dispatch_next(state, step);
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) {
- address entry = __ pc();
- // If state != vtos, we're returning from a native method, which put it's result
- // into the result register. So move the value out of the return register back
- // to the TOS cache of current frame.
-
- switch (state) {
- case ltos:
- case btos:
- case ctos:
- case stos:
- case atos:
- case itos: __ mr(R17_tos, R3_RET); break; // GR_RET -> TOS cache
- case ftos:
- case dtos: __ fmr(F15_ftos, F1_RET); break; // TOS cache -> GR_FRET
- case vtos: break; // Nothing to do, this was a void return.
- default : ShouldNotReachHere();
- }
-
- // Load LcpoolCache @@@ should be already set!
- __ get_constant_pool_cache(R27_constPoolCache);
-
- // Handle a pending exception, fall through if none.
- __ check_and_forward_exception(R11_scratch1, R12_scratch2);
-
- // Start executing bytecodes.
- __ dispatch_next(state, step);
-
- return entry;
-}
-
-// A result handler converts the native result into java format.
-// Use the shared code between c++ and template interpreter.
-address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) {
- return AbstractInterpreterGenerator::generate_result_handler_for(type);
-}
-
-address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) {
- address entry = __ pc();
-
- __ push(state);
- __ call_VM(noreg, runtime_entry);
- __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos));
-
- return entry;
-}
-
-// Helpers for commoning out cases in the various type of method entries.
-
-// Increment invocation count & check for overflow.
-//
-// Note: checking for negative value instead of overflow
-// so we have a 'sticky' overflow test.
-//
-void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) {
- // Note: In tiered we increment either counters in method or in MDO depending if we're profiling or not.
- Register Rscratch1 = R11_scratch1;
- Register Rscratch2 = R12_scratch2;
- Register R3_counters = R3_ARG1;
- Label done;
-
- if (TieredCompilation) {
- const int increment = InvocationCounter::count_increment;
- const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift;
- Label no_mdo;
- if (ProfileInterpreter) {
- const Register Rmdo = Rscratch1;
- // If no method data exists, go to profile_continue.
- __ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method);
- __ cmpdi(CCR0, Rmdo, 0);
- __ beq(CCR0, no_mdo);
-
- // Increment backedge counter in the MDO.
- const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
- __ lwz(Rscratch2, mdo_bc_offs, Rmdo);
- __ addi(Rscratch2, Rscratch2, increment);
- __ stw(Rscratch2, mdo_bc_offs, Rmdo);
- __ load_const_optimized(Rscratch1, mask, R0);
- __ and_(Rscratch1, Rscratch2, Rscratch1);
- __ bne(CCR0, done);
- __ b(*overflow);
- }
-
- // Increment counter in MethodCounters*.
- const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
- __ bind(no_mdo);
- __ get_method_counters(R19_method, R3_counters, done);
- __ lwz(Rscratch2, mo_bc_offs, R3_counters);
- __ addi(Rscratch2, Rscratch2, increment);
- __ stw(Rscratch2, mo_bc_offs, R3_counters);
- __ load_const_optimized(Rscratch1, mask, R0);
- __ and_(Rscratch1, Rscratch2, Rscratch1);
- __ beq(CCR0, *overflow);
-
- __ bind(done);
-
- } else {
-
- // Update standard invocation counters.
- Register Rsum_ivc_bec = R4_ARG2;
- __ get_method_counters(R19_method, R3_counters, done);
- __ increment_invocation_counter(R3_counters, Rsum_ivc_bec, R12_scratch2);
- // Increment interpreter invocation counter.
- if (ProfileInterpreter) { // %%% Merge this into methodDataOop.
- __ lwz(R12_scratch2, in_bytes(MethodCounters::interpreter_invocation_counter_offset()), R3_counters);
- __ addi(R12_scratch2, R12_scratch2, 1);
- __ stw(R12_scratch2, in_bytes(MethodCounters::interpreter_invocation_counter_offset()), R3_counters);
- }
- // Check if we must create a method data obj.
- if (ProfileInterpreter && profile_method != NULL) {
- const Register profile_limit = Rscratch1;
- int pl_offs = __ load_const_optimized(profile_limit, &InvocationCounter::InterpreterProfileLimit, R0, true);
- __ lwz(profile_limit, pl_offs, profile_limit);
- // Test to see if we should create a method data oop.
- __ cmpw(CCR0, Rsum_ivc_bec, profile_limit);
- __ blt(CCR0, *profile_method_continue);
- // If no method data exists, go to profile_method.
- __ test_method_data_pointer(*profile_method);
- }
- // Finally check for counter overflow.
- if (overflow) {
- const Register invocation_limit = Rscratch1;
- int il_offs = __ load_const_optimized(invocation_limit, &InvocationCounter::InterpreterInvocationLimit, R0, true);
- __ lwz(invocation_limit, il_offs, invocation_limit);
- assert(4 == sizeof(InvocationCounter::InterpreterInvocationLimit), "unexpected field size");
- __ cmpw(CCR0, Rsum_ivc_bec, invocation_limit);
- __ bge(CCR0, *overflow);
- }
-
- __ bind(done);
- }
-}
-
-// Generate code to initiate compilation on invocation counter overflow.
-void TemplateInterpreterGenerator::generate_counter_overflow(Label& continue_entry) {
- // Generate code to initiate compilation on the counter overflow.
-
- // InterpreterRuntime::frequency_counter_overflow takes one arguments,
- // which indicates if the counter overflow occurs at a backwards branch (NULL bcp)
- // We pass zero in.
- // The call returns the address of the verified entry point for the method or NULL
- // if the compilation did not complete (either went background or bailed out).
- //
- // Unlike the C++ interpreter above: Check exceptions!
- // Assumption: Caller must set the flag "do_not_unlock_if_sychronized" if the monitor of a sync'ed
- // method has not yet been created. Thus, no unlocking of a non-existing monitor can occur.
-
- __ li(R4_ARG2, 0);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true);
-
- // Returns verified_entry_point or NULL.
- // We ignore it in any case.
- __ b(continue_entry);
-}
-
-void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rmem_frame_size, Register Rscratch1) {
- assert_different_registers(Rmem_frame_size, Rscratch1);
- __ generate_stack_overflow_check_with_compare_and_throw(Rmem_frame_size, Rscratch1);
-}
-
-void TemplateInterpreterGenerator::unlock_method(bool check_exceptions) {
- __ unlock_object(R26_monitor, check_exceptions);
-}
-
-// Lock the current method, interpreter register window must be set up!
-void TemplateInterpreterGenerator::lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded) {
- const Register Robj_to_lock = Rscratch2;
-
- {
- if (!flags_preloaded) {
- __ lwz(Rflags, method_(access_flags));
- }
-
-#ifdef ASSERT
- // Check if methods needs synchronization.
- {
- Label Lok;
- __ testbitdi(CCR0, R0, Rflags, JVM_ACC_SYNCHRONIZED_BIT);
- __ btrue(CCR0,Lok);
- __ stop("method doesn't need synchronization");
- __ bind(Lok);
- }
-#endif // ASSERT
- }
-
- // Get synchronization object to Rscratch2.
- {
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- Label Lstatic;
- Label Ldone;
-
- __ testbitdi(CCR0, R0, Rflags, JVM_ACC_STATIC_BIT);
- __ btrue(CCR0, Lstatic);
-
- // Non-static case: load receiver obj from stack and we're done.
- __ ld(Robj_to_lock, R18_locals);
- __ b(Ldone);
-
- __ bind(Lstatic); // Static case: Lock the java mirror
- __ ld(Robj_to_lock, in_bytes(Method::const_offset()), R19_method);
- __ ld(Robj_to_lock, in_bytes(ConstMethod::constants_offset()), Robj_to_lock);
- __ ld(Robj_to_lock, ConstantPool::pool_holder_offset_in_bytes(), Robj_to_lock);
- __ ld(Robj_to_lock, mirror_offset, Robj_to_lock);
-
- __ bind(Ldone);
- __ verify_oop(Robj_to_lock);
- }
-
- // Got the oop to lock => execute!
- __ add_monitor_to_stack(true, Rscratch1, R0);
-
- __ std(Robj_to_lock, BasicObjectLock::obj_offset_in_bytes(), R26_monitor);
- __ lock_object(R26_monitor, Robj_to_lock);
-}
-
-// Generate a fixed interpreter frame for pure interpreter
-// and I2N native transition frames.
-//
-// Before (stack grows downwards):
-//
-// | ... |
-// |------------- |
-// | java arg0 |
-// | ... |
-// | java argn |
-// | | <- R15_esp
-// | |
-// |--------------|
-// | abi_112 |
-// | | <- R1_SP
-// |==============|
-//
-//
-// After:
-//
-// | ... |
-// | java arg0 |<- R18_locals
-// | ... |
-// | java argn |
-// |--------------|
-// | |
-// | java locals |
-// | |
-// |--------------|
-// | abi_48 |
-// |==============|
-// | |
-// | istate |
-// | |
-// |--------------|
-// | monitor |<- R26_monitor
-// |--------------|
-// | |<- R15_esp
-// | expression |
-// | stack |
-// | |
-// |--------------|
-// | |
-// | abi_112 |<- R1_SP
-// |==============|
-//
-// The top most frame needs an abi space of 112 bytes. This space is needed,
-// since we call to c. The c function may spill their arguments to the caller
-// frame. When we call to java, we don't need these spill slots. In order to save
-// space on the stack, we resize the caller. However, java local reside in
-// the caller frame and the frame has to be increased. The frame_size for the
-// current frame was calculated based on max_stack as size for the expression
-// stack. At the call, just a part of the expression stack might be used.
-// We don't want to waste this space and cut the frame back accordingly.
-// The resulting amount for resizing is calculated as follows:
-// resize = (number_of_locals - number_of_arguments) * slot_size
-// + (R1_SP - R15_esp) + 48
-//
-// The size for the callee frame is calculated:
-// framesize = 112 + max_stack + monitor + state_size
-//
-// maxstack: Max number of slots on the expression stack, loaded from the method.
-// monitor: We statically reserve room for one monitor object.
-// state_size: We save the current state of the interpreter to this area.
-//
-void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call, Register Rsize_of_parameters, Register Rsize_of_locals) {
- Register parent_frame_resize = R6_ARG4, // Frame will grow by this number of bytes.
- top_frame_size = R7_ARG5,
- Rconst_method = R8_ARG6;
-
- assert_different_registers(Rsize_of_parameters, Rsize_of_locals, parent_frame_resize, top_frame_size);
-
- __ ld(Rconst_method, method_(const));
- __ lhz(Rsize_of_parameters /* number of params */,
- in_bytes(ConstMethod::size_of_parameters_offset()), Rconst_method);
- if (native_call) {
- // If we're calling a native method, we reserve space for the worst-case signature
- // handler varargs vector, which is max(Argument::n_register_parameters, parameter_count+2).
- // We add two slots to the parameter_count, one for the jni
- // environment and one for a possible native mirror.
- Label skip_native_calculate_max_stack;
- __ addi(top_frame_size, Rsize_of_parameters, 2);
- __ cmpwi(CCR0, top_frame_size, Argument::n_register_parameters);
- __ bge(CCR0, skip_native_calculate_max_stack);
- __ li(top_frame_size, Argument::n_register_parameters);
- __ bind(skip_native_calculate_max_stack);
- __ sldi(Rsize_of_parameters, Rsize_of_parameters, Interpreter::logStackElementSize);
- __ sldi(top_frame_size, top_frame_size, Interpreter::logStackElementSize);
- __ sub(parent_frame_resize, R1_SP, R15_esp); // <0, off by Interpreter::stackElementSize!
- assert(Rsize_of_locals == noreg, "Rsize_of_locals not initialized"); // Only relevant value is Rsize_of_parameters.
- } else {
- __ lhz(Rsize_of_locals /* number of params */, in_bytes(ConstMethod::size_of_locals_offset()), Rconst_method);
- __ sldi(Rsize_of_parameters, Rsize_of_parameters, Interpreter::logStackElementSize);
- __ sldi(Rsize_of_locals, Rsize_of_locals, Interpreter::logStackElementSize);
- __ lhz(top_frame_size, in_bytes(ConstMethod::max_stack_offset()), Rconst_method);
- __ sub(R11_scratch1, Rsize_of_locals, Rsize_of_parameters); // >=0
- __ sub(parent_frame_resize, R1_SP, R15_esp); // <0, off by Interpreter::stackElementSize!
- __ sldi(top_frame_size, top_frame_size, Interpreter::logStackElementSize);
- __ add(parent_frame_resize, parent_frame_resize, R11_scratch1);
- }
-
- // Compute top frame size.
- __ addi(top_frame_size, top_frame_size, frame::abi_reg_args_size + frame::ijava_state_size);
-
- // Cut back area between esp and max_stack.
- __ addi(parent_frame_resize, parent_frame_resize, frame::abi_minframe_size - Interpreter::stackElementSize);
-
- __ round_to(top_frame_size, frame::alignment_in_bytes);
- __ round_to(parent_frame_resize, frame::alignment_in_bytes);
- // parent_frame_resize = (locals-parameters) - (ESP-SP-ABI48) Rounded to frame alignment size.
- // Enlarge by locals-parameters (not in case of native_call), shrink by ESP-SP-ABI48.
-
- {
- // --------------------------------------------------------------------------
- // Stack overflow check
-
- Label cont;
- __ add(R11_scratch1, parent_frame_resize, top_frame_size);
- generate_stack_overflow_check(R11_scratch1, R12_scratch2);
- }
-
- // Set up interpreter state registers.
-
- __ add(R18_locals, R15_esp, Rsize_of_parameters);
- __ ld(R27_constPoolCache, in_bytes(ConstMethod::constants_offset()), Rconst_method);
- __ ld(R27_constPoolCache, ConstantPool::cache_offset_in_bytes(), R27_constPoolCache);
-
- // Set method data pointer.
- if (ProfileInterpreter) {
- Label zero_continue;
- __ ld(R28_mdx, method_(method_data));
- __ cmpdi(CCR0, R28_mdx, 0);
- __ beq(CCR0, zero_continue);
- __ addi(R28_mdx, R28_mdx, in_bytes(MethodData::data_offset()));
- __ bind(zero_continue);
- }
-
- if (native_call) {
- __ li(R14_bcp, 0); // Must initialize.
- } else {
- __ add(R14_bcp, in_bytes(ConstMethod::codes_offset()), Rconst_method);
- }
-
- // Resize parent frame.
- __ mflr(R12_scratch2);
- __ neg(parent_frame_resize, parent_frame_resize);
- __ resize_frame(parent_frame_resize, R11_scratch1);
- __ std(R12_scratch2, _abi(lr), R1_SP);
-
- __ addi(R26_monitor, R1_SP, - frame::ijava_state_size);
- __ addi(R15_esp, R26_monitor, - Interpreter::stackElementSize);
-
- // Store values.
- // R15_esp, R14_bcp, R26_monitor, R28_mdx are saved at java calls
- // in InterpreterMacroAssembler::call_from_interpreter.
- __ std(R19_method, _ijava_state_neg(method), R1_SP);
- __ std(R21_sender_SP, _ijava_state_neg(sender_sp), R1_SP);
- __ std(R27_constPoolCache, _ijava_state_neg(cpoolCache), R1_SP);
- __ std(R18_locals, _ijava_state_neg(locals), R1_SP);
-
- // Note: esp, bcp, monitor, mdx live in registers. Hence, the correct version can only
- // be found in the frame after save_interpreter_state is done. This is always true
- // for non-top frames. But when a signal occurs, dumping the top frame can go wrong,
- // because e.g. frame::interpreter_frame_bcp() will not access the correct value
- // (Enhanced Stack Trace).
- // The signal handler does not save the interpreter state into the frame.
- __ li(R0, 0);
-#ifdef ASSERT
- // Fill remaining slots with constants.
- __ load_const_optimized(R11_scratch1, 0x5afe);
- __ load_const_optimized(R12_scratch2, 0xdead);
-#endif
- // We have to initialize some frame slots for native calls (accessed by GC).
- if (native_call) {
- __ std(R26_monitor, _ijava_state_neg(monitors), R1_SP);
- __ std(R14_bcp, _ijava_state_neg(bcp), R1_SP);
- if (ProfileInterpreter) { __ std(R28_mdx, _ijava_state_neg(mdx), R1_SP); }
- }
-#ifdef ASSERT
- else {
- __ std(R12_scratch2, _ijava_state_neg(monitors), R1_SP);
- __ std(R12_scratch2, _ijava_state_neg(bcp), R1_SP);
- __ std(R12_scratch2, _ijava_state_neg(mdx), R1_SP);
- }
- __ std(R11_scratch1, _ijava_state_neg(ijava_reserved), R1_SP);
- __ std(R12_scratch2, _ijava_state_neg(esp), R1_SP);
- __ std(R12_scratch2, _ijava_state_neg(lresult), R1_SP);
- __ std(R12_scratch2, _ijava_state_neg(fresult), R1_SP);
-#endif
- __ subf(R12_scratch2, top_frame_size, R1_SP);
- __ std(R0, _ijava_state_neg(oop_tmp), R1_SP);
- __ std(R12_scratch2, _ijava_state_neg(top_frame_sp), R1_SP);
-
- // Push top frame.
- __ push_frame(top_frame_size, R11_scratch1);
-}
-
-// End of helpers
-
-
-// Support abs and sqrt like in compiler.
-// For others we can use a normal (native) entry.
-
-inline bool math_entry_available(AbstractInterpreter::MethodKind kind) {
- if (!InlineIntrinsics) return false;
-
- return ((kind==Interpreter::java_lang_math_sqrt && VM_Version::has_fsqrt()) ||
- (kind==Interpreter::java_lang_math_abs));
-}
-
-address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) {
- if (!math_entry_available(kind)) {
- NOT_PRODUCT(__ should_not_reach_here();)
- return NULL;
- }
-
- address entry = __ pc();
-
- __ lfd(F1_RET, Interpreter::stackElementSize, R15_esp);
-
- // Pop c2i arguments (if any) off when we return.
-#ifdef ASSERT
- __ ld(R9_ARG7, 0, R1_SP);
- __ ld(R10_ARG8, 0, R21_sender_SP);
- __ cmpd(CCR0, R9_ARG7, R10_ARG8);
- __ asm_assert_eq("backlink", 0x545);
-#endif // ASSERT
- __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
-
- if (kind == Interpreter::java_lang_math_sqrt) {
- __ fsqrt(F1_RET, F1_RET);
- } else if (kind == Interpreter::java_lang_math_abs) {
- __ fabs(F1_RET, F1_RET);
- } else {
- ShouldNotReachHere();
+int AbstractInterpreter::BasicType_as_index(BasicType type) {
+ int i = 0;
+ switch (type) {
+ case T_BOOLEAN: i = 0; break;
+ case T_CHAR : i = 1; break;
+ case T_BYTE : i = 2; break;
+ case T_SHORT : i = 3; break;
+ case T_INT : i = 4; break;
+ case T_LONG : i = 5; break;
+ case T_VOID : i = 6; break;
+ case T_FLOAT : i = 7; break;
+ case T_DOUBLE : i = 8; break;
+ case T_OBJECT : i = 9; break;
+ case T_ARRAY : i = 9; break;
+ default : ShouldNotReachHere();
}
-
- // And we're done.
- __ blr();
-
- __ flush();
-
- return entry;
-}
-
-// Interpreter stub for calling a native method. (asm interpreter)
-// This sets up a somewhat different looking stack for calling the
-// native method than the typical interpreter frame setup.
-//
-// On entry:
-// R19_method - method
-// R16_thread - JavaThread*
-// R15_esp - intptr_t* sender tos
-//
-// abstract stack (grows up)
-// [ IJava (caller of JNI callee) ] <-- ASP
-// ...
-address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
-
- address entry = __ pc();
-
- const bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // -----------------------------------------------------------------------------
- // Allocate a new frame that represents the native callee (i2n frame).
- // This is not a full-blown interpreter frame, but in particular, the
- // following registers are valid after this:
- // - R19_method
- // - R18_local (points to start of argumuments to native function)
- //
- // abstract stack (grows up)
- // [ IJava (caller of JNI callee) ] <-- ASP
- // ...
-
- const Register signature_handler_fd = R11_scratch1;
- const Register pending_exception = R0;
- const Register result_handler_addr = R31;
- const Register native_method_fd = R11_scratch1;
- const Register access_flags = R22_tmp2;
- const Register active_handles = R11_scratch1; // R26_monitor saved to state.
- const Register sync_state = R12_scratch2;
- const Register sync_state_addr = sync_state; // Address is dead after use.
- const Register suspend_flags = R11_scratch1;
-
- //=============================================================================
- // Allocate new frame and initialize interpreter state.
-
- Label exception_return;
- Label exception_return_sync_check;
- Label stack_overflow_return;
-
- // Generate new interpreter state and jump to stack_overflow_return in case of
- // a stack overflow.
- //generate_compute_interpreter_state(stack_overflow_return);
-
- Register size_of_parameters = R22_tmp2;
-
- generate_fixed_frame(true, size_of_parameters, noreg /* unused */);
-
- //=============================================================================
- // Increment invocation counter. On overflow, entry to JNI method
- // will be compiled.
- Label invocation_counter_overflow, continue_after_compile;
- if (inc_counter) {
- if (synchronized) {
- // Since at this point in the method invocation the exception handler
- // would try to exit the monitor of synchronized methods which hasn't
- // been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. If any exception was thrown by
- // runtime, exception handling i.e. unlock_if_synchronized_method will
- // check this thread local flag.
- // This flag has two effects, one is to force an unwind in the topmost
- // interpreter frame and not perform an unlock while doing so.
- __ li(R0, 1);
- __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
- }
- generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
-
- BIND(continue_after_compile);
- // Reset the _do_not_unlock_if_synchronized flag.
- if (synchronized) {
- __ li(R0, 0);
- __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
- }
- }
-
- // access_flags = method->access_flags();
- // Load access flags.
- assert(access_flags->is_nonvolatile(),
- "access_flags must be in a non-volatile register");
- // Type check.
- assert(4 == sizeof(AccessFlags), "unexpected field size");
- __ lwz(access_flags, method_(access_flags));
-
- // We don't want to reload R19_method and access_flags after calls
- // to some helper functions.
- assert(R19_method->is_nonvolatile(),
- "R19_method must be a non-volatile register");
-
- // Check for synchronized methods. Must happen AFTER invocation counter
- // check, so method is not locked if counter overflows.
-
- if (synchronized) {
- lock_method(access_flags, R11_scratch1, R12_scratch2, true);
-
- // Update monitor in state.
- __ ld(R11_scratch1, 0, R1_SP);
- __ std(R26_monitor, _ijava_state_neg(monitors), R11_scratch1);
- }
-
- // jvmti/jvmpi support
- __ notify_method_entry();
-
- //=============================================================================
- // Get and call the signature handler.
-
- __ ld(signature_handler_fd, method_(signature_handler));
- Label call_signature_handler;
-
- __ cmpdi(CCR0, signature_handler_fd, 0);
- __ bne(CCR0, call_signature_handler);
-
- // Method has never been called. Either generate a specialized
- // handler or point to the slow one.
- //
- // Pass parameter 'false' to avoid exception check in call_VM.
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), R19_method, false);
-
- // Check for an exception while looking up the target method. If we
- // incurred one, bail.
- __ ld(pending_exception, thread_(pending_exception));
- __ cmpdi(CCR0, pending_exception, 0);
- __ bne(CCR0, exception_return_sync_check); // Has pending exception.
-
- // Reload signature handler, it may have been created/assigned in the meanwhile.
- __ ld(signature_handler_fd, method_(signature_handler));
- __ twi_0(signature_handler_fd); // Order wrt. load of klass mirror and entry point (isync is below).
-
- BIND(call_signature_handler);
-
- // Before we call the signature handler we push a new frame to
- // protect the interpreter frame volatile registers when we return
- // from jni but before we can get back to Java.
-
- // First set the frame anchor while the SP/FP registers are
- // convenient and the slow signature handler can use this same frame
- // anchor.
-
- // We have a TOP_IJAVA_FRAME here, which belongs to us.
- __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R12_scratch2/*tmp*/);
-
- // Now the interpreter frame (and its call chain) have been
- // invalidated and flushed. We are now protected against eager
- // being enabled in native code. Even if it goes eager the
- // registers will be reloaded as clean and we will invalidate after
- // the call so no spurious flush should be possible.
-
- // Call signature handler and pass locals address.
- //
- // Our signature handlers copy required arguments to the C stack
- // (outgoing C args), R3_ARG1 to R10_ARG8, and FARG1 to FARG13.
- __ mr(R3_ARG1, R18_locals);
-#if !defined(ABI_ELFv2)
- __ ld(signature_handler_fd, 0, signature_handler_fd);
-#endif
-
- __ call_stub(signature_handler_fd);
-
- // Remove the register parameter varargs slots we allocated in
- // compute_interpreter_state. SP+16 ends up pointing to the ABI
- // outgoing argument area.
- //
- // Not needed on PPC64.
- //__ add(SP, SP, Argument::n_register_parameters*BytesPerWord);
-
- assert(result_handler_addr->is_nonvolatile(), "result_handler_addr must be in a non-volatile register");
- // Save across call to native method.
- __ mr(result_handler_addr, R3_RET);
-
- __ isync(); // Acquire signature handler before trying to fetch the native entry point and klass mirror.
-
- // Set up fixed parameters and call the native method.
- // If the method is static, get mirror into R4_ARG2.
- {
- Label method_is_not_static;
- // Access_flags is non-volatile and still, no need to restore it.
-
- // Restore access flags.
- __ testbitdi(CCR0, R0, access_flags, JVM_ACC_STATIC_BIT);
- __ bfalse(CCR0, method_is_not_static);
-
- // constants = method->constants();
- __ ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method);
- __ ld(R11_scratch1, in_bytes(ConstMethod::constants_offset()), R11_scratch1);
- // pool_holder = method->constants()->pool_holder();
- __ ld(R11_scratch1/*pool_holder*/, ConstantPool::pool_holder_offset_in_bytes(),
- R11_scratch1/*constants*/);
-
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
-
- // mirror = pool_holder->klass_part()->java_mirror();
- __ ld(R0/*mirror*/, mirror_offset, R11_scratch1/*pool_holder*/);
- // state->_native_mirror = mirror;
-
- __ ld(R11_scratch1, 0, R1_SP);
- __ std(R0/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1);
- // R4_ARG2 = &state->_oop_temp;
- __ addi(R4_ARG2, R11_scratch1, _ijava_state_neg(oop_tmp));
- BIND(method_is_not_static);
- }
-
- // At this point, arguments have been copied off the stack into
- // their JNI positions. Oops are boxed in-place on the stack, with
- // handles copied to arguments. The result handler address is in a
- // register.
-
- // Pass JNIEnv address as first parameter.
- __ addir(R3_ARG1, thread_(jni_environment));
-
- // Load the native_method entry before we change the thread state.
- __ ld(native_method_fd, method_(native_function));
-
- //=============================================================================
- // Transition from _thread_in_Java to _thread_in_native. As soon as
- // we make this change the safepoint code needs to be certain that
- // the last Java frame we established is good. The pc in that frame
- // just needs to be near here not an actual return address.
-
- // We use release_store_fence to update values like the thread state, where
- // we don't want the current thread to continue until all our prior memory
- // accesses (including the new thread state) are visible to other threads.
- __ li(R0, _thread_in_native);
- __ release();
-
- // TODO PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size");
- __ stw(R0, thread_(thread_state));
-
- if (UseMembar) {
- __ fence();
- }
-
- //=============================================================================
- // Call the native method. Argument registers must not have been
- // overwritten since "__ call_stub(signature_handler);" (except for
- // ARG1 and ARG2 for static methods).
- __ call_c(native_method_fd);
-
- __ li(R0, 0);
- __ ld(R11_scratch1, 0, R1_SP);
- __ std(R3_RET, _ijava_state_neg(lresult), R11_scratch1);
- __ stfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1);
- __ std(R0/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1); // reset
-
- // Note: C++ interpreter needs the following here:
- // The frame_manager_lr field, which we use for setting the last
- // java frame, gets overwritten by the signature handler. Restore
- // it now.
- //__ get_PC_trash_LR(R11_scratch1);
- //__ std(R11_scratch1, _top_ijava_frame_abi(frame_manager_lr), R1_SP);
-
- // Because of GC R19_method may no longer be valid.
-
- // Block, if necessary, before resuming in _thread_in_Java state.
- // In order for GC to work, don't clear the last_Java_sp until after
- // blocking.
-
- //=============================================================================
- // Switch thread to "native transition" state before reading the
- // synchronization state. This additional state is necessary
- // because reading and testing the synchronization state is not
- // atomic w.r.t. GC, as this scenario demonstrates: Java thread A,
- // in _thread_in_native state, loads _not_synchronized and is
- // preempted. VM thread changes sync state to synchronizing and
- // suspends threads for GC. Thread A is resumed to finish this
- // native method, but doesn't block here since it didn't see any
- // synchronization in progress, and escapes.
-
- // We use release_store_fence to update values like the thread state, where
- // we don't want the current thread to continue until all our prior memory
- // accesses (including the new thread state) are visible to other threads.
- __ li(R0/*thread_state*/, _thread_in_native_trans);
- __ release();
- __ stw(R0/*thread_state*/, thread_(thread_state));
- if (UseMembar) {
- __ fence();
- }
- // Write serialization page so that the 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 due to cache line collision.
- else {
- __ serialize_memory(R16_thread, R11_scratch1, R12_scratch2);
- }
-
- // Now before we return to java we must look for a current safepoint
- // (a new safepoint can not start since we entered native_trans).
- // We must check here because a current safepoint could be modifying
- // the callers registers right this moment.
-
- // Acquire isn't strictly necessary here because of the fence, but
- // sync_state is declared to be volatile, so we do it anyway
- // (cmp-br-isync on one path, release (same as acquire on PPC64) on the other path).
- int sync_state_offs = __ load_const_optimized(sync_state_addr, SafepointSynchronize::address_of_state(), /*temp*/R0, true);
-
- // TODO PPC port assert(4 == SafepointSynchronize::sz_state(), "unexpected field size");
- __ lwz(sync_state, sync_state_offs, sync_state_addr);
-
- // TODO PPC port assert(4 == Thread::sz_suspend_flags(), "unexpected field size");
- __ lwz(suspend_flags, thread_(suspend_flags));
-
- Label sync_check_done;
- Label do_safepoint;
- // No synchronization in progress nor yet synchronized.
- __ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized);
- // Not suspended.
- __ cmpwi(CCR1, suspend_flags, 0);
-
- __ bne(CCR0, do_safepoint);
- __ beq(CCR1, sync_check_done);
- __ bind(do_safepoint);
- __ isync();
- // Block. We do the call directly and leave the current
- // last_Java_frame setup undisturbed. We must save any possible
- // native result across the call. No oop is present.
-
- __ mr(R3_ARG1, R16_thread);
-#if defined(ABI_ELFv2)
- __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
- relocInfo::none);
-#else
- __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans),
- relocInfo::none);
-#endif
-
- __ bind(sync_check_done);
-
- //=============================================================================
- // <<<<<< Back in Interpreter Frame >>>>>
-
- // We are in thread_in_native_trans here and back in the normal
- // interpreter frame. We don't have to do anything special about
- // safepoints and we can switch to Java mode anytime we are ready.
-
- // Note: frame::interpreter_frame_result has a dependency on how the
- // method result is saved across the call to post_method_exit. For
- // native methods it assumes that the non-FPU/non-void result is
- // saved in _native_lresult and a FPU result in _native_fresult. If
- // this changes then the interpreter_frame_result implementation
- // will need to be updated too.
-
- // On PPC64, we have stored the result directly after the native call.
-
- //=============================================================================
- // Back in Java
-
- // We use release_store_fence to update values like the thread state, where
- // we don't want the current thread to continue until all our prior memory
- // accesses (including the new thread state) are visible to other threads.
- __ li(R0/*thread_state*/, _thread_in_Java);
- __ release();
- __ stw(R0/*thread_state*/, thread_(thread_state));
- if (UseMembar) {
- __ fence();
- }
-
- __ reset_last_Java_frame();
-
- // Jvmdi/jvmpi support. Whether we've got an exception pending or
- // not, and whether unlocking throws an exception or not, we notify
- // on native method exit. If we do have an exception, we'll end up
- // in the caller's context to handle it, so if we don't do the
- // notify here, we'll drop it on the floor.
- __ notify_method_exit(true/*native method*/,
- ilgl /*illegal state (not used for native methods)*/,
- InterpreterMacroAssembler::NotifyJVMTI,
- false /*check_exceptions*/);
-
- //=============================================================================
- // Handle exceptions
-
- if (synchronized) {
- // Don't check for exceptions since we're still in the i2n frame. Do that
- // manually afterwards.
- unlock_method(false);
- }
-
- // Reset active handles after returning from native.
- // thread->active_handles()->clear();
- __ ld(active_handles, thread_(active_handles));
- // TODO PPC port assert(4 == JNIHandleBlock::top_size_in_bytes(), "unexpected field size");
- __ li(R0, 0);
- __ stw(R0, JNIHandleBlock::top_offset_in_bytes(), active_handles);
-
- Label exception_return_sync_check_already_unlocked;
- __ ld(R0/*pending_exception*/, thread_(pending_exception));
- __ cmpdi(CCR0, R0/*pending_exception*/, 0);
- __ bne(CCR0, exception_return_sync_check_already_unlocked);
-
- //-----------------------------------------------------------------------------
- // No exception pending.
-
- // Move native method result back into proper registers and return.
- // Invoke result handler (may unbox/promote).
- __ ld(R11_scratch1, 0, R1_SP);
- __ ld(R3_RET, _ijava_state_neg(lresult), R11_scratch1);
- __ lfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1);
- __ call_stub(result_handler_addr);
-
- __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2);
-
- // Must use the return pc which was loaded from the caller's frame
- // as the VM uses return-pc-patching for deoptimization.
- __ mtlr(R0);
- __ blr();
-
- //-----------------------------------------------------------------------------
- // An exception is pending. We call into the runtime only if the
- // caller was not interpreted. If it was interpreted the
- // interpreter will do the correct thing. If it isn't interpreted
- // (call stub/compiled code) we will change our return and continue.
-
- BIND(exception_return_sync_check);
-
- if (synchronized) {
- // Don't check for exceptions since we're still in the i2n frame. Do that
- // manually afterwards.
- unlock_method(false);
- }
- BIND(exception_return_sync_check_already_unlocked);
-
- const Register return_pc = R31;
-
- __ ld(return_pc, 0, R1_SP);
- __ ld(return_pc, _abi(lr), return_pc);
-
- // Get the address of the exception handler.
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
- R16_thread,
- return_pc /* return pc */);
- __ merge_frames(/*top_frame_sp*/ R21_sender_SP, noreg, R11_scratch1, R12_scratch2);
-
- // Load the PC of the the exception handler into LR.
- __ mtlr(R3_RET);
-
- // Load exception into R3_ARG1 and clear pending exception in thread.
- __ ld(R3_ARG1/*exception*/, thread_(pending_exception));
- __ li(R4_ARG2, 0);
- __ std(R4_ARG2, thread_(pending_exception));
-
- // Load the original return pc into R4_ARG2.
- __ mr(R4_ARG2/*issuing_pc*/, return_pc);
-
- // Return to exception handler.
- __ blr();
-
- //=============================================================================
- // Counter overflow.
-
- if (inc_counter) {
- // Handle invocation counter overflow.
- __ bind(invocation_counter_overflow);
-
- generate_counter_overflow(continue_after_compile);
- }
-
- return entry;
-}
-
-// Generic interpreted method entry to (asm) interpreter.
-//
-address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
- address entry = __ pc();
- // Generate the code to allocate the interpreter stack frame.
- Register Rsize_of_parameters = R4_ARG2, // Written by generate_fixed_frame.
- Rsize_of_locals = R5_ARG3; // Written by generate_fixed_frame.
-
- generate_fixed_frame(false, Rsize_of_parameters, Rsize_of_locals);
-
- // --------------------------------------------------------------------------
- // Zero out non-parameter locals.
- // Note: *Always* zero out non-parameter locals as Sparc does. It's not
- // worth to ask the flag, just do it.
- Register Rslot_addr = R6_ARG4,
- Rnum = R7_ARG5;
- Label Lno_locals, Lzero_loop;
-
- // Set up the zeroing loop.
- __ subf(Rnum, Rsize_of_parameters, Rsize_of_locals);
- __ subf(Rslot_addr, Rsize_of_parameters, R18_locals);
- __ srdi_(Rnum, Rnum, Interpreter::logStackElementSize);
- __ beq(CCR0, Lno_locals);
- __ li(R0, 0);
- __ mtctr(Rnum);
-
- // The zero locals loop.
- __ bind(Lzero_loop);
- __ std(R0, 0, Rslot_addr);
- __ addi(Rslot_addr, Rslot_addr, -Interpreter::stackElementSize);
- __ bdnz(Lzero_loop);
-
- __ bind(Lno_locals);
-
- // --------------------------------------------------------------------------
- // Counter increment and overflow check.
- Label invocation_counter_overflow,
- profile_method,
- profile_method_continue;
- if (inc_counter || ProfileInterpreter) {
-
- Register Rdo_not_unlock_if_synchronized_addr = R11_scratch1;
- if (synchronized) {
- // Since at this point in the method invocation the exception handler
- // would try to exit the monitor of synchronized methods which hasn't
- // been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. If any exception was thrown by
- // runtime, exception handling i.e. unlock_if_synchronized_method will
- // check this thread local flag.
- // This flag has two effects, one is to force an unwind in the topmost
- // interpreter frame and not perform an unlock while doing so.
- __ li(R0, 1);
- __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
- }
-
- // Argument and return type profiling.
- __ profile_parameters_type(R3_ARG1, R4_ARG2, R5_ARG3, R6_ARG4);
-
- // Increment invocation counter and check for overflow.
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue);
- }
-
- __ bind(profile_method_continue);
-
- // Reset the _do_not_unlock_if_synchronized flag.
- if (synchronized) {
- __ li(R0, 0);
- __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
- }
- }
-
- // --------------------------------------------------------------------------
- // Locking of synchronized methods. Must happen AFTER invocation_counter
- // check and stack overflow check, so method is not locked if overflows.
- if (synchronized) {
- lock_method(R3_ARG1, R4_ARG2, R5_ARG3);
- }
-#ifdef ASSERT
- else {
- Label Lok;
- __ lwz(R0, in_bytes(Method::access_flags_offset()), R19_method);
- __ andi_(R0, R0, JVM_ACC_SYNCHRONIZED);
- __ asm_assert_eq("method needs synchronization", 0x8521);
- __ bind(Lok);
- }
-#endif // ASSERT
-
- __ verify_thread();
-
- // --------------------------------------------------------------------------
- // JVMTI support
- __ notify_method_entry();
-
- // --------------------------------------------------------------------------
- // Start executing instructions.
- __ dispatch_next(vtos);
-
- // --------------------------------------------------------------------------
- // Out of line counter overflow and MDO creation code.
- if (ProfileInterpreter) {
- // We have decided to profile this method in the interpreter.
- __ bind(profile_method);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
- __ set_method_data_pointer_for_bcp();
- __ b(profile_method_continue);
- }
-
- if (inc_counter) {
- // Handle invocation counter overflow.
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(profile_method_continue);
- }
- return entry;
-}
-
-// CRC32 Intrinsics.
-//
-// Contract on scratch and work registers.
-// =======================================
-//
-// On ppc, the register set {R2..R12} is available in the interpreter as scratch/work registers.
-// You should, however, keep in mind that {R3_ARG1..R10_ARG8} is the C-ABI argument register set.
-// You can't rely on these registers across calls.
-//
-// The generators for CRC32_update and for CRC32_updateBytes use the
-// scratch/work register set internally, passing the work registers
-// as arguments to the MacroAssembler emitters as required.
-//
-// R3_ARG1..R6_ARG4 are preset to hold the incoming java arguments.
-// Their contents is not constant but may change according to the requirements
-// of the emitted code.
-//
-// All other registers from the scratch/work register set are used "internally"
-// and contain garbage (i.e. unpredictable values) once blr() is reached.
-// Basically, only R3_RET contains a defined value which is the function result.
-//
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.update(int crc, int b)
- */
-address InterpreterGenerator::generate_CRC32_update_entry() {
- if (UseCRC32Intrinsics) {
- address start = __ pc(); // Remember stub start address (is rtn value).
- Label slow_path;
-
- // Safepoint check
- const Register sync_state = R11_scratch1;
- int sync_state_offs = __ load_const_optimized(sync_state, SafepointSynchronize::address_of_state(), /*temp*/R0, true);
- __ lwz(sync_state, sync_state_offs, sync_state);
- __ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized);
- __ bne(CCR0, slow_path);
-
- // We don't generate local frame and don't align stack because
- // we not even call stub code (we generate the code inline)
- // and there is no safepoint on this path.
-
- // Load java parameters.
- // R15_esp is callers operand stack pointer, i.e. it points to the parameters.
- const Register argP = R15_esp;
- const Register crc = R3_ARG1; // crc value
- const Register data = R4_ARG2; // address of java byte value (kernel_crc32 needs address)
- const Register dataLen = R5_ARG3; // source data len (1 byte). Not used because calling the single-byte emitter.
- const Register table = R6_ARG4; // address of crc32 table
- const Register tmp = dataLen; // Reuse unused len register to show we don't actually need a separate tmp here.
-
- BLOCK_COMMENT("CRC32_update {");
-
- // Arguments are reversed on java expression stack
-#ifdef VM_LITTLE_ENDIAN
- __ addi(data, argP, 0+1*wordSize); // (stack) address of byte value. Emitter expects address, not value.
- // Being passed as an int, the single byte is at offset +0.
-#else
- __ addi(data, argP, 3+1*wordSize); // (stack) address of byte value. Emitter expects address, not value.
- // Being passed from java as an int, the single byte is at offset +3.
-#endif
- __ lwz(crc, 2*wordSize, argP); // Current crc state, zero extend to 64 bit to have a clean register.
-
- StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
- __ kernel_crc32_singleByte(crc, data, dataLen, table, tmp);
-
- // Restore caller sp for c2i case and return.
- __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
- __ blr();
-
- // 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;
- }
-
- return NULL;
-}
-
-// CRC32 Intrinsics.
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.updateBytes( int crc, byte[] b, int off, int len)
- * int java.util.zip.CRC32.updateByteBuffer(int crc, long* buf, int off, int len)
- */
-address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
- if (UseCRC32Intrinsics) {
- address start = __ pc(); // Remember stub start address (is rtn value).
- Label slow_path;
-
- // Safepoint check
- const Register sync_state = R11_scratch1;
- int sync_state_offs = __ load_const_optimized(sync_state, SafepointSynchronize::address_of_state(), /*temp*/R0, true);
- __ lwz(sync_state, sync_state_offs, sync_state);
- __ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized);
- __ bne(CCR0, slow_path);
-
- // We don't generate local frame and don't align stack because
- // we not even call stub code (we generate the code inline)
- // and there is no safepoint on this path.
-
- // Load parameters.
- // Z_esp is callers operand stack pointer, i.e. it points to the parameters.
- const Register argP = R15_esp;
- const Register crc = R3_ARG1; // crc value
- const Register data = R4_ARG2; // address of java byte array
- const Register dataLen = R5_ARG3; // source data len
- const Register table = R6_ARG4; // address of crc32 table
-
- const Register t0 = R9; // scratch registers for crc calculation
- const Register t1 = R10;
- const Register t2 = R11;
- const Register t3 = R12;
-
- const Register tc0 = R2; // registers to hold pre-calculated column addresses
- const Register tc1 = R7;
- const Register tc2 = R8;
- const Register tc3 = table; // table address is reconstructed at the end of kernel_crc32_* emitters
-
- const Register tmp = t0; // Only used very locally to calculate byte buffer address.
-
- // Arguments are reversed on java expression stack.
- // Calculate address of start element.
- if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) { // Used for "updateByteBuffer direct".
- BLOCK_COMMENT("CRC32_updateByteBuffer {");
- // crc @ (SP + 5W) (32bit)
- // buf @ (SP + 3W) (64bit ptr to long array)
- // off @ (SP + 2W) (32bit)
- // dataLen @ (SP + 1W) (32bit)
- // data = buf + off
- __ ld( data, 3*wordSize, argP); // start of byte buffer
- __ lwa( tmp, 2*wordSize, argP); // byte buffer offset
- __ lwa( dataLen, 1*wordSize, argP); // #bytes to process
- __ lwz( crc, 5*wordSize, argP); // current crc state
- __ add( data, data, tmp); // Add byte buffer offset.
- } else { // Used for "updateBytes update".
- BLOCK_COMMENT("CRC32_updateBytes {");
- // crc @ (SP + 4W) (32bit)
- // buf @ (SP + 3W) (64bit ptr to byte array)
- // off @ (SP + 2W) (32bit)
- // dataLen @ (SP + 1W) (32bit)
- // data = buf + off + base_offset
- __ ld( data, 3*wordSize, argP); // start of byte buffer
- __ lwa( tmp, 2*wordSize, argP); // byte buffer offset
- __ lwa( dataLen, 1*wordSize, argP); // #bytes to process
- __ add( data, data, tmp); // add byte buffer offset
- __ lwz( crc, 4*wordSize, argP); // current crc state
- __ addi(data, data, arrayOopDesc::base_offset_in_bytes(T_BYTE));
- }
-
- StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
-
- // Performance measurements show the 1word and 2word variants to be almost equivalent,
- // with very light advantages for the 1word variant. We chose the 1word variant for
- // code compactness.
- __ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, tc3);
-
- // Restore caller sp for c2i case and return.
- __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
- __ blr();
-
- // 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;
- }
-
- return NULL;
+ assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds");
+ return i;
}
// These should never be compiled since the interpreter will prefer
// the compiled version to the intrinsic version.
bool AbstractInterpreter::can_be_compiled(methodHandle m) {
- return !math_entry_available(method_kind(m));
+ return !TemplateInterpreter::math_entry_available(method_kind(m));
}
// How much stack a method activation needs in stack slots.
@@ -1505,411 +154,14 @@
}
}
-// =============================================================================
-// Exceptions
-
-void TemplateInterpreterGenerator::generate_throw_exception() {
- Register Rexception = R17_tos,
- Rcontinuation = R3_RET;
-
- // --------------------------------------------------------------------------
- // Entry point if an method returns with a pending exception (rethrow).
- Interpreter::_rethrow_exception_entry = __ pc();
- {
- __ restore_interpreter_state(R11_scratch1); // Sets R11_scratch1 = fp.
- __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1);
- __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0);
-
- // Compiled code destroys templateTableBase, reload.
- __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1);
- }
-
- // Entry point if a interpreted method throws an exception (throw).
- Interpreter::_throw_exception_entry = __ pc();
- {
- __ mr(Rexception, R3_RET);
-
- __ verify_thread();
- __ verify_oop(Rexception);
-
- // Expression stack must be empty before entering the VM in case of an exception.
- __ empty_expression_stack();
- // Find exception handler address and preserve exception oop.
- // Call C routine to find handler and jump to it.
- __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), Rexception);
- __ mtctr(Rcontinuation);
- // Push exception for exception handler bytecodes.
- __ push_ptr(Rexception);
-
- // Jump to exception handler (may be remove activation entry!).
- __ bctr();
- }
-
- // If the exception is not handled in the current frame the frame is
- // removed and the exception is rethrown (i.e. exception
- // continuation is _rethrow_exception).
- //
- // Note: At this point the bci is still the bxi for the instruction
- // which caused the exception and the expression stack is
- // empty. Thus, for any VM calls at this point, GC will find a legal
- // oop map (with empty expression stack).
-
- // In current activation
- // tos: exception
- // bcp: exception bcp
-
- // --------------------------------------------------------------------------
- // JVMTI PopFrame support
-
- Interpreter::_remove_activation_preserving_args_entry = __ pc();
- {
- // Set the popframe_processing bit in popframe_condition indicating that we are
- // currently handling popframe, so that call_VMs that may happen later do not
- // trigger new popframe handling cycles.
- __ lwz(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
- __ ori(R11_scratch1, R11_scratch1, JavaThread::popframe_processing_bit);
- __ stw(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
-
- // Empty the expression stack, as in normal exception handling.
- __ empty_expression_stack();
- __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, /* install_monitor_exception */ false);
-
- // Check to see whether we are returning to a deoptimized frame.
- // (The PopFrame call ensures that the caller of the popped frame is
- // either interpreted or compiled and deoptimizes it if compiled.)
- // Note that we don't compare the return PC against the
- // deoptimization blob's unpack entry because of the presence of
- // adapter frames in C2.
- Label Lcaller_not_deoptimized;
- Register return_pc = R3_ARG1;
- __ ld(return_pc, 0, R1_SP);
- __ ld(return_pc, _abi(lr), return_pc);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), return_pc);
- __ cmpdi(CCR0, R3_RET, 0);
- __ bne(CCR0, Lcaller_not_deoptimized);
+// Support abs and sqrt like in compiler.
+// For others we can use a normal (native) entry.
- // The deoptimized case.
- // In this case, we can't call dispatch_next() after the frame is
- // popped, but instead must save the incoming arguments and restore
- // them after deoptimization has occurred.
- __ ld(R4_ARG2, in_bytes(Method::const_offset()), R19_method);
- __ lhz(R4_ARG2 /* number of params */, in_bytes(ConstMethod::size_of_parameters_offset()), R4_ARG2);
- __ slwi(R4_ARG2, R4_ARG2, Interpreter::logStackElementSize);
- __ addi(R5_ARG3, R18_locals, Interpreter::stackElementSize);
- __ subf(R5_ARG3, R4_ARG2, R5_ARG3);
- // Save these arguments.
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), R16_thread, R4_ARG2, R5_ARG3);
-
- // Inform deoptimization that it is responsible for restoring these arguments.
- __ load_const_optimized(R11_scratch1, JavaThread::popframe_force_deopt_reexecution_bit);
- __ stw(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
-
- // Return from the current method into the deoptimization blob. Will eventually
- // end up in the deopt interpeter entry, deoptimization prepared everything that
- // we will reexecute the call that called us.
- __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*reload return_pc*/ return_pc, R11_scratch1, R12_scratch2);
- __ mtlr(return_pc);
- __ blr();
-
- // The non-deoptimized case.
- __ bind(Lcaller_not_deoptimized);
-
- // Clear the popframe condition flag.
- __ li(R0, 0);
- __ stw(R0, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
-
- // Get out of the current method and re-execute the call that called us.
- __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ noreg, R11_scratch1, R12_scratch2);
- __ restore_interpreter_state(R11_scratch1);
- __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1);
- __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0);
- if (ProfileInterpreter) {
- __ set_method_data_pointer_for_bcp();
- __ ld(R11_scratch1, 0, R1_SP);
- __ std(R28_mdx, _ijava_state_neg(mdx), R11_scratch1);
- }
-#if INCLUDE_JVMTI
- Label L_done;
-
- __ lbz(R11_scratch1, 0, R14_bcp);
- __ cmpwi(CCR0, R11_scratch1, Bytecodes::_invokestatic);
- __ bne(CCR0, L_done);
+bool TemplateInterpreter::math_entry_available(AbstractInterpreter::MethodKind kind) {
+ if (!InlineIntrinsics) return false;
- // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
- // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
- __ ld(R4_ARG2, 0, R18_locals);
- __ MacroAssembler::call_VM(R4_ARG2, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), R4_ARG2, R19_method, R14_bcp, false);
- __ restore_interpreter_state(R11_scratch1, /*bcp_and_mdx_only*/ true);
- __ cmpdi(CCR0, R4_ARG2, 0);
- __ beq(CCR0, L_done);
- __ std(R4_ARG2, wordSize, R15_esp);
- __ bind(L_done);
-#endif // INCLUDE_JVMTI
- __ dispatch_next(vtos);
- }
- // end of JVMTI PopFrame support
-
- // --------------------------------------------------------------------------
- // Remove activation exception entry.
- // This is jumped to if an interpreted method can't handle an exception itself
- // (we come from the throw/rethrow exception entry above). We're going to call
- // into the VM to find the exception handler in the caller, pop the current
- // frame and return the handler we calculated.
- Interpreter::_remove_activation_entry = __ pc();
- {
- __ pop_ptr(Rexception);
- __ verify_thread();
- __ verify_oop(Rexception);
- __ std(Rexception, in_bytes(JavaThread::vm_result_offset()), R16_thread);
-
- __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, true);
- __ notify_method_exit(false, vtos, InterpreterMacroAssembler::SkipNotifyJVMTI, false);
-
- __ get_vm_result(Rexception);
-
- // We are done with this activation frame; find out where to go next.
- // The continuation point will be an exception handler, which expects
- // the following registers set up:
- //
- // RET: exception oop
- // ARG2: Issuing PC (see generate_exception_blob()), only used if the caller is compiled.
-
- Register return_pc = R31; // Needs to survive the runtime call.
- __ ld(return_pc, 0, R1_SP);
- __ ld(return_pc, _abi(lr), return_pc);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, return_pc);
-
- // Remove the current activation.
- __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ noreg, R11_scratch1, R12_scratch2);
-
- __ mr(R4_ARG2, return_pc);
- __ mtlr(R3_RET);
- __ mr(R3_RET, Rexception);
- __ blr();
- }
+ return ((kind==Interpreter::java_lang_math_sqrt && VM_Version::has_fsqrt()) ||
+ (kind==Interpreter::java_lang_math_abs));
}
-// JVMTI ForceEarlyReturn support.
-// Returns "in the middle" of a method with a "fake" return value.
-address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
- Register Rscratch1 = R11_scratch1,
- Rscratch2 = R12_scratch2;
-
- address entry = __ pc();
- __ empty_expression_stack();
-
- __ load_earlyret_value(state, Rscratch1);
-
- __ ld(Rscratch1, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread);
- // Clear the earlyret state.
- __ li(R0, 0);
- __ stw(R0, in_bytes(JvmtiThreadState::earlyret_state_offset()), Rscratch1);
-
- __ remove_activation(state, false, false);
- // Copied from TemplateTable::_return.
- // Restoration of lr done by remove_activation.
- switch (state) {
- case ltos:
- case btos:
- case ctos:
- case stos:
- case atos:
- case itos: __ mr(R3_RET, R17_tos); break;
- case ftos:
- case dtos: __ fmr(F1_RET, F15_ftos); break;
- case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need
- // to get visible before the reference to the object gets stored anywhere.
- __ membar(Assembler::StoreStore); break;
- default : ShouldNotReachHere();
- }
- __ blr();
-
- return entry;
-} // end of ForceEarlyReturn support
-
-//-----------------------------------------------------------------------------
-// Helper for vtos entry point generation
-
-void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
- address& bep,
- address& cep,
- address& sep,
- address& aep,
- address& iep,
- address& lep,
- address& fep,
- address& dep,
- address& vep) {
- assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
- Label L;
-
- aep = __ pc(); __ push_ptr(); __ b(L);
- fep = __ pc(); __ push_f(); __ b(L);
- dep = __ pc(); __ push_d(); __ b(L);
- lep = __ pc(); __ push_l(); __ b(L);
- __ align(32, 12, 24); // align L
- bep = cep = sep =
- iep = __ pc(); __ push_i();
- vep = __ pc();
- __ bind(L);
- generate_and_dispatch(t);
-}
-
-//-----------------------------------------------------------------------------
-// Generation of individual instructions
-
-// helpers for generate_and_dispatch
-
-InterpreterGenerator::InterpreterGenerator(StubQueue* code)
- : TemplateInterpreterGenerator(code) {
- generate_all(); // Down here so it can be "virtual".
-}
-
-//-----------------------------------------------------------------------------
-
-// Non-product code
-#ifndef PRODUCT
-address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
- //__ flush_bundle();
- address entry = __ pc();
-
- const char *bname = NULL;
- uint tsize = 0;
- switch(state) {
- case ftos:
- bname = "trace_code_ftos {";
- tsize = 2;
- break;
- case btos:
- bname = "trace_code_btos {";
- tsize = 2;
- break;
- case ctos:
- bname = "trace_code_ctos {";
- tsize = 2;
- break;
- case stos:
- bname = "trace_code_stos {";
- tsize = 2;
- break;
- case itos:
- bname = "trace_code_itos {";
- tsize = 2;
- break;
- case ltos:
- bname = "trace_code_ltos {";
- tsize = 3;
- break;
- case atos:
- bname = "trace_code_atos {";
- tsize = 2;
- break;
- case vtos:
- // Note: In case of vtos, the topmost of stack value could be a int or doubl
- // In case of a double (2 slots) we won't see the 2nd stack value.
- // Maybe we simply should print the topmost 3 stack slots to cope with the problem.
- bname = "trace_code_vtos {";
- tsize = 2;
-
- break;
- case dtos:
- bname = "trace_code_dtos {";
- tsize = 3;
- break;
- default:
- ShouldNotReachHere();
- }
- BLOCK_COMMENT(bname);
-
- // Support short-cut for TraceBytecodesAt.
- // Don't call into the VM if we don't want to trace to speed up things.
- Label Lskip_vm_call;
- if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) {
- int offs1 = __ load_const_optimized(R11_scratch1, (address) &TraceBytecodesAt, R0, true);
- int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true);
- __ ld(R11_scratch1, offs1, R11_scratch1);
- __ lwa(R12_scratch2, offs2, R12_scratch2);
- __ cmpd(CCR0, R12_scratch2, R11_scratch1);
- __ blt(CCR0, Lskip_vm_call);
- }
-
- __ push(state);
- // Load 2 topmost expression stack values.
- __ ld(R6_ARG4, tsize*Interpreter::stackElementSize, R15_esp);
- __ ld(R5_ARG3, Interpreter::stackElementSize, R15_esp);
- __ mflr(R31);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), /* unused */ R4_ARG2, R5_ARG3, R6_ARG4, false);
- __ mtlr(R31);
- __ pop(state);
-
- if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) {
- __ bind(Lskip_vm_call);
- }
- __ blr();
- BLOCK_COMMENT("} trace_code");
- return entry;
-}
-
-void TemplateInterpreterGenerator::count_bytecode() {
- int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeCounter::_counter_value, R12_scratch2, true);
- __ lwz(R12_scratch2, offs, R11_scratch1);
- __ addi(R12_scratch2, R12_scratch2, 1);
- __ stw(R12_scratch2, offs, R11_scratch1);
-}
-
-void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
- int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeHistogram::_counters[t->bytecode()], R12_scratch2, true);
- __ lwz(R12_scratch2, offs, R11_scratch1);
- __ addi(R12_scratch2, R12_scratch2, 1);
- __ stw(R12_scratch2, offs, R11_scratch1);
-}
-
-void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) {
- const Register addr = R11_scratch1,
- tmp = R12_scratch2;
- // Get index, shift out old bytecode, bring in new bytecode, and store it.
- // _index = (_index >> log2_number_of_codes) |
- // (bytecode << log2_number_of_codes);
- int offs1 = __ load_const_optimized(addr, (address)&BytecodePairHistogram::_index, tmp, true);
- __ lwz(tmp, offs1, addr);
- __ srwi(tmp, tmp, BytecodePairHistogram::log2_number_of_codes);
- __ ori(tmp, tmp, ((int) t->bytecode()) << BytecodePairHistogram::log2_number_of_codes);
- __ stw(tmp, offs1, addr);
-
- // Bump bucket contents.
- // _counters[_index] ++;
- int offs2 = __ load_const_optimized(addr, (address)&BytecodePairHistogram::_counters, R0, true);
- __ sldi(tmp, tmp, LogBytesPerInt);
- __ add(addr, tmp, addr);
- __ lwz(tmp, offs2, addr);
- __ addi(tmp, tmp, 1);
- __ stw(tmp, offs2, addr);
-}
-
-void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
- // Call a little run-time stub to avoid blow-up for each bytecode.
- // The run-time runtime saves the right registers, depending on
- // the tosca in-state for the given template.
-
- assert(Interpreter::trace_code(t->tos_in()) != NULL,
- "entry must have been generated");
-
- // Note: we destroy LR here.
- __ bl(Interpreter::trace_code(t->tos_in()));
-}
-
-void TemplateInterpreterGenerator::stop_interpreter_at() {
- Label L;
- int offs1 = __ load_const_optimized(R11_scratch1, (address) &StopInterpreterAt, R0, true);
- int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true);
- __ ld(R11_scratch1, offs1, R11_scratch1);
- __ lwa(R12_scratch2, offs2, R12_scratch2);
- __ cmpd(CCR0, R12_scratch2, R11_scratch1);
- __ bne(CCR0, L);
- __ illtrap();
- __ bind(L);
-}
-
-#endif // !PRODUCT
-#endif // !CC_INTERP
--- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013, 2015 SAP AG. All rights reserved.
+ * Copyright (c) 2013, 2015 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,14 +28,17 @@
protected:
- // Size of interpreter code. Increase if too small. Interpreter will
+ // Size of interpreter code. Increase if too small. Interpreter will
// fail with a guarantee ("not enough space for interpreter generation");
// if too small.
// Run with +PrintInterpreter to get the VM to print out the size.
// Max size with JVMTI
-
const static int InterpreterCodeSize = 230*K;
+ public:
+ // Support abs and sqrt like in compiler.
+ // For others we can use a normal (native) entry.
+ static bool math_entry_available(AbstractInterpreter::MethodKind kind);
#endif // CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP
--- a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -38,7 +38,6 @@
#include "prims/jvmtiThreadState.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
@@ -62,30 +61,6 @@
//----------------------------------------------------------------------------------------------------
-
-
-
-int AbstractInterpreter::BasicType_as_index(BasicType type) {
- int i = 0;
- switch (type) {
- case T_BOOLEAN: i = 0; break;
- case T_CHAR : i = 1; break;
- case T_BYTE : i = 2; break;
- case T_SHORT : i = 3; break;
- case T_INT : i = 4; break;
- case T_LONG : i = 5; break;
- case T_VOID : i = 6; break;
- case T_FLOAT : i = 7; break;
- case T_DOUBLE : i = 8; break;
- case T_OBJECT : i = 9; break;
- case T_ARRAY : i = 9; break;
- default : ShouldNotReachHere();
- }
- assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds");
- return i;
-}
-
-
#ifndef _LP64
address AbstractInterpreterGenerator::generate_slow_signature_handler() {
address entry = __ pc();
@@ -254,28 +229,3 @@
return entry;
}
-
-bool AbstractInterpreter::can_be_compiled(methodHandle m) {
- // No special entry points that preclude compilation
- return true;
-}
-
-void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) {
-
- // This code is sort of the equivalent of C2IAdapter::setup_stack_frame back in
- // the days we had adapter frames. When we deoptimize a situation where a
- // compiled caller calls a compiled caller will have registers it expects
- // to survive the call to the callee. If we deoptimize the callee the only
- // way we can restore these registers is to have the oldest interpreter
- // frame that we create restore these values. That is what this routine
- // will accomplish.
-
- // At the moment we have modified c2 to not have any callee save registers
- // so this problem does not exist and this routine is just a place holder.
-
- assert(f->is_interpreted_frame(), "must be interpreted");
-}
-
-
-//----------------------------------------------------------------------------------------------------
-// Exceptions
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -360,10 +360,10 @@
#ifdef ASSERT
// a hook for debugging
static Thread* reinitialize_thread() {
- return ThreadLocalStorage::thread();
+ return Thread::current();
}
#else
-#define reinitialize_thread ThreadLocalStorage::thread
+#define reinitialize_thread Thread::current
#endif
#ifdef ASSERT
@@ -393,7 +393,7 @@
}
static Thread* verify_thread_subroutine(Thread* gthread_value) {
- Thread* correct_value = ThreadLocalStorage::thread();
+ Thread* correct_value = Thread::current();
guarantee(gthread_value == correct_value, "G2_thread value must be the thread");
return correct_value;
}
--- a/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -52,7 +52,7 @@
inline void fill_subword(void* start, void* end, int value) {
STATIC_ASSERT(BytesPerWord == 8);
- assert(pointer_delta(end, start, 1) < BytesPerWord, "precondition");
+ assert(pointer_delta(end, start, 1) < (size_t)BytesPerWord, "precondition");
// Dispatch on (end - start).
void* pc;
__asm__ volatile(
@@ -73,10 +73,10 @@
" stb %[value], [%[end]-3]\n\t"
" stb %[value], [%[end]-2]\n\t"
" stb %[value], [%[end]-1]\n\t" // end[-1] = value
- : /* no outputs */
- [pc] "&=r" (pc) // temp
- : [offset] "&+r" (start),
- [end] "r" (end),
+ : /* only temporaries/overwritten outputs */
+ [pc] "=&r" (pc), // temp
+ [offset] "+&r" (start)
+ : [end] "r" (end),
[value] "r" (value)
: "memory");
}
@@ -84,7 +84,7 @@
void memset_with_concurrent_readers(void* to, int value, size_t size) {
Prefetch::write(to, 0);
void* end = static_cast<char*>(to) + size;
- if (size >= BytesPerWord) {
+ if (size >= (size_t)BytesPerWord) {
// Fill any partial word prefix.
uintx* aligned_to = static_cast<uintx*>(align_ptr_up(to, BytesPerWord));
fill_subword(to, aligned_to, value);
@@ -144,10 +144,10 @@
" stx %[xvalue], [%[aend]-24]\n\t"
" stx %[xvalue], [%[aend]-16]\n\t"
" stx %[xvalue], [%[aend]-8]\n\t" // aligned_end[-1] = xvalue
- : /* no outputs */
- [temp] "&=r" (temp)
- : [ato] "&+r" (aligned_to),
- [aend] "r" (aligned_end),
+ : /* only temporaries/overwritten outputs */
+ [temp] "=&r" (temp),
+ [ato] "+&r" (aligned_to)
+ : [aend] "r" (aligned_end),
[xvalue] "r" (xvalue)
: "cc", "memory");
to = aligned_end; // setup for suffix
--- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -433,7 +433,7 @@
void NativeMovConstReg32::print() {
- tty->print_cr(INTPTR_FORMAT ": mov reg, " INTPTR_FORMAT, instruction_address(), data());
+ tty->print_cr(INTPTR_FORMAT ": mov reg, " INTPTR_FORMAT, p2i(instruction_address()), data());
}
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Wed Jul 05 21:09:54 2017 +0200
@@ -1651,6 +1651,7 @@
#endif // !_LP64
Unimplemented();
+ return 0;
}
#ifndef PRODUCT
--- a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -36,7 +36,7 @@
address _flush_reg_windows(); // in .s file.
// Flush registers to stack. In case of error we will need to stack walk.
address bootstrap_flush_windows(void) {
- Thread* thread = ThreadLocalStorage::get_thread_slow();
+ Thread* thread = Thread::current_or_null();
// Very early in process there is no thread.
if (thread != NULL) {
guarantee(thread->is_Java_thread(), "Not a Java thread.");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,1832 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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/macroAssembler.hpp"
+#include "interpreter/bytecodeHistogram.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterGenerator.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/interp_masm.hpp"
+#include "interpreter/templateTable.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/methodData.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "prims/jvmtiThreadState.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/synchronizer.hpp"
+#include "runtime/timer.hpp"
+#include "runtime/vframeArray.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/macros.hpp"
+
+#ifndef CC_INTERP
+#ifndef FAST_DISPATCH
+#define FAST_DISPATCH 1
+#endif
+#undef FAST_DISPATCH
+
+
+// Generation of Interpreter
+//
+// The InterpreterGenerator generates the interpreter into Interpreter::_code.
+
+
+#define __ _masm->
+
+
+//----------------------------------------------------------------------------------------------------
+
+
+void InterpreterGenerator::save_native_result(void) {
+ // result potentially in O0/O1: save it across calls
+ const Address& l_tmp = InterpreterMacroAssembler::l_tmp;
+
+ // result potentially in F0/F1: save it across calls
+ const Address& d_tmp = InterpreterMacroAssembler::d_tmp;
+
+ // save and restore any potential method result value around the unlocking operation
+ __ stf(FloatRegisterImpl::D, F0, d_tmp);
+#ifdef _LP64
+ __ stx(O0, l_tmp);
+#else
+ __ std(O0, l_tmp);
+#endif
+}
+
+void InterpreterGenerator::restore_native_result(void) {
+ const Address& l_tmp = InterpreterMacroAssembler::l_tmp;
+ const Address& d_tmp = InterpreterMacroAssembler::d_tmp;
+
+ // Restore any method result value
+ __ ldf(FloatRegisterImpl::D, d_tmp, F0);
+#ifdef _LP64
+ __ ldx(l_tmp, O0);
+#else
+ __ ldd(l_tmp, O0);
+#endif
+}
+
+address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
+ assert(!pass_oop || message == NULL, "either oop or message but not both");
+ address entry = __ pc();
+ // expression stack must be empty before entering the VM if an exception happened
+ __ empty_expression_stack();
+ // load exception object
+ __ set((intptr_t)name, G3_scratch);
+ if (pass_oop) {
+ __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), G3_scratch, Otos_i);
+ } else {
+ __ set((intptr_t)message, G4_scratch);
+ __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), G3_scratch, G4_scratch);
+ }
+ // throw exception
+ assert(Interpreter::throw_exception_entry() != NULL, "generate it first");
+ AddressLiteral thrower(Interpreter::throw_exception_entry());
+ __ jump_to(thrower, G3_scratch);
+ __ delayed()->nop();
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
+ address entry = __ pc();
+ // expression stack must be empty before entering the VM if an exception
+ // happened
+ __ empty_expression_stack();
+ // load exception object
+ __ call_VM(Oexception,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_ClassCastException),
+ Otos_i);
+ __ should_not_reach_here();
+ return entry;
+}
+
+
+address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
+ address entry = __ pc();
+ // expression stack must be empty before entering the VM if an exception happened
+ __ empty_expression_stack();
+ // convention: expect aberrant index in register G3_scratch, then shuffle the
+ // index to G4_scratch for the VM call
+ __ mov(G3_scratch, G4_scratch);
+ __ set((intptr_t)name, G3_scratch);
+ __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException), G3_scratch, G4_scratch);
+ __ should_not_reach_here();
+ return entry;
+}
+
+
+address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
+ address entry = __ pc();
+ // expression stack must be empty before entering the VM if an exception happened
+ __ empty_expression_stack();
+ __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_StackOverflowError));
+ __ should_not_reach_here();
+ return entry;
+}
+
+
+address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
+ address entry = __ pc();
+
+ if (state == atos) {
+ __ profile_return_type(O0, G3_scratch, G1_scratch);
+ }
+
+#if !defined(_LP64) && defined(COMPILER2)
+ // All return values are where we want them, except for Longs. C2 returns
+ // longs in G1 in the 32-bit build whereas the interpreter wants them in O0/O1.
+ // Since the interpreter will return longs in G1 and O0/O1 in the 32bit
+ // build even if we are returning from interpreted we just do a little
+ // stupid shuffing.
+ // Note: I tried to make c2 return longs in O0/O1 and G1 so we wouldn't have to
+ // do this here. Unfortunately if we did a rethrow we'd see an machepilog node
+ // first which would move g1 -> O0/O1 and destroy the exception we were throwing.
+
+ if (state == ltos) {
+ __ srl (G1, 0, O1);
+ __ srlx(G1, 32, O0);
+ }
+#endif // !_LP64 && COMPILER2
+
+ // The callee returns with the stack possibly adjusted by adapter transition
+ // We remove that possible adjustment here.
+ // All interpreter local registers are untouched. Any result is passed back
+ // in the O0/O1 or float registers. Before continuing, the arguments must be
+ // popped from the java expression stack; i.e., Lesp must be adjusted.
+
+ __ mov(Llast_SP, SP); // Remove any adapter added stack space.
+
+ const Register cache = G3_scratch;
+ const Register index = G1_scratch;
+ __ get_cache_and_index_at_bcp(cache, index, 1, index_size);
+
+ const Register flags = cache;
+ __ ld_ptr(cache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset(), flags);
+ const Register parameter_size = flags;
+ __ and3(flags, ConstantPoolCacheEntry::parameter_size_mask, parameter_size); // argument size in words
+ __ sll(parameter_size, Interpreter::logStackElementSize, parameter_size); // each argument size in bytes
+ __ add(Lesp, parameter_size, Lesp); // pop arguments
+ __ dispatch_next(state, step);
+
+ return entry;
+}
+
+
+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.
+ __ br_null_short(Gtemp, Assembler::pt, L);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception));
+ __ should_not_reach_here();
+ __ bind(L);
+ }
+ __ dispatch_next(state, step);
+ return entry;
+}
+
+// A result handler converts/unboxes a native call result into
+// a java interpreter/compiler result. The current frame is an
+// interpreter frame. The activation frame unwind code must be
+// consistent with that of TemplateTable::_return(...). In the
+// case of native methods, the caller's SP was not modified.
+address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) {
+ address entry = __ pc();
+ Register Itos_i = Otos_i ->after_save();
+ Register Itos_l = Otos_l ->after_save();
+ Register Itos_l1 = Otos_l1->after_save();
+ Register Itos_l2 = Otos_l2->after_save();
+ switch (type) {
+ case T_BOOLEAN: __ subcc(G0, O0, G0); __ addc(G0, 0, Itos_i); break; // !0 => true; 0 => false
+ case T_CHAR : __ sll(O0, 16, O0); __ srl(O0, 16, Itos_i); break; // cannot use and3, 0xFFFF too big as immediate value!
+ case T_BYTE : __ sll(O0, 24, O0); __ sra(O0, 24, Itos_i); break;
+ case T_SHORT : __ sll(O0, 16, O0); __ sra(O0, 16, Itos_i); break;
+ case T_LONG :
+#ifndef _LP64
+ __ mov(O1, Itos_l2); // move other half of long
+#endif // ifdef or no ifdef, fall through to the T_INT case
+ case T_INT : __ mov(O0, Itos_i); break;
+ case T_VOID : /* nothing to do */ break;
+ case T_FLOAT : assert(F0 == Ftos_f, "fix this code" ); break;
+ case T_DOUBLE : assert(F0 == Ftos_d, "fix this code" ); break;
+ case T_OBJECT :
+ __ ld_ptr(FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS, Itos_i);
+ __ verify_oop(Itos_i);
+ break;
+ default : ShouldNotReachHere();
+ }
+ __ ret(); // return from interpreter activation
+ __ delayed()->restore(I5_savedSP, G0, SP); // remove interpreter frame
+ NOT_PRODUCT(__ emit_int32(0);) // marker for disassembly
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) {
+ address entry = __ pc();
+ __ push(state);
+ __ call_VM(noreg, runtime_entry);
+ __ dispatch_via(vtos, Interpreter::normal_table(vtos));
+ return entry;
+}
+
+
+address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
+ address entry = __ pc();
+ __ dispatch_next(state);
+ return entry;
+}
+
+//
+// Helpers for commoning out cases in the various type of method entries.
+//
+
+// increment invocation count & check for overflow
+//
+// Note: checking for negative value instead of overflow
+// so we have a 'sticky' overflow test
+//
+// Lmethod: method
+// ??: invocation counter
+//
+void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) {
+ // Note: In tiered we increment either counters in MethodCounters* or in
+ // MDO depending if we're profiling or not.
+ const Register G3_method_counters = G3_scratch;
+ Label done;
+
+ if (TieredCompilation) {
+ const int increment = InvocationCounter::count_increment;
+ Label no_mdo;
+ if (ProfileInterpreter) {
+ // If no method data exists, go to profile_continue.
+ __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch);
+ __ br_null_short(G4_scratch, Assembler::pn, no_mdo);
+ // Increment counter
+ Address mdo_invocation_counter(G4_scratch,
+ in_bytes(MethodData::invocation_counter_offset()) +
+ in_bytes(InvocationCounter::counter_offset()));
+ Address mask(G4_scratch, in_bytes(MethodData::invoke_mask_offset()));
+ __ increment_mask_and_jump(mdo_invocation_counter, increment, mask,
+ G3_scratch, Lscratch,
+ Assembler::zero, overflow);
+ __ ba_short(done);
+ }
+
+ // Increment counter in MethodCounters*
+ __ bind(no_mdo);
+ Address invocation_counter(G3_method_counters,
+ in_bytes(MethodCounters::invocation_counter_offset()) +
+ in_bytes(InvocationCounter::counter_offset()));
+ __ get_method_counters(Lmethod, G3_method_counters, done);
+ Address mask(G3_method_counters, in_bytes(MethodCounters::invoke_mask_offset()));
+ __ increment_mask_and_jump(invocation_counter, increment, mask,
+ G4_scratch, Lscratch,
+ Assembler::zero, overflow);
+ __ bind(done);
+ } else { // not TieredCompilation
+ // Update standard invocation counters
+ __ get_method_counters(Lmethod, G3_method_counters, done);
+ __ increment_invocation_counter(G3_method_counters, O0, G4_scratch);
+ if (ProfileInterpreter) {
+ Address interpreter_invocation_counter(G3_method_counters,
+ in_bytes(MethodCounters::interpreter_invocation_counter_offset()));
+ __ ld(interpreter_invocation_counter, G4_scratch);
+ __ inc(G4_scratch);
+ __ st(G4_scratch, interpreter_invocation_counter);
+ }
+
+ if (ProfileInterpreter && profile_method != NULL) {
+ // Test to see if we should create a method data oop
+ Address profile_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_profile_limit_offset()));
+ __ ld(profile_limit, G1_scratch);
+ __ cmp_and_br_short(O0, G1_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue);
+
+ // if no method data exists, go to profile_method
+ __ test_method_data_pointer(*profile_method);
+ }
+
+ Address invocation_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_limit_offset()));
+ __ ld(invocation_limit, G3_scratch);
+ __ cmp(O0, G3_scratch);
+ __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); // Far distance
+ __ delayed()->nop();
+ __ bind(done);
+ }
+
+}
+
+// Allocate monitor and lock method (asm interpreter)
+// ebx - Method*
+//
+void TemplateInterpreterGenerator::lock_method() {
+ __ ld(Lmethod, in_bytes(Method::access_flags_offset()), O0); // Load access flags.
+
+#ifdef ASSERT
+ { Label ok;
+ __ btst(JVM_ACC_SYNCHRONIZED, O0);
+ __ br( Assembler::notZero, false, Assembler::pt, ok);
+ __ delayed()->nop();
+ __ stop("method doesn't need synchronization");
+ __ bind(ok);
+ }
+#endif // ASSERT
+
+ // get synchronization object to O0
+ { Label done;
+ const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+ __ btst(JVM_ACC_STATIC, O0);
+ __ br( Assembler::zero, true, Assembler::pt, done);
+ __ delayed()->ld_ptr(Llocals, Interpreter::local_offset_in_bytes(0), O0); // get receiver for not-static case
+
+ __ ld_ptr( Lmethod, in_bytes(Method::const_offset()), O0);
+ __ ld_ptr( O0, in_bytes(ConstMethod::constants_offset()), O0);
+ __ ld_ptr( O0, ConstantPool::pool_holder_offset_in_bytes(), O0);
+
+ // lock the mirror, not the Klass*
+ __ ld_ptr( O0, mirror_offset, O0);
+
+#ifdef ASSERT
+ __ tst(O0);
+ __ breakpoint_trap(Assembler::zero, Assembler::ptr_cc);
+#endif // ASSERT
+
+ __ bind(done);
+ }
+
+ __ add_monitor_to_stack(true, noreg, noreg); // allocate monitor elem
+ __ st_ptr( O0, Lmonitors, BasicObjectLock::obj_offset_in_bytes()); // store object
+ // __ untested("lock_object from method entry");
+ __ lock_object(Lmonitors, O0);
+}
+
+
+void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rframe_size,
+ Register Rscratch,
+ Register Rscratch2) {
+ const int page_size = os::vm_page_size();
+ Label after_frame_check;
+
+ assert_different_registers(Rframe_size, Rscratch, Rscratch2);
+
+ __ set(page_size, Rscratch);
+ __ cmp_and_br_short(Rframe_size, Rscratch, Assembler::lessEqual, Assembler::pt, after_frame_check);
+
+ // get the stack base, and in debug, verify it is non-zero
+ __ ld_ptr( G2_thread, Thread::stack_base_offset(), Rscratch );
+#ifdef ASSERT
+ Label base_not_zero;
+ __ br_notnull_short(Rscratch, Assembler::pn, base_not_zero);
+ __ stop("stack base is zero in generate_stack_overflow_check");
+ __ bind(base_not_zero);
+#endif
+
+ // get the stack size, and in debug, verify it is non-zero
+ assert( sizeof(size_t) == sizeof(intptr_t), "wrong load size" );
+ __ ld_ptr( G2_thread, Thread::stack_size_offset(), Rscratch2 );
+#ifdef ASSERT
+ Label size_not_zero;
+ __ br_notnull_short(Rscratch2, Assembler::pn, size_not_zero);
+ __ stop("stack size is zero in generate_stack_overflow_check");
+ __ bind(size_not_zero);
+#endif
+
+ // compute the beginning of the protected zone minus the requested frame size
+ __ sub( Rscratch, Rscratch2, Rscratch );
+ __ set( (StackRedPages+StackYellowPages) * page_size, Rscratch2 );
+ __ add( Rscratch, Rscratch2, Rscratch );
+
+ // Add in the size of the frame (which is the same as subtracting it from the
+ // SP, which would take another register
+ __ add( Rscratch, Rframe_size, Rscratch );
+
+ // the frame is greater than one page in size, so check against
+ // the bottom of the stack
+ __ cmp_and_brx_short(SP, Rscratch, Assembler::greaterUnsigned, Assembler::pt, after_frame_check);
+
+ // the stack will overflow, throw an exception
+
+ // Note that SP is restored to sender's sp (in the delay slot). This
+ // is necessary if the sender's frame is an extended compiled frame
+ // (see gen_c2i_adapter()) and safer anyway in case of JSR292
+ // adaptations.
+
+ // Note also that the restored frame is not necessarily interpreted.
+ // Use the shared runtime version of the StackOverflowError.
+ assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "stub not yet generated");
+ AddressLiteral stub(StubRoutines::throw_StackOverflowError_entry());
+ __ jump_to(stub, Rscratch);
+ __ delayed()->mov(O5_savedSP, SP);
+
+ // if you get to here, then there is enough stack space
+ __ bind( after_frame_check );
+}
+
+
+//
+// Generate a fixed interpreter frame. This is identical setup for interpreted
+// methods and for native methods hence the shared code.
+
+
+//----------------------------------------------------------------------------------------------------
+// Stack frame layout
+//
+// When control flow reaches any of the entry types for the interpreter
+// the following holds ->
+//
+// C2 Calling Conventions:
+//
+// The entry code below assumes that the following registers are set
+// when coming in:
+// G5_method: holds the Method* of the method to call
+// Lesp: points to the TOS of the callers expression stack
+// after having pushed all the parameters
+//
+// The entry code does the following to setup an interpreter frame
+// pop parameters from the callers stack by adjusting Lesp
+// set O0 to Lesp
+// compute X = (max_locals - num_parameters)
+// bump SP up by X to accomadate the extra locals
+// compute X = max_expression_stack
+// + vm_local_words
+// + 16 words of register save area
+// save frame doing a save sp, -X, sp growing towards lower addresses
+// set Lbcp, Lmethod, LcpoolCache
+// set Llocals to i0
+// set Lmonitors to FP - rounded_vm_local_words
+// set Lesp to Lmonitors - 4
+//
+// The frame has now been setup to do the rest of the entry code
+
+// Try this optimization: Most method entries could live in a
+// "one size fits all" stack frame without all the dynamic size
+// calculations. It might be profitable to do all this calculation
+// statically and approximately for "small enough" methods.
+
+//-----------------------------------------------------------------------------------------------
+
+// C1 Calling conventions
+//
+// Upon method entry, the following registers are setup:
+//
+// g2 G2_thread: current thread
+// g5 G5_method: method to activate
+// g4 Gargs : pointer to last argument
+//
+//
+// Stack:
+//
+// +---------------+ <--- sp
+// | |
+// : reg save area :
+// | |
+// +---------------+ <--- sp + 0x40
+// | |
+// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later)
+// | |
+// +---------------+ <--- sp + 0x5c
+// | |
+// : free :
+// | |
+// +---------------+ <--- Gargs
+// | |
+// : arguments :
+// | |
+// +---------------+
+// | |
+//
+//
+//
+// AFTER FRAME HAS BEEN SETUP for method interpretation the stack looks like:
+//
+// +---------------+ <--- sp
+// | |
+// : reg save area :
+// | |
+// +---------------+ <--- sp + 0x40
+// | |
+// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later)
+// | |
+// +---------------+ <--- sp + 0x5c
+// | |
+// : :
+// | | <--- Lesp
+// +---------------+ <--- Lmonitors (fp - 0x18)
+// | VM locals |
+// +---------------+ <--- fp
+// | |
+// : reg save area :
+// | |
+// +---------------+ <--- fp + 0x40
+// | |
+// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later)
+// | |
+// +---------------+ <--- fp + 0x5c
+// | |
+// : free :
+// | |
+// +---------------+
+// | |
+// : nonarg locals :
+// | |
+// +---------------+
+// | |
+// : arguments :
+// | | <--- Llocals
+// +---------------+ <--- Gargs
+// | |
+
+void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
+ //
+ //
+ // The entry code sets up a new interpreter frame in 4 steps:
+ //
+ // 1) Increase caller's SP by for the extra local space needed:
+ // (check for overflow)
+ // Efficient implementation of xload/xstore bytecodes requires
+ // that arguments and non-argument locals are in a contigously
+ // addressable memory block => non-argument locals must be
+ // allocated in the caller's frame.
+ //
+ // 2) Create a new stack frame and register window:
+ // The new stack frame must provide space for the standard
+ // register save area, the maximum java expression stack size,
+ // the monitor slots (0 slots initially), and some frame local
+ // scratch locations.
+ //
+ // 3) The following interpreter activation registers must be setup:
+ // Lesp : expression stack pointer
+ // Lbcp : bytecode pointer
+ // Lmethod : method
+ // Llocals : locals pointer
+ // Lmonitors : monitor pointer
+ // LcpoolCache: constant pool cache
+ //
+ // 4) Initialize the non-argument locals if necessary:
+ // Non-argument locals may need to be initialized to NULL
+ // for GC to work. If the oop-map information is accurate
+ // (in the absence of the JSR problem), no initialization
+ // is necessary.
+ //
+ // (gri - 2/25/2000)
+
+
+ int rounded_vm_local_words = round_to( frame::interpreter_frame_vm_local_words, WordsPerLong );
+
+ const int extra_space =
+ rounded_vm_local_words + // frame local scratch space
+ Method::extra_stack_entries() + // extra stack for jsr 292
+ frame::memory_parameter_word_sp_offset + // register save area
+ (native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0);
+
+ const Register Glocals_size = G3;
+ const Register RconstMethod = Glocals_size;
+ const Register Otmp1 = O3;
+ const Register Otmp2 = O4;
+ // Lscratch can't be used as a temporary because the call_stub uses
+ // it to assert that the stack frame was setup correctly.
+ const Address constMethod (G5_method, Method::const_offset());
+ const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
+
+ __ ld_ptr( constMethod, RconstMethod );
+ __ lduh( size_of_parameters, Glocals_size);
+
+ // Gargs points to first local + BytesPerWord
+ // Set the saved SP after the register window save
+ //
+ assert_different_registers(Gargs, Glocals_size, Gframe_size, O5_savedSP);
+ __ sll(Glocals_size, Interpreter::logStackElementSize, Otmp1);
+ __ add(Gargs, Otmp1, Gargs);
+
+ if (native_call) {
+ __ calc_mem_param_words( Glocals_size, Gframe_size );
+ __ add( Gframe_size, extra_space, Gframe_size);
+ __ round_to( Gframe_size, WordsPerLong );
+ __ sll( Gframe_size, LogBytesPerWord, Gframe_size );
+ } else {
+
+ //
+ // Compute number of locals in method apart from incoming parameters
+ //
+ const Address size_of_locals (Otmp1, ConstMethod::size_of_locals_offset());
+ __ ld_ptr( constMethod, Otmp1 );
+ __ lduh( size_of_locals, Otmp1 );
+ __ sub( Otmp1, Glocals_size, Glocals_size );
+ __ round_to( Glocals_size, WordsPerLong );
+ __ sll( Glocals_size, Interpreter::logStackElementSize, Glocals_size );
+
+ // see if the frame is greater than one page in size. If so,
+ // then we need to verify there is enough stack space remaining
+ // Frame_size = (max_stack + extra_space) * BytesPerWord;
+ __ ld_ptr( constMethod, Gframe_size );
+ __ lduh( Gframe_size, in_bytes(ConstMethod::max_stack_offset()), Gframe_size );
+ __ add( Gframe_size, extra_space, Gframe_size );
+ __ round_to( Gframe_size, WordsPerLong );
+ __ sll( Gframe_size, Interpreter::logStackElementSize, Gframe_size);
+
+ // Add in java locals size for stack overflow check only
+ __ add( Gframe_size, Glocals_size, Gframe_size );
+
+ const Register Otmp2 = O4;
+ assert_different_registers(Otmp1, Otmp2, O5_savedSP);
+ generate_stack_overflow_check(Gframe_size, Otmp1, Otmp2);
+
+ __ sub( Gframe_size, Glocals_size, Gframe_size);
+
+ //
+ // bump SP to accomodate the extra locals
+ //
+ __ sub( SP, Glocals_size, SP );
+ }
+
+ //
+ // now set up a stack frame with the size computed above
+ //
+ __ neg( Gframe_size );
+ __ save( SP, Gframe_size, SP );
+
+ //
+ // now set up all the local cache registers
+ //
+ // NOTE: At this point, Lbyte_code/Lscratch has been modified. Note
+ // that all present references to Lbyte_code initialize the register
+ // immediately before use
+ if (native_call) {
+ __ mov(G0, Lbcp);
+ } else {
+ __ ld_ptr(G5_method, Method::const_offset(), Lbcp);
+ __ add(Lbcp, in_bytes(ConstMethod::codes_offset()), Lbcp);
+ }
+ __ mov( G5_method, Lmethod); // set Lmethod
+ __ get_constant_pool_cache( LcpoolCache ); // set LcpoolCache
+ __ sub(FP, rounded_vm_local_words * BytesPerWord, Lmonitors ); // set Lmonitors
+#ifdef _LP64
+ __ add( Lmonitors, STACK_BIAS, Lmonitors ); // Account for 64 bit stack bias
+#endif
+ __ sub(Lmonitors, BytesPerWord, Lesp); // set Lesp
+
+ // setup interpreter activation registers
+ __ sub(Gargs, BytesPerWord, Llocals); // set Llocals
+
+ if (ProfileInterpreter) {
+#ifdef FAST_DISPATCH
+ // FAST_DISPATCH and ProfileInterpreter are mutually exclusive since
+ // they both use I2.
+ assert(0, "FAST_DISPATCH and +ProfileInterpreter are mutually exclusive");
+#endif // FAST_DISPATCH
+ __ set_method_data_pointer();
+ }
+
+}
+
+// Method entry for java.lang.ref.Reference.get.
+address InterpreterGenerator::generate_Reference_get_entry(void) {
+#if INCLUDE_ALL_GCS
+ // Code: _aload_0, _getfield, _areturn
+ // parameter size = 1
+ //
+ // The code that gets generated by this routine is split into 2 parts:
+ // 1. The "intrinsified" code for G1 (or any SATB based GC),
+ // 2. The slow path - which is an expansion of the regular method entry.
+ //
+ // Notes:-
+ // * In the G1 code we do not check whether we need to block for
+ // a safepoint. If G1 is enabled then we must execute the specialized
+ // code for Reference.get (except when the Reference object is null)
+ // so that we can log the value in the referent field with an SATB
+ // update buffer.
+ // If the code for the getfield template is modified so that the
+ // G1 pre-barrier code is executed when the current method is
+ // Reference.get() then going through the normal method entry
+ // will be fine.
+ // * The G1 code can, however, check the receiver object (the instance
+ // of java.lang.Reference) and jump to the slow path if null. If the
+ // Reference object is null then we obviously cannot fetch the referent
+ // and so we don't need to call the G1 pre-barrier. Thus we can use the
+ // regular method entry code to generate the NPE.
+ //
+ // This code is based on generate_accessor_enty.
+
+ 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;
+
+ // In the G1 code we don't check if we need to reach a safepoint. We
+ // continue and the thread will safepoint at the next bytecode dispatch.
+
+ // Check if local 0 != NULL
+ // If the receiver is null then it is OK to jump to the slow path.
+ __ ld_ptr(Gargs, G0, Otos_i ); // get local 0
+ // check if local 0 == NULL and go the slow path
+ __ cmp_and_brx_short(Otos_i, 0, Assembler::equal, Assembler::pn, slow_path);
+
+
+ // Load the value of the referent field.
+ if (Assembler::is_simm13(referent_offset)) {
+ __ load_heap_oop(Otos_i, referent_offset, Otos_i);
+ } else {
+ __ set(referent_offset, G3_scratch);
+ __ load_heap_oop(Otos_i, G3_scratch, Otos_i);
+ }
+
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer. Note with
+ // these parameters the pre-barrier does not generate
+ // the load of the previous value
+
+ __ g1_write_barrier_pre(noreg /* obj */, noreg /* index */, 0 /* offset */,
+ Otos_i /* pre_val */,
+ G3_scratch /* tmp */,
+ true /* preserve_o_regs */);
+
+ // _areturn
+ __ retl(); // return from leaf routine
+ __ delayed()->mov(O5_savedSP, SP);
+
+ // Generate regular method entry
+ __ bind(slow_path);
+ __ 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 NULL;
+}
+
+/**
+ * Method entry for static native methods:
+ * int java.util.zip.CRC32.update(int crc, int b)
+ */
+address InterpreterGenerator::generate_CRC32_update_entry() {
+
+ if (UseCRC32Intrinsics) {
+ address entry = __ pc();
+
+ Label L_slow_path;
+ // If we need a safepoint check, generate full interpreter entry.
+ ExternalAddress state(SafepointSynchronize::address_of_state());
+ __ set(ExternalAddress(SafepointSynchronize::address_of_state()), O2);
+ __ set(SafepointSynchronize::_not_synchronized, O3);
+ __ cmp_and_br_short(O2, O3, Assembler::notEqual, Assembler::pt, L_slow_path);
+
+ // Load parameters
+ const Register crc = O0; // initial crc
+ const Register val = O1; // byte to update with
+ const Register table = O2; // address of 256-entry lookup table
+
+ __ ldub(Gargs, 3, val);
+ __ lduw(Gargs, 8, crc);
+
+ __ set(ExternalAddress(StubRoutines::crc_table_addr()), table);
+
+ __ not1(crc); // ~crc
+ __ clruwu(crc);
+ __ update_byte_crc32(crc, val, table);
+ __ not1(crc); // ~crc
+
+ // result in O0
+ __ retl();
+ __ delayed()->nop();
+
+ // generate a vanilla native entry as the slow path
+ __ bind(L_slow_path);
+ __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native));
+ return entry;
+ }
+ return NULL;
+}
+
+/**
+ * Method entry for static native methods:
+ * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len)
+ * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len)
+ */
+address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
+
+ if (UseCRC32Intrinsics) {
+ address entry = __ pc();
+
+ Label L_slow_path;
+ // If we need a safepoint check, generate full interpreter entry.
+ ExternalAddress state(SafepointSynchronize::address_of_state());
+ __ set(ExternalAddress(SafepointSynchronize::address_of_state()), O2);
+ __ set(SafepointSynchronize::_not_synchronized, O3);
+ __ cmp_and_br_short(O2, O3, Assembler::notEqual, Assembler::pt, L_slow_path);
+
+ // Load parameters from the stack
+ const Register crc = O0; // initial crc
+ const Register buf = O1; // source java byte array address
+ const Register len = O2; // len
+ const Register offset = O3; // offset
+
+ // Arguments are reversed on java expression stack
+ // Calculate address of start element
+ if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) {
+ __ lduw(Gargs, 0, len);
+ __ lduw(Gargs, 8, offset);
+ __ ldx( Gargs, 16, buf);
+ __ lduw(Gargs, 32, crc);
+ __ add(buf, offset, buf);
+ } else {
+ __ lduw(Gargs, 0, len);
+ __ lduw(Gargs, 8, offset);
+ __ ldx( Gargs, 16, buf);
+ __ lduw(Gargs, 24, crc);
+ __ add(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE), buf); // account for the header size
+ __ add(buf ,offset, buf);
+ }
+
+ // Call the crc32 kernel
+ __ MacroAssembler::save_thread(L7_thread_cache);
+ __ kernel_crc32(crc, buf, len, O3);
+ __ MacroAssembler::restore_thread(L7_thread_cache);
+
+ // result in O0
+ __ retl();
+ __ delayed()->nop();
+
+ // generate a vanilla native entry as the slow path
+ __ bind(L_slow_path);
+ __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native));
+ return entry;
+ }
+ return NULL;
+}
+
+//
+// Interpreter stub for calling a native method. (asm interpreter)
+// This sets up a somewhat different looking stack for calling the native method
+// than the typical interpreter frame setup.
+//
+
+address InterpreterGenerator::generate_native_entry(bool synchronized) {
+ address entry = __ pc();
+
+ // the following temporary registers are used during frame creation
+ const Register Gtmp1 = G3_scratch ;
+ const Register Gtmp2 = G1_scratch;
+ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
+
+ // make sure registers are different!
+ assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2);
+
+ const Address Laccess_flags(Lmethod, Method::access_flags_offset());
+
+ const Register Glocals_size = G3;
+ assert_different_registers(Glocals_size, G4_scratch, Gframe_size);
+
+ // make sure method is native & not abstract
+ // rethink these assertions - they can be simplified and shared (gri 2/25/2000)
+#ifdef ASSERT
+ __ ld(G5_method, Method::access_flags_offset(), Gtmp1);
+ {
+ Label L;
+ __ btst(JVM_ACC_NATIVE, Gtmp1);
+ __ br(Assembler::notZero, false, Assembler::pt, L);
+ __ delayed()->nop();
+ __ stop("tried to execute non-native method as native");
+ __ bind(L);
+ }
+ { Label L;
+ __ btst(JVM_ACC_ABSTRACT, Gtmp1);
+ __ br(Assembler::zero, false, Assembler::pt, L);
+ __ delayed()->nop();
+ __ stop("tried to execute abstract method as non-abstract");
+ __ bind(L);
+ }
+#endif // ASSERT
+
+ // generate the code to allocate the interpreter stack frame
+ generate_fixed_frame(true);
+
+ //
+ // No locals to initialize for native method
+ //
+
+ // this slot will be set later, we initialize it to null here just in
+ // case we get a GC before the actual value is stored later
+ __ st_ptr(G0, FP, (frame::interpreter_frame_oop_temp_offset * wordSize) + STACK_BIAS);
+
+ const Address do_not_unlock_if_synchronized(G2_thread,
+ JavaThread::do_not_unlock_if_synchronized_offset());
+ // Since at this point in the method invocation the exception handler
+ // would try to exit the monitor of synchronized methods which hasn't
+ // been entered yet, we set the thread local variable
+ // _do_not_unlock_if_synchronized to true. If any exception was thrown by
+ // runtime, exception handling i.e. unlock_if_synchronized_method will
+ // check this thread local flag.
+ // This flag has two effects, one is to force an unwind in the topmost
+ // interpreter frame and not perform an unlock while doing so.
+
+ __ movbool(true, G3_scratch);
+ __ stbool(G3_scratch, do_not_unlock_if_synchronized);
+
+ // increment invocation counter and check for overflow
+ //
+ // Note: checking for negative value instead of overflow
+ // so we have a 'sticky' overflow test (may be of
+ // importance as soon as we have true MT/MP)
+ Label invocation_counter_overflow;
+ Label Lcontinue;
+ if (inc_counter) {
+ generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
+
+ }
+ __ bind(Lcontinue);
+
+ bang_stack_shadow_pages(true);
+
+ // reset the _do_not_unlock_if_synchronized flag
+ __ stbool(G0, do_not_unlock_if_synchronized);
+
+ // check for synchronized methods
+ // Must happen AFTER invocation_counter check and stack overflow check,
+ // so method is not locked if overflows.
+
+ if (synchronized) {
+ lock_method();
+ } else {
+#ifdef ASSERT
+ { Label ok;
+ __ ld(Laccess_flags, O0);
+ __ btst(JVM_ACC_SYNCHRONIZED, O0);
+ __ br( Assembler::zero, false, Assembler::pt, ok);
+ __ delayed()->nop();
+ __ stop("method needs synchronization");
+ __ bind(ok);
+ }
+#endif // ASSERT
+ }
+
+
+ // start execution
+ __ verify_thread();
+
+ // JVMTI support
+ __ notify_method_entry();
+
+ // native call
+
+ // (note that O0 is never an oop--at most it is a handle)
+ // It is important not to smash any handles created by this call,
+ // until any oop handle in O0 is dereferenced.
+
+ // (note that the space for outgoing params is preallocated)
+
+ // get signature handler
+ { Label L;
+ Address signature_handler(Lmethod, Method::signature_handler_offset());
+ __ ld_ptr(signature_handler, G3_scratch);
+ __ br_notnull_short(G3_scratch, Assembler::pt, L);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), Lmethod);
+ __ ld_ptr(signature_handler, G3_scratch);
+ __ bind(L);
+ }
+
+ // Push a new frame so that the args will really be stored in
+ // Copy a few locals across so the new frame has the variables
+ // we need but these values will be dead at the jni call and
+ // therefore not gc volatile like the values in the current
+ // frame (Lmethod in particular)
+
+ // Flush the method pointer to the register save area
+ __ st_ptr(Lmethod, SP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS);
+ __ mov(Llocals, O1);
+
+ // calculate where the mirror handle body is allocated in the interpreter frame:
+ __ add(FP, (frame::interpreter_frame_oop_temp_offset * wordSize) + STACK_BIAS, O2);
+
+ // Calculate current frame size
+ __ sub(SP, FP, O3); // Calculate negative of current frame size
+ __ save(SP, O3, SP); // Allocate an identical sized frame
+
+ // Note I7 has leftover trash. Slow signature handler will fill it in
+ // should we get there. Normal jni call will set reasonable last_Java_pc
+ // below (and fix I7 so the stack trace doesn't have a meaningless frame
+ // in it).
+
+ // Load interpreter frame's Lmethod into same register here
+
+ __ ld_ptr(FP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS, Lmethod);
+
+ __ mov(I1, Llocals);
+ __ mov(I2, Lscratch2); // save the address of the mirror
+
+
+ // ONLY Lmethod and Llocals are valid here!
+
+ // call signature handler, It will move the arg properly since Llocals in current frame
+ // matches that in outer frame
+
+ __ callr(G3_scratch, 0);
+ __ delayed()->nop();
+
+ // Result handler is in Lscratch
+
+ // Reload interpreter frame's Lmethod since slow signature handler may block
+ __ ld_ptr(FP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS, Lmethod);
+
+ { Label not_static;
+
+ __ ld(Laccess_flags, O0);
+ __ btst(JVM_ACC_STATIC, O0);
+ __ br( Assembler::zero, false, Assembler::pt, not_static);
+ // get native function entry point(O0 is a good temp until the very end)
+ __ delayed()->ld_ptr(Lmethod, in_bytes(Method::native_function_offset()), O0);
+ // for static methods insert the mirror argument
+ const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+
+ __ ld_ptr(Lmethod, Method:: const_offset(), O1);
+ __ ld_ptr(O1, ConstMethod::constants_offset(), O1);
+ __ ld_ptr(O1, ConstantPool::pool_holder_offset_in_bytes(), O1);
+ __ ld_ptr(O1, mirror_offset, O1);
+#ifdef ASSERT
+ if (!PrintSignatureHandlers) // do not dirty the output with this
+ { Label L;
+ __ br_notnull_short(O1, Assembler::pt, L);
+ __ stop("mirror is missing");
+ __ bind(L);
+ }
+#endif // ASSERT
+ __ st_ptr(O1, Lscratch2, 0);
+ __ mov(Lscratch2, O1);
+ __ bind(not_static);
+ }
+
+ // At this point, arguments have been copied off of stack into
+ // their JNI positions, which are O1..O5 and SP[68..].
+ // Oops are boxed in-place on the stack, with handles copied to arguments.
+ // The result handler is in Lscratch. O0 will shortly hold the JNIEnv*.
+
+#ifdef ASSERT
+ { Label L;
+ __ br_notnull_short(O0, Assembler::pt, L);
+ __ stop("native entry point is missing");
+ __ bind(L);
+ }
+#endif // ASSERT
+
+ //
+ // setup the frame anchor
+ //
+ // The scavenge function only needs to know that the PC of this frame is
+ // in the interpreter method entry code, it doesn't need to know the exact
+ // PC and hence we can use O7 which points to the return address from the
+ // previous call in the code stream (signature handler function)
+ //
+ // The other trick is we set last_Java_sp to FP instead of the usual SP because
+ // we have pushed the extra frame in order to protect the volatile register(s)
+ // in that frame when we return from the jni call
+ //
+
+ __ set_last_Java_frame(FP, O7);
+ __ mov(O7, I7); // make dummy interpreter frame look like one above,
+ // not meaningless information that'll confuse me.
+
+ // flush the windows now. We don't care about the current (protection) frame
+ // only the outer frames
+
+ __ flushw();
+
+ // mark windows as flushed
+ Address flags(G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::flags_offset());
+ __ set(JavaFrameAnchor::flushed, G3_scratch);
+ __ st(G3_scratch, flags);
+
+ // Transition from _thread_in_Java to _thread_in_native. We are already safepoint ready.
+
+ Address thread_state(G2_thread, JavaThread::thread_state_offset());
+#ifdef ASSERT
+ { Label L;
+ __ ld(thread_state, G3_scratch);
+ __ cmp_and_br_short(G3_scratch, _thread_in_Java, Assembler::equal, Assembler::pt, L);
+ __ stop("Wrong thread state in native stub");
+ __ bind(L);
+ }
+#endif // ASSERT
+ __ set(_thread_in_native, G3_scratch);
+ __ st(G3_scratch, thread_state);
+
+ // Call the jni method, using the delay slot to set the JNIEnv* argument.
+ __ save_thread(L7_thread_cache); // save Gthread
+ __ callr(O0, 0);
+ __ delayed()->
+ add(L7_thread_cache, in_bytes(JavaThread::jni_environment_offset()), O0);
+
+ // Back from jni method Lmethod in this frame is DEAD, DEAD, DEAD
+
+ __ restore_thread(L7_thread_cache); // restore G2_thread
+ __ reinit_heapbase();
+
+ // must we block?
+
+ // Block, if necessary, before resuming in _thread_in_Java state.
+ // In order for GC to work, don't clear the last_Java_sp until after blocking.
+ { Label no_block;
+ AddressLiteral sync_state(SafepointSynchronize::address_of_state());
+
+ // Switch thread to "native transition" state before reading the synchronization state.
+ // This additional state is necessary because reading and testing the synchronization
+ // state is not atomic w.r.t. GC, as this scenario demonstrates:
+ // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted.
+ // VM thread changes sync state to synchronizing and suspends threads for GC.
+ // 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.
+ __ set(_thread_in_native_trans, G3_scratch);
+ __ st(G3_scratch, thread_state);
+ if(os::is_MP()) {
+ if (UseMembar) {
+ // Force this write out before the read below
+ __ membar(Assembler::StoreLoad);
+ } else {
+ // 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
+ // due to cache line collision.
+ __ serialize_memory(G2_thread, G1_scratch, G3_scratch);
+ }
+ }
+ __ load_contents(sync_state, G3_scratch);
+ __ cmp(G3_scratch, SafepointSynchronize::_not_synchronized);
+
+ Label L;
+ __ br(Assembler::notEqual, false, Assembler::pn, L);
+ __ delayed()->ld(G2_thread, JavaThread::suspend_flags_offset(), G3_scratch);
+ __ cmp_and_br_short(G3_scratch, 0, Assembler::equal, Assembler::pt, no_block);
+ __ bind(L);
+
+ // Block. Save any potential method result value before the operation and
+ // use a leaf call to leave the last_Java_frame setup undisturbed.
+ save_native_result();
+ __ call_VM_leaf(L7_thread_cache,
+ CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
+ G2_thread);
+
+ // Restore any method result value
+ restore_native_result();
+ __ bind(no_block);
+ }
+
+ // Clear the frame anchor now
+
+ __ reset_last_Java_frame();
+
+ // Move the result handler address
+ __ mov(Lscratch, G3_scratch);
+ // return possible result to the outer frame
+#ifndef __LP64
+ __ mov(O0, I0);
+ __ restore(O1, G0, O1);
+#else
+ __ restore(O0, G0, O0);
+#endif /* __LP64 */
+
+ // Move result handler to expected register
+ __ mov(G3_scratch, Lscratch);
+
+ // Back in normal (native) interpreter frame. State is thread_in_native_trans
+ // switch to thread_in_Java.
+
+ __ set(_thread_in_Java, G3_scratch);
+ __ st(G3_scratch, thread_state);
+
+ // reset handle block
+ __ ld_ptr(G2_thread, JavaThread::active_handles_offset(), G3_scratch);
+ __ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
+
+ // If we have an oop result store it where it will be safe for any further gc
+ // until we return now that we've released the handle it might be protected by
+
+ {
+ Label no_oop, store_result;
+
+ __ set((intptr_t)AbstractInterpreter::result_handler(T_OBJECT), G3_scratch);
+ __ cmp_and_brx_short(G3_scratch, Lscratch, Assembler::notEqual, Assembler::pt, no_oop);
+ __ addcc(G0, O0, O0);
+ __ brx(Assembler::notZero, true, Assembler::pt, store_result); // if result is not NULL:
+ __ delayed()->ld_ptr(O0, 0, O0); // unbox it
+ __ mov(G0, O0);
+
+ __ bind(store_result);
+ // Store it where gc will look for it and result handler expects it.
+ __ st_ptr(O0, FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS);
+
+ __ bind(no_oop);
+
+ }
+
+
+ // handle exceptions (exception handling will handle unlocking!)
+ { Label L;
+ Address exception_addr(G2_thread, Thread::pending_exception_offset());
+ __ ld_ptr(exception_addr, Gtemp);
+ __ br_null_short(Gtemp, Assembler::pt, L);
+ // Note: This could be handled more efficiently since we know that the native
+ // method doesn't have an exception handler. We could directly return
+ // to the exception handler for the caller.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception));
+ __ should_not_reach_here();
+ __ bind(L);
+ }
+
+ // JVMTI support (preserves thread register)
+ __ notify_method_exit(true, ilgl, InterpreterMacroAssembler::NotifyJVMTI);
+
+ if (synchronized) {
+ // save and restore any potential method result value around the unlocking operation
+ save_native_result();
+
+ __ add( __ top_most_monitor(), O1);
+ __ unlock_object(O1);
+
+ restore_native_result();
+ }
+
+#if defined(COMPILER2) && !defined(_LP64)
+
+ // C2 expects long results in G1 we can't tell if we're returning to interpreted
+ // or compiled so just be safe.
+
+ __ sllx(O0, 32, G1); // Shift bits into high G1
+ __ srl (O1, 0, O1); // Zero extend O1
+ __ or3 (O1, G1, G1); // OR 64 bits into G1
+
+#endif /* COMPILER2 && !_LP64 */
+
+ // dispose of return address and remove activation
+#ifdef ASSERT
+ {
+ Label ok;
+ __ cmp_and_brx_short(I5_savedSP, FP, Assembler::greaterEqualUnsigned, Assembler::pt, ok);
+ __ stop("bad I5_savedSP value");
+ __ should_not_reach_here();
+ __ bind(ok);
+ }
+#endif
+ if (TraceJumps) {
+ // Move target to register that is recordable
+ __ mov(Lscratch, G3_scratch);
+ __ JMP(G3_scratch, 0);
+ } else {
+ __ jmp(Lscratch, 0);
+ }
+ __ delayed()->nop();
+
+
+ if (inc_counter) {
+ // handle invocation counter overflow
+ __ bind(invocation_counter_overflow);
+ generate_counter_overflow(Lcontinue);
+ }
+
+
+
+ return entry;
+}
+
+
+// Generic method entry to (asm) interpreter
+address InterpreterGenerator::generate_normal_entry(bool synchronized) {
+ address entry = __ pc();
+
+ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
+
+ // the following temporary registers are used during frame creation
+ const Register Gtmp1 = G3_scratch ;
+ const Register Gtmp2 = G1_scratch;
+
+ // make sure registers are different!
+ assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2);
+
+ const Address constMethod (G5_method, Method::const_offset());
+ // Seems like G5_method is live at the point this is used. So we could make this look consistent
+ // and use in the asserts.
+ const Address access_flags (Lmethod, Method::access_flags_offset());
+
+ const Register Glocals_size = G3;
+ assert_different_registers(Glocals_size, G4_scratch, Gframe_size);
+
+ // make sure method is not native & not abstract
+ // rethink these assertions - they can be simplified and shared (gri 2/25/2000)
+#ifdef ASSERT
+ __ ld(G5_method, Method::access_flags_offset(), Gtmp1);
+ {
+ Label L;
+ __ btst(JVM_ACC_NATIVE, Gtmp1);
+ __ br(Assembler::zero, false, Assembler::pt, L);
+ __ delayed()->nop();
+ __ stop("tried to execute native method as non-native");
+ __ bind(L);
+ }
+ { Label L;
+ __ btst(JVM_ACC_ABSTRACT, Gtmp1);
+ __ br(Assembler::zero, false, Assembler::pt, L);
+ __ delayed()->nop();
+ __ stop("tried to execute abstract method as non-abstract");
+ __ bind(L);
+ }
+#endif // ASSERT
+
+ // generate the code to allocate the interpreter stack frame
+
+ generate_fixed_frame(false);
+
+#ifdef FAST_DISPATCH
+ __ set((intptr_t)Interpreter::dispatch_table(), IdispatchTables);
+ // set bytecode dispatch table base
+#endif
+
+ //
+ // Code to initialize the extra (i.e. non-parm) locals
+ //
+ Register init_value = noreg; // will be G0 if we must clear locals
+ // The way the code was setup before zerolocals was always true for vanilla java entries.
+ // It could only be false for the specialized entries like accessor or empty which have
+ // no extra locals so the testing was a waste of time and the extra locals were always
+ // initialized. We removed this extra complication to already over complicated code.
+
+ init_value = G0;
+ Label clear_loop;
+
+ const Register RconstMethod = O1;
+ const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
+ const Address size_of_locals (RconstMethod, ConstMethod::size_of_locals_offset());
+
+ // NOTE: If you change the frame layout, this code will need to
+ // be updated!
+ __ ld_ptr( constMethod, RconstMethod );
+ __ lduh( size_of_locals, O2 );
+ __ lduh( size_of_parameters, O1 );
+ __ sll( O2, Interpreter::logStackElementSize, O2);
+ __ sll( O1, Interpreter::logStackElementSize, O1 );
+ __ sub( Llocals, O2, O2 );
+ __ sub( Llocals, O1, O1 );
+
+ __ bind( clear_loop );
+ __ inc( O2, wordSize );
+
+ __ cmp( O2, O1 );
+ __ brx( Assembler::lessEqualUnsigned, true, Assembler::pt, clear_loop );
+ __ delayed()->st_ptr( init_value, O2, 0 );
+
+ const Address do_not_unlock_if_synchronized(G2_thread,
+ JavaThread::do_not_unlock_if_synchronized_offset());
+ // Since at this point in the method invocation the exception handler
+ // would try to exit the monitor of synchronized methods which hasn't
+ // been entered yet, we set the thread local variable
+ // _do_not_unlock_if_synchronized to true. If any exception was thrown by
+ // runtime, exception handling i.e. unlock_if_synchronized_method will
+ // check this thread local flag.
+ __ movbool(true, G3_scratch);
+ __ stbool(G3_scratch, do_not_unlock_if_synchronized);
+
+ __ profile_parameters_type(G1_scratch, G3_scratch, G4_scratch, Lscratch);
+ // increment invocation counter and check for overflow
+ //
+ // Note: checking for negative value instead of overflow
+ // so we have a 'sticky' overflow test (may be of
+ // importance as soon as we have true MT/MP)
+ Label invocation_counter_overflow;
+ Label profile_method;
+ Label profile_method_continue;
+ Label Lcontinue;
+ if (inc_counter) {
+ generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue);
+ if (ProfileInterpreter) {
+ __ bind(profile_method_continue);
+ }
+ }
+ __ bind(Lcontinue);
+
+ bang_stack_shadow_pages(false);
+
+ // reset the _do_not_unlock_if_synchronized flag
+ __ stbool(G0, do_not_unlock_if_synchronized);
+
+ // check for synchronized methods
+ // Must happen AFTER invocation_counter check and stack overflow check,
+ // so method is not locked if overflows.
+
+ if (synchronized) {
+ lock_method();
+ } else {
+#ifdef ASSERT
+ { Label ok;
+ __ ld(access_flags, O0);
+ __ btst(JVM_ACC_SYNCHRONIZED, O0);
+ __ br( Assembler::zero, false, Assembler::pt, ok);
+ __ delayed()->nop();
+ __ stop("method needs synchronization");
+ __ bind(ok);
+ }
+#endif // ASSERT
+ }
+
+ // start execution
+
+ __ verify_thread();
+
+ // jvmti support
+ __ notify_method_entry();
+
+ // start executing instructions
+ __ dispatch_next(vtos);
+
+
+ if (inc_counter) {
+ if (ProfileInterpreter) {
+ // We have decided to profile this method in the interpreter
+ __ bind(profile_method);
+
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
+ __ set_method_data_pointer_for_bcp();
+ __ ba_short(profile_method_continue);
+ }
+
+ // handle invocation counter overflow
+ __ bind(invocation_counter_overflow);
+ generate_counter_overflow(Lcontinue);
+ }
+
+
+ return entry;
+}
+
+//----------------------------------------------------------------------------------------------------
+// Exceptions
+void TemplateInterpreterGenerator::generate_throw_exception() {
+
+ // Entry point in previous activation (i.e., if the caller was interpreted)
+ Interpreter::_rethrow_exception_entry = __ pc();
+ // O0: exception
+
+ // entry point for exceptions thrown within interpreter code
+ Interpreter::_throw_exception_entry = __ pc();
+ __ verify_thread();
+ // expression stack is undefined here
+ // O0: exception, i.e. Oexception
+ // Lbcp: exception bcp
+ __ verify_oop(Oexception);
+
+
+ // expression stack must be empty before entering the VM in case of an exception
+ __ empty_expression_stack();
+ // find exception handler address and preserve exception oop
+ // call C routine to find handler and jump to it
+ __ call_VM(O1, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), Oexception);
+ __ push_ptr(O1); // push exception for exception handler bytecodes
+
+ __ JMP(O0, 0); // jump to exception handler (may be remove activation entry!)
+ __ delayed()->nop();
+
+
+ // if the exception is not handled in the current frame
+ // the frame is removed and the exception is rethrown
+ // (i.e. exception continuation is _rethrow_exception)
+ //
+ // Note: At this point the bci is still the bxi for the instruction which caused
+ // the exception and the expression stack is empty. Thus, for any VM calls
+ // at this point, GC will find a legal oop map (with empty expression stack).
+
+ // in current activation
+ // tos: exception
+ // Lbcp: exception bcp
+
+ //
+ // JVMTI PopFrame support
+ //
+
+ Interpreter::_remove_activation_preserving_args_entry = __ pc();
+ Address popframe_condition_addr(G2_thread, JavaThread::popframe_condition_offset());
+ // Set the popframe_processing bit in popframe_condition indicating that we are
+ // currently handling popframe, so that call_VMs that may happen later do not trigger new
+ // popframe handling cycles.
+
+ __ ld(popframe_condition_addr, G3_scratch);
+ __ or3(G3_scratch, JavaThread::popframe_processing_bit, G3_scratch);
+ __ stw(G3_scratch, popframe_condition_addr);
+
+ // Empty the expression stack, as in normal exception handling
+ __ empty_expression_stack();
+ __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, /* install_monitor_exception */ false);
+
+ {
+ // Check to see whether we are returning to a deoptimized frame.
+ // (The PopFrame call ensures that the caller of the popped frame is
+ // either interpreted or compiled and deoptimizes it if compiled.)
+ // In this case, we can't call dispatch_next() after the frame is
+ // popped, but instead must save the incoming arguments and restore
+ // them after deoptimization has occurred.
+ //
+ // Note that we don't compare the return PC against the
+ // deoptimization blob's unpack entry because of the presence of
+ // adapter frames in C2.
+ Label caller_not_deoptimized;
+ __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), I7);
+ __ br_notnull_short(O0, Assembler::pt, caller_not_deoptimized);
+
+ const Register Gtmp1 = G3_scratch;
+ const Register Gtmp2 = G1_scratch;
+ const Register RconstMethod = Gtmp1;
+ const Address constMethod(Lmethod, Method::const_offset());
+ const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
+
+ // Compute size of arguments for saving when returning to deoptimized caller
+ __ ld_ptr(constMethod, RconstMethod);
+ __ lduh(size_of_parameters, Gtmp1);
+ __ sll(Gtmp1, Interpreter::logStackElementSize, Gtmp1);
+ __ sub(Llocals, Gtmp1, Gtmp2);
+ __ add(Gtmp2, wordSize, Gtmp2);
+ // Save these arguments
+ __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), G2_thread, Gtmp1, Gtmp2);
+ // Inform deoptimization that it is responsible for restoring these arguments
+ __ set(JavaThread::popframe_force_deopt_reexecution_bit, Gtmp1);
+ Address popframe_condition_addr(G2_thread, JavaThread::popframe_condition_offset());
+ __ st(Gtmp1, popframe_condition_addr);
+
+ // Return from the current method
+ // The caller's SP was adjusted upon method entry to accomodate
+ // the callee's non-argument locals. Undo that adjustment.
+ __ ret();
+ __ delayed()->restore(I5_savedSP, G0, SP);
+
+ __ bind(caller_not_deoptimized);
+ }
+
+ // Clear the popframe condition flag
+ __ stw(G0 /* popframe_inactive */, popframe_condition_addr);
+
+ // Get out of the current method (how this is done depends on the particular compiler calling
+ // convention that the interpreter currently follows)
+ // The caller's SP was adjusted upon method entry to accomodate
+ // the callee's non-argument locals. Undo that adjustment.
+ __ restore(I5_savedSP, G0, SP);
+ // The method data pointer was incremented already during
+ // call profiling. We have to restore the mdp for the current bcp.
+ if (ProfileInterpreter) {
+ __ set_method_data_pointer_for_bcp();
+ }
+
+#if INCLUDE_JVMTI
+ {
+ Label L_done;
+
+ __ ldub(Address(Lbcp, 0), G1_scratch); // Load current bytecode
+ __ cmp_and_br_short(G1_scratch, Bytecodes::_invokestatic, Assembler::notEqual, Assembler::pn, L_done);
+
+ // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
+ // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
+
+ __ call_VM(G1_scratch, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), I0, Lmethod, Lbcp);
+
+ __ br_null(G1_scratch, false, Assembler::pn, L_done);
+ __ delayed()->nop();
+
+ __ st_ptr(G1_scratch, Lesp, wordSize);
+ __ bind(L_done);
+ }
+#endif // INCLUDE_JVMTI
+
+ // Resume bytecode interpretation at the current bcp
+ __ dispatch_next(vtos);
+ // end of JVMTI PopFrame support
+
+ Interpreter::_remove_activation_entry = __ pc();
+
+ // preserve exception over this code sequence (remove activation calls the vm, but oopmaps are not correct here)
+ __ pop_ptr(Oexception); // get exception
+
+ // Intel has the following comment:
+ //// remove the activation (without doing throws on illegalMonitorExceptions)
+ // They remove the activation without checking for bad monitor state.
+ // %%% We should make sure this is the right semantics before implementing.
+
+ __ set_vm_result(Oexception);
+ __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false);
+
+ __ notify_method_exit(false, vtos, InterpreterMacroAssembler::SkipNotifyJVMTI);
+
+ __ get_vm_result(Oexception);
+ __ verify_oop(Oexception);
+
+ const int return_reg_adjustment = frame::pc_return_offset;
+ Address issuing_pc_addr(I7, return_reg_adjustment);
+
+ // We are done with this activation frame; find out where to go next.
+ // The continuation point will be an exception handler, which expects
+ // the following registers set up:
+ //
+ // Oexception: exception
+ // Oissuing_pc: the local call that threw exception
+ // Other On: garbage
+ // In/Ln: the contents of the caller's register window
+ //
+ // We do the required restore at the last possible moment, because we
+ // need to preserve some state across a runtime call.
+ // (Remember that the caller activation is unknown--it might not be
+ // interpreted, so things like Lscratch are useless in the caller.)
+
+ // Although the Intel version uses call_C, we can use the more
+ // compact call_VM. (The only real difference on SPARC is a
+ // harmlessly ignored [re]set_last_Java_frame, compared with
+ // the Intel code which lacks this.)
+ __ mov(Oexception, Oexception ->after_save()); // get exception in I0 so it will be on O0 after restore
+ __ add(issuing_pc_addr, Oissuing_pc->after_save()); // likewise set I1 to a value local to the caller
+ __ super_call_VM_leaf(L7_thread_cache,
+ CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
+ G2_thread, Oissuing_pc->after_save());
+
+ // The caller's SP was adjusted upon method entry to accomodate
+ // the callee's non-argument locals. Undo that adjustment.
+ __ JMP(O0, 0); // return exception handler in caller
+ __ delayed()->restore(I5_savedSP, G0, SP);
+
+ // (same old exception object is already in Oexception; see above)
+ // Note that an "issuing PC" is actually the next PC after the call
+}
+
+
+//
+// JVMTI ForceEarlyReturn support
+//
+
+address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
+ address entry = __ pc();
+
+ __ empty_expression_stack();
+ __ load_earlyret_value(state);
+
+ __ ld_ptr(G2_thread, JavaThread::jvmti_thread_state_offset(), G3_scratch);
+ Address cond_addr(G3_scratch, JvmtiThreadState::earlyret_state_offset());
+
+ // Clear the earlyret state
+ __ stw(G0 /* JvmtiThreadState::earlyret_inactive */, cond_addr);
+
+ __ remove_activation(state,
+ /* throw_monitor_exception */ false,
+ /* install_monitor_exception */ false);
+
+ // The caller's SP was adjusted upon method entry to accomodate
+ // the callee's non-argument locals. Undo that adjustment.
+ __ ret(); // return to caller
+ __ delayed()->restore(I5_savedSP, G0, SP);
+
+ return entry;
+} // end of JVMTI ForceEarlyReturn support
+
+
+//------------------------------------------------------------------------------------------------------------------------
+// Helper for vtos entry point generation
+
+void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) {
+ assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
+ Label L;
+ aep = __ pc(); __ push_ptr(); __ ba_short(L);
+ fep = __ pc(); __ push_f(); __ ba_short(L);
+ dep = __ pc(); __ push_d(); __ ba_short(L);
+ lep = __ pc(); __ push_l(); __ ba_short(L);
+ iep = __ pc(); __ push_i();
+ bep = cep = sep = iep; // there aren't any
+ vep = __ pc(); __ bind(L); // fall through
+ generate_and_dispatch(t);
+}
+
+// --------------------------------------------------------------------------------
+
+
+InterpreterGenerator::InterpreterGenerator(StubQueue* code)
+ : TemplateInterpreterGenerator(code) {
+ generate_all(); // down here so it can be "virtual"
+}
+
+// --------------------------------------------------------------------------------
+
+// Non-product code
+#ifndef PRODUCT
+address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
+ address entry = __ pc();
+
+ __ push(state);
+ __ mov(O7, Lscratch); // protect return address within interpreter
+
+ // Pass a 0 (not used in sparc) and the top of stack to the bytecode tracer
+ __ mov( Otos_l2, G3_scratch );
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), G0, Otos_l1, G3_scratch);
+ __ mov(Lscratch, O7); // restore return address
+ __ pop(state);
+ __ retl();
+ __ delayed()->nop();
+
+ return entry;
+}
+
+
+// helpers for generate_and_dispatch
+
+void TemplateInterpreterGenerator::count_bytecode() {
+ __ inc_counter(&BytecodeCounter::_counter_value, G3_scratch, G4_scratch);
+}
+
+
+void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
+ __ inc_counter(&BytecodeHistogram::_counters[t->bytecode()], G3_scratch, G4_scratch);
+}
+
+
+void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) {
+ AddressLiteral index (&BytecodePairHistogram::_index);
+ AddressLiteral counters((address) &BytecodePairHistogram::_counters);
+
+ // get index, shift out old bytecode, bring in new bytecode, and store it
+ // _index = (_index >> log2_number_of_codes) |
+ // (bytecode << log2_number_of_codes);
+
+ __ load_contents(index, G4_scratch);
+ __ srl( G4_scratch, BytecodePairHistogram::log2_number_of_codes, G4_scratch );
+ __ set( ((int)t->bytecode()) << BytecodePairHistogram::log2_number_of_codes, G3_scratch );
+ __ or3( G3_scratch, G4_scratch, G4_scratch );
+ __ store_contents(G4_scratch, index, G3_scratch);
+
+ // bump bucket contents
+ // _counters[_index] ++;
+
+ __ set(counters, G3_scratch); // loads into G3_scratch
+ __ sll( G4_scratch, LogBytesPerWord, G4_scratch ); // Index is word address
+ __ add (G3_scratch, G4_scratch, G3_scratch); // Add in index
+ __ ld (G3_scratch, 0, G4_scratch);
+ __ inc (G4_scratch);
+ __ st (G4_scratch, 0, G3_scratch);
+}
+
+
+void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
+ // Call a little run-time stub to avoid blow-up for each bytecode.
+ // The run-time runtime saves the right registers, depending on
+ // the tosca in-state for the given template.
+ address entry = Interpreter::trace_code(t->tos_in());
+ guarantee(entry != NULL, "entry must have been generated");
+ __ call(entry, relocInfo::none);
+ __ delayed()->nop();
+}
+
+
+void TemplateInterpreterGenerator::stop_interpreter_at() {
+ AddressLiteral counter(&BytecodeCounter::_counter_value);
+ __ load_contents(counter, G3_scratch);
+ AddressLiteral stop_at(&StopInterpreterAt);
+ __ load_ptr_contents(stop_at, G4_scratch);
+ __ cmp(G3_scratch, G4_scratch);
+ __ breakpoint_trap(Assembler::equal, Assembler::icc);
+}
+#endif // not PRODUCT
+#endif // !CC_INTERP
--- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -23,1483 +23,39 @@
*/
#include "precompiled.hpp"
-#include "asm/macroAssembler.hpp"
-#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterGenerator.hpp"
-#include "interpreter/interpreterRuntime.hpp"
-#include "interpreter/interp_masm.hpp"
-#include "interpreter/templateTable.hpp"
-#include "oops/arrayOop.hpp"
-#include "oops/methodData.hpp"
+#include "oops/constMethod.hpp"
#include "oops/method.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/jvmtiExport.hpp"
-#include "prims/jvmtiThreadState.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.hpp"
-#include "runtime/timer.hpp"
-#include "runtime/vframeArray.hpp"
-#include "utilities/debug.hpp"
#include "utilities/macros.hpp"
-#ifndef CC_INTERP
-#ifndef FAST_DISPATCH
-#define FAST_DISPATCH 1
-#endif
-#undef FAST_DISPATCH
-
-
-// Generation of Interpreter
-//
-// The InterpreterGenerator generates the interpreter into Interpreter::_code.
-
-
-#define __ _masm->
-
-
-//----------------------------------------------------------------------------------------------------
-
-
-void InterpreterGenerator::save_native_result(void) {
- // result potentially in O0/O1: save it across calls
- const Address& l_tmp = InterpreterMacroAssembler::l_tmp;
-
- // result potentially in F0/F1: save it across calls
- const Address& d_tmp = InterpreterMacroAssembler::d_tmp;
-
- // save and restore any potential method result value around the unlocking operation
- __ stf(FloatRegisterImpl::D, F0, d_tmp);
-#ifdef _LP64
- __ stx(O0, l_tmp);
-#else
- __ std(O0, l_tmp);
-#endif
-}
-
-void InterpreterGenerator::restore_native_result(void) {
- const Address& l_tmp = InterpreterMacroAssembler::l_tmp;
- const Address& d_tmp = InterpreterMacroAssembler::d_tmp;
-
- // Restore any method result value
- __ ldf(FloatRegisterImpl::D, d_tmp, F0);
-#ifdef _LP64
- __ ldx(l_tmp, O0);
-#else
- __ ldd(l_tmp, O0);
-#endif
-}
-
-address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
- assert(!pass_oop || message == NULL, "either oop or message but not both");
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an exception happened
- __ empty_expression_stack();
- // load exception object
- __ set((intptr_t)name, G3_scratch);
- if (pass_oop) {
- __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), G3_scratch, Otos_i);
- } else {
- __ set((intptr_t)message, G4_scratch);
- __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), G3_scratch, G4_scratch);
- }
- // throw exception
- assert(Interpreter::throw_exception_entry() != NULL, "generate it first");
- AddressLiteral thrower(Interpreter::throw_exception_entry());
- __ jump_to(thrower, G3_scratch);
- __ delayed()->nop();
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an exception
- // happened
- __ empty_expression_stack();
- // load exception object
- __ call_VM(Oexception,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_ClassCastException),
- Otos_i);
- __ should_not_reach_here();
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an exception happened
- __ empty_expression_stack();
- // convention: expect aberrant index in register G3_scratch, then shuffle the
- // index to G4_scratch for the VM call
- __ mov(G3_scratch, G4_scratch);
- __ set((intptr_t)name, G3_scratch);
- __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException), G3_scratch, G4_scratch);
- __ should_not_reach_here();
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an exception happened
- __ empty_expression_stack();
- __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_StackOverflowError));
- __ should_not_reach_here();
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
- address entry = __ pc();
-
- if (state == atos) {
- __ profile_return_type(O0, G3_scratch, G1_scratch);
- }
-
-#if !defined(_LP64) && defined(COMPILER2)
- // All return values are where we want them, except for Longs. C2 returns
- // longs in G1 in the 32-bit build whereas the interpreter wants them in O0/O1.
- // Since the interpreter will return longs in G1 and O0/O1 in the 32bit
- // build even if we are returning from interpreted we just do a little
- // stupid shuffing.
- // Note: I tried to make c2 return longs in O0/O1 and G1 so we wouldn't have to
- // do this here. Unfortunately if we did a rethrow we'd see an machepilog node
- // first which would move g1 -> O0/O1 and destroy the exception we were throwing.
-
- if (state == ltos) {
- __ srl (G1, 0, O1);
- __ srlx(G1, 32, O0);
- }
-#endif // !_LP64 && COMPILER2
-
- // The callee returns with the stack possibly adjusted by adapter transition
- // We remove that possible adjustment here.
- // All interpreter local registers are untouched. Any result is passed back
- // in the O0/O1 or float registers. Before continuing, the arguments must be
- // popped from the java expression stack; i.e., Lesp must be adjusted.
-
- __ mov(Llast_SP, SP); // Remove any adapter added stack space.
-
- const Register cache = G3_scratch;
- const Register index = G1_scratch;
- __ get_cache_and_index_at_bcp(cache, index, 1, index_size);
-
- const Register flags = cache;
- __ ld_ptr(cache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset(), flags);
- const Register parameter_size = flags;
- __ and3(flags, ConstantPoolCacheEntry::parameter_size_mask, parameter_size); // argument size in words
- __ sll(parameter_size, Interpreter::logStackElementSize, parameter_size); // each argument size in bytes
- __ add(Lesp, parameter_size, Lesp); // pop arguments
- __ dispatch_next(state, step);
-
- return entry;
-}
-
-
-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.
- __ br_null_short(Gtemp, Assembler::pt, L);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception));
- __ should_not_reach_here();
- __ bind(L);
- }
- __ dispatch_next(state, step);
- return entry;
-}
-
-// A result handler converts/unboxes a native call result into
-// a java interpreter/compiler result. The current frame is an
-// interpreter frame. The activation frame unwind code must be
-// consistent with that of TemplateTable::_return(...). In the
-// case of native methods, the caller's SP was not modified.
-address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) {
- address entry = __ pc();
- Register Itos_i = Otos_i ->after_save();
- Register Itos_l = Otos_l ->after_save();
- Register Itos_l1 = Otos_l1->after_save();
- Register Itos_l2 = Otos_l2->after_save();
- switch (type) {
- case T_BOOLEAN: __ subcc(G0, O0, G0); __ addc(G0, 0, Itos_i); break; // !0 => true; 0 => false
- case T_CHAR : __ sll(O0, 16, O0); __ srl(O0, 16, Itos_i); break; // cannot use and3, 0xFFFF too big as immediate value!
- case T_BYTE : __ sll(O0, 24, O0); __ sra(O0, 24, Itos_i); break;
- case T_SHORT : __ sll(O0, 16, O0); __ sra(O0, 16, Itos_i); break;
- case T_LONG :
-#ifndef _LP64
- __ mov(O1, Itos_l2); // move other half of long
-#endif // ifdef or no ifdef, fall through to the T_INT case
- case T_INT : __ mov(O0, Itos_i); break;
- case T_VOID : /* nothing to do */ break;
- case T_FLOAT : assert(F0 == Ftos_f, "fix this code" ); break;
- case T_DOUBLE : assert(F0 == Ftos_d, "fix this code" ); break;
- case T_OBJECT :
- __ ld_ptr(FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS, Itos_i);
- __ verify_oop(Itos_i);
- break;
- default : ShouldNotReachHere();
- }
- __ ret(); // return from interpreter activation
- __ delayed()->restore(I5_savedSP, G0, SP); // remove interpreter frame
- NOT_PRODUCT(__ emit_int32(0);) // marker for disassembly
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) {
- address entry = __ pc();
- __ push(state);
- __ call_VM(noreg, runtime_entry);
- __ dispatch_via(vtos, Interpreter::normal_table(vtos));
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
- address entry = __ pc();
- __ dispatch_next(state);
- return entry;
-}
-
-//
-// Helpers for commoning out cases in the various type of method entries.
-//
-
-// increment invocation count & check for overflow
-//
-// Note: checking for negative value instead of overflow
-// so we have a 'sticky' overflow test
-//
-// Lmethod: method
-// ??: invocation counter
-//
-void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) {
- // Note: In tiered we increment either counters in MethodCounters* or in
- // MDO depending if we're profiling or not.
- const Register G3_method_counters = G3_scratch;
- Label done;
-
- if (TieredCompilation) {
- const int increment = InvocationCounter::count_increment;
- Label no_mdo;
- if (ProfileInterpreter) {
- // If no method data exists, go to profile_continue.
- __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch);
- __ br_null_short(G4_scratch, Assembler::pn, no_mdo);
- // Increment counter
- Address mdo_invocation_counter(G4_scratch,
- in_bytes(MethodData::invocation_counter_offset()) +
- in_bytes(InvocationCounter::counter_offset()));
- Address mask(G4_scratch, in_bytes(MethodData::invoke_mask_offset()));
- __ increment_mask_and_jump(mdo_invocation_counter, increment, mask,
- G3_scratch, Lscratch,
- Assembler::zero, overflow);
- __ ba_short(done);
- }
-
- // Increment counter in MethodCounters*
- __ bind(no_mdo);
- Address invocation_counter(G3_method_counters,
- in_bytes(MethodCounters::invocation_counter_offset()) +
- in_bytes(InvocationCounter::counter_offset()));
- __ get_method_counters(Lmethod, G3_method_counters, done);
- Address mask(G3_method_counters, in_bytes(MethodCounters::invoke_mask_offset()));
- __ increment_mask_and_jump(invocation_counter, increment, mask,
- G4_scratch, Lscratch,
- Assembler::zero, overflow);
- __ bind(done);
- } else { // not TieredCompilation
- // Update standard invocation counters
- __ get_method_counters(Lmethod, G3_method_counters, done);
- __ increment_invocation_counter(G3_method_counters, O0, G4_scratch);
- if (ProfileInterpreter) {
- Address interpreter_invocation_counter(G3_method_counters,
- in_bytes(MethodCounters::interpreter_invocation_counter_offset()));
- __ ld(interpreter_invocation_counter, G4_scratch);
- __ inc(G4_scratch);
- __ st(G4_scratch, interpreter_invocation_counter);
- }
-
- if (ProfileInterpreter && profile_method != NULL) {
- // Test to see if we should create a method data oop
- Address profile_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_profile_limit_offset()));
- __ ld(profile_limit, G1_scratch);
- __ cmp_and_br_short(O0, G1_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue);
-
- // if no method data exists, go to profile_method
- __ test_method_data_pointer(*profile_method);
- }
-
- Address invocation_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_limit_offset()));
- __ ld(invocation_limit, G3_scratch);
- __ cmp(O0, G3_scratch);
- __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); // Far distance
- __ delayed()->nop();
- __ bind(done);
- }
-
-}
-
-// Allocate monitor and lock method (asm interpreter)
-// ebx - Method*
-//
-void TemplateInterpreterGenerator::lock_method() {
- __ ld(Lmethod, in_bytes(Method::access_flags_offset()), O0); // Load access flags.
-
-#ifdef ASSERT
- { Label ok;
- __ btst(JVM_ACC_SYNCHRONIZED, O0);
- __ br( Assembler::notZero, false, Assembler::pt, ok);
- __ delayed()->nop();
- __ stop("method doesn't need synchronization");
- __ bind(ok);
- }
-#endif // ASSERT
-
- // get synchronization object to O0
- { Label done;
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- __ btst(JVM_ACC_STATIC, O0);
- __ br( Assembler::zero, true, Assembler::pt, done);
- __ delayed()->ld_ptr(Llocals, Interpreter::local_offset_in_bytes(0), O0); // get receiver for not-static case
-
- __ ld_ptr( Lmethod, in_bytes(Method::const_offset()), O0);
- __ ld_ptr( O0, in_bytes(ConstMethod::constants_offset()), O0);
- __ ld_ptr( O0, ConstantPool::pool_holder_offset_in_bytes(), O0);
-
- // lock the mirror, not the Klass*
- __ ld_ptr( O0, mirror_offset, O0);
-
-#ifdef ASSERT
- __ tst(O0);
- __ breakpoint_trap(Assembler::zero, Assembler::ptr_cc);
-#endif // ASSERT
-
- __ bind(done);
+int AbstractInterpreter::BasicType_as_index(BasicType type) {
+ int i = 0;
+ switch (type) {
+ case T_BOOLEAN: i = 0; break;
+ case T_CHAR : i = 1; break;
+ case T_BYTE : i = 2; break;
+ case T_SHORT : i = 3; break;
+ case T_INT : i = 4; break;
+ case T_LONG : i = 5; break;
+ case T_VOID : i = 6; break;
+ case T_FLOAT : i = 7; break;
+ case T_DOUBLE : i = 8; break;
+ case T_OBJECT : i = 9; break;
+ case T_ARRAY : i = 9; break;
+ default : ShouldNotReachHere();
}
-
- __ add_monitor_to_stack(true, noreg, noreg); // allocate monitor elem
- __ st_ptr( O0, Lmonitors, BasicObjectLock::obj_offset_in_bytes()); // store object
- // __ untested("lock_object from method entry");
- __ lock_object(Lmonitors, O0);
-}
-
-
-void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rframe_size,
- Register Rscratch,
- Register Rscratch2) {
- const int page_size = os::vm_page_size();
- Label after_frame_check;
-
- assert_different_registers(Rframe_size, Rscratch, Rscratch2);
-
- __ set(page_size, Rscratch);
- __ cmp_and_br_short(Rframe_size, Rscratch, Assembler::lessEqual, Assembler::pt, after_frame_check);
-
- // get the stack base, and in debug, verify it is non-zero
- __ ld_ptr( G2_thread, Thread::stack_base_offset(), Rscratch );
-#ifdef ASSERT
- Label base_not_zero;
- __ br_notnull_short(Rscratch, Assembler::pn, base_not_zero);
- __ stop("stack base is zero in generate_stack_overflow_check");
- __ bind(base_not_zero);
-#endif
-
- // get the stack size, and in debug, verify it is non-zero
- assert( sizeof(size_t) == sizeof(intptr_t), "wrong load size" );
- __ ld_ptr( G2_thread, Thread::stack_size_offset(), Rscratch2 );
-#ifdef ASSERT
- Label size_not_zero;
- __ br_notnull_short(Rscratch2, Assembler::pn, size_not_zero);
- __ stop("stack size is zero in generate_stack_overflow_check");
- __ bind(size_not_zero);
-#endif
-
- // compute the beginning of the protected zone minus the requested frame size
- __ sub( Rscratch, Rscratch2, Rscratch );
- __ set( (StackRedPages+StackYellowPages) * page_size, Rscratch2 );
- __ add( Rscratch, Rscratch2, Rscratch );
-
- // Add in the size of the frame (which is the same as subtracting it from the
- // SP, which would take another register
- __ add( Rscratch, Rframe_size, Rscratch );
-
- // the frame is greater than one page in size, so check against
- // the bottom of the stack
- __ cmp_and_brx_short(SP, Rscratch, Assembler::greaterUnsigned, Assembler::pt, after_frame_check);
-
- // the stack will overflow, throw an exception
-
- // Note that SP is restored to sender's sp (in the delay slot). This
- // is necessary if the sender's frame is an extended compiled frame
- // (see gen_c2i_adapter()) and safer anyway in case of JSR292
- // adaptations.
-
- // Note also that the restored frame is not necessarily interpreted.
- // Use the shared runtime version of the StackOverflowError.
- assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "stub not yet generated");
- AddressLiteral stub(StubRoutines::throw_StackOverflowError_entry());
- __ jump_to(stub, Rscratch);
- __ delayed()->mov(O5_savedSP, SP);
-
- // if you get to here, then there is enough stack space
- __ bind( after_frame_check );
-}
-
-
-//
-// Generate a fixed interpreter frame. This is identical setup for interpreted
-// methods and for native methods hence the shared code.
-
-
-//----------------------------------------------------------------------------------------------------
-// Stack frame layout
-//
-// When control flow reaches any of the entry types for the interpreter
-// the following holds ->
-//
-// C2 Calling Conventions:
-//
-// The entry code below assumes that the following registers are set
-// when coming in:
-// G5_method: holds the Method* of the method to call
-// Lesp: points to the TOS of the callers expression stack
-// after having pushed all the parameters
-//
-// The entry code does the following to setup an interpreter frame
-// pop parameters from the callers stack by adjusting Lesp
-// set O0 to Lesp
-// compute X = (max_locals - num_parameters)
-// bump SP up by X to accomadate the extra locals
-// compute X = max_expression_stack
-// + vm_local_words
-// + 16 words of register save area
-// save frame doing a save sp, -X, sp growing towards lower addresses
-// set Lbcp, Lmethod, LcpoolCache
-// set Llocals to i0
-// set Lmonitors to FP - rounded_vm_local_words
-// set Lesp to Lmonitors - 4
-//
-// The frame has now been setup to do the rest of the entry code
-
-// Try this optimization: Most method entries could live in a
-// "one size fits all" stack frame without all the dynamic size
-// calculations. It might be profitable to do all this calculation
-// statically and approximately for "small enough" methods.
-
-//-----------------------------------------------------------------------------------------------
-
-// C1 Calling conventions
-//
-// Upon method entry, the following registers are setup:
-//
-// g2 G2_thread: current thread
-// g5 G5_method: method to activate
-// g4 Gargs : pointer to last argument
-//
-//
-// Stack:
-//
-// +---------------+ <--- sp
-// | |
-// : reg save area :
-// | |
-// +---------------+ <--- sp + 0x40
-// | |
-// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later)
-// | |
-// +---------------+ <--- sp + 0x5c
-// | |
-// : free :
-// | |
-// +---------------+ <--- Gargs
-// | |
-// : arguments :
-// | |
-// +---------------+
-// | |
-//
-//
-//
-// AFTER FRAME HAS BEEN SETUP for method interpretation the stack looks like:
-//
-// +---------------+ <--- sp
-// | |
-// : reg save area :
-// | |
-// +---------------+ <--- sp + 0x40
-// | |
-// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later)
-// | |
-// +---------------+ <--- sp + 0x5c
-// | |
-// : :
-// | | <--- Lesp
-// +---------------+ <--- Lmonitors (fp - 0x18)
-// | VM locals |
-// +---------------+ <--- fp
-// | |
-// : reg save area :
-// | |
-// +---------------+ <--- fp + 0x40
-// | |
-// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later)
-// | |
-// +---------------+ <--- fp + 0x5c
-// | |
-// : free :
-// | |
-// +---------------+
-// | |
-// : nonarg locals :
-// | |
-// +---------------+
-// | |
-// : arguments :
-// | | <--- Llocals
-// +---------------+ <--- Gargs
-// | |
-
-void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
- //
- //
- // The entry code sets up a new interpreter frame in 4 steps:
- //
- // 1) Increase caller's SP by for the extra local space needed:
- // (check for overflow)
- // Efficient implementation of xload/xstore bytecodes requires
- // that arguments and non-argument locals are in a contigously
- // addressable memory block => non-argument locals must be
- // allocated in the caller's frame.
- //
- // 2) Create a new stack frame and register window:
- // The new stack frame must provide space for the standard
- // register save area, the maximum java expression stack size,
- // the monitor slots (0 slots initially), and some frame local
- // scratch locations.
- //
- // 3) The following interpreter activation registers must be setup:
- // Lesp : expression stack pointer
- // Lbcp : bytecode pointer
- // Lmethod : method
- // Llocals : locals pointer
- // Lmonitors : monitor pointer
- // LcpoolCache: constant pool cache
- //
- // 4) Initialize the non-argument locals if necessary:
- // Non-argument locals may need to be initialized to NULL
- // for GC to work. If the oop-map information is accurate
- // (in the absence of the JSR problem), no initialization
- // is necessary.
- //
- // (gri - 2/25/2000)
-
-
- int rounded_vm_local_words = round_to( frame::interpreter_frame_vm_local_words, WordsPerLong );
-
- const int extra_space =
- rounded_vm_local_words + // frame local scratch space
- Method::extra_stack_entries() + // extra stack for jsr 292
- frame::memory_parameter_word_sp_offset + // register save area
- (native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0);
-
- const Register Glocals_size = G3;
- const Register RconstMethod = Glocals_size;
- const Register Otmp1 = O3;
- const Register Otmp2 = O4;
- // Lscratch can't be used as a temporary because the call_stub uses
- // it to assert that the stack frame was setup correctly.
- const Address constMethod (G5_method, Method::const_offset());
- const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
-
- __ ld_ptr( constMethod, RconstMethod );
- __ lduh( size_of_parameters, Glocals_size);
-
- // Gargs points to first local + BytesPerWord
- // Set the saved SP after the register window save
- //
- assert_different_registers(Gargs, Glocals_size, Gframe_size, O5_savedSP);
- __ sll(Glocals_size, Interpreter::logStackElementSize, Otmp1);
- __ add(Gargs, Otmp1, Gargs);
-
- if (native_call) {
- __ calc_mem_param_words( Glocals_size, Gframe_size );
- __ add( Gframe_size, extra_space, Gframe_size);
- __ round_to( Gframe_size, WordsPerLong );
- __ sll( Gframe_size, LogBytesPerWord, Gframe_size );
- } else {
-
- //
- // Compute number of locals in method apart from incoming parameters
- //
- const Address size_of_locals (Otmp1, ConstMethod::size_of_locals_offset());
- __ ld_ptr( constMethod, Otmp1 );
- __ lduh( size_of_locals, Otmp1 );
- __ sub( Otmp1, Glocals_size, Glocals_size );
- __ round_to( Glocals_size, WordsPerLong );
- __ sll( Glocals_size, Interpreter::logStackElementSize, Glocals_size );
-
- // see if the frame is greater than one page in size. If so,
- // then we need to verify there is enough stack space remaining
- // Frame_size = (max_stack + extra_space) * BytesPerWord;
- __ ld_ptr( constMethod, Gframe_size );
- __ lduh( Gframe_size, in_bytes(ConstMethod::max_stack_offset()), Gframe_size );
- __ add( Gframe_size, extra_space, Gframe_size );
- __ round_to( Gframe_size, WordsPerLong );
- __ sll( Gframe_size, Interpreter::logStackElementSize, Gframe_size);
-
- // Add in java locals size for stack overflow check only
- __ add( Gframe_size, Glocals_size, Gframe_size );
-
- const Register Otmp2 = O4;
- assert_different_registers(Otmp1, Otmp2, O5_savedSP);
- generate_stack_overflow_check(Gframe_size, Otmp1, Otmp2);
-
- __ sub( Gframe_size, Glocals_size, Gframe_size);
-
- //
- // bump SP to accomodate the extra locals
- //
- __ sub( SP, Glocals_size, SP );
- }
-
- //
- // now set up a stack frame with the size computed above
- //
- __ neg( Gframe_size );
- __ save( SP, Gframe_size, SP );
-
- //
- // now set up all the local cache registers
- //
- // NOTE: At this point, Lbyte_code/Lscratch has been modified. Note
- // that all present references to Lbyte_code initialize the register
- // immediately before use
- if (native_call) {
- __ mov(G0, Lbcp);
- } else {
- __ ld_ptr(G5_method, Method::const_offset(), Lbcp);
- __ add(Lbcp, in_bytes(ConstMethod::codes_offset()), Lbcp);
- }
- __ mov( G5_method, Lmethod); // set Lmethod
- __ get_constant_pool_cache( LcpoolCache ); // set LcpoolCache
- __ sub(FP, rounded_vm_local_words * BytesPerWord, Lmonitors ); // set Lmonitors
-#ifdef _LP64
- __ add( Lmonitors, STACK_BIAS, Lmonitors ); // Account for 64 bit stack bias
-#endif
- __ sub(Lmonitors, BytesPerWord, Lesp); // set Lesp
-
- // setup interpreter activation registers
- __ sub(Gargs, BytesPerWord, Llocals); // set Llocals
-
- if (ProfileInterpreter) {
-#ifdef FAST_DISPATCH
- // FAST_DISPATCH and ProfileInterpreter are mutually exclusive since
- // they both use I2.
- assert(0, "FAST_DISPATCH and +ProfileInterpreter are mutually exclusive");
-#endif // FAST_DISPATCH
- __ set_method_data_pointer();
- }
-
+ assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds");
+ return i;
}
-// Method entry for java.lang.ref.Reference.get.
-address InterpreterGenerator::generate_Reference_get_entry(void) {
-#if INCLUDE_ALL_GCS
- // Code: _aload_0, _getfield, _areturn
- // parameter size = 1
- //
- // The code that gets generated by this routine is split into 2 parts:
- // 1. The "intrinsified" code for G1 (or any SATB based GC),
- // 2. The slow path - which is an expansion of the regular method entry.
- //
- // Notes:-
- // * In the G1 code we do not check whether we need to block for
- // a safepoint. If G1 is enabled then we must execute the specialized
- // code for Reference.get (except when the Reference object is null)
- // so that we can log the value in the referent field with an SATB
- // update buffer.
- // If the code for the getfield template is modified so that the
- // G1 pre-barrier code is executed when the current method is
- // Reference.get() then going through the normal method entry
- // will be fine.
- // * The G1 code can, however, check the receiver object (the instance
- // of java.lang.Reference) and jump to the slow path if null. If the
- // Reference object is null then we obviously cannot fetch the referent
- // and so we don't need to call the G1 pre-barrier. Thus we can use the
- // regular method entry code to generate the NPE.
- //
- // This code is based on generate_accessor_enty.
-
- 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;
-
- // In the G1 code we don't check if we need to reach a safepoint. We
- // continue and the thread will safepoint at the next bytecode dispatch.
-
- // Check if local 0 != NULL
- // If the receiver is null then it is OK to jump to the slow path.
- __ ld_ptr(Gargs, G0, Otos_i ); // get local 0
- // check if local 0 == NULL and go the slow path
- __ cmp_and_brx_short(Otos_i, 0, Assembler::equal, Assembler::pn, slow_path);
-
-
- // Load the value of the referent field.
- if (Assembler::is_simm13(referent_offset)) {
- __ load_heap_oop(Otos_i, referent_offset, Otos_i);
- } else {
- __ set(referent_offset, G3_scratch);
- __ load_heap_oop(Otos_i, G3_scratch, Otos_i);
- }
-
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer. Note with
- // these parameters the pre-barrier does not generate
- // the load of the previous value
-
- __ g1_write_barrier_pre(noreg /* obj */, noreg /* index */, 0 /* offset */,
- Otos_i /* pre_val */,
- G3_scratch /* tmp */,
- true /* preserve_o_regs */);
-
- // _areturn
- __ retl(); // return from leaf routine
- __ delayed()->mov(O5_savedSP, SP);
-
- // Generate regular method entry
- __ bind(slow_path);
- __ 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 NULL;
-}
-
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.update(int crc, int b)
- */
-address InterpreterGenerator::generate_CRC32_update_entry() {
-
- if (UseCRC32Intrinsics) {
- address entry = __ pc();
-
- Label L_slow_path;
- // If we need a safepoint check, generate full interpreter entry.
- ExternalAddress state(SafepointSynchronize::address_of_state());
- __ set(ExternalAddress(SafepointSynchronize::address_of_state()), O2);
- __ set(SafepointSynchronize::_not_synchronized, O3);
- __ cmp_and_br_short(O2, O3, Assembler::notEqual, Assembler::pt, L_slow_path);
-
- // Load parameters
- const Register crc = O0; // initial crc
- const Register val = O1; // byte to update with
- const Register table = O2; // address of 256-entry lookup table
-
- __ ldub(Gargs, 3, val);
- __ lduw(Gargs, 8, crc);
-
- __ set(ExternalAddress(StubRoutines::crc_table_addr()), table);
-
- __ not1(crc); // ~crc
- __ clruwu(crc);
- __ update_byte_crc32(crc, val, table);
- __ not1(crc); // ~crc
-
- // result in O0
- __ retl();
- __ delayed()->nop();
-
- // generate a vanilla native entry as the slow path
- __ bind(L_slow_path);
- __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native));
- return entry;
- }
- return NULL;
-}
-
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len)
- * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len)
- */
-address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
-
- if (UseCRC32Intrinsics) {
- address entry = __ pc();
-
- Label L_slow_path;
- // If we need a safepoint check, generate full interpreter entry.
- ExternalAddress state(SafepointSynchronize::address_of_state());
- __ set(ExternalAddress(SafepointSynchronize::address_of_state()), O2);
- __ set(SafepointSynchronize::_not_synchronized, O3);
- __ cmp_and_br_short(O2, O3, Assembler::notEqual, Assembler::pt, L_slow_path);
-
- // Load parameters from the stack
- const Register crc = O0; // initial crc
- const Register buf = O1; // source java byte array address
- const Register len = O2; // len
- const Register offset = O3; // offset
-
- // Arguments are reversed on java expression stack
- // Calculate address of start element
- if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) {
- __ lduw(Gargs, 0, len);
- __ lduw(Gargs, 8, offset);
- __ ldx( Gargs, 16, buf);
- __ lduw(Gargs, 32, crc);
- __ add(buf, offset, buf);
- } else {
- __ lduw(Gargs, 0, len);
- __ lduw(Gargs, 8, offset);
- __ ldx( Gargs, 16, buf);
- __ lduw(Gargs, 24, crc);
- __ add(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE), buf); // account for the header size
- __ add(buf ,offset, buf);
- }
-
- // Call the crc32 kernel
- __ MacroAssembler::save_thread(L7_thread_cache);
- __ kernel_crc32(crc, buf, len, O3);
- __ MacroAssembler::restore_thread(L7_thread_cache);
-
- // result in O0
- __ retl();
- __ delayed()->nop();
-
- // generate a vanilla native entry as the slow path
- __ bind(L_slow_path);
- __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native));
- return entry;
- }
- return NULL;
-}
-
-//
-// Interpreter stub for calling a native method. (asm interpreter)
-// This sets up a somewhat different looking stack for calling the native method
-// than the typical interpreter frame setup.
-//
-
-address InterpreterGenerator::generate_native_entry(bool synchronized) {
- address entry = __ pc();
-
- // the following temporary registers are used during frame creation
- const Register Gtmp1 = G3_scratch ;
- const Register Gtmp2 = G1_scratch;
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // make sure registers are different!
- assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2);
-
- const Address Laccess_flags(Lmethod, Method::access_flags_offset());
-
- const Register Glocals_size = G3;
- assert_different_registers(Glocals_size, G4_scratch, Gframe_size);
-
- // make sure method is native & not abstract
- // rethink these assertions - they can be simplified and shared (gri 2/25/2000)
-#ifdef ASSERT
- __ ld(G5_method, Method::access_flags_offset(), Gtmp1);
- {
- Label L;
- __ btst(JVM_ACC_NATIVE, Gtmp1);
- __ br(Assembler::notZero, false, Assembler::pt, L);
- __ delayed()->nop();
- __ stop("tried to execute non-native method as native");
- __ bind(L);
- }
- { Label L;
- __ btst(JVM_ACC_ABSTRACT, Gtmp1);
- __ br(Assembler::zero, false, Assembler::pt, L);
- __ delayed()->nop();
- __ stop("tried to execute abstract method as non-abstract");
- __ bind(L);
- }
-#endif // ASSERT
-
- // generate the code to allocate the interpreter stack frame
- generate_fixed_frame(true);
-
- //
- // No locals to initialize for native method
- //
-
- // this slot will be set later, we initialize it to null here just in
- // case we get a GC before the actual value is stored later
- __ st_ptr(G0, FP, (frame::interpreter_frame_oop_temp_offset * wordSize) + STACK_BIAS);
-
- const Address do_not_unlock_if_synchronized(G2_thread,
- JavaThread::do_not_unlock_if_synchronized_offset());
- // Since at this point in the method invocation the exception handler
- // would try to exit the monitor of synchronized methods which hasn't
- // been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. If any exception was thrown by
- // runtime, exception handling i.e. unlock_if_synchronized_method will
- // check this thread local flag.
- // This flag has two effects, one is to force an unwind in the topmost
- // interpreter frame and not perform an unlock while doing so.
-
- __ movbool(true, G3_scratch);
- __ stbool(G3_scratch, do_not_unlock_if_synchronized);
-
- // increment invocation counter and check for overflow
- //
- // Note: checking for negative value instead of overflow
- // so we have a 'sticky' overflow test (may be of
- // importance as soon as we have true MT/MP)
- Label invocation_counter_overflow;
- Label Lcontinue;
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
-
- }
- __ bind(Lcontinue);
-
- bang_stack_shadow_pages(true);
-
- // reset the _do_not_unlock_if_synchronized flag
- __ stbool(G0, do_not_unlock_if_synchronized);
-
- // check for synchronized methods
- // Must happen AFTER invocation_counter check and stack overflow check,
- // so method is not locked if overflows.
-
- if (synchronized) {
- lock_method();
- } else {
-#ifdef ASSERT
- { Label ok;
- __ ld(Laccess_flags, O0);
- __ btst(JVM_ACC_SYNCHRONIZED, O0);
- __ br( Assembler::zero, false, Assembler::pt, ok);
- __ delayed()->nop();
- __ stop("method needs synchronization");
- __ bind(ok);
- }
-#endif // ASSERT
- }
-
-
- // start execution
- __ verify_thread();
-
- // JVMTI support
- __ notify_method_entry();
-
- // native call
-
- // (note that O0 is never an oop--at most it is a handle)
- // It is important not to smash any handles created by this call,
- // until any oop handle in O0 is dereferenced.
-
- // (note that the space for outgoing params is preallocated)
-
- // get signature handler
- { Label L;
- Address signature_handler(Lmethod, Method::signature_handler_offset());
- __ ld_ptr(signature_handler, G3_scratch);
- __ br_notnull_short(G3_scratch, Assembler::pt, L);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), Lmethod);
- __ ld_ptr(signature_handler, G3_scratch);
- __ bind(L);
- }
-
- // Push a new frame so that the args will really be stored in
- // Copy a few locals across so the new frame has the variables
- // we need but these values will be dead at the jni call and
- // therefore not gc volatile like the values in the current
- // frame (Lmethod in particular)
-
- // Flush the method pointer to the register save area
- __ st_ptr(Lmethod, SP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS);
- __ mov(Llocals, O1);
-
- // calculate where the mirror handle body is allocated in the interpreter frame:
- __ add(FP, (frame::interpreter_frame_oop_temp_offset * wordSize) + STACK_BIAS, O2);
-
- // Calculate current frame size
- __ sub(SP, FP, O3); // Calculate negative of current frame size
- __ save(SP, O3, SP); // Allocate an identical sized frame
-
- // Note I7 has leftover trash. Slow signature handler will fill it in
- // should we get there. Normal jni call will set reasonable last_Java_pc
- // below (and fix I7 so the stack trace doesn't have a meaningless frame
- // in it).
-
- // Load interpreter frame's Lmethod into same register here
-
- __ ld_ptr(FP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS, Lmethod);
-
- __ mov(I1, Llocals);
- __ mov(I2, Lscratch2); // save the address of the mirror
-
-
- // ONLY Lmethod and Llocals are valid here!
-
- // call signature handler, It will move the arg properly since Llocals in current frame
- // matches that in outer frame
-
- __ callr(G3_scratch, 0);
- __ delayed()->nop();
-
- // Result handler is in Lscratch
-
- // Reload interpreter frame's Lmethod since slow signature handler may block
- __ ld_ptr(FP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS, Lmethod);
-
- { Label not_static;
-
- __ ld(Laccess_flags, O0);
- __ btst(JVM_ACC_STATIC, O0);
- __ br( Assembler::zero, false, Assembler::pt, not_static);
- // get native function entry point(O0 is a good temp until the very end)
- __ delayed()->ld_ptr(Lmethod, in_bytes(Method::native_function_offset()), O0);
- // for static methods insert the mirror argument
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
-
- __ ld_ptr(Lmethod, Method:: const_offset(), O1);
- __ ld_ptr(O1, ConstMethod::constants_offset(), O1);
- __ ld_ptr(O1, ConstantPool::pool_holder_offset_in_bytes(), O1);
- __ ld_ptr(O1, mirror_offset, O1);
-#ifdef ASSERT
- if (!PrintSignatureHandlers) // do not dirty the output with this
- { Label L;
- __ br_notnull_short(O1, Assembler::pt, L);
- __ stop("mirror is missing");
- __ bind(L);
- }
-#endif // ASSERT
- __ st_ptr(O1, Lscratch2, 0);
- __ mov(Lscratch2, O1);
- __ bind(not_static);
- }
-
- // At this point, arguments have been copied off of stack into
- // their JNI positions, which are O1..O5 and SP[68..].
- // Oops are boxed in-place on the stack, with handles copied to arguments.
- // The result handler is in Lscratch. O0 will shortly hold the JNIEnv*.
-
-#ifdef ASSERT
- { Label L;
- __ br_notnull_short(O0, Assembler::pt, L);
- __ stop("native entry point is missing");
- __ bind(L);
- }
-#endif // ASSERT
-
- //
- // setup the frame anchor
- //
- // The scavenge function only needs to know that the PC of this frame is
- // in the interpreter method entry code, it doesn't need to know the exact
- // PC and hence we can use O7 which points to the return address from the
- // previous call in the code stream (signature handler function)
- //
- // The other trick is we set last_Java_sp to FP instead of the usual SP because
- // we have pushed the extra frame in order to protect the volatile register(s)
- // in that frame when we return from the jni call
- //
-
- __ set_last_Java_frame(FP, O7);
- __ mov(O7, I7); // make dummy interpreter frame look like one above,
- // not meaningless information that'll confuse me.
-
- // flush the windows now. We don't care about the current (protection) frame
- // only the outer frames
-
- __ flushw();
-
- // mark windows as flushed
- Address flags(G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::flags_offset());
- __ set(JavaFrameAnchor::flushed, G3_scratch);
- __ st(G3_scratch, flags);
-
- // Transition from _thread_in_Java to _thread_in_native. We are already safepoint ready.
-
- Address thread_state(G2_thread, JavaThread::thread_state_offset());
-#ifdef ASSERT
- { Label L;
- __ ld(thread_state, G3_scratch);
- __ cmp_and_br_short(G3_scratch, _thread_in_Java, Assembler::equal, Assembler::pt, L);
- __ stop("Wrong thread state in native stub");
- __ bind(L);
- }
-#endif // ASSERT
- __ set(_thread_in_native, G3_scratch);
- __ st(G3_scratch, thread_state);
-
- // Call the jni method, using the delay slot to set the JNIEnv* argument.
- __ save_thread(L7_thread_cache); // save Gthread
- __ callr(O0, 0);
- __ delayed()->
- add(L7_thread_cache, in_bytes(JavaThread::jni_environment_offset()), O0);
-
- // Back from jni method Lmethod in this frame is DEAD, DEAD, DEAD
-
- __ restore_thread(L7_thread_cache); // restore G2_thread
- __ reinit_heapbase();
-
- // must we block?
-
- // Block, if necessary, before resuming in _thread_in_Java state.
- // In order for GC to work, don't clear the last_Java_sp until after blocking.
- { Label no_block;
- AddressLiteral sync_state(SafepointSynchronize::address_of_state());
-
- // Switch thread to "native transition" state before reading the synchronization state.
- // This additional state is necessary because reading and testing the synchronization
- // state is not atomic w.r.t. GC, as this scenario demonstrates:
- // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted.
- // VM thread changes sync state to synchronizing and suspends threads for GC.
- // 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.
- __ set(_thread_in_native_trans, G3_scratch);
- __ st(G3_scratch, thread_state);
- if(os::is_MP()) {
- if (UseMembar) {
- // Force this write out before the read below
- __ membar(Assembler::StoreLoad);
- } else {
- // 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
- // due to cache line collision.
- __ serialize_memory(G2_thread, G1_scratch, G3_scratch);
- }
- }
- __ load_contents(sync_state, G3_scratch);
- __ cmp(G3_scratch, SafepointSynchronize::_not_synchronized);
-
- Label L;
- __ br(Assembler::notEqual, false, Assembler::pn, L);
- __ delayed()->ld(G2_thread, JavaThread::suspend_flags_offset(), G3_scratch);
- __ cmp_and_br_short(G3_scratch, 0, Assembler::equal, Assembler::pt, no_block);
- __ bind(L);
-
- // Block. Save any potential method result value before the operation and
- // use a leaf call to leave the last_Java_frame setup undisturbed.
- save_native_result();
- __ call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
- G2_thread);
-
- // Restore any method result value
- restore_native_result();
- __ bind(no_block);
- }
-
- // Clear the frame anchor now
-
- __ reset_last_Java_frame();
-
- // Move the result handler address
- __ mov(Lscratch, G3_scratch);
- // return possible result to the outer frame
-#ifndef __LP64
- __ mov(O0, I0);
- __ restore(O1, G0, O1);
-#else
- __ restore(O0, G0, O0);
-#endif /* __LP64 */
-
- // Move result handler to expected register
- __ mov(G3_scratch, Lscratch);
-
- // Back in normal (native) interpreter frame. State is thread_in_native_trans
- // switch to thread_in_Java.
-
- __ set(_thread_in_Java, G3_scratch);
- __ st(G3_scratch, thread_state);
-
- // reset handle block
- __ ld_ptr(G2_thread, JavaThread::active_handles_offset(), G3_scratch);
- __ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
-
- // If we have an oop result store it where it will be safe for any further gc
- // until we return now that we've released the handle it might be protected by
-
- {
- Label no_oop, store_result;
-
- __ set((intptr_t)AbstractInterpreter::result_handler(T_OBJECT), G3_scratch);
- __ cmp_and_brx_short(G3_scratch, Lscratch, Assembler::notEqual, Assembler::pt, no_oop);
- __ addcc(G0, O0, O0);
- __ brx(Assembler::notZero, true, Assembler::pt, store_result); // if result is not NULL:
- __ delayed()->ld_ptr(O0, 0, O0); // unbox it
- __ mov(G0, O0);
-
- __ bind(store_result);
- // Store it where gc will look for it and result handler expects it.
- __ st_ptr(O0, FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS);
-
- __ bind(no_oop);
-
- }
-
-
- // handle exceptions (exception handling will handle unlocking!)
- { Label L;
- Address exception_addr(G2_thread, Thread::pending_exception_offset());
- __ ld_ptr(exception_addr, Gtemp);
- __ br_null_short(Gtemp, Assembler::pt, L);
- // Note: This could be handled more efficiently since we know that the native
- // method doesn't have an exception handler. We could directly return
- // to the exception handler for the caller.
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception));
- __ should_not_reach_here();
- __ bind(L);
- }
-
- // JVMTI support (preserves thread register)
- __ notify_method_exit(true, ilgl, InterpreterMacroAssembler::NotifyJVMTI);
-
- if (synchronized) {
- // save and restore any potential method result value around the unlocking operation
- save_native_result();
-
- __ add( __ top_most_monitor(), O1);
- __ unlock_object(O1);
-
- restore_native_result();
- }
-
-#if defined(COMPILER2) && !defined(_LP64)
-
- // C2 expects long results in G1 we can't tell if we're returning to interpreted
- // or compiled so just be safe.
-
- __ sllx(O0, 32, G1); // Shift bits into high G1
- __ srl (O1, 0, O1); // Zero extend O1
- __ or3 (O1, G1, G1); // OR 64 bits into G1
-
-#endif /* COMPILER2 && !_LP64 */
-
- // dispose of return address and remove activation
-#ifdef ASSERT
- {
- Label ok;
- __ cmp_and_brx_short(I5_savedSP, FP, Assembler::greaterEqualUnsigned, Assembler::pt, ok);
- __ stop("bad I5_savedSP value");
- __ should_not_reach_here();
- __ bind(ok);
- }
-#endif
- if (TraceJumps) {
- // Move target to register that is recordable
- __ mov(Lscratch, G3_scratch);
- __ JMP(G3_scratch, 0);
- } else {
- __ jmp(Lscratch, 0);
- }
- __ delayed()->nop();
-
-
- if (inc_counter) {
- // handle invocation counter overflow
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(Lcontinue);
- }
-
-
-
- return entry;
-}
-
-
-// Generic method entry to (asm) interpreter
-address InterpreterGenerator::generate_normal_entry(bool synchronized) {
- address entry = __ pc();
-
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // the following temporary registers are used during frame creation
- const Register Gtmp1 = G3_scratch ;
- const Register Gtmp2 = G1_scratch;
-
- // make sure registers are different!
- assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2);
-
- const Address constMethod (G5_method, Method::const_offset());
- // Seems like G5_method is live at the point this is used. So we could make this look consistent
- // and use in the asserts.
- const Address access_flags (Lmethod, Method::access_flags_offset());
-
- const Register Glocals_size = G3;
- assert_different_registers(Glocals_size, G4_scratch, Gframe_size);
-
- // make sure method is not native & not abstract
- // rethink these assertions - they can be simplified and shared (gri 2/25/2000)
-#ifdef ASSERT
- __ ld(G5_method, Method::access_flags_offset(), Gtmp1);
- {
- Label L;
- __ btst(JVM_ACC_NATIVE, Gtmp1);
- __ br(Assembler::zero, false, Assembler::pt, L);
- __ delayed()->nop();
- __ stop("tried to execute native method as non-native");
- __ bind(L);
- }
- { Label L;
- __ btst(JVM_ACC_ABSTRACT, Gtmp1);
- __ br(Assembler::zero, false, Assembler::pt, L);
- __ delayed()->nop();
- __ stop("tried to execute abstract method as non-abstract");
- __ bind(L);
- }
-#endif // ASSERT
-
- // generate the code to allocate the interpreter stack frame
-
- generate_fixed_frame(false);
-
-#ifdef FAST_DISPATCH
- __ set((intptr_t)Interpreter::dispatch_table(), IdispatchTables);
- // set bytecode dispatch table base
-#endif
-
- //
- // Code to initialize the extra (i.e. non-parm) locals
- //
- Register init_value = noreg; // will be G0 if we must clear locals
- // The way the code was setup before zerolocals was always true for vanilla java entries.
- // It could only be false for the specialized entries like accessor or empty which have
- // no extra locals so the testing was a waste of time and the extra locals were always
- // initialized. We removed this extra complication to already over complicated code.
-
- init_value = G0;
- Label clear_loop;
-
- const Register RconstMethod = O1;
- const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
- const Address size_of_locals (RconstMethod, ConstMethod::size_of_locals_offset());
-
- // NOTE: If you change the frame layout, this code will need to
- // be updated!
- __ ld_ptr( constMethod, RconstMethod );
- __ lduh( size_of_locals, O2 );
- __ lduh( size_of_parameters, O1 );
- __ sll( O2, Interpreter::logStackElementSize, O2);
- __ sll( O1, Interpreter::logStackElementSize, O1 );
- __ sub( Llocals, O2, O2 );
- __ sub( Llocals, O1, O1 );
-
- __ bind( clear_loop );
- __ inc( O2, wordSize );
-
- __ cmp( O2, O1 );
- __ brx( Assembler::lessEqualUnsigned, true, Assembler::pt, clear_loop );
- __ delayed()->st_ptr( init_value, O2, 0 );
-
- const Address do_not_unlock_if_synchronized(G2_thread,
- JavaThread::do_not_unlock_if_synchronized_offset());
- // Since at this point in the method invocation the exception handler
- // would try to exit the monitor of synchronized methods which hasn't
- // been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. If any exception was thrown by
- // runtime, exception handling i.e. unlock_if_synchronized_method will
- // check this thread local flag.
- __ movbool(true, G3_scratch);
- __ stbool(G3_scratch, do_not_unlock_if_synchronized);
-
- __ profile_parameters_type(G1_scratch, G3_scratch, G4_scratch, Lscratch);
- // increment invocation counter and check for overflow
- //
- // Note: checking for negative value instead of overflow
- // so we have a 'sticky' overflow test (may be of
- // importance as soon as we have true MT/MP)
- Label invocation_counter_overflow;
- Label profile_method;
- Label profile_method_continue;
- Label Lcontinue;
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue);
- if (ProfileInterpreter) {
- __ bind(profile_method_continue);
- }
- }
- __ bind(Lcontinue);
-
- bang_stack_shadow_pages(false);
-
- // reset the _do_not_unlock_if_synchronized flag
- __ stbool(G0, do_not_unlock_if_synchronized);
-
- // check for synchronized methods
- // Must happen AFTER invocation_counter check and stack overflow check,
- // so method is not locked if overflows.
-
- if (synchronized) {
- lock_method();
- } else {
-#ifdef ASSERT
- { Label ok;
- __ ld(access_flags, O0);
- __ btst(JVM_ACC_SYNCHRONIZED, O0);
- __ br( Assembler::zero, false, Assembler::pt, ok);
- __ delayed()->nop();
- __ stop("method needs synchronization");
- __ bind(ok);
- }
-#endif // ASSERT
- }
-
- // start execution
-
- __ verify_thread();
-
- // jvmti support
- __ notify_method_entry();
-
- // start executing instructions
- __ dispatch_next(vtos);
-
-
- if (inc_counter) {
- if (ProfileInterpreter) {
- // We have decided to profile this method in the interpreter
- __ bind(profile_method);
-
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
- __ set_method_data_pointer_for_bcp();
- __ ba_short(profile_method_continue);
- }
-
- // handle invocation counter overflow
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(Lcontinue);
- }
-
-
- return entry;
+bool AbstractInterpreter::can_be_compiled(methodHandle m) {
+ // No special entry points that preclude compilation
+ return true;
}
static int size_activation_helper(int callee_extra_locals, int max_stack, int monitor_size) {
@@ -1747,332 +303,3 @@
assert(lo <= esp && esp < monitors, "esp in bounds");
#endif // ASSERT
}
-
-//----------------------------------------------------------------------------------------------------
-// Exceptions
-void TemplateInterpreterGenerator::generate_throw_exception() {
-
- // Entry point in previous activation (i.e., if the caller was interpreted)
- Interpreter::_rethrow_exception_entry = __ pc();
- // O0: exception
-
- // entry point for exceptions thrown within interpreter code
- Interpreter::_throw_exception_entry = __ pc();
- __ verify_thread();
- // expression stack is undefined here
- // O0: exception, i.e. Oexception
- // Lbcp: exception bcp
- __ verify_oop(Oexception);
-
-
- // expression stack must be empty before entering the VM in case of an exception
- __ empty_expression_stack();
- // find exception handler address and preserve exception oop
- // call C routine to find handler and jump to it
- __ call_VM(O1, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), Oexception);
- __ push_ptr(O1); // push exception for exception handler bytecodes
-
- __ JMP(O0, 0); // jump to exception handler (may be remove activation entry!)
- __ delayed()->nop();
-
-
- // if the exception is not handled in the current frame
- // the frame is removed and the exception is rethrown
- // (i.e. exception continuation is _rethrow_exception)
- //
- // Note: At this point the bci is still the bxi for the instruction which caused
- // the exception and the expression stack is empty. Thus, for any VM calls
- // at this point, GC will find a legal oop map (with empty expression stack).
-
- // in current activation
- // tos: exception
- // Lbcp: exception bcp
-
- //
- // JVMTI PopFrame support
- //
-
- Interpreter::_remove_activation_preserving_args_entry = __ pc();
- Address popframe_condition_addr(G2_thread, JavaThread::popframe_condition_offset());
- // Set the popframe_processing bit in popframe_condition indicating that we are
- // currently handling popframe, so that call_VMs that may happen later do not trigger new
- // popframe handling cycles.
-
- __ ld(popframe_condition_addr, G3_scratch);
- __ or3(G3_scratch, JavaThread::popframe_processing_bit, G3_scratch);
- __ stw(G3_scratch, popframe_condition_addr);
-
- // Empty the expression stack, as in normal exception handling
- __ empty_expression_stack();
- __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, /* install_monitor_exception */ false);
-
- {
- // Check to see whether we are returning to a deoptimized frame.
- // (The PopFrame call ensures that the caller of the popped frame is
- // either interpreted or compiled and deoptimizes it if compiled.)
- // In this case, we can't call dispatch_next() after the frame is
- // popped, but instead must save the incoming arguments and restore
- // them after deoptimization has occurred.
- //
- // Note that we don't compare the return PC against the
- // deoptimization blob's unpack entry because of the presence of
- // adapter frames in C2.
- Label caller_not_deoptimized;
- __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), I7);
- __ br_notnull_short(O0, Assembler::pt, caller_not_deoptimized);
-
- const Register Gtmp1 = G3_scratch;
- const Register Gtmp2 = G1_scratch;
- const Register RconstMethod = Gtmp1;
- const Address constMethod(Lmethod, Method::const_offset());
- const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
-
- // Compute size of arguments for saving when returning to deoptimized caller
- __ ld_ptr(constMethod, RconstMethod);
- __ lduh(size_of_parameters, Gtmp1);
- __ sll(Gtmp1, Interpreter::logStackElementSize, Gtmp1);
- __ sub(Llocals, Gtmp1, Gtmp2);
- __ add(Gtmp2, wordSize, Gtmp2);
- // Save these arguments
- __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), G2_thread, Gtmp1, Gtmp2);
- // Inform deoptimization that it is responsible for restoring these arguments
- __ set(JavaThread::popframe_force_deopt_reexecution_bit, Gtmp1);
- Address popframe_condition_addr(G2_thread, JavaThread::popframe_condition_offset());
- __ st(Gtmp1, popframe_condition_addr);
-
- // Return from the current method
- // The caller's SP was adjusted upon method entry to accomodate
- // the callee's non-argument locals. Undo that adjustment.
- __ ret();
- __ delayed()->restore(I5_savedSP, G0, SP);
-
- __ bind(caller_not_deoptimized);
- }
-
- // Clear the popframe condition flag
- __ stw(G0 /* popframe_inactive */, popframe_condition_addr);
-
- // Get out of the current method (how this is done depends on the particular compiler calling
- // convention that the interpreter currently follows)
- // The caller's SP was adjusted upon method entry to accomodate
- // the callee's non-argument locals. Undo that adjustment.
- __ restore(I5_savedSP, G0, SP);
- // The method data pointer was incremented already during
- // call profiling. We have to restore the mdp for the current bcp.
- if (ProfileInterpreter) {
- __ set_method_data_pointer_for_bcp();
- }
-
-#if INCLUDE_JVMTI
- {
- Label L_done;
-
- __ ldub(Address(Lbcp, 0), G1_scratch); // Load current bytecode
- __ cmp_and_br_short(G1_scratch, Bytecodes::_invokestatic, Assembler::notEqual, Assembler::pn, L_done);
-
- // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
- // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
-
- __ call_VM(G1_scratch, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), I0, Lmethod, Lbcp);
-
- __ br_null(G1_scratch, false, Assembler::pn, L_done);
- __ delayed()->nop();
-
- __ st_ptr(G1_scratch, Lesp, wordSize);
- __ bind(L_done);
- }
-#endif // INCLUDE_JVMTI
-
- // Resume bytecode interpretation at the current bcp
- __ dispatch_next(vtos);
- // end of JVMTI PopFrame support
-
- Interpreter::_remove_activation_entry = __ pc();
-
- // preserve exception over this code sequence (remove activation calls the vm, but oopmaps are not correct here)
- __ pop_ptr(Oexception); // get exception
-
- // Intel has the following comment:
- //// remove the activation (without doing throws on illegalMonitorExceptions)
- // They remove the activation without checking for bad monitor state.
- // %%% We should make sure this is the right semantics before implementing.
-
- __ set_vm_result(Oexception);
- __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false);
-
- __ notify_method_exit(false, vtos, InterpreterMacroAssembler::SkipNotifyJVMTI);
-
- __ get_vm_result(Oexception);
- __ verify_oop(Oexception);
-
- const int return_reg_adjustment = frame::pc_return_offset;
- Address issuing_pc_addr(I7, return_reg_adjustment);
-
- // We are done with this activation frame; find out where to go next.
- // The continuation point will be an exception handler, which expects
- // the following registers set up:
- //
- // Oexception: exception
- // Oissuing_pc: the local call that threw exception
- // Other On: garbage
- // In/Ln: the contents of the caller's register window
- //
- // We do the required restore at the last possible moment, because we
- // need to preserve some state across a runtime call.
- // (Remember that the caller activation is unknown--it might not be
- // interpreted, so things like Lscratch are useless in the caller.)
-
- // Although the Intel version uses call_C, we can use the more
- // compact call_VM. (The only real difference on SPARC is a
- // harmlessly ignored [re]set_last_Java_frame, compared with
- // the Intel code which lacks this.)
- __ mov(Oexception, Oexception ->after_save()); // get exception in I0 so it will be on O0 after restore
- __ add(issuing_pc_addr, Oissuing_pc->after_save()); // likewise set I1 to a value local to the caller
- __ super_call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
- G2_thread, Oissuing_pc->after_save());
-
- // The caller's SP was adjusted upon method entry to accomodate
- // the callee's non-argument locals. Undo that adjustment.
- __ JMP(O0, 0); // return exception handler in caller
- __ delayed()->restore(I5_savedSP, G0, SP);
-
- // (same old exception object is already in Oexception; see above)
- // Note that an "issuing PC" is actually the next PC after the call
-}
-
-
-//
-// JVMTI ForceEarlyReturn support
-//
-
-address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
- address entry = __ pc();
-
- __ empty_expression_stack();
- __ load_earlyret_value(state);
-
- __ ld_ptr(G2_thread, JavaThread::jvmti_thread_state_offset(), G3_scratch);
- Address cond_addr(G3_scratch, JvmtiThreadState::earlyret_state_offset());
-
- // Clear the earlyret state
- __ stw(G0 /* JvmtiThreadState::earlyret_inactive */, cond_addr);
-
- __ remove_activation(state,
- /* throw_monitor_exception */ false,
- /* install_monitor_exception */ false);
-
- // The caller's SP was adjusted upon method entry to accomodate
- // the callee's non-argument locals. Undo that adjustment.
- __ ret(); // return to caller
- __ delayed()->restore(I5_savedSP, G0, SP);
-
- return entry;
-} // end of JVMTI ForceEarlyReturn support
-
-
-//------------------------------------------------------------------------------------------------------------------------
-// Helper for vtos entry point generation
-
-void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) {
- assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
- Label L;
- aep = __ pc(); __ push_ptr(); __ ba_short(L);
- fep = __ pc(); __ push_f(); __ ba_short(L);
- dep = __ pc(); __ push_d(); __ ba_short(L);
- lep = __ pc(); __ push_l(); __ ba_short(L);
- iep = __ pc(); __ push_i();
- bep = cep = sep = iep; // there aren't any
- vep = __ pc(); __ bind(L); // fall through
- generate_and_dispatch(t);
-}
-
-// --------------------------------------------------------------------------------
-
-
-InterpreterGenerator::InterpreterGenerator(StubQueue* code)
- : TemplateInterpreterGenerator(code) {
- generate_all(); // down here so it can be "virtual"
-}
-
-// --------------------------------------------------------------------------------
-
-// Non-product code
-#ifndef PRODUCT
-address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
- address entry = __ pc();
-
- __ push(state);
- __ mov(O7, Lscratch); // protect return address within interpreter
-
- // Pass a 0 (not used in sparc) and the top of stack to the bytecode tracer
- __ mov( Otos_l2, G3_scratch );
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), G0, Otos_l1, G3_scratch);
- __ mov(Lscratch, O7); // restore return address
- __ pop(state);
- __ retl();
- __ delayed()->nop();
-
- return entry;
-}
-
-
-// helpers for generate_and_dispatch
-
-void TemplateInterpreterGenerator::count_bytecode() {
- __ inc_counter(&BytecodeCounter::_counter_value, G3_scratch, G4_scratch);
-}
-
-
-void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
- __ inc_counter(&BytecodeHistogram::_counters[t->bytecode()], G3_scratch, G4_scratch);
-}
-
-
-void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) {
- AddressLiteral index (&BytecodePairHistogram::_index);
- AddressLiteral counters((address) &BytecodePairHistogram::_counters);
-
- // get index, shift out old bytecode, bring in new bytecode, and store it
- // _index = (_index >> log2_number_of_codes) |
- // (bytecode << log2_number_of_codes);
-
- __ load_contents(index, G4_scratch);
- __ srl( G4_scratch, BytecodePairHistogram::log2_number_of_codes, G4_scratch );
- __ set( ((int)t->bytecode()) << BytecodePairHistogram::log2_number_of_codes, G3_scratch );
- __ or3( G3_scratch, G4_scratch, G4_scratch );
- __ store_contents(G4_scratch, index, G3_scratch);
-
- // bump bucket contents
- // _counters[_index] ++;
-
- __ set(counters, G3_scratch); // loads into G3_scratch
- __ sll( G4_scratch, LogBytesPerWord, G4_scratch ); // Index is word address
- __ add (G3_scratch, G4_scratch, G3_scratch); // Add in index
- __ ld (G3_scratch, 0, G4_scratch);
- __ inc (G4_scratch);
- __ st (G4_scratch, 0, G3_scratch);
-}
-
-
-void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
- // Call a little run-time stub to avoid blow-up for each bytecode.
- // The run-time runtime saves the right registers, depending on
- // the tosca in-state for the given template.
- address entry = Interpreter::trace_code(t->tos_in());
- guarantee(entry != NULL, "entry must have been generated");
- __ call(entry, relocInfo::none);
- __ delayed()->nop();
-}
-
-
-void TemplateInterpreterGenerator::stop_interpreter_at() {
- AddressLiteral counter(&BytecodeCounter::_counter_value);
- __ load_contents(counter, G3_scratch);
- AddressLiteral stop_at(&StopInterpreterAt);
- __ load_ptr_contents(stop_at, G4_scratch);
- __ cmp(G3_scratch, G4_scratch);
- __ breakpoint_trap(Assembler::equal, Assembler::icc);
-}
-#endif // not PRODUCT
-#endif // !CC_INTERP
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -175,6 +175,7 @@
movptr(rsp, Address(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize));
// NULL last_sp until next java call
movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
+ NOT_LP64(empty_FPU_stack());
}
// Helpers for swap and dup
--- a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -38,7 +38,6 @@
#include "prims/jvmtiThreadState.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
@@ -184,20 +183,3 @@
return entry_point;
}
-
-
-void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) {
-
- // This code is sort of the equivalent of C2IAdapter::setup_stack_frame back in
- // the days we had adapter frames. When we deoptimize a situation where a
- // compiled caller calls a compiled caller will have registers it expects
- // to survive the call to the callee. If we deoptimize the callee the only
- // way we can restore these registers is to have the oldest interpreter
- // frame that we create restore these values. That is what this routine
- // will accomplish.
-
- // At the moment we have modified c2 to not have any callee save registers
- // so this problem does not exist and this routine is just a place holder.
-
- assert(f->is_interpreted_frame(), "must be interpreted");
-}
--- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,6 @@
#include "prims/jvmtiThreadState.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
@@ -298,19 +297,3 @@
return entry_point;
}
-
-void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) {
-
- // This code is sort of the equivalent of C2IAdapter::setup_stack_frame back in
- // the days we had adapter frames. When we deoptimize a situation where a
- // compiled caller calls a compiled caller will have registers it expects
- // to survive the call to the callee. If we deoptimize the callee the only
- // way we can restore these registers is to have the oldest interpreter
- // frame that we create restore these values. That is what this routine
- // will accomplish.
-
- // At the moment we have modified c2 to not have any callee save registers
- // so this problem does not exist and this routine is just a place holder.
-
- assert(f->is_interpreted_frame(), "must be interpreted");
-}
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -39,6 +39,7 @@
#include "runtime/os.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1CollectedHeap.inline.hpp"
@@ -10834,3 +10835,43 @@
SkipIfEqual::~SkipIfEqual() {
_masm->bind(_label);
}
+
+// 32-bit Windows has its own fast-path implementation
+// of get_thread
+#if !defined(WIN32) || defined(_LP64)
+
+// This is simply a call to Thread::current()
+void MacroAssembler::get_thread(Register thread) {
+ if (thread != rax) {
+ push(rax);
+ }
+ LP64_ONLY(push(rdi);)
+ LP64_ONLY(push(rsi);)
+ push(rdx);
+ push(rcx);
+#ifdef _LP64
+ push(r8);
+ push(r9);
+ push(r10);
+ push(r11);
+#endif
+
+ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, Thread::current), 0);
+
+#ifdef _LP64
+ pop(r11);
+ pop(r10);
+ pop(r9);
+ pop(r8);
+#endif
+ pop(rcx);
+ pop(rdx);
+ LP64_ONLY(pop(rsi);)
+ LP64_ONLY(pop(rdi);)
+ if (thread != rax) {
+ mov(thread, rax);
+ pop(rax);
+ }
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,1874 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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/macroAssembler.hpp"
+#include "interpreter/bytecodeHistogram.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterGenerator.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/interp_masm.hpp"
+#include "interpreter/templateTable.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/methodData.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "prims/jvmtiThreadState.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/synchronizer.hpp"
+#include "runtime/timer.hpp"
+#include "runtime/vframeArray.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/macros.hpp"
+
+#define __ _masm->
+
+#ifndef CC_INTERP
+
+// Global Register Names
+static const Register rbcp = LP64_ONLY(r13) NOT_LP64(rsi);
+static const Register rlocals = LP64_ONLY(r14) NOT_LP64(rdi);
+
+const int method_offset = frame::interpreter_frame_method_offset * wordSize;
+const int bcp_offset = frame::interpreter_frame_bcp_offset * wordSize;
+const int locals_offset = frame::interpreter_frame_locals_offset * wordSize;
+
+//-----------------------------------------------------------------------------
+
+address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
+ address entry = __ pc();
+
+#ifdef ASSERT
+ {
+ Label L;
+ __ lea(rax, Address(rbp,
+ frame::interpreter_frame_monitor_block_top_offset *
+ wordSize));
+ __ cmpptr(rax, rsp); // rax = maximal rsp for current rbp (stack
+ // grows negative)
+ __ jcc(Assembler::aboveEqual, L); // check if frame is complete
+ __ stop ("interpreter frame not set up");
+ __ bind(L);
+ }
+#endif // ASSERT
+ // Restore bcp under the assumption that the current frame is still
+ // interpreted
+ __ restore_bcp();
+
+ // expression stack must be empty before entering the VM if an
+ // exception happened
+ __ empty_expression_stack();
+ // throw exception
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_StackOverflowError));
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(
+ const char* name) {
+ address entry = __ pc();
+ // expression stack must be empty before entering the VM if an
+ // exception happened
+ __ empty_expression_stack();
+ // setup parameters
+ // ??? convention: expect aberrant index in register ebx
+ Register rarg = NOT_LP64(rax) LP64_ONLY(c_rarg1);
+ __ lea(rarg, ExternalAddress((address)name));
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::
+ throw_ArrayIndexOutOfBoundsException),
+ rarg, rbx);
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
+ address entry = __ pc();
+
+ // object is at TOS
+ Register rarg = NOT_LP64(rax) LP64_ONLY(c_rarg1);
+ __ pop(rarg);
+
+ // expression stack must be empty before entering the VM if an
+ // exception happened
+ __ empty_expression_stack();
+
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::
+ throw_ClassCastException),
+ rarg);
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_exception_handler_common(
+ const char* name, const char* message, bool pass_oop) {
+ assert(!pass_oop || message == NULL, "either oop or message but not both");
+ address entry = __ pc();
+
+ Register rarg = NOT_LP64(rax) LP64_ONLY(c_rarg1);
+ Register rarg2 = NOT_LP64(rbx) LP64_ONLY(c_rarg2);
+
+ if (pass_oop) {
+ // object is at TOS
+ __ pop(rarg2);
+ }
+ // expression stack must be empty before entering the VM if an
+ // exception happened
+ __ empty_expression_stack();
+ // setup parameters
+ __ lea(rarg, ExternalAddress((address)name));
+ if (pass_oop) {
+ __ call_VM(rax, CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::
+ create_klass_exception),
+ rarg, rarg2);
+ } else {
+ // kind of lame ExternalAddress can't take NULL because
+ // external_word_Relocation will assert.
+ if (message != NULL) {
+ __ lea(rarg2, ExternalAddress((address)message));
+ } else {
+ __ movptr(rarg2, NULL_WORD);
+ }
+ __ call_VM(rax,
+ CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception),
+ rarg, rarg2);
+ }
+ // throw exception
+ __ jump(ExternalAddress(Interpreter::throw_exception_entry()));
+ return entry;
+}
+
+
+address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
+ address entry = __ pc();
+ // NULL last_sp until next java call
+ __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
+ __ dispatch_next(state);
+ return entry;
+}
+
+
+address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
+ address entry = __ pc();
+
+#ifndef _LP64
+#ifdef COMPILER2
+ // The FPU stack is clean if UseSSE >= 2 but must be cleaned in other cases
+ if ((state == ftos && UseSSE < 1) || (state == dtos && UseSSE < 2)) {
+ for (int i = 1; i < 8; i++) {
+ __ ffree(i);
+ }
+ } else if (UseSSE < 2) {
+ __ empty_FPU_stack();
+ }
+#endif // COMPILER2
+ if ((state == ftos && UseSSE < 1) || (state == dtos && UseSSE < 2)) {
+ __ MacroAssembler::verify_FPU(1, "generate_return_entry_for compiled");
+ } else {
+ __ MacroAssembler::verify_FPU(0, "generate_return_entry_for compiled");
+ }
+
+ if (state == ftos) {
+ __ MacroAssembler::verify_FPU(UseSSE >= 1 ? 0 : 1, "generate_return_entry_for in interpreter");
+ } else if (state == dtos) {
+ __ MacroAssembler::verify_FPU(UseSSE >= 2 ? 0 : 1, "generate_return_entry_for in interpreter");
+ }
+#endif // _LP64
+
+ // Restore stack bottom in case i2c adjusted stack
+ __ movptr(rsp, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
+ // and NULL it as marker that esp is now tos until next java call
+ __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
+
+ __ restore_bcp();
+ __ restore_locals();
+
+ if (state == atos) {
+ Register mdp = rbx;
+ Register tmp = rcx;
+ __ profile_return_type(mdp, rax, tmp);
+ }
+
+ const Register cache = rbx;
+ const Register index = rcx;
+ __ get_cache_and_index_at_bcp(cache, index, 1, index_size);
+
+ const Register flags = cache;
+ __ movl(flags, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
+ __ andl(flags, ConstantPoolCacheEntry::parameter_size_mask);
+ __ lea(rsp, Address(rsp, flags, Interpreter::stackElementScale()));
+ __ dispatch_next(state, step);
+
+ return entry;
+}
+
+
+address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) {
+ address entry = __ pc();
+
+#ifndef _LP64
+ if (state == ftos) {
+ __ MacroAssembler::verify_FPU(UseSSE >= 1 ? 0 : 1, "generate_deopt_entry_for in interpreter");
+ } else if (state == dtos) {
+ __ MacroAssembler::verify_FPU(UseSSE >= 2 ? 0 : 1, "generate_deopt_entry_for in interpreter");
+ }
+#endif // _LP64
+
+ // 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();
+ const Register thread = NOT_LP64(rcx) LP64_ONLY(r15_thread);
+ NOT_LP64(__ get_thread(thread));
+#if INCLUDE_JVMCI
+ // Check if we need to take lock at entry of synchronized method.
+ if (UseJVMCICompiler) {
+ Label L;
+ __ cmpb(Address(thread, JavaThread::pending_monitorenter_offset()), 0);
+ __ jcc(Assembler::zero, L);
+ // Clear flag.
+ __ movb(Address(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;
+ __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
+ __ jcc(Assembler::zero, L);
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_pending_exception));
+ __ should_not_reach_here();
+ __ bind(L);
+ }
+ __ dispatch_next(state, step);
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_result_handler_for(
+ BasicType type) {
+ address entry = __ pc();
+ switch (type) {
+ case T_BOOLEAN: __ c2bool(rax); break;
+#ifndef _LP64
+ case T_CHAR : __ andptr(rax, 0xFFFF); break;
+#else
+ case T_CHAR : __ movzwl(rax, rax); break;
+#endif // _LP64
+ case T_BYTE : __ sign_extend_byte(rax); break;
+ case T_SHORT : __ sign_extend_short(rax); break;
+ case T_INT : /* nothing to do */ break;
+ case T_LONG : /* nothing to do */ break;
+ case T_VOID : /* nothing to do */ break;
+#ifndef _LP64
+ case T_DOUBLE :
+ case T_FLOAT :
+ { const Register t = InterpreterRuntime::SignatureHandlerGenerator::temp();
+ __ pop(t); // remove return address first
+ // Must return a result for interpreter or compiler. In SSE
+ // mode, results are returned in xmm0 and the FPU stack must
+ // be empty.
+ if (type == T_FLOAT && UseSSE >= 1) {
+ // Load ST0
+ __ fld_d(Address(rsp, 0));
+ // Store as float and empty fpu stack
+ __ fstp_s(Address(rsp, 0));
+ // and reload
+ __ movflt(xmm0, Address(rsp, 0));
+ } else if (type == T_DOUBLE && UseSSE >= 2 ) {
+ __ movdbl(xmm0, Address(rsp, 0));
+ } else {
+ // restore ST0
+ __ fld_d(Address(rsp, 0));
+ }
+ // and pop the temp
+ __ addptr(rsp, 2 * wordSize);
+ __ push(t); // restore return address
+ }
+ break;
+#else
+ case T_FLOAT : /* nothing to do */ break;
+ case T_DOUBLE : /* nothing to do */ break;
+#endif // _LP64
+
+ case T_OBJECT :
+ // retrieve result from frame
+ __ movptr(rax, Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize));
+ // and verify it
+ __ verify_oop(rax);
+ break;
+ default : ShouldNotReachHere();
+ }
+ __ ret(0); // return from result handler
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_safept_entry_for(
+ TosState state,
+ address runtime_entry) {
+ address entry = __ pc();
+ __ push(state);
+ __ call_VM(noreg, runtime_entry);
+ __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos));
+ return entry;
+}
+
+
+
+// Helpers for commoning out cases in the various type of method entries.
+//
+
+
+// increment invocation count & check for overflow
+//
+// Note: checking for negative value instead of overflow
+// so we have a 'sticky' overflow test
+//
+// rbx: method
+// rcx: invocation counter
+//
+void InterpreterGenerator::generate_counter_incr(
+ Label* overflow,
+ Label* profile_method,
+ Label* profile_method_continue) {
+ Label done;
+ // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not.
+ if (TieredCompilation) {
+ int increment = InvocationCounter::count_increment;
+ Label no_mdo;
+ if (ProfileInterpreter) {
+ // Are we profiling?
+ __ movptr(rax, Address(rbx, Method::method_data_offset()));
+ __ testptr(rax, rax);
+ __ jccb(Assembler::zero, no_mdo);
+ // Increment counter in the MDO
+ const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) +
+ in_bytes(InvocationCounter::counter_offset()));
+ const Address mask(rax, in_bytes(MethodData::invoke_mask_offset()));
+ __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow);
+ __ jmp(done);
+ }
+ __ bind(no_mdo);
+ // Increment counter in MethodCounters
+ const Address invocation_counter(rax,
+ MethodCounters::invocation_counter_offset() +
+ InvocationCounter::counter_offset());
+ __ get_method_counters(rbx, rax, done);
+ const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset()));
+ __ increment_mask_and_jump(invocation_counter, increment, mask, rcx,
+ false, Assembler::zero, overflow);
+ __ bind(done);
+ } else { // not TieredCompilation
+ const Address backedge_counter(rax,
+ MethodCounters::backedge_counter_offset() +
+ InvocationCounter::counter_offset());
+ const Address invocation_counter(rax,
+ MethodCounters::invocation_counter_offset() +
+ InvocationCounter::counter_offset());
+
+ __ get_method_counters(rbx, rax, done);
+
+ if (ProfileInterpreter) {
+ __ incrementl(Address(rax,
+ MethodCounters::interpreter_invocation_counter_offset()));
+ }
+ // Update standard invocation counters
+ __ movl(rcx, invocation_counter);
+ __ incrementl(rcx, InvocationCounter::count_increment);
+ __ movl(invocation_counter, rcx); // save invocation count
+
+ __ movl(rax, backedge_counter); // load backedge counter
+ __ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits
+
+ __ addl(rcx, rax); // add both counters
+
+ // profile_method is non-null only for interpreted method so
+ // profile_method != NULL == !native_call
+
+ if (ProfileInterpreter && profile_method != NULL) {
+ // Test to see if we should create a method data oop
+ __ movptr(rax, Address(rbx, Method::method_counters_offset()));
+ __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset())));
+ __ jcc(Assembler::less, *profile_method_continue);
+
+ // if no method data exists, go to profile_method
+ __ test_method_data_pointer(rax, *profile_method);
+ }
+
+ __ movptr(rax, Address(rbx, Method::method_counters_offset()));
+ __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset())));
+ __ jcc(Assembler::aboveEqual, *overflow);
+ __ bind(done);
+ }
+}
+
+void InterpreterGenerator::generate_counter_overflow(Label* do_continue) {
+
+ // Asm interpreter on entry
+ // r14/rdi - locals
+ // r13/rsi - bcp
+ // rbx - method
+ // rdx - cpool --- DOES NOT APPEAR TO BE TRUE
+ // rbp - interpreter frame
+
+ // On return (i.e. jump to entry_point) [ back to invocation of interpreter ]
+ // Everything as it was on entry
+ // rdx is not restored. Doesn't appear to really be set.
+
+ // InterpreterRuntime::frequency_counter_overflow takes two
+ // arguments, the first (thread) is passed by call_VM, the second
+ // indicates if the counter overflow occurs at a backwards branch
+ // (NULL bcp). We pass zero for it. The call returns the address
+ // of the verified entry point for the method or NULL if the
+ // compilation did not complete (either went background or bailed
+ // out).
+ Register rarg = NOT_LP64(rax) LP64_ONLY(c_rarg1);
+ __ movl(rarg, 0);
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::frequency_counter_overflow),
+ rarg);
+
+ __ movptr(rbx, Address(rbp, method_offset)); // restore Method*
+ // Preserve invariant that r13/r14 contain bcp/locals of sender frame
+ // and jump to the interpreted entry.
+ __ jmp(*do_continue, relocInfo::none);
+}
+
+// See if we've got enough room on the stack for locals plus overhead.
+// The expression stack grows down incrementally, so the normal guard
+// page mechanism will work for that.
+//
+// NOTE: Since the additional locals are also always pushed (wasn't
+// obvious in generate_fixed_frame) so the guard should work for them
+// too.
+//
+// Args:
+// rdx: number of additional locals this frame needs (what we must check)
+// rbx: Method*
+//
+// Kills:
+// rax
+void InterpreterGenerator::generate_stack_overflow_check(void) {
+
+ // monitor entry size: see picture of stack in frame_x86.hpp
+ const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
+
+ // total overhead size: entry_size + (saved rbp through expr stack
+ // bottom). be sure to change this if you add/subtract anything
+ // to/from the overhead area
+ const int overhead_size =
+ -(frame::interpreter_frame_initial_sp_offset * wordSize) + entry_size;
+
+ const int page_size = os::vm_page_size();
+
+ Label after_frame_check;
+
+ // see if the frame is greater than one page in size. If so,
+ // then we need to verify there is enough stack space remaining
+ // for the additional locals.
+ __ cmpl(rdx, (page_size - overhead_size) / Interpreter::stackElementSize);
+ __ jcc(Assembler::belowEqual, after_frame_check);
+
+ // compute rsp as if this were going to be the last frame on
+ // the stack before the red zone
+
+ Label after_frame_check_pop;
+ const Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread);
+#ifndef _LP64
+ __ push(thread);
+ __ get_thread(thread);
+#endif
+
+ const Address stack_base(thread, Thread::stack_base_offset());
+ const Address stack_size(thread, Thread::stack_size_offset());
+
+ // locals + overhead, in bytes
+ __ mov(rax, rdx);
+ __ shlptr(rax, Interpreter::logStackElementSize); // 2 slots per parameter.
+ __ addptr(rax, overhead_size);
+
+#ifdef ASSERT
+ Label stack_base_okay, stack_size_okay;
+ // verify that thread stack base is non-zero
+ __ cmpptr(stack_base, (int32_t)NULL_WORD);
+ __ jcc(Assembler::notEqual, stack_base_okay);
+ __ stop("stack base is zero");
+ __ bind(stack_base_okay);
+ // verify that thread stack size is non-zero
+ __ cmpptr(stack_size, 0);
+ __ jcc(Assembler::notEqual, stack_size_okay);
+ __ stop("stack size is zero");
+ __ bind(stack_size_okay);
+#endif
+
+ // Add stack base to locals and subtract stack size
+ __ addptr(rax, stack_base);
+ __ subptr(rax, stack_size);
+
+ // Use the maximum number of pages we might bang.
+ const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages :
+ (StackRedPages+StackYellowPages);
+
+ // add in the red and yellow zone sizes
+ __ addptr(rax, max_pages * page_size);
+
+ // check against the current stack bottom
+ __ cmpptr(rsp, rax);
+
+ __ jcc(Assembler::above, after_frame_check_pop);
+ NOT_LP64(__ pop(rsi)); // get saved bcp
+
+ // Restore sender's sp as SP. This is necessary if the sender's
+ // frame is an extended compiled frame (see gen_c2i_adapter())
+ // and safer anyway in case of JSR292 adaptations.
+
+ __ pop(rax); // return address must be moved if SP is changed
+ __ mov(rsp, rbcp);
+ __ push(rax);
+
+ // Note: the restored frame is not necessarily interpreted.
+ // Use the shared runtime version of the StackOverflowError.
+ assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "stub not yet generated");
+ __ jump(ExternalAddress(StubRoutines::throw_StackOverflowError_entry()));
+ // all done with frame size check
+ __ bind(after_frame_check_pop);
+ NOT_LP64(__ pop(rsi));
+
+ // all done with frame size check
+ __ bind(after_frame_check);
+}
+
+// Allocate monitor and lock method (asm interpreter)
+//
+// Args:
+// rbx: Method*
+// r14/rdi: locals
+//
+// Kills:
+// rax
+// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs)
+// rscratch1, rscratch2 (scratch regs)
+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);
+ const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
+
+#ifdef ASSERT
+ {
+ Label L;
+ __ movl(rax, access_flags);
+ __ testl(rax, JVM_ACC_SYNCHRONIZED);
+ __ jcc(Assembler::notZero, L);
+ __ stop("method doesn't need synchronization");
+ __ bind(L);
+ }
+#endif // ASSERT
+
+ // get synchronization object
+ {
+ const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+ Label done;
+ __ movl(rax, access_flags);
+ __ testl(rax, JVM_ACC_STATIC);
+ // get receiver (assume this is frequent case)
+ __ movptr(rax, Address(rlocals, Interpreter::local_offset_in_bytes(0)));
+ __ jcc(Assembler::zero, done);
+ __ movptr(rax, Address(rbx, Method::const_offset()));
+ __ movptr(rax, Address(rax, ConstMethod::constants_offset()));
+ __ movptr(rax, Address(rax,
+ ConstantPool::pool_holder_offset_in_bytes()));
+ __ movptr(rax, Address(rax, mirror_offset));
+
+#ifdef ASSERT
+ {
+ Label L;
+ __ testptr(rax, rax);
+ __ jcc(Assembler::notZero, L);
+ __ stop("synchronization object is NULL");
+ __ bind(L);
+ }
+#endif // ASSERT
+
+ __ bind(done);
+ }
+
+ // add space for monitor & lock
+ __ subptr(rsp, entry_size); // add space for a monitor entry
+ __ movptr(monitor_block_top, rsp); // set new monitor block top
+ // store object
+ __ movptr(Address(rsp, BasicObjectLock::obj_offset_in_bytes()), rax);
+ const Register lockreg = NOT_LP64(rdx) LP64_ONLY(c_rarg1);
+ __ movptr(lockreg, rsp); // object address
+ __ lock_object(lockreg);
+}
+
+// Generate a fixed interpreter frame. This is identical setup for
+// interpreted methods and for native methods hence the shared code.
+//
+// Args:
+// rax: return address
+// rbx: Method*
+// r14/rdi: pointer to locals
+// r13/rsi: sender sp
+// rdx: cp cache
+void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
+ // initialize fixed part of activation frame
+ __ push(rax); // save return address
+ __ enter(); // save old & set new rbp
+ __ push(rbcp); // set sender sp
+ __ push((int)NULL_WORD); // leave last_sp as null
+ __ movptr(rbcp, Address(rbx, Method::const_offset())); // get ConstMethod*
+ __ lea(rbcp, Address(rbcp, ConstMethod::codes_offset())); // get codebase
+ __ push(rbx); // save Method*
+ if (ProfileInterpreter) {
+ Label method_data_continue;
+ __ movptr(rdx, Address(rbx, in_bytes(Method::method_data_offset())));
+ __ testptr(rdx, rdx);
+ __ jcc(Assembler::zero, method_data_continue);
+ __ addptr(rdx, in_bytes(MethodData::data_offset()));
+ __ bind(method_data_continue);
+ __ push(rdx); // set the mdp (method data pointer)
+ } else {
+ __ push(0);
+ }
+
+ __ movptr(rdx, Address(rbx, Method::const_offset()));
+ __ movptr(rdx, Address(rdx, ConstMethod::constants_offset()));
+ __ movptr(rdx, Address(rdx, ConstantPool::cache_offset_in_bytes()));
+ __ push(rdx); // set constant pool cache
+ __ push(rlocals); // set locals pointer
+ if (native_call) {
+ __ push(0); // no bcp
+ } else {
+ __ push(rbcp); // set bcp
+ }
+ __ push(0); // reserve word for pointer to expression stack bottom
+ __ movptr(Address(rsp, 0), rsp); // set expression stack bottom
+}
+
+// End of helpers
+
+// Method entry for java.lang.ref.Reference.get.
+address InterpreterGenerator::generate_Reference_get_entry(void) {
+#if INCLUDE_ALL_GCS
+ // Code: _aload_0, _getfield, _areturn
+ // parameter size = 1
+ //
+ // The code that gets generated by this routine is split into 2 parts:
+ // 1. The "intrinsified" code for G1 (or any SATB based GC),
+ // 2. The slow path - which is an expansion of the regular method entry.
+ //
+ // Notes:-
+ // * In the G1 code we do not check whether we need to block for
+ // a safepoint. If G1 is enabled then we must execute the specialized
+ // code for Reference.get (except when the Reference object is null)
+ // so that we can log the value in the referent field with an SATB
+ // update buffer.
+ // If the code for the getfield template is modified so that the
+ // G1 pre-barrier code is executed when the current method is
+ // Reference.get() then going through the normal method entry
+ // will be fine.
+ // * The G1 code can, however, check the receiver object (the instance
+ // of java.lang.Reference) and jump to the slow path if null. If the
+ // Reference object is null then we obviously cannot fetch the referent
+ // and so we don't need to call the G1 pre-barrier. Thus we can use the
+ // regular method entry code to generate the NPE.
+ //
+ // rbx: Method*
+
+ // r13: senderSP must preserve for slow path, set SP to it on fast path
+
+ 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;
+ // rbx: method
+
+ // Check if local 0 != NULL
+ // If the receiver is null then it is OK to jump to the slow path.
+ __ movptr(rax, Address(rsp, wordSize));
+
+ __ testptr(rax, rax);
+ __ jcc(Assembler::zero, slow_path);
+
+ // rax: local 0
+ // rbx: method (but can be used as scratch now)
+ // rdx: scratch
+ // rdi: scratch
+
+ // Preserve the sender sp in case the pre-barrier
+ // calls the runtime
+ NOT_LP64(__ push(rsi));
+
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer.
+
+ // Load the value of the referent field.
+ const Address field_address(rax, referent_offset);
+ __ load_heap_oop(rax, field_address);
+
+ const Register sender_sp = NOT_LP64(rsi) LP64_ONLY(r13);
+ const Register thread = NOT_LP64(rcx) LP64_ONLY(r15_thread);
+ NOT_LP64(__ get_thread(thread));
+
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer.
+ __ g1_write_barrier_pre(noreg /* obj */,
+ rax /* pre_val */,
+ thread /* thread */,
+ rbx /* tmp */,
+ true /* tosca_live */,
+ true /* expand_call */);
+
+ // _areturn
+ NOT_LP64(__ pop(rsi)); // get sender sp
+ __ pop(rdi); // get return address
+ __ mov(rsp, sender_sp); // set sp to sender sp
+ __ jmp(rdi);
+ __ ret(0);
+
+ // generate a vanilla interpreter entry as the slow path
+ __ bind(slow_path);
+ __ 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 NULL;
+}
+
+// Interpreter stub for calling a native method. (asm interpreter)
+// This sets up a somewhat different looking stack for calling the
+// native method than the typical interpreter frame setup.
+address InterpreterGenerator::generate_native_entry(bool synchronized) {
+ // determine code generation flags
+ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
+
+ // rbx: Method*
+ // rbcp: sender sp
+
+ address entry_point = __ pc();
+
+ const Address constMethod (rbx, Method::const_offset());
+ const Address access_flags (rbx, Method::access_flags_offset());
+ const Address size_of_parameters(rcx, ConstMethod::
+ size_of_parameters_offset());
+
+
+ // get parameter size (always needed)
+ __ movptr(rcx, constMethod);
+ __ load_unsigned_short(rcx, size_of_parameters);
+
+ // native calls don't need the stack size check since they have no
+ // expression stack and the arguments are already on the stack and
+ // we only add a handful of words to the stack
+
+ // rbx: Method*
+ // rcx: size of parameters
+ // rbcp: sender sp
+ __ pop(rax); // get return address
+
+ // for natives the size of locals is zero
+
+ // compute beginning of parameters
+ __ lea(rlocals, Address(rsp, rcx, Interpreter::stackElementScale(), -wordSize));
+
+ // add 2 zero-initialized slots for native calls
+ // initialize result_handler slot
+ __ push((int) NULL_WORD);
+ // slot for oop temp
+ // (static native method holder mirror/jni oop result)
+ __ push((int) NULL_WORD);
+
+ // initialize fixed part of activation frame
+ generate_fixed_frame(true);
+
+ // make sure method is native & not abstract
+#ifdef ASSERT
+ __ movl(rax, access_flags);
+ {
+ Label L;
+ __ testl(rax, JVM_ACC_NATIVE);
+ __ jcc(Assembler::notZero, L);
+ __ stop("tried to execute non-native method as native");
+ __ bind(L);
+ }
+ {
+ Label L;
+ __ testl(rax, JVM_ACC_ABSTRACT);
+ __ jcc(Assembler::zero, L);
+ __ stop("tried to execute abstract method in interpreter");
+ __ bind(L);
+ }
+#endif
+
+ // Since at this point in the method invocation the exception handler
+ // would try to exit the monitor of synchronized methods which hasn't
+ // been entered yet, we set the thread local variable
+ // _do_not_unlock_if_synchronized to true. The remove_activation will
+ // check this flag.
+
+ const Register thread1 = NOT_LP64(rax) LP64_ONLY(r15_thread);
+ NOT_LP64(__ get_thread(thread1));
+ const Address do_not_unlock_if_synchronized(thread1,
+ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
+ __ movbool(do_not_unlock_if_synchronized, true);
+
+ // increment invocation count & check for overflow
+ Label invocation_counter_overflow;
+ if (inc_counter) {
+ generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
+ }
+
+ Label continue_after_compile;
+ __ bind(continue_after_compile);
+
+ bang_stack_shadow_pages(true);
+
+ // reset the _do_not_unlock_if_synchronized flag
+ NOT_LP64(__ get_thread(thread1));
+ __ movbool(do_not_unlock_if_synchronized, false);
+
+ // check for synchronized methods
+ // Must happen AFTER invocation_counter check and stack overflow check,
+ // so method is not locked if overflows.
+ if (synchronized) {
+ lock_method();
+ } else {
+ // no synchronization necessary
+#ifdef ASSERT
+ {
+ Label L;
+ __ movl(rax, access_flags);
+ __ testl(rax, JVM_ACC_SYNCHRONIZED);
+ __ jcc(Assembler::zero, L);
+ __ stop("method needs synchronization");
+ __ bind(L);
+ }
+#endif
+ }
+
+ // start execution
+#ifdef ASSERT
+ {
+ Label L;
+ const Address monitor_block_top(rbp,
+ frame::interpreter_frame_monitor_block_top_offset * wordSize);
+ __ movptr(rax, monitor_block_top);
+ __ cmpptr(rax, rsp);
+ __ jcc(Assembler::equal, L);
+ __ stop("broken stack frame setup in interpreter");
+ __ bind(L);
+ }
+#endif
+
+ // jvmti support
+ __ notify_method_entry();
+
+ // work registers
+ const Register method = rbx;
+ const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread);
+ const Register t = NOT_LP64(rcx) LP64_ONLY(r11);
+
+ // allocate space for parameters
+ __ get_method(method);
+ __ movptr(t, Address(method, Method::const_offset()));
+ __ load_unsigned_short(t, Address(t, ConstMethod::size_of_parameters_offset()));
+
+#ifndef _LP64
+ __ shlptr(t, Interpreter::logStackElementSize);
+ __ addptr(t, 2*wordSize); // allocate two more slots for JNIEnv and possible mirror
+ __ subptr(rsp, t);
+ __ andptr(rsp, -(StackAlignmentInBytes)); // gcc needs 16 byte aligned stacks to do XMM intrinsics
+#else
+ __ shll(t, Interpreter::logStackElementSize);
+
+ __ subptr(rsp, t);
+ __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
+ __ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI)
+#endif // _LP64
+
+ // get signature handler
+ {
+ Label L;
+ __ movptr(t, Address(method, Method::signature_handler_offset()));
+ __ testptr(t, t);
+ __ jcc(Assembler::notZero, L);
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::prepare_native_call),
+ method);
+ __ get_method(method);
+ __ movptr(t, Address(method, Method::signature_handler_offset()));
+ __ bind(L);
+ }
+
+ // call signature handler
+ assert(InterpreterRuntime::SignatureHandlerGenerator::from() == rlocals,
+ "adjust this code");
+ assert(InterpreterRuntime::SignatureHandlerGenerator::to() == rsp,
+ "adjust this code");
+ assert(InterpreterRuntime::SignatureHandlerGenerator::temp() == NOT_LP64(t) LP64_ONLY(rscratch1),
+ "adjust this code");
+
+ // The generated handlers do not touch RBX (the method oop).
+ // However, large signatures cannot be cached and are generated
+ // each time here. The slow-path generator can do a GC on return,
+ // so we must reload it after the call.
+ __ call(t);
+ __ get_method(method); // slow path can do a GC, reload RBX
+
+
+ // result handler is in rax
+ // set result handler
+ __ movptr(Address(rbp,
+ (frame::interpreter_frame_result_handler_offset) * wordSize),
+ rax);
+
+ // pass mirror handle if static call
+ {
+ Label L;
+ const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+ __ movl(t, Address(method, Method::access_flags_offset()));
+ __ testl(t, JVM_ACC_STATIC);
+ __ jcc(Assembler::zero, L);
+ // get mirror
+ __ movptr(t, Address(method, Method::const_offset()));
+ __ movptr(t, Address(t, ConstMethod::constants_offset()));
+ __ movptr(t, Address(t, ConstantPool::pool_holder_offset_in_bytes()));
+ __ movptr(t, Address(t, mirror_offset));
+ // copy mirror into activation frame
+ __ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset * wordSize),
+ t);
+ // pass handle to mirror
+#ifndef _LP64
+ __ lea(t, Address(rbp, frame::interpreter_frame_oop_temp_offset * wordSize));
+ __ movptr(Address(rsp, wordSize), t);
+#else
+ __ lea(c_rarg1,
+ Address(rbp, frame::interpreter_frame_oop_temp_offset * wordSize));
+#endif // _LP64
+ __ bind(L);
+ }
+
+ // get native function entry point
+ {
+ Label L;
+ __ movptr(rax, Address(method, Method::native_function_offset()));
+ ExternalAddress unsatisfied(SharedRuntime::native_method_throw_unsatisfied_link_error_entry());
+ __ cmpptr(rax, unsatisfied.addr());
+ __ jcc(Assembler::notEqual, L);
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::prepare_native_call),
+ method);
+ __ get_method(method);
+ __ movptr(rax, Address(method, Method::native_function_offset()));
+ __ bind(L);
+ }
+
+ // pass JNIEnv
+#ifndef _LP64
+ __ get_thread(thread);
+ __ lea(t, Address(thread, JavaThread::jni_environment_offset()));
+ __ movptr(Address(rsp, 0), t);
+
+ // set_last_Java_frame_before_call
+ // It is enough that the pc()
+ // points into the right code segment. It does not have to be the correct return pc.
+ __ set_last_Java_frame(thread, noreg, rbp, __ pc());
+#else
+ __ lea(c_rarg0, Address(r15_thread, JavaThread::jni_environment_offset()));
+
+ // It is enough that the pc() points into the right code
+ // segment. It does not have to be the correct return pc.
+ __ set_last_Java_frame(rsp, rbp, (address) __ pc());
+#endif // _LP64
+
+ // change thread state
+#ifdef ASSERT
+ {
+ Label L;
+ __ movl(t, Address(thread, JavaThread::thread_state_offset()));
+ __ cmpl(t, _thread_in_Java);
+ __ jcc(Assembler::equal, L);
+ __ stop("Wrong thread state in native stub");
+ __ bind(L);
+ }
+#endif
+
+ // Change state to native
+
+ __ movl(Address(thread, JavaThread::thread_state_offset()),
+ _thread_in_native);
+
+ // Call the native method.
+ __ call(rax);
+ // 32: result potentially in rdx:rax or ST0
+ // 64: result potentially in rax or xmm0
+
+ // Verify or restore cpu control state after JNI call
+ __ restore_cpu_control_state_after_jni();
+
+ // NOTE: The order of these pushes is known to frame::interpreter_frame_result
+ // in order to extract the result of a method call. If the order of these
+ // pushes change or anything else is added to the stack then the code in
+ // interpreter_frame_result must also change.
+
+#ifndef _LP64
+ // save potential result in ST(0) & rdx:rax
+ // (if result handler is the T_FLOAT or T_DOUBLE handler, result must be in ST0 -
+ // the check is necessary to avoid potential Intel FPU overflow problems by saving/restoring 'empty' FPU registers)
+ // It is safe to do this push because state is _thread_in_native and return address will be found
+ // via _last_native_pc and not via _last_jave_sp
+
+ // NOTE: the order of theses push(es) is known to frame::interpreter_frame_result.
+ // If the order changes or anything else is added to the stack the code in
+ // interpreter_frame_result will have to be changed.
+
+ { Label L;
+ Label push_double;
+ ExternalAddress float_handler(AbstractInterpreter::result_handler(T_FLOAT));
+ ExternalAddress double_handler(AbstractInterpreter::result_handler(T_DOUBLE));
+ __ cmpptr(Address(rbp, (frame::interpreter_frame_oop_temp_offset + 1)*wordSize),
+ float_handler.addr());
+ __ jcc(Assembler::equal, push_double);
+ __ cmpptr(Address(rbp, (frame::interpreter_frame_oop_temp_offset + 1)*wordSize),
+ double_handler.addr());
+ __ jcc(Assembler::notEqual, L);
+ __ bind(push_double);
+ __ push_d(); // FP values are returned using the FPU, so push FPU contents (even if UseSSE > 0).
+ __ bind(L);
+ }
+#else
+ __ push(dtos);
+#endif // _LP64
+
+ __ push(ltos);
+
+ // change thread state
+ NOT_LP64(__ get_thread(thread));
+ __ movl(Address(thread, JavaThread::thread_state_offset()),
+ _thread_in_native_trans);
+
+ if (os::is_MP()) {
+ if (UseMembar) {
+ // Force this write out before the read below
+ __ membar(Assembler::Membar_mask_bits(
+ Assembler::LoadLoad | Assembler::LoadStore |
+ Assembler::StoreLoad | Assembler::StoreStore));
+ } else {
+ // 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
+ // due to cache line collision.
+ __ serialize_memory(thread, rcx);
+ }
+ }
+
+#ifndef _LP64
+ if (AlwaysRestoreFPU) {
+ // Make sure the control word is correct.
+ __ fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std()));
+ }
+#endif // _LP64
+
+ // check for safepoint operation in progress and/or pending suspend requests
+ {
+ Label Continue;
+ __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
+ SafepointSynchronize::_not_synchronized);
+
+ Label L;
+ __ jcc(Assembler::notEqual, L);
+ __ cmpl(Address(thread, JavaThread::suspend_flags_offset()), 0);
+ __ jcc(Assembler::equal, 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. Also can't use
+ // call_VM_leaf either as it will check to see if r13 & r14 are
+ // preserved and correspond to the bcp/locals pointers. So we do a
+ // runtime call by hand.
+ //
+#ifndef _LP64
+ __ push(thread);
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address,
+ JavaThread::check_special_condition_for_native_trans)));
+ __ increment(rsp, wordSize);
+ __ get_thread(thread);
+#else
+ __ mov(c_rarg0, r15_thread);
+ __ mov(r12, rsp); // remember sp (can only use r12 if not using call_VM)
+ __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
+ __ andptr(rsp, -16); // align stack as required by ABI
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)));
+ __ mov(rsp, r12); // restore sp
+ __ reinit_heapbase();
+#endif // _LP64
+ __ bind(Continue);
+ }
+
+ // change thread state
+ __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_Java);
+
+ // reset_last_Java_frame
+ __ reset_last_Java_frame(thread, true, true);
+
+ // reset handle block
+ __ movptr(t, Address(thread, JavaThread::active_handles_offset()));
+ __ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
+
+ // If result is an oop unbox and store it in frame where gc will see it
+ // and result handler will pick it up
+
+ {
+ Label no_oop, store_result;
+ __ lea(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT)));
+ __ cmpptr(t, Address(rbp, frame::interpreter_frame_result_handler_offset*wordSize));
+ __ jcc(Assembler::notEqual, no_oop);
+ // retrieve result
+ __ pop(ltos);
+ __ testptr(rax, rax);
+ __ jcc(Assembler::zero, store_result);
+ __ movptr(rax, Address(rax, 0));
+ __ bind(store_result);
+ __ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize), rax);
+ // keep stack depth as expected by pushing oop which will eventually be discarded
+ __ push(ltos);
+ __ bind(no_oop);
+ }
+
+
+ {
+ Label no_reguard;
+ __ cmpl(Address(thread, JavaThread::stack_guard_state_offset()),
+ JavaThread::stack_guard_yellow_disabled);
+ __ jcc(Assembler::notEqual, no_reguard);
+
+ __ pusha(); // XXX only save smashed registers
+#ifndef _LP64
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)));
+ __ popa();
+#else
+ __ mov(r12, rsp); // remember sp (can only use r12 if not using call_VM)
+ __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
+ __ andptr(rsp, -16); // align stack as required by ABI
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)));
+ __ mov(rsp, r12); // restore sp
+ __ popa(); // XXX only restore smashed registers
+ __ reinit_heapbase();
+#endif // _LP64
+
+ __ bind(no_reguard);
+ }
+
+
+ // The method register is junk from after the thread_in_native transition
+ // until here. Also can't call_VM until the bcp has been
+ // restored. Need bcp for throwing exception below so get it now.
+ __ get_method(method);
+
+ // restore to have legal interpreter frame, i.e., bci == 0 <=> code_base()
+ __ movptr(rbcp, Address(method, Method::const_offset())); // get ConstMethod*
+ __ lea(rbcp, Address(rbcp, ConstMethod::codes_offset())); // get codebase
+
+ // handle exceptions (exception handling will handle unlocking!)
+ {
+ Label L;
+ __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
+ __ jcc(Assembler::zero, L);
+ // Note: At some point we may want to unify this with the code
+ // used in call_VM_base(); i.e., we should use the
+ // StubRoutines::forward_exception code. For now this doesn't work
+ // here because the rsp is not correctly set at this point.
+ __ MacroAssembler::call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_pending_exception));
+ __ should_not_reach_here();
+ __ bind(L);
+ }
+
+ // do unlocking if necessary
+ {
+ Label L;
+ __ movl(t, Address(method, Method::access_flags_offset()));
+ __ testl(t, JVM_ACC_SYNCHRONIZED);
+ __ jcc(Assembler::zero, L);
+ // the code below should be shared with interpreter macro
+ // assembler implementation
+ {
+ Label unlock;
+ // BasicObjectLock will be first in list, since this is a
+ // synchronized method. However, need to check that the object
+ // has not been unlocked by an explicit monitorexit bytecode.
+ const Address monitor(rbp,
+ (intptr_t)(frame::interpreter_frame_initial_sp_offset *
+ wordSize - (int)sizeof(BasicObjectLock)));
+
+ const Register regmon = NOT_LP64(rdx) LP64_ONLY(c_rarg1);
+
+ // monitor expect in c_rarg1 for slow unlock path
+ __ lea(regmon, monitor); // address of first monitor
+
+ __ movptr(t, Address(regmon, BasicObjectLock::obj_offset_in_bytes()));
+ __ testptr(t, t);
+ __ jcc(Assembler::notZero, unlock);
+
+ // Entry already unlocked, need to throw exception
+ __ MacroAssembler::call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_illegal_monitor_state_exception));
+ __ should_not_reach_here();
+
+ __ bind(unlock);
+ __ unlock_object(regmon);
+ }
+ __ bind(L);
+ }
+
+ // jvmti support
+ // Note: This must happen _after_ handling/throwing any exceptions since
+ // the exception handler code notifies the runtime of method exits
+ // too. If this happens before, method entry/exit notifications are
+ // not properly paired (was bug - gri 11/22/99).
+ __ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI);
+
+ // restore potential result in edx:eax, call result handler to
+ // restore potential result in ST0 & handle result
+
+ __ pop(ltos);
+ LP64_ONLY( __ pop(dtos));
+
+ __ movptr(t, Address(rbp,
+ (frame::interpreter_frame_result_handler_offset) * wordSize));
+ __ call(t);
+
+ // remove activation
+ __ movptr(t, Address(rbp,
+ frame::interpreter_frame_sender_sp_offset *
+ wordSize)); // get sender sp
+ __ leave(); // remove frame anchor
+ __ pop(rdi); // get return address
+ __ mov(rsp, t); // set sp to sender sp
+ __ jmp(rdi);
+
+ if (inc_counter) {
+ // Handle overflow of counter and compile method
+ __ bind(invocation_counter_overflow);
+ generate_counter_overflow(&continue_after_compile);
+ }
+
+ return entry_point;
+}
+
+//
+// Generic interpreted method entry to (asm) interpreter
+//
+address InterpreterGenerator::generate_normal_entry(bool synchronized) {
+ // determine code generation flags
+ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
+
+ // ebx: Method*
+ // rbcp: sender sp
+ address entry_point = __ pc();
+
+ const Address constMethod(rbx, Method::const_offset());
+ const Address access_flags(rbx, Method::access_flags_offset());
+ const Address size_of_parameters(rdx,
+ ConstMethod::size_of_parameters_offset());
+ const Address size_of_locals(rdx, ConstMethod::size_of_locals_offset());
+
+
+ // get parameter size (always needed)
+ __ movptr(rdx, constMethod);
+ __ load_unsigned_short(rcx, size_of_parameters);
+
+ // rbx: Method*
+ // rcx: size of parameters
+ // rbcp: sender_sp (could differ from sp+wordSize if we were called via c2i )
+
+ __ load_unsigned_short(rdx, size_of_locals); // get size of locals in words
+ __ subl(rdx, rcx); // rdx = no. of additional locals
+
+ // YYY
+// __ incrementl(rdx);
+// __ andl(rdx, -2);
+
+ // see if we've got enough room on the stack for locals plus overhead.
+ generate_stack_overflow_check();
+
+ // get return address
+ __ pop(rax);
+
+ // compute beginning of parameters
+ __ lea(rlocals, Address(rsp, rcx, Interpreter::stackElementScale(), -wordSize));
+
+ // rdx - # of additional locals
+ // allocate space for locals
+ // explicitly initialize locals
+ {
+ Label exit, loop;
+ __ testl(rdx, rdx);
+ __ jcc(Assembler::lessEqual, exit); // do nothing if rdx <= 0
+ __ bind(loop);
+ __ push((int) NULL_WORD); // initialize local variables
+ __ decrementl(rdx); // until everything initialized
+ __ jcc(Assembler::greater, loop);
+ __ bind(exit);
+ }
+
+ // initialize fixed part of activation frame
+ generate_fixed_frame(false);
+
+ // make sure method is not native & not abstract
+#ifdef ASSERT
+ __ movl(rax, access_flags);
+ {
+ Label L;
+ __ testl(rax, JVM_ACC_NATIVE);
+ __ jcc(Assembler::zero, L);
+ __ stop("tried to execute native method as non-native");
+ __ bind(L);
+ }
+ {
+ Label L;
+ __ testl(rax, JVM_ACC_ABSTRACT);
+ __ jcc(Assembler::zero, L);
+ __ stop("tried to execute abstract method in interpreter");
+ __ bind(L);
+ }
+#endif
+
+ // Since at this point in the method invocation the exception
+ // handler would try to exit the monitor of synchronized methods
+ // which hasn't been entered yet, we set the thread local variable
+ // _do_not_unlock_if_synchronized to true. The remove_activation
+ // will check this flag.
+
+ const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);
+ NOT_LP64(__ get_thread(thread));
+ const Address do_not_unlock_if_synchronized(thread,
+ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
+ __ movbool(do_not_unlock_if_synchronized, true);
+
+ __ profile_parameters_type(rax, rcx, rdx);
+ // increment invocation count & check for overflow
+ Label invocation_counter_overflow;
+ Label profile_method;
+ Label profile_method_continue;
+ if (inc_counter) {
+ generate_counter_incr(&invocation_counter_overflow,
+ &profile_method,
+ &profile_method_continue);
+ if (ProfileInterpreter) {
+ __ bind(profile_method_continue);
+ }
+ }
+
+ Label continue_after_compile;
+ __ bind(continue_after_compile);
+
+ // check for synchronized interpreted methods
+ bang_stack_shadow_pages(false);
+
+ // reset the _do_not_unlock_if_synchronized flag
+ NOT_LP64(__ get_thread(thread));
+ __ movbool(do_not_unlock_if_synchronized, false);
+
+ // check for synchronized methods
+ // Must happen AFTER invocation_counter check and stack overflow check,
+ // so method is not locked if overflows.
+ if (synchronized) {
+ // Allocate monitor and lock method
+ lock_method();
+ } else {
+ // no synchronization necessary
+#ifdef ASSERT
+ {
+ Label L;
+ __ movl(rax, access_flags);
+ __ testl(rax, JVM_ACC_SYNCHRONIZED);
+ __ jcc(Assembler::zero, L);
+ __ stop("method needs synchronization");
+ __ bind(L);
+ }
+#endif
+ }
+
+ // start execution
+#ifdef ASSERT
+ {
+ Label L;
+ const Address monitor_block_top (rbp,
+ frame::interpreter_frame_monitor_block_top_offset * wordSize);
+ __ movptr(rax, monitor_block_top);
+ __ cmpptr(rax, rsp);
+ __ jcc(Assembler::equal, L);
+ __ stop("broken stack frame setup in interpreter");
+ __ bind(L);
+ }
+#endif
+
+ // jvmti support
+ __ notify_method_entry();
+
+ __ dispatch_next(vtos);
+
+ // invocation counter overflow
+ if (inc_counter) {
+ if (ProfileInterpreter) {
+ // We have decided to profile this method in the interpreter
+ __ bind(profile_method);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
+ __ set_method_data_pointer_for_bcp();
+ __ get_method(rbx);
+ __ jmp(profile_method_continue);
+ }
+ // Handle overflow of counter and compile method
+ __ bind(invocation_counter_overflow);
+ generate_counter_overflow(&continue_after_compile);
+ }
+
+ return entry_point;
+}
+
+//-----------------------------------------------------------------------------
+// Exceptions
+
+void TemplateInterpreterGenerator::generate_throw_exception() {
+ // Entry point in previous activation (i.e., if the caller was
+ // interpreted)
+ Interpreter::_rethrow_exception_entry = __ pc();
+ // Restore sp to interpreter_frame_last_sp even though we are going
+ // to empty the expression stack for the exception processing.
+ __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
+ // rax: exception
+ // rdx: return address/pc that threw exception
+ __ restore_bcp(); // r13/rsi points to call/send
+ __ restore_locals();
+ LP64_ONLY(__ reinit_heapbase()); // restore r12 as heapbase.
+ // Entry point for exceptions thrown within interpreter code
+ Interpreter::_throw_exception_entry = __ pc();
+ // expression stack is undefined here
+ // rax: exception
+ // r13/rsi: exception bcp
+ __ verify_oop(rax);
+ Register rarg = NOT_LP64(rax) LP64_ONLY(c_rarg1);
+ LP64_ONLY(__ mov(c_rarg1, rax));
+
+ // expression stack must be empty before entering the VM in case of
+ // an exception
+ __ empty_expression_stack();
+ // find exception handler address and preserve exception oop
+ __ call_VM(rdx,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::exception_handler_for_exception),
+ rarg);
+ // rax: exception handler entry point
+ // rdx: preserved exception oop
+ // r13/rsi: bcp for exception handler
+ __ push_ptr(rdx); // push exception which is now the only value on the stack
+ __ jmp(rax); // jump to exception handler (may be _remove_activation_entry!)
+
+ // If the exception is not handled in the current frame the frame is
+ // removed and the exception is rethrown (i.e. exception
+ // continuation is _rethrow_exception).
+ //
+ // Note: At this point the bci is still the bxi for the instruction
+ // which caused the exception and the expression stack is
+ // empty. Thus, for any VM calls at this point, GC will find a legal
+ // oop map (with empty expression stack).
+
+ // In current activation
+ // tos: exception
+ // esi: exception bcp
+
+ //
+ // JVMTI PopFrame support
+ //
+
+ Interpreter::_remove_activation_preserving_args_entry = __ pc();
+ __ empty_expression_stack();
+ // Set the popframe_processing bit in pending_popframe_condition
+ // indicating that we are currently handling popframe, so that
+ // call_VMs that may happen later do not trigger new popframe
+ // handling cycles.
+ const Register thread = NOT_LP64(rcx) LP64_ONLY(r15_thread);
+ NOT_LP64(__ get_thread(thread));
+ __ movl(rdx, Address(thread, JavaThread::popframe_condition_offset()));
+ __ orl(rdx, JavaThread::popframe_processing_bit);
+ __ movl(Address(thread, JavaThread::popframe_condition_offset()), rdx);
+
+ {
+ // Check to see whether we are returning to a deoptimized frame.
+ // (The PopFrame call ensures that the caller of the popped frame is
+ // either interpreted or compiled and deoptimizes it if compiled.)
+ // In this case, we can't call dispatch_next() after the frame is
+ // popped, but instead must save the incoming arguments and restore
+ // them after deoptimization has occurred.
+ //
+ // Note that we don't compare the return PC against the
+ // deoptimization blob's unpack entry because of the presence of
+ // adapter frames in C2.
+ Label caller_not_deoptimized;
+ Register rarg = NOT_LP64(rdx) LP64_ONLY(c_rarg1);
+ __ movptr(rarg, Address(rbp, frame::return_addr_offset * wordSize));
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::interpreter_contains), rarg);
+ __ testl(rax, rax);
+ __ jcc(Assembler::notZero, caller_not_deoptimized);
+
+ // Compute size of arguments for saving when returning to
+ // deoptimized caller
+ __ get_method(rax);
+ __ movptr(rax, Address(rax, Method::const_offset()));
+ __ load_unsigned_short(rax, Address(rax, in_bytes(ConstMethod::
+ size_of_parameters_offset())));
+ __ shll(rax, Interpreter::logStackElementSize);
+ __ restore_locals();
+ __ subptr(rlocals, rax);
+ __ addptr(rlocals, wordSize);
+ // Save these arguments
+ NOT_LP64(__ get_thread(thread));
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
+ Deoptimization::
+ popframe_preserve_args),
+ thread, rax, rlocals);
+
+ __ remove_activation(vtos, rdx,
+ /* throw_monitor_exception */ false,
+ /* install_monitor_exception */ false,
+ /* notify_jvmdi */ false);
+
+ // Inform deoptimization that it is responsible for restoring
+ // these arguments
+ NOT_LP64(__ get_thread(thread));
+ __ movl(Address(thread, JavaThread::popframe_condition_offset()),
+ JavaThread::popframe_force_deopt_reexecution_bit);
+
+ // Continue in deoptimization handler
+ __ jmp(rdx);
+
+ __ bind(caller_not_deoptimized);
+ }
+
+ __ remove_activation(vtos, rdx, /* rdx result (retaddr) is not used */
+ /* throw_monitor_exception */ false,
+ /* install_monitor_exception */ false,
+ /* notify_jvmdi */ false);
+
+ // Finish with popframe handling
+ // A previous I2C followed by a deoptimization might have moved the
+ // outgoing arguments further up the stack. PopFrame expects the
+ // mutations to those outgoing arguments to be preserved and other
+ // constraints basically require this frame to look exactly as
+ // though it had previously invoked an interpreted activation with
+ // no space between the top of the expression stack (current
+ // last_sp) and the top of stack. Rather than force deopt to
+ // maintain this kind of invariant all the time we call a small
+ // fixup routine to move the mutated arguments onto the top of our
+ // expression stack if necessary.
+#ifndef _LP64
+ __ mov(rax, rsp);
+ __ movptr(rbx, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
+ __ get_thread(thread);
+ // PC must point into interpreter here
+ __ set_last_Java_frame(thread, noreg, rbp, __ pc());
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), thread, rax, rbx);
+ __ get_thread(thread);
+#else
+ __ mov(c_rarg1, rsp);
+ __ movptr(c_rarg2, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
+ // PC must point into interpreter here
+ __ set_last_Java_frame(noreg, rbp, __ pc());
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), r15_thread, c_rarg1, c_rarg2);
+#endif
+ __ reset_last_Java_frame(thread, true, true);
+
+ // Restore the last_sp and null it out
+ __ movptr(rsp, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
+ __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
+
+ __ restore_bcp();
+ __ restore_locals();
+ // The method data pointer was incremented already during
+ // call profiling. We have to restore the mdp for the current bcp.
+ if (ProfileInterpreter) {
+ __ set_method_data_pointer_for_bcp();
+ }
+
+ // Clear the popframe condition flag
+ NOT_LP64(__ get_thread(thread));
+ __ movl(Address(thread, JavaThread::popframe_condition_offset()),
+ JavaThread::popframe_inactive);
+
+#if INCLUDE_JVMTI
+ {
+ Label L_done;
+ const Register local0 = rlocals;
+
+ __ cmpb(Address(rbcp, 0), Bytecodes::_invokestatic);
+ __ jcc(Assembler::notEqual, L_done);
+
+ // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
+ // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
+
+ __ get_method(rdx);
+ __ movptr(rax, Address(local0, 0));
+ __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), rax, rdx, rbcp);
+
+ __ testptr(rax, rax);
+ __ jcc(Assembler::zero, L_done);
+
+ __ movptr(Address(rbx, 0), rax);
+ __ bind(L_done);
+ }
+#endif // INCLUDE_JVMTI
+
+ __ dispatch_next(vtos);
+ // end of PopFrame support
+
+ Interpreter::_remove_activation_entry = __ pc();
+
+ // preserve exception over this code sequence
+ __ pop_ptr(rax);
+ NOT_LP64(__ get_thread(thread));
+ __ movptr(Address(thread, JavaThread::vm_result_offset()), rax);
+ // remove the activation (without doing throws on illegalMonitorExceptions)
+ __ remove_activation(vtos, rdx, false, true, false);
+ // restore exception
+ NOT_LP64(__ get_thread(thread));
+ __ get_vm_result(rax, thread);
+
+ // In between activations - previous activation type unknown yet
+ // compute continuation point - the continuation point expects the
+ // following registers set up:
+ //
+ // rax: exception
+ // rdx: return address/pc that threw exception
+ // rsp: expression stack of caller
+ // rbp: ebp of caller
+ __ push(rax); // save exception
+ __ push(rdx); // save return address
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
+ SharedRuntime::exception_handler_for_return_address),
+ thread, rdx);
+ __ mov(rbx, rax); // save exception handler
+ __ pop(rdx); // restore return address
+ __ pop(rax); // restore exception
+ // Note that an "issuing PC" is actually the next PC after the call
+ __ jmp(rbx); // jump to exception
+ // handler of caller
+}
+
+
+//
+// JVMTI ForceEarlyReturn support
+//
+address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
+ address entry = __ pc();
+
+ __ restore_bcp();
+ __ restore_locals();
+ __ empty_expression_stack();
+ __ load_earlyret_value(state); // 32 bits returns value in rdx, so don't reuse
+
+ const Register thread = NOT_LP64(rcx) LP64_ONLY(r15_thread);
+ NOT_LP64(__ get_thread(thread));
+ __ movptr(rcx, Address(thread, JavaThread::jvmti_thread_state_offset()));
+ Address cond_addr(rcx, JvmtiThreadState::earlyret_state_offset());
+
+ // Clear the earlyret state
+ __ movl(cond_addr, JvmtiThreadState::earlyret_inactive);
+
+ __ remove_activation(state, rsi,
+ false, /* throw_monitor_exception */
+ false, /* install_monitor_exception */
+ true); /* notify_jvmdi */
+ __ jmp(rsi);
+
+ return entry;
+} // end of ForceEarlyReturn support
+
+
+//-----------------------------------------------------------------------------
+// Helper for vtos entry point generation
+
+void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
+ address& bep,
+ address& cep,
+ address& sep,
+ address& aep,
+ address& iep,
+ address& lep,
+ address& fep,
+ address& dep,
+ address& vep) {
+ assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
+ Label L;
+ aep = __ pc(); __ push_ptr(); __ jmp(L);
+#ifndef _LP64
+ fep = __ pc(); __ push(ftos); __ jmp(L);
+ dep = __ pc(); __ push(dtos); __ jmp(L);
+#else
+ fep = __ pc(); __ push_f(xmm0); __ jmp(L);
+ dep = __ pc(); __ push_d(xmm0); __ jmp(L);
+#endif // _LP64
+ lep = __ pc(); __ push_l(); __ jmp(L);
+ bep = cep = sep =
+ iep = __ pc(); __ push_i();
+ vep = __ pc();
+ __ bind(L);
+ generate_and_dispatch(t);
+}
+
+
+//-----------------------------------------------------------------------------
+// Generation of individual instructions
+
+// helpers for generate_and_dispatch
+
+
+InterpreterGenerator::InterpreterGenerator(StubQueue* code)
+ : TemplateInterpreterGenerator(code) {
+ generate_all(); // down here so it can be "virtual"
+}
+
+//-----------------------------------------------------------------------------
+
+// Non-product code
+#ifndef PRODUCT
+
+address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
+ address entry = __ pc();
+
+#ifndef _LP64
+ // prepare expression stack
+ __ pop(rcx); // pop return address so expression stack is 'pure'
+ __ push(state); // save tosca
+
+ // pass tosca registers as arguments & call tracer
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), rcx, rax, rdx);
+ __ mov(rcx, rax); // make sure return address is not destroyed by pop(state)
+ __ pop(state); // restore tosca
+
+ // return
+ __ jmp(rcx);
+#else
+ __ push(state);
+ __ push(c_rarg0);
+ __ push(c_rarg1);
+ __ push(c_rarg2);
+ __ push(c_rarg3);
+ __ mov(c_rarg2, rax); // Pass itos
+#ifdef _WIN64
+ __ movflt(xmm3, xmm0); // Pass ftos
+#endif
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode),
+ c_rarg1, c_rarg2, c_rarg3);
+ __ pop(c_rarg3);
+ __ pop(c_rarg2);
+ __ pop(c_rarg1);
+ __ pop(c_rarg0);
+ __ pop(state);
+ __ ret(0); // return from result handler
+#endif // _LP64
+
+ return entry;
+}
+
+void TemplateInterpreterGenerator::count_bytecode() {
+ __ incrementl(ExternalAddress((address) &BytecodeCounter::_counter_value));
+}
+
+void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
+ __ incrementl(ExternalAddress((address) &BytecodeHistogram::_counters[t->bytecode()]));
+}
+
+void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) {
+ __ mov32(rbx, ExternalAddress((address) &BytecodePairHistogram::_index));
+ __ shrl(rbx, BytecodePairHistogram::log2_number_of_codes);
+ __ orl(rbx,
+ ((int) t->bytecode()) <<
+ BytecodePairHistogram::log2_number_of_codes);
+ __ mov32(ExternalAddress((address) &BytecodePairHistogram::_index), rbx);
+ __ lea(rscratch1, ExternalAddress((address) BytecodePairHistogram::_counters));
+ __ incrementl(Address(rscratch1, rbx, Address::times_4));
+}
+
+
+void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
+ // Call a little run-time stub to avoid blow-up for each bytecode.
+ // The run-time runtime saves the right registers, depending on
+ // the tosca in-state for the given template.
+
+ assert(Interpreter::trace_code(t->tos_in()) != NULL,
+ "entry must have been generated");
+#ifndef _LP64
+ __ call(RuntimeAddress(Interpreter::trace_code(t->tos_in())));
+#else
+ __ mov(r12, rsp); // remember sp (can only use r12 if not using call_VM)
+ __ andptr(rsp, -16); // align stack as required by ABI
+ __ call(RuntimeAddress(Interpreter::trace_code(t->tos_in())));
+ __ mov(rsp, r12); // restore sp
+ __ reinit_heapbase();
+#endif // _LP64
+}
+
+
+void TemplateInterpreterGenerator::stop_interpreter_at() {
+ Label L;
+ __ cmp32(ExternalAddress((address) &BytecodeCounter::_counter_value),
+ StopInterpreterAt);
+ __ jcc(Assembler::notEqual, L);
+ __ int3();
+ __ bind(L);
+}
+#endif // !PRODUCT
+#endif // ! CC_INTERP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,305 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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/macroAssembler.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterGenerator.hpp"
+#include "runtime/arguments.hpp"
+
+#define __ _masm->
+
+
+#ifndef CC_INTERP
+
+/**
+ * Method entry for static native methods:
+ * int java.util.zip.CRC32.update(int crc, int b)
+ */
+address InterpreterGenerator::generate_CRC32_update_entry() {
+ if (UseCRC32Intrinsics) {
+ address entry = __ pc();
+
+ // rbx: Method*
+ // rsi: senderSP must preserved for slow path, set SP to it on fast path
+ // rdx: scratch
+ // rdi: scratch
+
+ Label slow_path;
+ // If we need a safepoint check, generate full interpreter entry.
+ ExternalAddress state(SafepointSynchronize::address_of_state());
+ __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
+ SafepointSynchronize::_not_synchronized);
+ __ jcc(Assembler::notEqual, slow_path);
+
+ // We don't generate local frame and don't align stack because
+ // we call stub code and there is no safepoint on this path.
+
+ // Load parameters
+ const Register crc = rax; // crc
+ const Register val = rdx; // source java byte value
+ const Register tbl = rdi; // scratch
+
+ // Arguments are reversed on java expression stack
+ __ movl(val, Address(rsp, wordSize)); // byte value
+ __ movl(crc, Address(rsp, 2*wordSize)); // Initial CRC
+
+ __ lea(tbl, ExternalAddress(StubRoutines::crc_table_addr()));
+ __ notl(crc); // ~crc
+ __ update_byte_crc32(crc, val, tbl);
+ __ notl(crc); // ~crc
+ // result in rax
+
+ // _areturn
+ __ pop(rdi); // get return address
+ __ mov(rsp, rsi); // set sp to sender sp
+ __ jmp(rdi);
+
+ // 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;
+}
+
+/**
+ * Method entry for static native methods:
+ * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len)
+ * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len)
+ */
+address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
+ if (UseCRC32Intrinsics) {
+ address entry = __ pc();
+
+ // rbx,: Method*
+ // rsi: senderSP must preserved for slow path, set SP to it on fast path
+ // rdx: scratch
+ // rdi: scratch
+
+ Label slow_path;
+ // If we need a safepoint check, generate full interpreter entry.
+ ExternalAddress state(SafepointSynchronize::address_of_state());
+ __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
+ SafepointSynchronize::_not_synchronized);
+ __ jcc(Assembler::notEqual, slow_path);
+
+ // We don't generate local frame and don't align stack because
+ // we call stub code and there is no safepoint on this path.
+
+ // Load parameters
+ const Register crc = rax; // crc
+ 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, 4 + 0)); // Length
+ // Calculate address of start element
+ if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) {
+ __ 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, 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::updateBytesCRC32()), crc, buf, len);
+ // result in rax
+
+ // _areturn
+ __ pop(rdi); // get return address
+ __ mov(rsp, rsi); // set sp to sender sp
+ __ jmp(rdi);
+
+ // 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;
+}
+
+/**
+* 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 NULL;
+}
+
+/**
+ * Method entry for static native method:
+ * java.lang.Float.intBitsToFloat(int bits)
+ */
+address InterpreterGenerator::generate_Float_intBitsToFloat_entry() {
+ if (UseSSE >= 1) {
+ address entry = __ pc();
+
+ // rsi: the sender's SP
+
+ // Skip safepoint check (compiler intrinsic versions of this method
+ // do not perform safepoint checks either).
+
+ // Load 'bits' into xmm0 (interpreter returns results in xmm0)
+ __ movflt(xmm0, Address(rsp, wordSize));
+
+ // Return
+ __ pop(rdi); // get return address
+ __ mov(rsp, rsi); // set rsp to the sender's SP
+ __ jmp(rdi);
+ return entry;
+ }
+
+ return NULL;
+}
+
+/**
+ * Method entry for static native method:
+ * java.lang.Float.floatToRawIntBits(float value)
+ */
+address InterpreterGenerator::generate_Float_floatToRawIntBits_entry() {
+ if (UseSSE >= 1) {
+ address entry = __ pc();
+
+ // rsi: the sender's SP
+
+ // Skip safepoint check (compiler intrinsic versions of this method
+ // do not perform safepoint checks either).
+
+ // Load the parameter (a floating-point value) into rax.
+ __ movl(rax, Address(rsp, wordSize));
+
+ // Return
+ __ pop(rdi); // get return address
+ __ mov(rsp, rsi); // set rsp to the sender's SP
+ __ jmp(rdi);
+ return entry;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Method entry for static native method:
+ * java.lang.Double.longBitsToDouble(long bits)
+ */
+address InterpreterGenerator::generate_Double_longBitsToDouble_entry() {
+ if (UseSSE >= 2) {
+ address entry = __ pc();
+
+ // rsi: the sender's SP
+
+ // Skip safepoint check (compiler intrinsic versions of this method
+ // do not perform safepoint checks either).
+
+ // Load 'bits' into xmm0 (interpreter returns results in xmm0)
+ __ movdbl(xmm0, Address(rsp, wordSize));
+
+ // Return
+ __ pop(rdi); // get return address
+ __ mov(rsp, rsi); // set rsp to the sender's SP
+ __ jmp(rdi);
+ return entry;
+ }
+
+ return NULL;
+}
+
+/**
+ * Method entry for static native method:
+ * java.lang.Double.doubleToRawLongBits(double value)
+ */
+address InterpreterGenerator::generate_Double_doubleToRawLongBits_entry() {
+ if (UseSSE >= 2) {
+ address entry = __ pc();
+
+ // rsi: the sender's SP
+
+ // Skip safepoint check (compiler intrinsic versions of this method
+ // do not perform safepoint checks either).
+
+ // Load the parameter (a floating-point value) into rax.
+ __ movl(rdx, Address(rsp, 2*wordSize));
+ __ movl(rax, Address(rsp, wordSize));
+
+ // Return
+ __ pop(rdi); // get return address
+ __ mov(rsp, rsi); // set rsp to the sender's SP
+ __ jmp(rdi);
+ return entry;
+ }
+
+ return NULL;
+}
+#endif // CC_INTERP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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/macroAssembler.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterGenerator.hpp"
+#include "runtime/arguments.hpp"
+
+#define __ _masm->
+
+#ifndef CC_INTERP
+
+/**
+ * Method entry for static native methods:
+ * int java.util.zip.CRC32.update(int crc, int b)
+ */
+address InterpreterGenerator::generate_CRC32_update_entry() {
+ if (UseCRC32Intrinsics) {
+ address entry = __ pc();
+
+ // rbx,: Method*
+ // r13: senderSP must preserved for slow path, set SP to it on fast path
+ // c_rarg0: scratch (rdi on non-Win64, rcx on Win64)
+ // c_rarg1: scratch (rsi on non-Win64, rdx on Win64)
+
+ Label slow_path;
+ // If we need a safepoint check, generate full interpreter entry.
+ ExternalAddress state(SafepointSynchronize::address_of_state());
+ __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
+ SafepointSynchronize::_not_synchronized);
+ __ jcc(Assembler::notEqual, slow_path);
+
+ // We don't generate local frame and don't align stack because
+ // we call stub code and there is no safepoint on this path.
+
+ // Load parameters
+ const Register crc = rax; // crc
+ const Register val = c_rarg0; // source java byte value
+ const Register tbl = c_rarg1; // scratch
+
+ // Arguments are reversed on java expression stack
+ __ movl(val, Address(rsp, wordSize)); // byte value
+ __ movl(crc, Address(rsp, 2*wordSize)); // Initial CRC
+
+ __ lea(tbl, ExternalAddress(StubRoutines::crc_table_addr()));
+ __ notl(crc); // ~crc
+ __ update_byte_crc32(crc, val, tbl);
+ __ notl(crc); // ~crc
+ // result in rax
+
+ // _areturn
+ __ pop(rdi); // get return address
+ __ mov(rsp, r13); // set sp to sender sp
+ __ jmp(rdi);
+
+ // 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;
+}
+
+/**
+ * Method entry for static native methods:
+ * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len)
+ * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len)
+ */
+address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
+ if (UseCRC32Intrinsics) {
+ address entry = __ pc();
+
+ // rbx,: Method*
+ // r13: senderSP must preserved for slow path, set SP to it on fast path
+
+ Label slow_path;
+ // If we need a safepoint check, generate full interpreter entry.
+ ExternalAddress state(SafepointSynchronize::address_of_state());
+ __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
+ SafepointSynchronize::_not_synchronized);
+ __ jcc(Assembler::notEqual, slow_path);
+
+ // We don't generate local frame and don't align stack because
+ // we call stub code and there is no safepoint on this path.
+
+ // Load parameters
+ const Register crc = c_rarg0; // crc
+ const Register buf = c_rarg1; // source java byte array address
+ const Register len = c_rarg2; // length
+ const Register off = len; // offset (never overlaps with 'len')
+
+ // Arguments are reversed on java expression stack
+ // Calculate address of start element
+ if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) {
+ __ 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
+ } 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
+ }
+ // Can now load 'len' since we're finished with 'off'
+ __ movl(len, Address(rsp, wordSize)); // Length
+
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32()), crc, buf, len);
+ // result in rax
+
+ // _areturn
+ __ pop(rdi); // get return address
+ __ mov(rsp, r13); // set sp to sender sp
+ __ jmp(rdi);
+
+ // 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;
+}
+
+/**
+* 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 NULL;
+}
+#endif // ! CC_INTERP
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -116,4 +116,87 @@
method->constants()->cache();
}
+#ifndef _LP64
+int AbstractInterpreter::BasicType_as_index(BasicType type) {
+ int i = 0;
+ switch (type) {
+ case T_BOOLEAN: i = 0; break;
+ case T_CHAR : i = 1; break;
+ case T_BYTE : i = 2; break;
+ case T_SHORT : i = 3; break;
+ case T_INT : // fall through
+ case T_LONG : // fall through
+ case T_VOID : i = 4; break;
+ case T_FLOAT : i = 5; break; // have to treat float and double separately for SSE
+ case T_DOUBLE : i = 6; break;
+ case T_OBJECT : // fall through
+ case T_ARRAY : i = 7; break;
+ default : ShouldNotReachHere();
+ }
+ assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds");
+ return i;
+}
+#else
+int AbstractInterpreter::BasicType_as_index(BasicType type) {
+ int i = 0;
+ switch (type) {
+ case T_BOOLEAN: i = 0; break;
+ case T_CHAR : i = 1; break;
+ case T_BYTE : i = 2; break;
+ case T_SHORT : i = 3; break;
+ case T_INT : i = 4; break;
+ case T_LONG : i = 5; break;
+ case T_VOID : i = 6; break;
+ case T_FLOAT : i = 7; break;
+ case T_DOUBLE : i = 8; break;
+ case T_OBJECT : i = 9; break;
+ case T_ARRAY : i = 9; break;
+ default : ShouldNotReachHere();
+ }
+ assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers,
+ "index out of bounds");
+ return i;
+}
+#endif // _LP64
+
+// These should never be compiled since the interpreter will prefer
+// the compiled version to the intrinsic version.
+bool AbstractInterpreter::can_be_compiled(methodHandle m) {
+ switch (method_kind(m)) {
+ case Interpreter::java_lang_math_sin : // fall thru
+ case Interpreter::java_lang_math_cos : // fall thru
+ case Interpreter::java_lang_math_tan : // fall thru
+ case Interpreter::java_lang_math_abs : // fall thru
+ case Interpreter::java_lang_math_log : // fall thru
+ case Interpreter::java_lang_math_log10 : // fall thru
+ case Interpreter::java_lang_math_sqrt : // fall thru
+ case Interpreter::java_lang_math_pow : // fall thru
+ case Interpreter::java_lang_math_exp :
+ return false;
+ default:
+ return true;
+ }
+}
+
+// How much stack a method activation needs in words.
+int AbstractInterpreter::size_top_interpreter_activation(Method* method) {
+ const int entry_size = frame::interpreter_frame_monitor_size();
+
+ // total overhead size: entry_size + (saved rbp thru expr stack
+ // bottom). be sure to change this if you add/subtract anything
+ // to/from the overhead area
+ const int overhead_size =
+ -(frame::interpreter_frame_initial_sp_offset) + entry_size;
+
+#ifndef _LP64
+ const int stub_code = 4; // see generate_call_stub
+#else
+ const int stub_code = frame::entry_frame_after_call_words;
+#endif
+
+ const int method_stack = (method->max_locals() + method->max_stack()) *
+ Interpreter::stackElementWords;
+ return (overhead_size + method_stack + stub_code);
+}
+
#endif // CC_INTERP
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1916 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/macroAssembler.hpp"
-#include "interpreter/bytecodeHistogram.hpp"
-#include "interpreter/interpreter.hpp"
-#include "interpreter/interpreterGenerator.hpp"
-#include "interpreter/interpreterRuntime.hpp"
-#include "interpreter/interp_masm.hpp"
-#include "interpreter/templateTable.hpp"
-#include "oops/arrayOop.hpp"
-#include "oops/methodData.hpp"
-#include "oops/method.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/jvmtiExport.hpp"
-#include "prims/jvmtiThreadState.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/synchronizer.hpp"
-#include "runtime/timer.hpp"
-#include "runtime/vframeArray.hpp"
-#include "utilities/debug.hpp"
-#include "utilities/macros.hpp"
-
-#define __ _masm->
-
-
-#ifndef CC_INTERP
-const int method_offset = frame::interpreter_frame_method_offset * wordSize;
-const int bcp_offset = frame::interpreter_frame_bcp_offset * wordSize;
-const int locals_offset = frame::interpreter_frame_locals_offset * wordSize;
-
-//------------------------------------------------------------------------------------------------------------------------
-
-address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
- address entry = __ pc();
-
- // Note: There should be a minimal interpreter frame set up when stack
- // overflow occurs since we check explicitly for it now.
- //
-#ifdef ASSERT
- { Label L;
- __ lea(rax, Address(rbp,
- frame::interpreter_frame_monitor_block_top_offset * wordSize));
- __ cmpptr(rax, rsp); // rax, = maximal rsp for current rbp,
- // (stack grows negative)
- __ jcc(Assembler::aboveEqual, L); // check if frame is complete
- __ stop ("interpreter frame not set up");
- __ bind(L);
- }
-#endif // ASSERT
- // Restore bcp under the assumption that the current frame is still
- // interpreted
- __ restore_bcp();
-
- // expression stack must be empty before entering the VM if an exception
- // happened
- __ empty_expression_stack();
- __ empty_FPU_stack();
- // throw exception
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_StackOverflowError));
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an exception happened
- __ empty_expression_stack();
- __ empty_FPU_stack();
- // setup parameters
- // ??? convention: expect aberrant index in register rbx,
- __ lea(rax, ExternalAddress((address)name));
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException), rax, rbx);
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
- address entry = __ pc();
- // object is at TOS
- __ pop(rax);
- // expression stack must be empty before entering the VM if an exception
- // happened
- __ empty_expression_stack();
- __ empty_FPU_stack();
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_ClassCastException),
- rax);
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
- assert(!pass_oop || message == NULL, "either oop or message but not both");
- address entry = __ pc();
- if (pass_oop) {
- // object is at TOS
- __ pop(rbx);
- }
- // expression stack must be empty before entering the VM if an exception happened
- __ empty_expression_stack();
- __ empty_FPU_stack();
- // setup parameters
- __ lea(rax, ExternalAddress((address)name));
- if (pass_oop) {
- __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), rax, rbx);
- } else {
- if (message != NULL) {
- __ lea(rbx, ExternalAddress((address)message));
- } else {
- __ movptr(rbx, NULL_WORD);
- }
- __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), rax, rbx);
- }
- // throw exception
- __ jump(ExternalAddress(Interpreter::throw_exception_entry()));
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
- address entry = __ pc();
- // NULL last_sp until next java call
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD);
- __ dispatch_next(state);
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
- address entry = __ pc();
-
-#ifdef COMPILER2
- // The FPU stack is clean if UseSSE >= 2 but must be cleaned in other cases
- if ((state == ftos && UseSSE < 1) || (state == dtos && UseSSE < 2)) {
- for (int i = 1; i < 8; i++) {
- __ ffree(i);
- }
- } else if (UseSSE < 2) {
- __ empty_FPU_stack();
- }
-#endif
- if ((state == ftos && UseSSE < 1) || (state == dtos && UseSSE < 2)) {
- __ MacroAssembler::verify_FPU(1, "generate_return_entry_for compiled");
- } else {
- __ MacroAssembler::verify_FPU(0, "generate_return_entry_for compiled");
- }
-
- if (state == ftos) {
- __ MacroAssembler::verify_FPU(UseSSE >= 1 ? 0 : 1, "generate_return_entry_for in interpreter");
- } else if (state == dtos) {
- __ MacroAssembler::verify_FPU(UseSSE >= 2 ? 0 : 1, "generate_return_entry_for in interpreter");
- }
-
- // Restore stack bottom in case i2c adjusted stack
- __ movptr(rsp, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
- // and NULL it as marker that rsp is now tos until next java call
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD);
-
- __ restore_bcp();
- __ restore_locals();
-
- if (state == atos) {
- Register mdp = rbx;
- Register tmp = rcx;
- __ profile_return_type(mdp, rax, tmp);
- }
-
- const Register cache = rbx;
- const Register index = rcx;
- __ get_cache_and_index_at_bcp(cache, index, 1, index_size);
-
- const Register flags = cache;
- __ movl(flags, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
- __ andl(flags, ConstantPoolCacheEntry::parameter_size_mask);
- __ lea(rsp, Address(rsp, flags, Interpreter::stackElementScale()));
- __ dispatch_next(state, step);
-
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) {
- address entry = __ pc();
-
- if (state == ftos) {
- __ MacroAssembler::verify_FPU(UseSSE >= 1 ? 0 : 1, "generate_deopt_entry_for in interpreter");
- } else if (state == dtos) {
- __ MacroAssembler::verify_FPU(UseSSE >= 2 ? 0 : 1, "generate_deopt_entry_for in interpreter");
- }
-
- // The stack is not extended by deopt but we must NULL last_sp as this
- // entry is like a "return".
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD);
- __ restore_bcp();
- __ restore_locals();
- // handle exceptions
- { Label L;
- const Register thread = rcx;
- __ get_thread(thread);
- __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD);
- __ jcc(Assembler::zero, L);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception));
- __ should_not_reach_here();
- __ bind(L);
- }
- __ dispatch_next(state, step);
- return entry;
-}
-
-
-int AbstractInterpreter::BasicType_as_index(BasicType type) {
- int i = 0;
- switch (type) {
- case T_BOOLEAN: i = 0; break;
- case T_CHAR : i = 1; break;
- case T_BYTE : i = 2; break;
- case T_SHORT : i = 3; break;
- case T_INT : // fall through
- case T_LONG : // fall through
- case T_VOID : i = 4; break;
- case T_FLOAT : i = 5; break; // have to treat float and double separately for SSE
- case T_DOUBLE : i = 6; break;
- case T_OBJECT : // fall through
- case T_ARRAY : i = 7; break;
- default : ShouldNotReachHere();
- }
- assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds");
- return i;
-}
-
-
-address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) {
- address entry = __ pc();
- switch (type) {
- case T_BOOLEAN: __ c2bool(rax); break;
- case T_CHAR : __ andptr(rax, 0xFFFF); break;
- case T_BYTE : __ sign_extend_byte (rax); break;
- case T_SHORT : __ sign_extend_short(rax); break;
- case T_INT : /* nothing to do */ break;
- case T_LONG : /* nothing to do */ break;
- case T_VOID : /* nothing to do */ break;
- case T_DOUBLE :
- case T_FLOAT :
- { const Register t = InterpreterRuntime::SignatureHandlerGenerator::temp();
- __ pop(t); // remove return address first
- // Must return a result for interpreter or compiler. In SSE
- // mode, results are returned in xmm0 and the FPU stack must
- // be empty.
- if (type == T_FLOAT && UseSSE >= 1) {
- // Load ST0
- __ fld_d(Address(rsp, 0));
- // Store as float and empty fpu stack
- __ fstp_s(Address(rsp, 0));
- // and reload
- __ movflt(xmm0, Address(rsp, 0));
- } else if (type == T_DOUBLE && UseSSE >= 2 ) {
- __ movdbl(xmm0, Address(rsp, 0));
- } else {
- // restore ST0
- __ fld_d(Address(rsp, 0));
- }
- // and pop the temp
- __ addptr(rsp, 2 * wordSize);
- __ push(t); // restore return address
- }
- break;
- case T_OBJECT :
- // retrieve result from frame
- __ movptr(rax, Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize));
- // and verify it
- __ verify_oop(rax);
- break;
- default : ShouldNotReachHere();
- }
- __ ret(0); // return from result handler
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) {
- address entry = __ pc();
- __ push(state);
- __ call_VM(noreg, runtime_entry);
- __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos));
- return entry;
-}
-
-
-// Helpers for commoning out cases in the various type of method entries.
-//
-
-// increment invocation count & check for overflow
-//
-// Note: checking for negative value instead of overflow
-// so we have a 'sticky' overflow test
-//
-// rbx,: method
-// rcx: invocation counter
-//
-void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) {
- Label done;
- // Note: In tiered we increment either counters in MethodCounters* or in MDO
- // depending if we're profiling or not.
- if (TieredCompilation) {
- int increment = InvocationCounter::count_increment;
- Label no_mdo;
- if (ProfileInterpreter) {
- // Are we profiling?
- __ movptr(rax, Address(rbx, Method::method_data_offset()));
- __ testptr(rax, rax);
- __ jccb(Assembler::zero, no_mdo);
- // Increment counter in the MDO
- const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) +
- in_bytes(InvocationCounter::counter_offset()));
- const Address mask(rax, in_bytes(MethodData::invoke_mask_offset()));
- __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow);
- __ jmp(done);
- }
- __ bind(no_mdo);
- // Increment counter in MethodCounters
- const Address invocation_counter(rax,
- MethodCounters::invocation_counter_offset() +
- InvocationCounter::counter_offset());
-
- __ get_method_counters(rbx, rax, done);
- const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset()));
- __ increment_mask_and_jump(invocation_counter, increment, mask,
- rcx, false, Assembler::zero, overflow);
- __ bind(done);
- } else { // not TieredCompilation
- const Address backedge_counter(rax,
- MethodCounters::backedge_counter_offset() +
- InvocationCounter::counter_offset());
- const Address invocation_counter(rax,
- MethodCounters::invocation_counter_offset() +
- InvocationCounter::counter_offset());
-
- __ get_method_counters(rbx, rax, done);
-
- if (ProfileInterpreter) {
- __ incrementl(Address(rax,
- MethodCounters::interpreter_invocation_counter_offset()));
- }
-
- // Update standard invocation counters
- __ movl(rcx, invocation_counter);
- __ incrementl(rcx, InvocationCounter::count_increment);
- __ movl(invocation_counter, rcx); // save invocation count
-
- __ movl(rax, backedge_counter); // load backedge counter
- __ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits
-
- __ addl(rcx, rax); // add both counters
-
- // profile_method is non-null only for interpreted method so
- // profile_method != NULL == !native_call
- // BytecodeInterpreter only calls for native so code is elided.
-
- if (ProfileInterpreter && profile_method != NULL) {
- // Test to see if we should create a method data oop
- __ movptr(rax, Address(rbx, Method::method_counters_offset()));
- __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset())));
- __ jcc(Assembler::less, *profile_method_continue);
-
- // if no method data exists, go to profile_method
- __ test_method_data_pointer(rax, *profile_method);
- }
-
- __ movptr(rax, Address(rbx, Method::method_counters_offset()));
- __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset())));
- __ jcc(Assembler::aboveEqual, *overflow);
- __ bind(done);
- }
-}
-
-void InterpreterGenerator::generate_counter_overflow(Label* do_continue) {
-
- // Asm interpreter on entry
- // rdi - locals
- // rsi - bcp
- // rbx, - method
- // rdx - cpool
- // rbp, - interpreter frame
-
- // C++ interpreter on entry
- // rsi - new interpreter state pointer
- // rbp - interpreter frame pointer
- // rbx - method
-
- // On return (i.e. jump to entry_point) [ back to invocation of interpreter ]
- // rbx, - method
- // rcx - rcvr (assuming there is one)
- // top of stack return address of interpreter caller
- // rsp - sender_sp
-
- // C++ interpreter only
- // rsi - previous interpreter state pointer
-
- // InterpreterRuntime::frequency_counter_overflow takes one argument
- // indicating if the counter overflow occurs at a backwards branch (non-NULL bcp).
- // The call returns the address of the verified entry point for the method or NULL
- // if the compilation did not complete (either went background or bailed out).
- __ movptr(rax, (intptr_t)false);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), rax);
-
- __ movptr(rbx, Address(rbp, method_offset)); // restore Method*
-
- // Preserve invariant that rsi/rdi contain bcp/locals of sender frame
- // and jump to the interpreted entry.
- __ jmp(*do_continue, relocInfo::none);
-
-}
-
-void InterpreterGenerator::generate_stack_overflow_check(void) {
- // see if we've got enough room on the stack for locals plus overhead.
- // the expression stack grows down incrementally, so the normal guard
- // page mechanism will work for that.
- //
- // Registers live on entry:
- //
- // Asm interpreter
- // rdx: number of additional locals this frame needs (what we must check)
- // rbx,: Method*
-
- // destroyed on exit
- // rax,
-
- // NOTE: since the additional locals are also always pushed (wasn't obvious in
- // generate_fixed_frame) so the guard should work for them too.
- //
-
- // monitor entry size: see picture of stack in frame_x86.hpp
- const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
-
- // total overhead size: entry_size + (saved rbp, thru expr stack bottom).
- // be sure to change this if you add/subtract anything to/from the overhead area
- const int overhead_size = -(frame::interpreter_frame_initial_sp_offset*wordSize) + entry_size;
-
- const int page_size = os::vm_page_size();
-
- Label after_frame_check;
-
- // see if the frame is greater than one page in size. If so,
- // then we need to verify there is enough stack space remaining
- // for the additional locals.
- __ cmpl(rdx, (page_size - overhead_size)/Interpreter::stackElementSize);
- __ jcc(Assembler::belowEqual, after_frame_check);
-
- // compute rsp as if this were going to be the last frame on
- // the stack before the red zone
-
- Label after_frame_check_pop;
-
- __ push(rsi);
-
- const Register thread = rsi;
-
- __ get_thread(thread);
-
- const Address stack_base(thread, Thread::stack_base_offset());
- const Address stack_size(thread, Thread::stack_size_offset());
-
- // locals + overhead, in bytes
- __ lea(rax, Address(noreg, rdx, Interpreter::stackElementScale(), overhead_size));
-
-#ifdef ASSERT
- Label stack_base_okay, stack_size_okay;
- // verify that thread stack base is non-zero
- __ cmpptr(stack_base, (int32_t)NULL_WORD);
- __ jcc(Assembler::notEqual, stack_base_okay);
- __ stop("stack base is zero");
- __ bind(stack_base_okay);
- // verify that thread stack size is non-zero
- __ cmpptr(stack_size, 0);
- __ jcc(Assembler::notEqual, stack_size_okay);
- __ stop("stack size is zero");
- __ bind(stack_size_okay);
-#endif
-
- // Add stack base to locals and subtract stack size
- __ addptr(rax, stack_base);
- __ subptr(rax, stack_size);
-
- // Use the maximum number of pages we might bang.
- const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages :
- (StackRedPages+StackYellowPages);
- __ addptr(rax, max_pages * page_size);
-
- // check against the current stack bottom
- __ cmpptr(rsp, rax);
- __ jcc(Assembler::above, after_frame_check_pop);
-
- __ pop(rsi); // get saved bcp / (c++ prev state ).
-
- // Restore sender's sp as SP. This is necessary if the sender's
- // frame is an extended compiled frame (see gen_c2i_adapter())
- // and safer anyway in case of JSR292 adaptations.
-
- __ pop(rax); // return address must be moved if SP is changed
- __ mov(rsp, rsi);
- __ push(rax);
-
- // Note: the restored frame is not necessarily interpreted.
- // Use the shared runtime version of the StackOverflowError.
- assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "stub not yet generated");
- __ jump(ExternalAddress(StubRoutines::throw_StackOverflowError_entry()));
- // all done with frame size check
- __ bind(after_frame_check_pop);
- __ pop(rsi);
-
- __ bind(after_frame_check);
-}
-
-// Allocate monitor and lock method (asm interpreter)
-// rbx, - Method*
-//
-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);
- const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
-
- #ifdef ASSERT
- { Label L;
- __ movl(rax, access_flags);
- __ testl(rax, JVM_ACC_SYNCHRONIZED);
- __ jcc(Assembler::notZero, L);
- __ stop("method doesn't need synchronization");
- __ bind(L);
- }
- #endif // ASSERT
- // get synchronization object
- { Label done;
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- __ movl(rax, access_flags);
- __ testl(rax, JVM_ACC_STATIC);
- __ movptr(rax, Address(rdi, Interpreter::local_offset_in_bytes(0))); // get receiver (assume this is frequent case)
- __ jcc(Assembler::zero, done);
- __ movptr(rax, Address(rbx, Method::const_offset()));
- __ movptr(rax, Address(rax, ConstMethod::constants_offset()));
- __ movptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes()));
- __ movptr(rax, Address(rax, mirror_offset));
- __ bind(done);
- }
- // add space for monitor & lock
- __ subptr(rsp, entry_size); // add space for a monitor entry
- __ movptr(monitor_block_top, rsp); // set new monitor block top
- __ movptr(Address(rsp, BasicObjectLock::obj_offset_in_bytes()), rax); // store object
- __ mov(rdx, rsp); // object address
- __ lock_object(rdx);
-}
-
-//
-// Generate a fixed interpreter frame. This is identical setup for interpreted methods
-// and for native methods hence the shared code.
-
-void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
- // initialize fixed part of activation frame
- __ push(rax); // save return address
- __ enter(); // save old & set new rbp,
-
-
- __ push(rsi); // set sender sp
- __ push((int32_t)NULL_WORD); // leave last_sp as null
- __ movptr(rsi, Address(rbx,Method::const_offset())); // get ConstMethod*
- __ lea(rsi, Address(rsi,ConstMethod::codes_offset())); // get codebase
- __ push(rbx); // save Method*
- if (ProfileInterpreter) {
- Label method_data_continue;
- __ movptr(rdx, Address(rbx, in_bytes(Method::method_data_offset())));
- __ testptr(rdx, rdx);
- __ jcc(Assembler::zero, method_data_continue);
- __ addptr(rdx, in_bytes(MethodData::data_offset()));
- __ bind(method_data_continue);
- __ push(rdx); // set the mdp (method data pointer)
- } else {
- __ push(0);
- }
-
- __ movptr(rdx, Address(rbx, Method::const_offset()));
- __ movptr(rdx, Address(rdx, ConstMethod::constants_offset()));
- __ movptr(rdx, Address(rdx, ConstantPool::cache_offset_in_bytes()));
- __ push(rdx); // set constant pool cache
- __ push(rdi); // set locals pointer
- if (native_call) {
- __ push(0); // no bcp
- } else {
- __ push(rsi); // set bcp
- }
- __ push(0); // reserve word for pointer to expression stack bottom
- __ movptr(Address(rsp, 0), rsp); // set expression stack bottom
-}
-
-
-// Method entry for java.lang.ref.Reference.get.
-address InterpreterGenerator::generate_Reference_get_entry(void) {
-#if INCLUDE_ALL_GCS
- // Code: _aload_0, _getfield, _areturn
- // parameter size = 1
- //
- // The code that gets generated by this routine is split into 2 parts:
- // 1. The "intrinsified" code for G1 (or any SATB based GC),
- // 2. The slow path - which is an expansion of the regular method entry.
- //
- // Notes:-
- // * In the G1 code we do not check whether we need to block for
- // a safepoint. If G1 is enabled then we must execute the specialized
- // code for Reference.get (except when the Reference object is null)
- // so that we can log the value in the referent field with an SATB
- // update buffer.
- // If the code for the getfield template is modified so that the
- // G1 pre-barrier code is executed when the current method is
- // Reference.get() then going through the normal method entry
- // will be fine.
- // * The G1 code below can, however, check the receiver object (the instance
- // of java.lang.Reference) and jump to the slow path if null. If the
- // Reference object is null then we obviously cannot fetch the referent
- // and so we don't need to call the G1 pre-barrier. Thus we can use the
- // regular method entry code to generate the NPE.
- //
- // This code is based on generate_accessor_enty.
-
- // rbx,: Method*
- // rcx: receiver (preserve for slow entry into asm interpreter)
-
- // rsi: senderSP must preserved for slow path, set SP to it on fast path
-
- 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;
-
- // Check if local 0 != NULL
- // If the receiver is null then it is OK to jump to the slow path.
- __ movptr(rax, Address(rsp, wordSize));
- __ testptr(rax, rax);
- __ jcc(Assembler::zero, slow_path);
-
- // rax: local 0 (must be preserved across the G1 barrier call)
- //
- // rbx: method (at this point it's scratch)
- // rcx: receiver (at this point it's scratch)
- // rdx: scratch
- // rdi: scratch
- //
- // rsi: sender sp
-
- // Preserve the sender sp in case the pre-barrier
- // calls the runtime
- __ push(rsi);
-
- // Load the value of the referent field.
- const Address field_address(rax, referent_offset);
- __ movptr(rax, field_address);
-
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer.
- __ get_thread(rcx);
- __ g1_write_barrier_pre(noreg /* obj */,
- rax /* pre_val */,
- rcx /* thread */,
- rbx /* tmp */,
- true /* tosca_save */,
- true /* expand_call */);
-
- // _areturn
- __ pop(rsi); // get sender sp
- __ pop(rdi); // get return address
- __ mov(rsp, rsi); // set sp to sender sp
- __ jmp(rdi);
-
- __ bind(slow_path);
- __ 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 NULL;
-}
-
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.update(int crc, int b)
- */
-address InterpreterGenerator::generate_CRC32_update_entry() {
- if (UseCRC32Intrinsics) {
- address entry = __ pc();
-
- // rbx: Method*
- // rsi: senderSP must preserved for slow path, set SP to it on fast path
- // rdx: scratch
- // rdi: scratch
-
- Label slow_path;
- // If we need a safepoint check, generate full interpreter entry.
- ExternalAddress state(SafepointSynchronize::address_of_state());
- __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
- SafepointSynchronize::_not_synchronized);
- __ jcc(Assembler::notEqual, slow_path);
-
- // We don't generate local frame and don't align stack because
- // we call stub code and there is no safepoint on this path.
-
- // Load parameters
- const Register crc = rax; // crc
- const Register val = rdx; // source java byte value
- const Register tbl = rdi; // scratch
-
- // Arguments are reversed on java expression stack
- __ movl(val, Address(rsp, wordSize)); // byte value
- __ movl(crc, Address(rsp, 2*wordSize)); // Initial CRC
-
- __ lea(tbl, ExternalAddress(StubRoutines::crc_table_addr()));
- __ notl(crc); // ~crc
- __ update_byte_crc32(crc, val, tbl);
- __ notl(crc); // ~crc
- // result in rax
-
- // _areturn
- __ pop(rdi); // get return address
- __ mov(rsp, rsi); // set sp to sender sp
- __ jmp(rdi);
-
- // 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;
-}
-
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len)
- * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len)
- */
-address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
- if (UseCRC32Intrinsics) {
- address entry = __ pc();
-
- // rbx,: Method*
- // rsi: senderSP must preserved for slow path, set SP to it on fast path
- // rdx: scratch
- // rdi: scratch
-
- Label slow_path;
- // If we need a safepoint check, generate full interpreter entry.
- ExternalAddress state(SafepointSynchronize::address_of_state());
- __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
- SafepointSynchronize::_not_synchronized);
- __ jcc(Assembler::notEqual, slow_path);
-
- // We don't generate local frame and don't align stack because
- // we call stub code and there is no safepoint on this path.
-
- // Load parameters
- const Register crc = rax; // crc
- 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, 4 + 0)); // Length
- // Calculate address of start element
- if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) {
- __ 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, 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::updateBytesCRC32()), crc, buf, len);
- // result in rax
-
- // _areturn
- __ pop(rdi); // get return address
- __ mov(rsp, rsi); // set sp to sender sp
- __ jmp(rdi);
-
- // 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;
-}
-
-/**
-* 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 NULL;
-}
-
-/**
- * Method entry for static native method:
- * java.lang.Float.intBitsToFloat(int bits)
- */
-address InterpreterGenerator::generate_Float_intBitsToFloat_entry() {
- if (UseSSE >= 1) {
- address entry = __ pc();
-
- // rsi: the sender's SP
-
- // Skip safepoint check (compiler intrinsic versions of this method
- // do not perform safepoint checks either).
-
- // Load 'bits' into xmm0 (interpreter returns results in xmm0)
- __ movflt(xmm0, Address(rsp, wordSize));
-
- // Return
- __ pop(rdi); // get return address
- __ mov(rsp, rsi); // set rsp to the sender's SP
- __ jmp(rdi);
- return entry;
- }
-
- return NULL;
-}
-
-/**
- * Method entry for static native method:
- * java.lang.Float.floatToRawIntBits(float value)
- */
-address InterpreterGenerator::generate_Float_floatToRawIntBits_entry() {
- if (UseSSE >= 1) {
- address entry = __ pc();
-
- // rsi: the sender's SP
-
- // Skip safepoint check (compiler intrinsic versions of this method
- // do not perform safepoint checks either).
-
- // Load the parameter (a floating-point value) into rax.
- __ movl(rax, Address(rsp, wordSize));
-
- // Return
- __ pop(rdi); // get return address
- __ mov(rsp, rsi); // set rsp to the sender's SP
- __ jmp(rdi);
- return entry;
- }
-
- return NULL;
-}
-
-
-/**
- * Method entry for static native method:
- * java.lang.Double.longBitsToDouble(long bits)
- */
-address InterpreterGenerator::generate_Double_longBitsToDouble_entry() {
- if (UseSSE >= 2) {
- address entry = __ pc();
-
- // rsi: the sender's SP
-
- // Skip safepoint check (compiler intrinsic versions of this method
- // do not perform safepoint checks either).
-
- // Load 'bits' into xmm0 (interpreter returns results in xmm0)
- __ movdbl(xmm0, Address(rsp, wordSize));
-
- // Return
- __ pop(rdi); // get return address
- __ mov(rsp, rsi); // set rsp to the sender's SP
- __ jmp(rdi);
- return entry;
- }
-
- return NULL;
-}
-
-/**
- * Method entry for static native method:
- * java.lang.Double.doubleToRawLongBits(double value)
- */
-address InterpreterGenerator::generate_Double_doubleToRawLongBits_entry() {
- if (UseSSE >= 2) {
- address entry = __ pc();
-
- // rsi: the sender's SP
-
- // Skip safepoint check (compiler intrinsic versions of this method
- // do not perform safepoint checks either).
-
- // Load the parameter (a floating-point value) into rax.
- __ movl(rdx, Address(rsp, 2*wordSize));
- __ movl(rax, Address(rsp, wordSize));
-
- // Return
- __ pop(rdi); // get return address
- __ mov(rsp, rsi); // set rsp to the sender's SP
- __ jmp(rdi);
- return entry;
- }
-
- return NULL;
-}
-
-//
-// Interpreter stub for calling a native method. (asm interpreter)
-// This sets up a somewhat different looking stack for calling the native method
-// than the typical interpreter frame setup.
-//
-
-address InterpreterGenerator::generate_native_entry(bool synchronized) {
- // determine code generation flags
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // rbx,: Method*
- // rsi: sender sp
- // rsi: previous interpreter state (C++ interpreter) must preserve
- address entry_point = __ pc();
-
- const Address constMethod (rbx, Method::const_offset());
- const Address access_flags (rbx, Method::access_flags_offset());
- const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset());
-
- // get parameter size (always needed)
- __ movptr(rcx, constMethod);
- __ load_unsigned_short(rcx, size_of_parameters);
-
- // native calls don't need the stack size check since they have no expression stack
- // and the arguments are already on the stack and we only add a handful of words
- // to the stack
-
- // rbx,: Method*
- // rcx: size of parameters
- // rsi: sender sp
-
- __ pop(rax); // get return address
- // for natives the size of locals is zero
-
- // compute beginning of parameters (rdi)
- __ lea(rdi, Address(rsp, rcx, Interpreter::stackElementScale(), -wordSize));
-
-
- // add 2 zero-initialized slots for native calls
- // NULL result handler
- __ push((int32_t)NULL_WORD);
- // NULL oop temp (mirror or jni oop result)
- __ push((int32_t)NULL_WORD);
-
- // initialize fixed part of activation frame
- generate_fixed_frame(true);
-
- // make sure method is native & not abstract
-#ifdef ASSERT
- __ movl(rax, access_flags);
- {
- Label L;
- __ testl(rax, JVM_ACC_NATIVE);
- __ jcc(Assembler::notZero, L);
- __ stop("tried to execute non-native method as native");
- __ bind(L);
- }
- { Label L;
- __ testl(rax, JVM_ACC_ABSTRACT);
- __ jcc(Assembler::zero, L);
- __ stop("tried to execute abstract method in interpreter");
- __ bind(L);
- }
-#endif
-
- // Since at this point in the method invocation the exception handler
- // would try to exit the monitor of synchronized methods which hasn't
- // been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. The remove_activation will
- // check this flag.
-
- __ get_thread(rax);
- const Address do_not_unlock_if_synchronized(rax,
- in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
- __ movbool(do_not_unlock_if_synchronized, true);
-
- // increment invocation count & check for overflow
- Label invocation_counter_overflow;
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
- }
-
- Label continue_after_compile;
- __ bind(continue_after_compile);
-
- bang_stack_shadow_pages(true);
-
- // reset the _do_not_unlock_if_synchronized flag
- __ get_thread(rax);
- __ movbool(do_not_unlock_if_synchronized, false);
-
- // check for synchronized methods
- // Must happen AFTER invocation_counter check and stack overflow check,
- // so method is not locked if overflows.
- //
- if (synchronized) {
- lock_method();
- } else {
- // no synchronization necessary
-#ifdef ASSERT
- { Label L;
- __ movl(rax, access_flags);
- __ testl(rax, JVM_ACC_SYNCHRONIZED);
- __ jcc(Assembler::zero, L);
- __ stop("method needs synchronization");
- __ bind(L);
- }
-#endif
- }
-
- // start execution
-#ifdef ASSERT
- { Label L;
- const Address monitor_block_top (rbp,
- frame::interpreter_frame_monitor_block_top_offset * wordSize);
- __ movptr(rax, monitor_block_top);
- __ cmpptr(rax, rsp);
- __ jcc(Assembler::equal, L);
- __ stop("broken stack frame setup in interpreter");
- __ bind(L);
- }
-#endif
-
- // jvmti/dtrace support
- __ notify_method_entry();
-
- // work registers
- const Register method = rbx;
- const Register thread = rdi;
- const Register t = rcx;
-
- // allocate space for parameters
- __ get_method(method);
- __ movptr(t, Address(method, Method::const_offset()));
- __ load_unsigned_short(t, Address(t, ConstMethod::size_of_parameters_offset()));
-
- __ shlptr(t, Interpreter::logStackElementSize);
- __ addptr(t, 2*wordSize); // allocate two more slots for JNIEnv and possible mirror
- __ subptr(rsp, t);
- __ andptr(rsp, -(StackAlignmentInBytes)); // gcc needs 16 byte aligned stacks to do XMM intrinsics
-
- // get signature handler
- { Label L;
- __ movptr(t, Address(method, Method::signature_handler_offset()));
- __ testptr(t, t);
- __ jcc(Assembler::notZero, L);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), method);
- __ get_method(method);
- __ movptr(t, Address(method, Method::signature_handler_offset()));
- __ bind(L);
- }
-
- // call signature handler
- assert(InterpreterRuntime::SignatureHandlerGenerator::from() == rdi, "adjust this code");
- assert(InterpreterRuntime::SignatureHandlerGenerator::to () == rsp, "adjust this code");
- assert(InterpreterRuntime::SignatureHandlerGenerator::temp() == t , "adjust this code");
- // The generated handlers do not touch RBX (the method oop).
- // However, large signatures cannot be cached and are generated
- // each time here. The slow-path generator will blow RBX
- // sometime, so we must reload it after the call.
- __ call(t);
- __ get_method(method); // slow path call blows RBX on DevStudio 5.0
-
- // result handler is in rax,
- // set result handler
- __ movptr(Address(rbp, frame::interpreter_frame_result_handler_offset*wordSize), rax);
-
- // pass mirror handle if static call
- { Label L;
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- __ movl(t, Address(method, Method::access_flags_offset()));
- __ testl(t, JVM_ACC_STATIC);
- __ jcc(Assembler::zero, L);
- // get mirror
- __ movptr(t, Address(method, Method:: const_offset()));
- __ movptr(t, Address(t, ConstMethod::constants_offset()));
- __ movptr(t, Address(t, ConstantPool::pool_holder_offset_in_bytes()));
- __ movptr(t, Address(t, mirror_offset));
- // copy mirror into activation frame
- __ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset * wordSize), t);
- // pass handle to mirror
- __ lea(t, Address(rbp, frame::interpreter_frame_oop_temp_offset * wordSize));
- __ movptr(Address(rsp, wordSize), t);
- __ bind(L);
- }
-
- // get native function entry point
- { Label L;
- __ movptr(rax, Address(method, Method::native_function_offset()));
- ExternalAddress unsatisfied(SharedRuntime::native_method_throw_unsatisfied_link_error_entry());
- __ cmpptr(rax, unsatisfied.addr());
- __ jcc(Assembler::notEqual, L);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), method);
- __ get_method(method);
- __ movptr(rax, Address(method, Method::native_function_offset()));
- __ bind(L);
- }
-
- // pass JNIEnv
- __ get_thread(thread);
- __ lea(t, Address(thread, JavaThread::jni_environment_offset()));
- __ movptr(Address(rsp, 0), t);
-
- // set_last_Java_frame_before_call
- // It is enough that the pc()
- // points into the right code segment. It does not have to be the correct return pc.
- __ set_last_Java_frame(thread, noreg, rbp, __ pc());
-
- // change thread state
-#ifdef ASSERT
- { Label L;
- __ movl(t, Address(thread, JavaThread::thread_state_offset()));
- __ cmpl(t, _thread_in_Java);
- __ jcc(Assembler::equal, L);
- __ stop("Wrong thread state in native stub");
- __ bind(L);
- }
-#endif
-
- // Change state to native
- __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_native);
- __ call(rax);
-
- // result potentially in rdx:rax or ST0
-
- // Verify or restore cpu control state after JNI call
- __ restore_cpu_control_state_after_jni();
-
- // save potential result in ST(0) & rdx:rax
- // (if result handler is the T_FLOAT or T_DOUBLE handler, result must be in ST0 -
- // the check is necessary to avoid potential Intel FPU overflow problems by saving/restoring 'empty' FPU registers)
- // It is safe to do this push because state is _thread_in_native and return address will be found
- // via _last_native_pc and not via _last_jave_sp
-
- // NOTE: the order of theses push(es) is known to frame::interpreter_frame_result.
- // If the order changes or anything else is added to the stack the code in
- // interpreter_frame_result will have to be changed.
-
- { Label L;
- Label push_double;
- ExternalAddress float_handler(AbstractInterpreter::result_handler(T_FLOAT));
- ExternalAddress double_handler(AbstractInterpreter::result_handler(T_DOUBLE));
- __ cmpptr(Address(rbp, (frame::interpreter_frame_oop_temp_offset + 1)*wordSize),
- float_handler.addr());
- __ jcc(Assembler::equal, push_double);
- __ cmpptr(Address(rbp, (frame::interpreter_frame_oop_temp_offset + 1)*wordSize),
- double_handler.addr());
- __ jcc(Assembler::notEqual, L);
- __ bind(push_double);
- __ push_d(); // FP values are returned using the FPU, so push FPU contents (even if UseSSE > 0).
- __ bind(L);
- }
- __ push(ltos);
-
- // change thread state
- __ get_thread(thread);
- __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_native_trans);
- if(os::is_MP()) {
- if (UseMembar) {
- // Force this write out before the read below
- __ membar(Assembler::Membar_mask_bits(
- Assembler::LoadLoad | Assembler::LoadStore |
- Assembler::StoreLoad | Assembler::StoreStore));
- } else {
- // 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
- // due to cache line collision.
- __ serialize_memory(thread, rcx);
- }
- }
-
- if (AlwaysRestoreFPU) {
- // Make sure the control word is correct.
- __ fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std()));
- }
-
- // check for safepoint operation in progress and/or pending suspend requests
- { Label Continue;
-
- __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
- SafepointSynchronize::_not_synchronized);
-
- Label L;
- __ jcc(Assembler::notEqual, L);
- __ cmpl(Address(thread, JavaThread::suspend_flags_offset()), 0);
- __ jcc(Assembler::equal, 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.
- // Also can't use call_VM_leaf either as it will check to see if rsi & rdi are
- // preserved and correspond to the bcp/locals pointers. So we do a runtime call
- // by hand.
- //
- __ push(thread);
- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address,
- JavaThread::check_special_condition_for_native_trans)));
- __ increment(rsp, wordSize);
- __ get_thread(thread);
-
- __ bind(Continue);
- }
-
- // change thread state
- __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_Java);
-
- __ reset_last_Java_frame(thread, true, true);
-
- // reset handle block
- __ movptr(t, Address(thread, JavaThread::active_handles_offset()));
- __ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
-
- // If result was an oop then unbox and save it in the frame
- { Label L;
- Label no_oop, store_result;
- ExternalAddress handler(AbstractInterpreter::result_handler(T_OBJECT));
- __ cmpptr(Address(rbp, frame::interpreter_frame_result_handler_offset*wordSize),
- handler.addr());
- __ jcc(Assembler::notEqual, no_oop);
- __ cmpptr(Address(rsp, 0), (int32_t)NULL_WORD);
- __ pop(ltos);
- __ testptr(rax, rax);
- __ jcc(Assembler::zero, store_result);
- // unbox
- __ movptr(rax, Address(rax, 0));
- __ bind(store_result);
- __ movptr(Address(rbp, (frame::interpreter_frame_oop_temp_offset)*wordSize), rax);
- // keep stack depth as expected by pushing oop which will eventually be discarded
- __ push(ltos);
- __ bind(no_oop);
- }
-
- {
- Label no_reguard;
- __ cmpl(Address(thread, JavaThread::stack_guard_state_offset()), JavaThread::stack_guard_yellow_disabled);
- __ jcc(Assembler::notEqual, no_reguard);
-
- __ pusha();
- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)));
- __ popa();
-
- __ bind(no_reguard);
- }
-
- // restore rsi to have legal interpreter frame,
- // i.e., bci == 0 <=> rsi == code_base()
- // Can't call_VM until bcp is within reasonable.
- __ get_method(method); // method is junk from thread_in_native to now.
- __ movptr(rsi, Address(method,Method::const_offset())); // get ConstMethod*
- __ lea(rsi, Address(rsi,ConstMethod::codes_offset())); // get codebase
-
- // handle exceptions (exception handling will handle unlocking!)
- { Label L;
- __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD);
- __ jcc(Assembler::zero, L);
- // Note: At some point we may want to unify this with the code used in call_VM_base();
- // i.e., we should use the StubRoutines::forward_exception code. For now this
- // doesn't work here because the rsp is not correctly set at this point.
- __ MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception));
- __ should_not_reach_here();
- __ bind(L);
- }
-
- // do unlocking if necessary
- { Label L;
- __ movl(t, Address(method, Method::access_flags_offset()));
- __ testl(t, JVM_ACC_SYNCHRONIZED);
- __ jcc(Assembler::zero, L);
- // the code below should be shared with interpreter macro assembler implementation
- { Label unlock;
- // BasicObjectLock will be first in list, since this is a synchronized method. However, need
- // to check that the object has not been unlocked by an explicit monitorexit bytecode.
- const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset * wordSize - (int)sizeof(BasicObjectLock));
-
- __ lea(rdx, monitor); // address of first monitor
-
- __ movptr(t, Address(rdx, BasicObjectLock::obj_offset_in_bytes()));
- __ testptr(t, t);
- __ jcc(Assembler::notZero, unlock);
-
- // Entry already unlocked, need to throw exception
- __ MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
- __ should_not_reach_here();
-
- __ bind(unlock);
- __ unlock_object(rdx);
- }
- __ bind(L);
- }
-
- // jvmti/dtrace support
- // Note: This must happen _after_ handling/throwing any exceptions since
- // the exception handler code notifies the runtime of method exits
- // too. If this happens before, method entry/exit notifications are
- // not properly paired (was bug - gri 11/22/99).
- __ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI);
-
- // restore potential result in rdx:rax, call result handler to restore potential result in ST0 & handle result
- __ pop(ltos);
- __ movptr(t, Address(rbp, frame::interpreter_frame_result_handler_offset*wordSize));
- __ call(t);
-
- // remove activation
- __ movptr(t, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp
- __ leave(); // remove frame anchor
- __ pop(rdi); // get return address
- __ mov(rsp, t); // set sp to sender sp
- __ jmp(rdi);
-
- if (inc_counter) {
- // Handle overflow of counter and compile method
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(&continue_after_compile);
- }
-
- return entry_point;
-}
-
-//
-// Generic interpreted method entry to (asm) interpreter
-//
-address InterpreterGenerator::generate_normal_entry(bool synchronized) {
- // determine code generation flags
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // rbx,: Method*
- // rsi: sender sp
- address entry_point = __ pc();
-
- const Address constMethod (rbx, Method::const_offset());
- const Address access_flags (rbx, Method::access_flags_offset());
- const Address size_of_parameters(rdx, ConstMethod::size_of_parameters_offset());
- const Address size_of_locals (rdx, ConstMethod::size_of_locals_offset());
-
- // get parameter size (always needed)
- __ movptr(rdx, constMethod);
- __ load_unsigned_short(rcx, size_of_parameters);
-
- // rbx,: Method*
- // rcx: size of parameters
-
- // rsi: sender_sp (could differ from sp+wordSize if we were called via c2i )
-
- __ load_unsigned_short(rdx, size_of_locals); // get size of locals in words
- __ subl(rdx, rcx); // rdx = no. of additional locals
-
- // see if we've got enough room on the stack for locals plus overhead.
- generate_stack_overflow_check();
-
- // get return address
- __ pop(rax);
-
- // compute beginning of parameters (rdi)
- __ lea(rdi, Address(rsp, rcx, Interpreter::stackElementScale(), -wordSize));
-
- // rdx - # of additional locals
- // allocate space for locals
- // explicitly initialize locals
- {
- Label exit, loop;
- __ testl(rdx, rdx);
- __ jcc(Assembler::lessEqual, exit); // do nothing if rdx <= 0
- __ bind(loop);
- __ push((int32_t)NULL_WORD); // initialize local variables
- __ decrement(rdx); // until everything initialized
- __ jcc(Assembler::greater, loop);
- __ bind(exit);
- }
-
- // initialize fixed part of activation frame
- generate_fixed_frame(false);
-
- // make sure method is not native & not abstract
-#ifdef ASSERT
- __ movl(rax, access_flags);
- {
- Label L;
- __ testl(rax, JVM_ACC_NATIVE);
- __ jcc(Assembler::zero, L);
- __ stop("tried to execute native method as non-native");
- __ bind(L);
- }
- { Label L;
- __ testl(rax, JVM_ACC_ABSTRACT);
- __ jcc(Assembler::zero, L);
- __ stop("tried to execute abstract method in interpreter");
- __ bind(L);
- }
-#endif
-
- // Since at this point in the method invocation the exception handler
- // would try to exit the monitor of synchronized methods which hasn't
- // been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. The remove_activation will
- // check this flag.
-
- __ get_thread(rax);
- const Address do_not_unlock_if_synchronized(rax,
- in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
- __ movbool(do_not_unlock_if_synchronized, true);
-
- __ profile_parameters_type(rax, rcx, rdx);
- // increment invocation count & check for overflow
- Label invocation_counter_overflow;
- Label profile_method;
- Label profile_method_continue;
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue);
- if (ProfileInterpreter) {
- __ bind(profile_method_continue);
- }
- }
- Label continue_after_compile;
- __ bind(continue_after_compile);
-
- bang_stack_shadow_pages(false);
-
- // reset the _do_not_unlock_if_synchronized flag
- __ get_thread(rax);
- __ movbool(do_not_unlock_if_synchronized, false);
-
- // check for synchronized methods
- // Must happen AFTER invocation_counter check and stack overflow check,
- // so method is not locked if overflows.
- //
- if (synchronized) {
- // Allocate monitor and lock method
- lock_method();
- } else {
- // no synchronization necessary
-#ifdef ASSERT
- { Label L;
- __ movl(rax, access_flags);
- __ testl(rax, JVM_ACC_SYNCHRONIZED);
- __ jcc(Assembler::zero, L);
- __ stop("method needs synchronization");
- __ bind(L);
- }
-#endif
- }
-
- // start execution
-#ifdef ASSERT
- { Label L;
- const Address monitor_block_top (rbp,
- frame::interpreter_frame_monitor_block_top_offset * wordSize);
- __ movptr(rax, monitor_block_top);
- __ cmpptr(rax, rsp);
- __ jcc(Assembler::equal, L);
- __ stop("broken stack frame setup in interpreter");
- __ bind(L);
- }
-#endif
-
- // jvmti support
- __ notify_method_entry();
-
- __ dispatch_next(vtos);
-
- // invocation counter overflow
- if (inc_counter) {
- if (ProfileInterpreter) {
- // We have decided to profile this method in the interpreter
- __ bind(profile_method);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
- __ set_method_data_pointer_for_bcp();
- __ get_method(rbx);
- __ jmp(profile_method_continue);
- }
- // Handle overflow of counter and compile method
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(&continue_after_compile);
- }
-
- return entry_point;
-}
-
-
-// These should never be compiled since the interpreter will prefer
-// the compiled version to the intrinsic version.
-bool AbstractInterpreter::can_be_compiled(methodHandle m) {
- switch (method_kind(m)) {
- case Interpreter::java_lang_math_sin : // fall thru
- case Interpreter::java_lang_math_cos : // fall thru
- case Interpreter::java_lang_math_tan : // fall thru
- case Interpreter::java_lang_math_abs : // fall thru
- case Interpreter::java_lang_math_log : // fall thru
- case Interpreter::java_lang_math_log10 : // fall thru
- case Interpreter::java_lang_math_sqrt : // fall thru
- case Interpreter::java_lang_math_pow : // fall thru
- case Interpreter::java_lang_math_exp :
- return false;
- default:
- return true;
- }
-}
-
-// How much stack a method activation needs in words.
-int AbstractInterpreter::size_top_interpreter_activation(Method* method) {
-
- const int stub_code = 4; // see generate_call_stub
- // Save space for one monitor to get into the interpreted method in case
- // the method is synchronized
- int monitor_size = method->is_synchronized() ?
- 1*frame::interpreter_frame_monitor_size() : 0;
-
- // total overhead size: entry_size + (saved rbp, thru expr stack bottom).
- // be sure to change this if you add/subtract anything to/from the overhead area
- const int overhead_size = -frame::interpreter_frame_initial_sp_offset;
-
- const int method_stack = (method->max_locals() + method->max_stack()) *
- Interpreter::stackElementWords;
- return overhead_size + method_stack + stub_code;
-}
-
-//------------------------------------------------------------------------------------------------------------------------
-// Exceptions
-
-void TemplateInterpreterGenerator::generate_throw_exception() {
- // Entry point in previous activation (i.e., if the caller was interpreted)
- Interpreter::_rethrow_exception_entry = __ pc();
- const Register thread = rcx;
-
- // Restore sp to interpreter_frame_last_sp even though we are going
- // to empty the expression stack for the exception processing.
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD);
- // rax,: exception
- // rdx: return address/pc that threw exception
- __ restore_bcp(); // rsi points to call/send
- __ restore_locals();
-
- // Entry point for exceptions thrown within interpreter code
- Interpreter::_throw_exception_entry = __ pc();
- // expression stack is undefined here
- // rax,: exception
- // rsi: exception bcp
- __ verify_oop(rax);
-
- // expression stack must be empty before entering the VM in case of an exception
- __ empty_expression_stack();
- __ empty_FPU_stack();
- // find exception handler address and preserve exception oop
- __ call_VM(rdx, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), rax);
- // rax,: exception handler entry point
- // rdx: preserved exception oop
- // rsi: bcp for exception handler
- __ push_ptr(rdx); // push exception which is now the only value on the stack
- __ jmp(rax); // jump to exception handler (may be _remove_activation_entry!)
-
- // If the exception is not handled in the current frame the frame is removed and
- // the exception is rethrown (i.e. exception continuation is _rethrow_exception).
- //
- // Note: At this point the bci is still the bxi for the instruction which caused
- // the exception and the expression stack is empty. Thus, for any VM calls
- // at this point, GC will find a legal oop map (with empty expression stack).
-
- // In current activation
- // tos: exception
- // rsi: exception bcp
-
- //
- // JVMTI PopFrame support
- //
-
- Interpreter::_remove_activation_preserving_args_entry = __ pc();
- __ empty_expression_stack();
- __ empty_FPU_stack();
- // Set the popframe_processing bit in pending_popframe_condition indicating that we are
- // currently handling popframe, so that call_VMs that may happen later do not trigger new
- // popframe handling cycles.
- __ get_thread(thread);
- __ movl(rdx, Address(thread, JavaThread::popframe_condition_offset()));
- __ orl(rdx, JavaThread::popframe_processing_bit);
- __ movl(Address(thread, JavaThread::popframe_condition_offset()), rdx);
-
- {
- // Check to see whether we are returning to a deoptimized frame.
- // (The PopFrame call ensures that the caller of the popped frame is
- // either interpreted or compiled and deoptimizes it if compiled.)
- // In this case, we can't call dispatch_next() after the frame is
- // popped, but instead must save the incoming arguments and restore
- // them after deoptimization has occurred.
- //
- // Note that we don't compare the return PC against the
- // deoptimization blob's unpack entry because of the presence of
- // adapter frames in C2.
- Label caller_not_deoptimized;
- __ movptr(rdx, Address(rbp, frame::return_addr_offset * wordSize));
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), rdx);
- __ testl(rax, rax);
- __ jcc(Assembler::notZero, caller_not_deoptimized);
-
- // Compute size of arguments for saving when returning to deoptimized caller
- __ get_method(rax);
- __ movptr(rax, Address(rax, Method::const_offset()));
- __ load_unsigned_short(rax, Address(rax, ConstMethod::size_of_parameters_offset()));
- __ shlptr(rax, Interpreter::logStackElementSize);
- __ restore_locals();
- __ subptr(rdi, rax);
- __ addptr(rdi, wordSize);
- // Save these arguments
- __ get_thread(thread);
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), thread, rax, rdi);
-
- __ remove_activation(vtos, rdx,
- /* throw_monitor_exception */ false,
- /* install_monitor_exception */ false,
- /* notify_jvmdi */ false);
-
- // Inform deoptimization that it is responsible for restoring these arguments
- __ get_thread(thread);
- __ movl(Address(thread, JavaThread::popframe_condition_offset()), JavaThread::popframe_force_deopt_reexecution_bit);
-
- // Continue in deoptimization handler
- __ jmp(rdx);
-
- __ bind(caller_not_deoptimized);
- }
-
- __ remove_activation(vtos, rdx,
- /* throw_monitor_exception */ false,
- /* install_monitor_exception */ false,
- /* notify_jvmdi */ false);
-
- // Finish with popframe handling
- // A previous I2C followed by a deoptimization might have moved the
- // outgoing arguments further up the stack. PopFrame expects the
- // mutations to those outgoing arguments to be preserved and other
- // constraints basically require this frame to look exactly as
- // though it had previously invoked an interpreted activation with
- // no space between the top of the expression stack (current
- // last_sp) and the top of stack. Rather than force deopt to
- // maintain this kind of invariant all the time we call a small
- // fixup routine to move the mutated arguments onto the top of our
- // expression stack if necessary.
- __ mov(rax, rsp);
- __ movptr(rbx, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
- __ get_thread(thread);
- // PC must point into interpreter here
- __ set_last_Java_frame(thread, noreg, rbp, __ pc());
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), thread, rax, rbx);
- __ get_thread(thread);
- __ reset_last_Java_frame(thread, true, true);
- // Restore the last_sp and null it out
- __ movptr(rsp, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD);
-
- __ restore_bcp();
- __ restore_locals();
- // The method data pointer was incremented already during
- // call profiling. We have to restore the mdp for the current bcp.
- if (ProfileInterpreter) {
- __ set_method_data_pointer_for_bcp();
- }
-
- // Clear the popframe condition flag
- __ get_thread(thread);
- __ movl(Address(thread, JavaThread::popframe_condition_offset()), JavaThread::popframe_inactive);
-
-#if INCLUDE_JVMTI
- {
- Label L_done;
- const Register local0 = rdi;
-
- __ cmpb(Address(rsi, 0), Bytecodes::_invokestatic);
- __ jcc(Assembler::notEqual, L_done);
-
- // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
- // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
-
- __ get_method(rdx);
- __ movptr(rax, Address(local0, 0));
- __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), rax, rdx, rsi);
-
- __ testptr(rax, rax);
- __ jcc(Assembler::zero, L_done);
-
- __ movptr(Address(rbx, 0), rax);
- __ bind(L_done);
- }
-#endif // INCLUDE_JVMTI
-
- __ dispatch_next(vtos);
- // end of PopFrame support
-
- Interpreter::_remove_activation_entry = __ pc();
-
- // preserve exception over this code sequence
- __ pop_ptr(rax);
- __ get_thread(thread);
- __ movptr(Address(thread, JavaThread::vm_result_offset()), rax);
- // remove the activation (without doing throws on illegalMonitorExceptions)
- __ remove_activation(vtos, rdx, false, true, false);
- // restore exception
- __ get_thread(thread);
- __ get_vm_result(rax, thread);
-
- // Inbetween activations - previous activation type unknown yet
- // compute continuation point - the continuation point expects
- // the following registers set up:
- //
- // rax: exception
- // rdx: return address/pc that threw exception
- // rsp: expression stack of caller
- // rbp: rbp, of caller
- __ push(rax); // save exception
- __ push(rdx); // save return address
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, rdx);
- __ mov(rbx, rax); // save exception handler
- __ pop(rdx); // restore return address
- __ pop(rax); // restore exception
- // Note that an "issuing PC" is actually the next PC after the call
- __ jmp(rbx); // jump to exception handler of caller
-}
-
-
-//
-// JVMTI ForceEarlyReturn support
-//
-address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
- address entry = __ pc();
- const Register thread = rcx;
-
- __ restore_bcp();
- __ restore_locals();
- __ empty_expression_stack();
- __ empty_FPU_stack();
- __ load_earlyret_value(state);
-
- __ get_thread(thread);
- __ movptr(rcx, Address(thread, JavaThread::jvmti_thread_state_offset()));
- const Address cond_addr(rcx, JvmtiThreadState::earlyret_state_offset());
-
- // Clear the earlyret state
- __ movl(cond_addr, JvmtiThreadState::earlyret_inactive);
-
- __ remove_activation(state, rsi,
- false, /* throw_monitor_exception */
- false, /* install_monitor_exception */
- true); /* notify_jvmdi */
- __ jmp(rsi);
- return entry;
-} // end of ForceEarlyReturn support
-
-
-//------------------------------------------------------------------------------------------------------------------------
-// Helper for vtos entry point generation
-
-void TemplateInterpreterGenerator::set_vtos_entry_points (Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) {
- assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
- Label L;
- fep = __ pc(); __ push(ftos); __ jmp(L);
- dep = __ pc(); __ push(dtos); __ jmp(L);
- lep = __ pc(); __ push(ltos); __ jmp(L);
- aep = __ pc(); __ push(atos); __ jmp(L);
- bep = cep = sep = // fall through
- iep = __ pc(); __ push(itos); // fall through
- vep = __ pc(); __ bind(L); // fall through
- generate_and_dispatch(t);
-}
-
-//------------------------------------------------------------------------------------------------------------------------
-// Generation of individual instructions
-
-// helpers for generate_and_dispatch
-
-
-
-InterpreterGenerator::InterpreterGenerator(StubQueue* code)
- : TemplateInterpreterGenerator(code) {
- generate_all(); // down here so it can be "virtual"
-}
-
-//------------------------------------------------------------------------------------------------------------------------
-
-// Non-product code
-#ifndef PRODUCT
-address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
- address entry = __ pc();
-
- // prepare expression stack
- __ pop(rcx); // pop return address so expression stack is 'pure'
- __ push(state); // save tosca
-
- // pass tosca registers as arguments & call tracer
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), rcx, rax, rdx);
- __ mov(rcx, rax); // make sure return address is not destroyed by pop(state)
- __ pop(state); // restore tosca
-
- // return
- __ jmp(rcx);
-
- return entry;
-}
-
-
-void TemplateInterpreterGenerator::count_bytecode() {
- __ incrementl(ExternalAddress((address) &BytecodeCounter::_counter_value));
-}
-
-
-void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
- __ incrementl(ExternalAddress((address) &BytecodeHistogram::_counters[t->bytecode()]));
-}
-
-
-void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) {
- __ mov32(ExternalAddress((address) &BytecodePairHistogram::_index), rbx);
- __ shrl(rbx, BytecodePairHistogram::log2_number_of_codes);
- __ orl(rbx, ((int)t->bytecode()) << BytecodePairHistogram::log2_number_of_codes);
- ExternalAddress table((address) BytecodePairHistogram::_counters);
- Address index(noreg, rbx, Address::times_4);
- __ incrementl(ArrayAddress(table, index));
-}
-
-
-void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
- // Call a little run-time stub to avoid blow-up for each bytecode.
- // The run-time runtime saves the right registers, depending on
- // the tosca in-state for the given template.
- assert(Interpreter::trace_code(t->tos_in()) != NULL,
- "entry must have been generated");
- __ call(RuntimeAddress(Interpreter::trace_code(t->tos_in())));
-}
-
-
-void TemplateInterpreterGenerator::stop_interpreter_at() {
- Label L;
- __ cmp32(ExternalAddress((address) &BytecodeCounter::_counter_value),
- StopInterpreterAt);
- __ jcc(Assembler::notEqual, L);
- __ int3();
- __ bind(L);
-}
-#endif // !PRODUCT
-#endif // CC_INTERP
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1866 +0,0 @@
-/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/macroAssembler.hpp"
-#include "interpreter/bytecodeHistogram.hpp"
-#include "interpreter/interpreter.hpp"
-#include "interpreter/interpreterGenerator.hpp"
-#include "interpreter/interpreterRuntime.hpp"
-#include "interpreter/interp_masm.hpp"
-#include "interpreter/templateTable.hpp"
-#include "oops/arrayOop.hpp"
-#include "oops/methodData.hpp"
-#include "oops/method.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/jvmtiExport.hpp"
-#include "prims/jvmtiThreadState.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/synchronizer.hpp"
-#include "runtime/timer.hpp"
-#include "runtime/vframeArray.hpp"
-#include "utilities/debug.hpp"
-#include "utilities/macros.hpp"
-
-#define __ _masm->
-
-#ifndef CC_INTERP
-
-const int method_offset = frame::interpreter_frame_method_offset * wordSize;
-const int bcp_offset = frame::interpreter_frame_bcp_offset * wordSize;
-const int locals_offset = frame::interpreter_frame_locals_offset * wordSize;
-
-//-----------------------------------------------------------------------------
-
-address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
- address entry = __ pc();
-
-#ifdef ASSERT
- {
- Label L;
- __ lea(rax, Address(rbp,
- frame::interpreter_frame_monitor_block_top_offset *
- wordSize));
- __ cmpptr(rax, rsp); // rax = maximal rsp for current rbp (stack
- // grows negative)
- __ jcc(Assembler::aboveEqual, L); // check if frame is complete
- __ stop ("interpreter frame not set up");
- __ bind(L);
- }
-#endif // ASSERT
- // Restore bcp under the assumption that the current frame is still
- // interpreted
- __ restore_bcp();
-
- // expression stack must be empty before entering the VM if an
- // exception happened
- __ empty_expression_stack();
- // throw exception
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_StackOverflowError));
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(
- const char* name) {
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an
- // exception happened
- __ empty_expression_stack();
- // setup parameters
- // ??? convention: expect aberrant index in register ebx
- __ lea(c_rarg1, ExternalAddress((address)name));
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::
- throw_ArrayIndexOutOfBoundsException),
- c_rarg1, rbx);
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
- address entry = __ pc();
-
- // object is at TOS
- __ pop(c_rarg1);
-
- // expression stack must be empty before entering the VM if an
- // exception happened
- __ empty_expression_stack();
-
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::
- throw_ClassCastException),
- c_rarg1);
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_exception_handler_common(
- const char* name, const char* message, bool pass_oop) {
- assert(!pass_oop || message == NULL, "either oop or message but not both");
- address entry = __ pc();
- if (pass_oop) {
- // object is at TOS
- __ pop(c_rarg2);
- }
- // expression stack must be empty before entering the VM if an
- // exception happened
- __ empty_expression_stack();
- // setup parameters
- __ lea(c_rarg1, ExternalAddress((address)name));
- if (pass_oop) {
- __ call_VM(rax, CAST_FROM_FN_PTR(address,
- InterpreterRuntime::
- create_klass_exception),
- c_rarg1, c_rarg2);
- } else {
- // kind of lame ExternalAddress can't take NULL because
- // external_word_Relocation will assert.
- if (message != NULL) {
- __ lea(c_rarg2, ExternalAddress((address)message));
- } else {
- __ movptr(c_rarg2, NULL_WORD);
- }
- __ call_VM(rax,
- CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception),
- c_rarg1, c_rarg2);
- }
- // throw exception
- __ jump(ExternalAddress(Interpreter::throw_exception_entry()));
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
- address entry = __ pc();
- // NULL last_sp until next java call
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
- __ dispatch_next(state);
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
- address entry = __ pc();
-
- // Restore stack bottom in case i2c adjusted stack
- __ movptr(rsp, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
- // and NULL it as marker that esp is now tos until next java call
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
-
- __ restore_bcp();
- __ restore_locals();
-
- if (state == atos) {
- Register mdp = rbx;
- Register tmp = rcx;
- __ profile_return_type(mdp, rax, tmp);
- }
-
- const Register cache = rbx;
- const Register index = rcx;
- __ get_cache_and_index_at_bcp(cache, index, 1, index_size);
-
- const Register flags = cache;
- __ movl(flags, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
- __ andl(flags, ConstantPoolCacheEntry::parameter_size_mask);
- __ lea(rsp, Address(rsp, flags, Interpreter::stackElementScale()));
- __ dispatch_next(state, step);
-
- return entry;
-}
-
-
-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;
- __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
- __ jcc(Assembler::zero, L);
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_pending_exception));
- __ should_not_reach_here();
- __ bind(L);
- }
- __ dispatch_next(state, step);
- return entry;
-}
-
-int AbstractInterpreter::BasicType_as_index(BasicType type) {
- int i = 0;
- switch (type) {
- case T_BOOLEAN: i = 0; break;
- case T_CHAR : i = 1; break;
- case T_BYTE : i = 2; break;
- case T_SHORT : i = 3; break;
- case T_INT : i = 4; break;
- case T_LONG : i = 5; break;
- case T_VOID : i = 6; break;
- case T_FLOAT : i = 7; break;
- case T_DOUBLE : i = 8; break;
- case T_OBJECT : i = 9; break;
- case T_ARRAY : i = 9; break;
- default : ShouldNotReachHere();
- }
- assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers,
- "index out of bounds");
- return i;
-}
-
-
-address TemplateInterpreterGenerator::generate_result_handler_for(
- BasicType type) {
- address entry = __ pc();
- switch (type) {
- case T_BOOLEAN: __ c2bool(rax); break;
- case T_CHAR : __ movzwl(rax, rax); break;
- case T_BYTE : __ sign_extend_byte(rax); break;
- case T_SHORT : __ sign_extend_short(rax); break;
- case T_INT : /* nothing to do */ break;
- case T_LONG : /* nothing to do */ break;
- case T_VOID : /* nothing to do */ break;
- case T_FLOAT : /* nothing to do */ break;
- case T_DOUBLE : /* nothing to do */ break;
- case T_OBJECT :
- // retrieve result from frame
- __ movptr(rax, Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize));
- // and verify it
- __ verify_oop(rax);
- break;
- default : ShouldNotReachHere();
- }
- __ ret(0); // return from result handler
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_safept_entry_for(
- TosState state,
- address runtime_entry) {
- address entry = __ pc();
- __ push(state);
- __ call_VM(noreg, runtime_entry);
- __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos));
- return entry;
-}
-
-
-
-// Helpers for commoning out cases in the various type of method entries.
-//
-
-
-// increment invocation count & check for overflow
-//
-// Note: checking for negative value instead of overflow
-// so we have a 'sticky' overflow test
-//
-// rbx: method
-// ecx: invocation counter
-//
-void InterpreterGenerator::generate_counter_incr(
- Label* overflow,
- Label* profile_method,
- Label* profile_method_continue) {
- Label done;
- // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not.
- if (TieredCompilation) {
- int increment = InvocationCounter::count_increment;
- Label no_mdo;
- if (ProfileInterpreter) {
- // Are we profiling?
- __ movptr(rax, Address(rbx, Method::method_data_offset()));
- __ testptr(rax, rax);
- __ jccb(Assembler::zero, no_mdo);
- // Increment counter in the MDO
- const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) +
- in_bytes(InvocationCounter::counter_offset()));
- const Address mask(rax, in_bytes(MethodData::invoke_mask_offset()));
- __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow);
- __ jmp(done);
- }
- __ bind(no_mdo);
- // Increment counter in MethodCounters
- const Address invocation_counter(rax,
- MethodCounters::invocation_counter_offset() +
- InvocationCounter::counter_offset());
- __ get_method_counters(rbx, rax, done);
- const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset()));
- __ increment_mask_and_jump(invocation_counter, increment, mask, rcx,
- false, Assembler::zero, overflow);
- __ bind(done);
- } else { // not TieredCompilation
- const Address backedge_counter(rax,
- MethodCounters::backedge_counter_offset() +
- InvocationCounter::counter_offset());
- const Address invocation_counter(rax,
- MethodCounters::invocation_counter_offset() +
- InvocationCounter::counter_offset());
-
- __ get_method_counters(rbx, rax, done);
-
- if (ProfileInterpreter) {
- __ incrementl(Address(rax,
- MethodCounters::interpreter_invocation_counter_offset()));
- }
- // Update standard invocation counters
- __ movl(rcx, invocation_counter);
- __ incrementl(rcx, InvocationCounter::count_increment);
- __ movl(invocation_counter, rcx); // save invocation count
-
- __ movl(rax, backedge_counter); // load backedge counter
- __ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits
-
- __ addl(rcx, rax); // add both counters
-
- // profile_method is non-null only for interpreted method so
- // profile_method != NULL == !native_call
-
- if (ProfileInterpreter && profile_method != NULL) {
- // Test to see if we should create a method data oop
- __ movptr(rax, Address(rbx, Method::method_counters_offset()));
- __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset())));
- __ jcc(Assembler::less, *profile_method_continue);
-
- // if no method data exists, go to profile_method
- __ test_method_data_pointer(rax, *profile_method);
- }
-
- __ movptr(rax, Address(rbx, Method::method_counters_offset()));
- __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset())));
- __ jcc(Assembler::aboveEqual, *overflow);
- __ bind(done);
- }
-}
-
-void InterpreterGenerator::generate_counter_overflow(Label* do_continue) {
-
- // Asm interpreter on entry
- // r14 - locals
- // r13 - bcp
- // rbx - method
- // edx - cpool --- DOES NOT APPEAR TO BE TRUE
- // rbp - interpreter frame
-
- // On return (i.e. jump to entry_point) [ back to invocation of interpreter ]
- // Everything as it was on entry
- // rdx is not restored. Doesn't appear to really be set.
-
- // InterpreterRuntime::frequency_counter_overflow takes two
- // arguments, the first (thread) is passed by call_VM, the second
- // indicates if the counter overflow occurs at a backwards branch
- // (NULL bcp). We pass zero for it. The call returns the address
- // of the verified entry point for the method or NULL if the
- // compilation did not complete (either went background or bailed
- // out).
- __ movl(c_rarg1, 0);
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::frequency_counter_overflow),
- c_rarg1);
-
- __ movptr(rbx, Address(rbp, method_offset)); // restore Method*
- // Preserve invariant that r13/r14 contain bcp/locals of sender frame
- // and jump to the interpreted entry.
- __ jmp(*do_continue, relocInfo::none);
-}
-
-// See if we've got enough room on the stack for locals plus overhead.
-// The expression stack grows down incrementally, so the normal guard
-// page mechanism will work for that.
-//
-// NOTE: Since the additional locals are also always pushed (wasn't
-// obvious in generate_fixed_frame) so the guard should work for them
-// too.
-//
-// Args:
-// rdx: number of additional locals this frame needs (what we must check)
-// rbx: Method*
-//
-// Kills:
-// rax
-void InterpreterGenerator::generate_stack_overflow_check(void) {
-
- // monitor entry size: see picture of stack in frame_x86.hpp
- const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
-
- // total overhead size: entry_size + (saved rbp through expr stack
- // bottom). be sure to change this if you add/subtract anything
- // to/from the overhead area
- const int overhead_size =
- -(frame::interpreter_frame_initial_sp_offset * wordSize) + entry_size;
-
- const int page_size = os::vm_page_size();
-
- Label after_frame_check;
-
- // see if the frame is greater than one page in size. If so,
- // then we need to verify there is enough stack space remaining
- // for the additional locals.
- __ cmpl(rdx, (page_size - overhead_size) / Interpreter::stackElementSize);
- __ jcc(Assembler::belowEqual, after_frame_check);
-
- // compute rsp as if this were going to be the last frame on
- // the stack before the red zone
-
- const Address stack_base(r15_thread, Thread::stack_base_offset());
- const Address stack_size(r15_thread, Thread::stack_size_offset());
-
- // locals + overhead, in bytes
- __ mov(rax, rdx);
- __ shlptr(rax, Interpreter::logStackElementSize); // 2 slots per parameter.
- __ addptr(rax, overhead_size);
-
-#ifdef ASSERT
- Label stack_base_okay, stack_size_okay;
- // verify that thread stack base is non-zero
- __ cmpptr(stack_base, (int32_t)NULL_WORD);
- __ jcc(Assembler::notEqual, stack_base_okay);
- __ stop("stack base is zero");
- __ bind(stack_base_okay);
- // verify that thread stack size is non-zero
- __ cmpptr(stack_size, 0);
- __ jcc(Assembler::notEqual, stack_size_okay);
- __ stop("stack size is zero");
- __ bind(stack_size_okay);
-#endif
-
- // Add stack base to locals and subtract stack size
- __ addptr(rax, stack_base);
- __ subptr(rax, stack_size);
-
- // Use the maximum number of pages we might bang.
- const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages :
- (StackRedPages+StackYellowPages);
-
- // add in the red and yellow zone sizes
- __ addptr(rax, max_pages * page_size);
-
- // check against the current stack bottom
- __ cmpptr(rsp, rax);
- __ jcc(Assembler::above, after_frame_check);
-
- // Restore sender's sp as SP. This is necessary if the sender's
- // frame is an extended compiled frame (see gen_c2i_adapter())
- // and safer anyway in case of JSR292 adaptations.
-
- __ pop(rax); // return address must be moved if SP is changed
- __ mov(rsp, r13);
- __ push(rax);
-
- // Note: the restored frame is not necessarily interpreted.
- // Use the shared runtime version of the StackOverflowError.
- assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "stub not yet generated");
- __ jump(ExternalAddress(StubRoutines::throw_StackOverflowError_entry()));
-
- // all done with frame size check
- __ bind(after_frame_check);
-}
-
-// Allocate monitor and lock method (asm interpreter)
-//
-// Args:
-// rbx: Method*
-// r14: locals
-//
-// Kills:
-// rax
-// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs)
-// rscratch1, rscratch2 (scratch regs)
-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);
- const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
-
-#ifdef ASSERT
- {
- Label L;
- __ movl(rax, access_flags);
- __ testl(rax, JVM_ACC_SYNCHRONIZED);
- __ jcc(Assembler::notZero, L);
- __ stop("method doesn't need synchronization");
- __ bind(L);
- }
-#endif // ASSERT
-
- // get synchronization object
- {
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- Label done;
- __ movl(rax, access_flags);
- __ testl(rax, JVM_ACC_STATIC);
- // get receiver (assume this is frequent case)
- __ movptr(rax, Address(r14, Interpreter::local_offset_in_bytes(0)));
- __ jcc(Assembler::zero, done);
- __ movptr(rax, Address(rbx, Method::const_offset()));
- __ movptr(rax, Address(rax, ConstMethod::constants_offset()));
- __ movptr(rax, Address(rax,
- ConstantPool::pool_holder_offset_in_bytes()));
- __ movptr(rax, Address(rax, mirror_offset));
-
-#ifdef ASSERT
- {
- Label L;
- __ testptr(rax, rax);
- __ jcc(Assembler::notZero, L);
- __ stop("synchronization object is NULL");
- __ bind(L);
- }
-#endif // ASSERT
-
- __ bind(done);
- }
-
- // add space for monitor & lock
- __ subptr(rsp, entry_size); // add space for a monitor entry
- __ movptr(monitor_block_top, rsp); // set new monitor block top
- // store object
- __ movptr(Address(rsp, BasicObjectLock::obj_offset_in_bytes()), rax);
- __ movptr(c_rarg1, rsp); // object address
- __ lock_object(c_rarg1);
-}
-
-// Generate a fixed interpreter frame. This is identical setup for
-// interpreted methods and for native methods hence the shared code.
-//
-// Args:
-// rax: return address
-// rbx: Method*
-// r14: pointer to locals
-// r13: sender sp
-// rdx: cp cache
-void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
- // initialize fixed part of activation frame
- __ push(rax); // save return address
- __ enter(); // save old & set new rbp
- __ push(r13); // set sender sp
- __ push((int)NULL_WORD); // leave last_sp as null
- __ movptr(r13, Address(rbx, Method::const_offset())); // get ConstMethod*
- __ lea(r13, Address(r13, ConstMethod::codes_offset())); // get codebase
- __ push(rbx); // save Method*
- if (ProfileInterpreter) {
- Label method_data_continue;
- __ movptr(rdx, Address(rbx, in_bytes(Method::method_data_offset())));
- __ testptr(rdx, rdx);
- __ jcc(Assembler::zero, method_data_continue);
- __ addptr(rdx, in_bytes(MethodData::data_offset()));
- __ bind(method_data_continue);
- __ push(rdx); // set the mdp (method data pointer)
- } else {
- __ push(0);
- }
-
- __ movptr(rdx, Address(rbx, Method::const_offset()));
- __ movptr(rdx, Address(rdx, ConstMethod::constants_offset()));
- __ movptr(rdx, Address(rdx, ConstantPool::cache_offset_in_bytes()));
- __ push(rdx); // set constant pool cache
- __ push(r14); // set locals pointer
- if (native_call) {
- __ push(0); // no bcp
- } else {
- __ push(r13); // set bcp
- }
- __ push(0); // reserve word for pointer to expression stack bottom
- __ movptr(Address(rsp, 0), rsp); // set expression stack bottom
-}
-
-// End of helpers
-
-// Method entry for java.lang.ref.Reference.get.
-address InterpreterGenerator::generate_Reference_get_entry(void) {
-#if INCLUDE_ALL_GCS
- // Code: _aload_0, _getfield, _areturn
- // parameter size = 1
- //
- // The code that gets generated by this routine is split into 2 parts:
- // 1. The "intrinsified" code for G1 (or any SATB based GC),
- // 2. The slow path - which is an expansion of the regular method entry.
- //
- // Notes:-
- // * In the G1 code we do not check whether we need to block for
- // a safepoint. If G1 is enabled then we must execute the specialized
- // code for Reference.get (except when the Reference object is null)
- // so that we can log the value in the referent field with an SATB
- // update buffer.
- // If the code for the getfield template is modified so that the
- // G1 pre-barrier code is executed when the current method is
- // Reference.get() then going through the normal method entry
- // will be fine.
- // * The G1 code can, however, check the receiver object (the instance
- // of java.lang.Reference) and jump to the slow path if null. If the
- // Reference object is null then we obviously cannot fetch the referent
- // and so we don't need to call the G1 pre-barrier. Thus we can use the
- // regular method entry code to generate the NPE.
- //
- // rbx: Method*
-
- // r13: senderSP must preserve for slow path, set SP to it on fast path
-
- 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;
- // rbx: method
-
- // Check if local 0 != NULL
- // If the receiver is null then it is OK to jump to the slow path.
- __ movptr(rax, Address(rsp, wordSize));
-
- __ testptr(rax, rax);
- __ jcc(Assembler::zero, slow_path);
-
- // rax: local 0
- // rbx: method (but can be used as scratch now)
- // rdx: scratch
- // rdi: scratch
-
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer.
-
- // Load the value of the referent field.
- const Address field_address(rax, referent_offset);
- __ load_heap_oop(rax, field_address);
-
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer.
- __ g1_write_barrier_pre(noreg /* obj */,
- rax /* pre_val */,
- r15_thread /* thread */,
- rbx /* tmp */,
- true /* tosca_live */,
- true /* expand_call */);
-
- // _areturn
- __ pop(rdi); // get return address
- __ mov(rsp, r13); // set sp to sender sp
- __ jmp(rdi);
- __ ret(0);
-
- // generate a vanilla interpreter entry as the slow path
- __ bind(slow_path);
- __ 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 NULL;
-}
-
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.update(int crc, int b)
- */
-address InterpreterGenerator::generate_CRC32_update_entry() {
- if (UseCRC32Intrinsics) {
- address entry = __ pc();
-
- // rbx,: Method*
- // r13: senderSP must preserved for slow path, set SP to it on fast path
- // c_rarg0: scratch (rdi on non-Win64, rcx on Win64)
- // c_rarg1: scratch (rsi on non-Win64, rdx on Win64)
-
- Label slow_path;
- // If we need a safepoint check, generate full interpreter entry.
- ExternalAddress state(SafepointSynchronize::address_of_state());
- __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
- SafepointSynchronize::_not_synchronized);
- __ jcc(Assembler::notEqual, slow_path);
-
- // We don't generate local frame and don't align stack because
- // we call stub code and there is no safepoint on this path.
-
- // Load parameters
- const Register crc = rax; // crc
- const Register val = c_rarg0; // source java byte value
- const Register tbl = c_rarg1; // scratch
-
- // Arguments are reversed on java expression stack
- __ movl(val, Address(rsp, wordSize)); // byte value
- __ movl(crc, Address(rsp, 2*wordSize)); // Initial CRC
-
- __ lea(tbl, ExternalAddress(StubRoutines::crc_table_addr()));
- __ notl(crc); // ~crc
- __ update_byte_crc32(crc, val, tbl);
- __ notl(crc); // ~crc
- // result in rax
-
- // _areturn
- __ pop(rdi); // get return address
- __ mov(rsp, r13); // set sp to sender sp
- __ jmp(rdi);
-
- // 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;
-}
-
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len)
- * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len)
- */
-address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
- if (UseCRC32Intrinsics) {
- address entry = __ pc();
-
- // rbx,: Method*
- // r13: senderSP must preserved for slow path, set SP to it on fast path
-
- Label slow_path;
- // If we need a safepoint check, generate full interpreter entry.
- ExternalAddress state(SafepointSynchronize::address_of_state());
- __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
- SafepointSynchronize::_not_synchronized);
- __ jcc(Assembler::notEqual, slow_path);
-
- // We don't generate local frame and don't align stack because
- // we call stub code and there is no safepoint on this path.
-
- // Load parameters
- const Register crc = c_rarg0; // crc
- const Register buf = c_rarg1; // source java byte array address
- const Register len = c_rarg2; // length
- const Register off = len; // offset (never overlaps with 'len')
-
- // Arguments are reversed on java expression stack
- // Calculate address of start element
- if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) {
- __ 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
- } 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
- }
- // Can now load 'len' since we're finished with 'off'
- __ movl(len, Address(rsp, wordSize)); // Length
-
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32()), crc, buf, len);
- // result in rax
-
- // _areturn
- __ pop(rdi); // get return address
- __ mov(rsp, r13); // set sp to sender sp
- __ jmp(rdi);
-
- // 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;
-}
-
-/**
-* 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 NULL;
-}
-
-// Interpreter stub for calling a native method. (asm interpreter)
-// This sets up a somewhat different looking stack for calling the
-// native method than the typical interpreter frame setup.
-address InterpreterGenerator::generate_native_entry(bool synchronized) {
- // determine code generation flags
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // rbx: Method*
- // r13: sender sp
-
- address entry_point = __ pc();
-
- const Address constMethod (rbx, Method::const_offset());
- const Address access_flags (rbx, Method::access_flags_offset());
- const Address size_of_parameters(rcx, ConstMethod::
- size_of_parameters_offset());
-
-
- // get parameter size (always needed)
- __ movptr(rcx, constMethod);
- __ load_unsigned_short(rcx, size_of_parameters);
-
- // native calls don't need the stack size check since they have no
- // expression stack and the arguments are already on the stack and
- // we only add a handful of words to the stack
-
- // rbx: Method*
- // rcx: size of parameters
- // r13: sender sp
- __ pop(rax); // get return address
-
- // for natives the size of locals is zero
-
- // compute beginning of parameters (r14)
- __ lea(r14, Address(rsp, rcx, Address::times_8, -wordSize));
-
- // add 2 zero-initialized slots for native calls
- // initialize result_handler slot
- __ push((int) NULL_WORD);
- // slot for oop temp
- // (static native method holder mirror/jni oop result)
- __ push((int) NULL_WORD);
-
- // initialize fixed part of activation frame
- generate_fixed_frame(true);
-
- // make sure method is native & not abstract
-#ifdef ASSERT
- __ movl(rax, access_flags);
- {
- Label L;
- __ testl(rax, JVM_ACC_NATIVE);
- __ jcc(Assembler::notZero, L);
- __ stop("tried to execute non-native method as native");
- __ bind(L);
- }
- {
- Label L;
- __ testl(rax, JVM_ACC_ABSTRACT);
- __ jcc(Assembler::zero, L);
- __ stop("tried to execute abstract method in interpreter");
- __ bind(L);
- }
-#endif
-
- // Since at this point in the method invocation the exception handler
- // would try to exit the monitor of synchronized methods which hasn't
- // been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. The remove_activation will
- // check this flag.
-
- const Address do_not_unlock_if_synchronized(r15_thread,
- in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
- __ movbool(do_not_unlock_if_synchronized, true);
-
- // increment invocation count & check for overflow
- Label invocation_counter_overflow;
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
- }
-
- Label continue_after_compile;
- __ bind(continue_after_compile);
-
- bang_stack_shadow_pages(true);
-
- // reset the _do_not_unlock_if_synchronized flag
- __ movbool(do_not_unlock_if_synchronized, false);
-
- // check for synchronized methods
- // Must happen AFTER invocation_counter check and stack overflow check,
- // so method is not locked if overflows.
- if (synchronized) {
- lock_method();
- } else {
- // no synchronization necessary
-#ifdef ASSERT
- {
- Label L;
- __ movl(rax, access_flags);
- __ testl(rax, JVM_ACC_SYNCHRONIZED);
- __ jcc(Assembler::zero, L);
- __ stop("method needs synchronization");
- __ bind(L);
- }
-#endif
- }
-
- // start execution
-#ifdef ASSERT
- {
- Label L;
- const Address monitor_block_top(rbp,
- frame::interpreter_frame_monitor_block_top_offset * wordSize);
- __ movptr(rax, monitor_block_top);
- __ cmpptr(rax, rsp);
- __ jcc(Assembler::equal, L);
- __ stop("broken stack frame setup in interpreter");
- __ bind(L);
- }
-#endif
-
- // jvmti support
- __ notify_method_entry();
-
- // work registers
- const Register method = rbx;
- const Register t = r11;
-
- // allocate space for parameters
- __ get_method(method);
- __ movptr(t, Address(method, Method::const_offset()));
- __ load_unsigned_short(t, Address(t, ConstMethod::size_of_parameters_offset()));
- __ shll(t, Interpreter::logStackElementSize);
-
- __ subptr(rsp, t);
- __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
- __ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI)
-
- // get signature handler
- {
- Label L;
- __ movptr(t, Address(method, Method::signature_handler_offset()));
- __ testptr(t, t);
- __ jcc(Assembler::notZero, L);
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::prepare_native_call),
- method);
- __ get_method(method);
- __ movptr(t, Address(method, Method::signature_handler_offset()));
- __ bind(L);
- }
-
- // call signature handler
- assert(InterpreterRuntime::SignatureHandlerGenerator::from() == r14,
- "adjust this code");
- assert(InterpreterRuntime::SignatureHandlerGenerator::to() == rsp,
- "adjust this code");
- assert(InterpreterRuntime::SignatureHandlerGenerator::temp() == rscratch1,
- "adjust this code");
-
- // The generated handlers do not touch RBX (the method oop).
- // However, large signatures cannot be cached and are generated
- // each time here. The slow-path generator can do a GC on return,
- // so we must reload it after the call.
- __ call(t);
- __ get_method(method); // slow path can do a GC, reload RBX
-
-
- // result handler is in rax
- // set result handler
- __ movptr(Address(rbp,
- (frame::interpreter_frame_result_handler_offset) * wordSize),
- rax);
-
- // pass mirror handle if static call
- {
- Label L;
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- __ movl(t, Address(method, Method::access_flags_offset()));
- __ testl(t, JVM_ACC_STATIC);
- __ jcc(Assembler::zero, L);
- // get mirror
- __ movptr(t, Address(method, Method::const_offset()));
- __ movptr(t, Address(t, ConstMethod::constants_offset()));
- __ movptr(t, Address(t, ConstantPool::pool_holder_offset_in_bytes()));
- __ movptr(t, Address(t, mirror_offset));
- // copy mirror into activation frame
- __ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset * wordSize),
- t);
- // pass handle to mirror
- __ lea(c_rarg1,
- Address(rbp, frame::interpreter_frame_oop_temp_offset * wordSize));
- __ bind(L);
- }
-
- // get native function entry point
- {
- Label L;
- __ movptr(rax, Address(method, Method::native_function_offset()));
- ExternalAddress unsatisfied(SharedRuntime::native_method_throw_unsatisfied_link_error_entry());
- __ movptr(rscratch2, unsatisfied.addr());
- __ cmpptr(rax, rscratch2);
- __ jcc(Assembler::notEqual, L);
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::prepare_native_call),
- method);
- __ get_method(method);
- __ movptr(rax, Address(method, Method::native_function_offset()));
- __ bind(L);
- }
-
- // pass JNIEnv
- __ lea(c_rarg0, Address(r15_thread, JavaThread::jni_environment_offset()));
-
- // It is enough that the pc() points into the right code
- // segment. It does not have to be the correct return pc.
- __ set_last_Java_frame(rsp, rbp, (address) __ pc());
-
- // change thread state
-#ifdef ASSERT
- {
- Label L;
- __ movl(t, Address(r15_thread, JavaThread::thread_state_offset()));
- __ cmpl(t, _thread_in_Java);
- __ jcc(Assembler::equal, L);
- __ stop("Wrong thread state in native stub");
- __ bind(L);
- }
-#endif
-
- // Change state to native
-
- __ movl(Address(r15_thread, JavaThread::thread_state_offset()),
- _thread_in_native);
-
- // Call the native method.
- __ call(rax);
- // result potentially in rax or xmm0
-
- // Verify or restore cpu control state after JNI call
- __ restore_cpu_control_state_after_jni();
-
- // NOTE: The order of these pushes is known to frame::interpreter_frame_result
- // in order to extract the result of a method call. If the order of these
- // pushes change or anything else is added to the stack then the code in
- // interpreter_frame_result must also change.
-
- __ push(dtos);
- __ push(ltos);
-
- // change thread state
- __ movl(Address(r15_thread, JavaThread::thread_state_offset()),
- _thread_in_native_trans);
-
- if (os::is_MP()) {
- if (UseMembar) {
- // Force this write out before the read below
- __ membar(Assembler::Membar_mask_bits(
- Assembler::LoadLoad | Assembler::LoadStore |
- Assembler::StoreLoad | Assembler::StoreStore));
- } else {
- // 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
- // due to cache line collision.
- __ serialize_memory(r15_thread, rscratch2);
- }
- }
-
- // check for safepoint operation in progress and/or pending suspend requests
- {
- Label Continue;
- __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
- SafepointSynchronize::_not_synchronized);
-
- Label L;
- __ jcc(Assembler::notEqual, L);
- __ cmpl(Address(r15_thread, JavaThread::suspend_flags_offset()), 0);
- __ jcc(Assembler::equal, 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. Also can't use
- // call_VM_leaf either as it will check to see if r13 & r14 are
- // preserved and correspond to the bcp/locals pointers. So we do a
- // runtime call by hand.
- //
- __ mov(c_rarg0, r15_thread);
- __ mov(r12, rsp); // remember sp (can only use r12 if not using call_VM)
- __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
- __ andptr(rsp, -16); // align stack as required by ABI
- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)));
- __ mov(rsp, r12); // restore sp
- __ reinit_heapbase();
- __ bind(Continue);
- }
-
- // change thread state
- __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java);
-
- // reset_last_Java_frame
- __ reset_last_Java_frame(true, true);
-
- // reset handle block
- __ movptr(t, Address(r15_thread, JavaThread::active_handles_offset()));
- __ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
-
- // If result is an oop unbox and store it in frame where gc will see it
- // and result handler will pick it up
-
- {
- Label no_oop, store_result;
- __ lea(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT)));
- __ cmpptr(t, Address(rbp, frame::interpreter_frame_result_handler_offset*wordSize));
- __ jcc(Assembler::notEqual, no_oop);
- // retrieve result
- __ pop(ltos);
- __ testptr(rax, rax);
- __ jcc(Assembler::zero, store_result);
- __ movptr(rax, Address(rax, 0));
- __ bind(store_result);
- __ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize), rax);
- // keep stack depth as expected by pushing oop which will eventually be discarde
- __ push(ltos);
- __ bind(no_oop);
- }
-
-
- {
- Label no_reguard;
- __ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()),
- JavaThread::stack_guard_yellow_disabled);
- __ jcc(Assembler::notEqual, no_reguard);
-
- __ pusha(); // XXX only save smashed registers
- __ mov(r12, rsp); // remember sp (can only use r12 if not using call_VM)
- __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
- __ andptr(rsp, -16); // align stack as required by ABI
- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)));
- __ mov(rsp, r12); // restore sp
- __ popa(); // XXX only restore smashed registers
- __ reinit_heapbase();
-
- __ bind(no_reguard);
- }
-
-
- // The method register is junk from after the thread_in_native transition
- // until here. Also can't call_VM until the bcp has been
- // restored. Need bcp for throwing exception below so get it now.
- __ get_method(method);
-
- // restore r13 to have legal interpreter frame, i.e., bci == 0 <=>
- // r13 == code_base()
- __ movptr(r13, Address(method, Method::const_offset())); // get ConstMethod*
- __ lea(r13, Address(r13, ConstMethod::codes_offset())); // get codebase
- // handle exceptions (exception handling will handle unlocking!)
- {
- Label L;
- __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
- __ jcc(Assembler::zero, L);
- // Note: At some point we may want to unify this with the code
- // used in call_VM_base(); i.e., we should use the
- // StubRoutines::forward_exception code. For now this doesn't work
- // here because the rsp is not correctly set at this point.
- __ MacroAssembler::call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_pending_exception));
- __ should_not_reach_here();
- __ bind(L);
- }
-
- // do unlocking if necessary
- {
- Label L;
- __ movl(t, Address(method, Method::access_flags_offset()));
- __ testl(t, JVM_ACC_SYNCHRONIZED);
- __ jcc(Assembler::zero, L);
- // the code below should be shared with interpreter macro
- // assembler implementation
- {
- Label unlock;
- // BasicObjectLock will be first in list, since this is a
- // synchronized method. However, need to check that the object
- // has not been unlocked by an explicit monitorexit bytecode.
- const Address monitor(rbp,
- (intptr_t)(frame::interpreter_frame_initial_sp_offset *
- wordSize - sizeof(BasicObjectLock)));
-
- // monitor expect in c_rarg1 for slow unlock path
- __ lea(c_rarg1, monitor); // address of first monitor
-
- __ movptr(t, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()));
- __ testptr(t, t);
- __ jcc(Assembler::notZero, unlock);
-
- // Entry already unlocked, need to throw exception
- __ MacroAssembler::call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_illegal_monitor_state_exception));
- __ should_not_reach_here();
-
- __ bind(unlock);
- __ unlock_object(c_rarg1);
- }
- __ bind(L);
- }
-
- // jvmti support
- // Note: This must happen _after_ handling/throwing any exceptions since
- // the exception handler code notifies the runtime of method exits
- // too. If this happens before, method entry/exit notifications are
- // not properly paired (was bug - gri 11/22/99).
- __ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI);
-
- // restore potential result in edx:eax, call result handler to
- // restore potential result in ST0 & handle result
-
- __ pop(ltos);
- __ pop(dtos);
-
- __ movptr(t, Address(rbp,
- (frame::interpreter_frame_result_handler_offset) * wordSize));
- __ call(t);
-
- // remove activation
- __ movptr(t, Address(rbp,
- frame::interpreter_frame_sender_sp_offset *
- wordSize)); // get sender sp
- __ leave(); // remove frame anchor
- __ pop(rdi); // get return address
- __ mov(rsp, t); // set sp to sender sp
- __ jmp(rdi);
-
- if (inc_counter) {
- // Handle overflow of counter and compile method
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(&continue_after_compile);
- }
-
- return entry_point;
-}
-
-//
-// Generic interpreted method entry to (asm) interpreter
-//
-address InterpreterGenerator::generate_normal_entry(bool synchronized) {
- // determine code generation flags
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // ebx: Method*
- // r13: sender sp
- address entry_point = __ pc();
-
- const Address constMethod(rbx, Method::const_offset());
- const Address access_flags(rbx, Method::access_flags_offset());
- const Address size_of_parameters(rdx,
- ConstMethod::size_of_parameters_offset());
- const Address size_of_locals(rdx, ConstMethod::size_of_locals_offset());
-
-
- // get parameter size (always needed)
- __ movptr(rdx, constMethod);
- __ load_unsigned_short(rcx, size_of_parameters);
-
- // rbx: Method*
- // rcx: size of parameters
- // r13: sender_sp (could differ from sp+wordSize if we were called via c2i )
-
- __ load_unsigned_short(rdx, size_of_locals); // get size of locals in words
- __ subl(rdx, rcx); // rdx = no. of additional locals
-
- // YYY
-// __ incrementl(rdx);
-// __ andl(rdx, -2);
-
- // see if we've got enough room on the stack for locals plus overhead.
- generate_stack_overflow_check();
-
- // get return address
- __ pop(rax);
-
- // compute beginning of parameters (r14)
- __ lea(r14, Address(rsp, rcx, Address::times_8, -wordSize));
-
- // rdx - # of additional locals
- // allocate space for locals
- // explicitly initialize locals
- {
- Label exit, loop;
- __ testl(rdx, rdx);
- __ jcc(Assembler::lessEqual, exit); // do nothing if rdx <= 0
- __ bind(loop);
- __ push((int) NULL_WORD); // initialize local variables
- __ decrementl(rdx); // until everything initialized
- __ jcc(Assembler::greater, loop);
- __ bind(exit);
- }
-
- // initialize fixed part of activation frame
- generate_fixed_frame(false);
-
- // make sure method is not native & not abstract
-#ifdef ASSERT
- __ movl(rax, access_flags);
- {
- Label L;
- __ testl(rax, JVM_ACC_NATIVE);
- __ jcc(Assembler::zero, L);
- __ stop("tried to execute native method as non-native");
- __ bind(L);
- }
- {
- Label L;
- __ testl(rax, JVM_ACC_ABSTRACT);
- __ jcc(Assembler::zero, L);
- __ stop("tried to execute abstract method in interpreter");
- __ bind(L);
- }
-#endif
-
- // Since at this point in the method invocation the exception
- // handler would try to exit the monitor of synchronized methods
- // which hasn't been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. The remove_activation
- // will check this flag.
-
- const Address do_not_unlock_if_synchronized(r15_thread,
- in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
- __ movbool(do_not_unlock_if_synchronized, true);
-
- __ profile_parameters_type(rax, rcx, rdx);
- // increment invocation count & check for overflow
- Label invocation_counter_overflow;
- Label profile_method;
- Label profile_method_continue;
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow,
- &profile_method,
- &profile_method_continue);
- if (ProfileInterpreter) {
- __ bind(profile_method_continue);
- }
- }
-
- Label continue_after_compile;
- __ bind(continue_after_compile);
-
- // check for synchronized interpreted methods
- bang_stack_shadow_pages(false);
-
- // reset the _do_not_unlock_if_synchronized flag
- __ movbool(do_not_unlock_if_synchronized, false);
-
- // check for synchronized methods
- // Must happen AFTER invocation_counter check and stack overflow check,
- // so method is not locked if overflows.
- if (synchronized) {
- // Allocate monitor and lock method
- lock_method();
- } else {
- // no synchronization necessary
-#ifdef ASSERT
- {
- Label L;
- __ movl(rax, access_flags);
- __ testl(rax, JVM_ACC_SYNCHRONIZED);
- __ jcc(Assembler::zero, L);
- __ stop("method needs synchronization");
- __ bind(L);
- }
-#endif
- }
-
- // start execution
-#ifdef ASSERT
- {
- Label L;
- const Address monitor_block_top (rbp,
- frame::interpreter_frame_monitor_block_top_offset * wordSize);
- __ movptr(rax, monitor_block_top);
- __ cmpptr(rax, rsp);
- __ jcc(Assembler::equal, L);
- __ stop("broken stack frame setup in interpreter");
- __ bind(L);
- }
-#endif
-
- // jvmti support
- __ notify_method_entry();
-
- __ dispatch_next(vtos);
-
- // invocation counter overflow
- if (inc_counter) {
- if (ProfileInterpreter) {
- // We have decided to profile this method in the interpreter
- __ bind(profile_method);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
- __ set_method_data_pointer_for_bcp();
- __ get_method(rbx);
- __ jmp(profile_method_continue);
- }
- // Handle overflow of counter and compile method
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(&continue_after_compile);
- }
-
- return entry_point;
-}
-
-
-// These should never be compiled since the interpreter will prefer
-// the compiled version to the intrinsic version.
-bool AbstractInterpreter::can_be_compiled(methodHandle m) {
- switch (method_kind(m)) {
- case Interpreter::java_lang_math_sin : // fall thru
- case Interpreter::java_lang_math_cos : // fall thru
- case Interpreter::java_lang_math_tan : // fall thru
- case Interpreter::java_lang_math_abs : // fall thru
- case Interpreter::java_lang_math_log : // fall thru
- case Interpreter::java_lang_math_log10 : // fall thru
- case Interpreter::java_lang_math_sqrt : // fall thru
- case Interpreter::java_lang_math_pow : // fall thru
- case Interpreter::java_lang_math_exp :
- return false;
- default:
- return true;
- }
-}
-
-// How much stack a method activation needs in words.
-int AbstractInterpreter::size_top_interpreter_activation(Method* method) {
- const int entry_size = frame::interpreter_frame_monitor_size();
-
- // total overhead size: entry_size + (saved rbp thru expr stack
- // bottom). be sure to change this if you add/subtract anything
- // to/from the overhead area
- const int overhead_size =
- -(frame::interpreter_frame_initial_sp_offset) + entry_size;
-
- const int stub_code = frame::entry_frame_after_call_words;
- const int method_stack = (method->max_locals() + method->max_stack()) *
- Interpreter::stackElementWords;
- return (overhead_size + method_stack + stub_code);
-}
-
-//-----------------------------------------------------------------------------
-// Exceptions
-
-void TemplateInterpreterGenerator::generate_throw_exception() {
- // Entry point in previous activation (i.e., if the caller was
- // interpreted)
- Interpreter::_rethrow_exception_entry = __ pc();
- // Restore sp to interpreter_frame_last_sp even though we are going
- // to empty the expression stack for the exception processing.
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
- // rax: exception
- // rdx: return address/pc that threw exception
- __ restore_bcp(); // r13 points to call/send
- __ restore_locals();
- __ reinit_heapbase(); // restore r12 as heapbase.
- // Entry point for exceptions thrown within interpreter code
- Interpreter::_throw_exception_entry = __ pc();
- // expression stack is undefined here
- // rax: exception
- // r13: exception bcp
- __ verify_oop(rax);
- __ mov(c_rarg1, rax);
-
- // expression stack must be empty before entering the VM in case of
- // an exception
- __ empty_expression_stack();
- // find exception handler address and preserve exception oop
- __ call_VM(rdx,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::exception_handler_for_exception),
- c_rarg1);
- // rax: exception handler entry point
- // rdx: preserved exception oop
- // r13: bcp for exception handler
- __ push_ptr(rdx); // push exception which is now the only value on the stack
- __ jmp(rax); // jump to exception handler (may be _remove_activation_entry!)
-
- // If the exception is not handled in the current frame the frame is
- // removed and the exception is rethrown (i.e. exception
- // continuation is _rethrow_exception).
- //
- // Note: At this point the bci is still the bxi for the instruction
- // which caused the exception and the expression stack is
- // empty. Thus, for any VM calls at this point, GC will find a legal
- // oop map (with empty expression stack).
-
- // In current activation
- // tos: exception
- // esi: exception bcp
-
- //
- // JVMTI PopFrame support
- //
-
- Interpreter::_remove_activation_preserving_args_entry = __ pc();
- __ empty_expression_stack();
- // Set the popframe_processing bit in pending_popframe_condition
- // indicating that we are currently handling popframe, so that
- // call_VMs that may happen later do not trigger new popframe
- // handling cycles.
- __ movl(rdx, Address(r15_thread, JavaThread::popframe_condition_offset()));
- __ orl(rdx, JavaThread::popframe_processing_bit);
- __ movl(Address(r15_thread, JavaThread::popframe_condition_offset()), rdx);
-
- {
- // Check to see whether we are returning to a deoptimized frame.
- // (The PopFrame call ensures that the caller of the popped frame is
- // either interpreted or compiled and deoptimizes it if compiled.)
- // In this case, we can't call dispatch_next() after the frame is
- // popped, but instead must save the incoming arguments and restore
- // them after deoptimization has occurred.
- //
- // Note that we don't compare the return PC against the
- // deoptimization blob's unpack entry because of the presence of
- // adapter frames in C2.
- Label caller_not_deoptimized;
- __ movptr(c_rarg1, Address(rbp, frame::return_addr_offset * wordSize));
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
- InterpreterRuntime::interpreter_contains), c_rarg1);
- __ testl(rax, rax);
- __ jcc(Assembler::notZero, caller_not_deoptimized);
-
- // Compute size of arguments for saving when returning to
- // deoptimized caller
- __ get_method(rax);
- __ movptr(rax, Address(rax, Method::const_offset()));
- __ load_unsigned_short(rax, Address(rax, in_bytes(ConstMethod::
- size_of_parameters_offset())));
- __ shll(rax, Interpreter::logStackElementSize);
- __ restore_locals(); // XXX do we need this?
- __ subptr(r14, rax);
- __ addptr(r14, wordSize);
- // Save these arguments
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
- Deoptimization::
- popframe_preserve_args),
- r15_thread, rax, r14);
-
- __ remove_activation(vtos, rdx,
- /* throw_monitor_exception */ false,
- /* install_monitor_exception */ false,
- /* notify_jvmdi */ false);
-
- // Inform deoptimization that it is responsible for restoring
- // these arguments
- __ movl(Address(r15_thread, JavaThread::popframe_condition_offset()),
- JavaThread::popframe_force_deopt_reexecution_bit);
-
- // Continue in deoptimization handler
- __ jmp(rdx);
-
- __ bind(caller_not_deoptimized);
- }
-
- __ remove_activation(vtos, rdx, /* rdx result (retaddr) is not used */
- /* throw_monitor_exception */ false,
- /* install_monitor_exception */ false,
- /* notify_jvmdi */ false);
-
- // Finish with popframe handling
- // A previous I2C followed by a deoptimization might have moved the
- // outgoing arguments further up the stack. PopFrame expects the
- // mutations to those outgoing arguments to be preserved and other
- // constraints basically require this frame to look exactly as
- // though it had previously invoked an interpreted activation with
- // no space between the top of the expression stack (current
- // last_sp) and the top of stack. Rather than force deopt to
- // maintain this kind of invariant all the time we call a small
- // fixup routine to move the mutated arguments onto the top of our
- // expression stack if necessary.
- __ mov(c_rarg1, rsp);
- __ movptr(c_rarg2, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
- // PC must point into interpreter here
- __ set_last_Java_frame(noreg, rbp, __ pc());
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), r15_thread, c_rarg1, c_rarg2);
- __ reset_last_Java_frame(true, true);
- // Restore the last_sp and null it out
- __ movptr(rsp, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
-
- __ restore_bcp(); // XXX do we need this?
- __ restore_locals(); // XXX do we need this?
- // The method data pointer was incremented already during
- // call profiling. We have to restore the mdp for the current bcp.
- if (ProfileInterpreter) {
- __ set_method_data_pointer_for_bcp();
- }
-
- // Clear the popframe condition flag
- __ movl(Address(r15_thread, JavaThread::popframe_condition_offset()),
- JavaThread::popframe_inactive);
-
-#if INCLUDE_JVMTI
- {
- Label L_done;
- const Register local0 = r14;
-
- __ cmpb(Address(r13, 0), Bytecodes::_invokestatic);
- __ jcc(Assembler::notEqual, L_done);
-
- // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
- // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
-
- __ get_method(rdx);
- __ movptr(rax, Address(local0, 0));
- __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), rax, rdx, r13);
-
- __ testptr(rax, rax);
- __ jcc(Assembler::zero, L_done);
-
- __ movptr(Address(rbx, 0), rax);
- __ bind(L_done);
- }
-#endif // INCLUDE_JVMTI
-
- __ dispatch_next(vtos);
- // end of PopFrame support
-
- Interpreter::_remove_activation_entry = __ pc();
-
- // preserve exception over this code sequence
- __ pop_ptr(rax);
- __ movptr(Address(r15_thread, JavaThread::vm_result_offset()), rax);
- // remove the activation (without doing throws on illegalMonitorExceptions)
- __ remove_activation(vtos, rdx, false, true, false);
- // restore exception
- __ get_vm_result(rax, r15_thread);
-
- // In between activations - previous activation type unknown yet
- // compute continuation point - the continuation point expects the
- // following registers set up:
- //
- // rax: exception
- // rdx: return address/pc that threw exception
- // rsp: expression stack of caller
- // rbp: ebp of caller
- __ push(rax); // save exception
- __ push(rdx); // save return address
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
- SharedRuntime::exception_handler_for_return_address),
- r15_thread, rdx);
- __ mov(rbx, rax); // save exception handler
- __ pop(rdx); // restore return address
- __ pop(rax); // restore exception
- // Note that an "issuing PC" is actually the next PC after the call
- __ jmp(rbx); // jump to exception
- // handler of caller
-}
-
-
-//
-// JVMTI ForceEarlyReturn support
-//
-address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
- address entry = __ pc();
-
- __ restore_bcp();
- __ restore_locals();
- __ empty_expression_stack();
- __ load_earlyret_value(state);
-
- __ movptr(rdx, Address(r15_thread, JavaThread::jvmti_thread_state_offset()));
- Address cond_addr(rdx, JvmtiThreadState::earlyret_state_offset());
-
- // Clear the earlyret state
- __ movl(cond_addr, JvmtiThreadState::earlyret_inactive);
-
- __ remove_activation(state, rsi,
- false, /* throw_monitor_exception */
- false, /* install_monitor_exception */
- true); /* notify_jvmdi */
- __ jmp(rsi);
-
- return entry;
-} // end of ForceEarlyReturn support
-
-
-//-----------------------------------------------------------------------------
-// Helper for vtos entry point generation
-
-void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
- address& bep,
- address& cep,
- address& sep,
- address& aep,
- address& iep,
- address& lep,
- address& fep,
- address& dep,
- address& vep) {
- assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
- Label L;
- aep = __ pc(); __ push_ptr(); __ jmp(L);
- fep = __ pc(); __ push_f(xmm0); __ jmp(L);
- dep = __ pc(); __ push_d(xmm0); __ jmp(L);
- lep = __ pc(); __ push_l(); __ jmp(L);
- bep = cep = sep =
- iep = __ pc(); __ push_i();
- vep = __ pc();
- __ bind(L);
- generate_and_dispatch(t);
-}
-
-
-//-----------------------------------------------------------------------------
-// Generation of individual instructions
-
-// helpers for generate_and_dispatch
-
-
-InterpreterGenerator::InterpreterGenerator(StubQueue* code)
- : TemplateInterpreterGenerator(code) {
- generate_all(); // down here so it can be "virtual"
-}
-
-//-----------------------------------------------------------------------------
-
-// Non-product code
-#ifndef PRODUCT
-address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
- address entry = __ pc();
-
- __ push(state);
- __ push(c_rarg0);
- __ push(c_rarg1);
- __ push(c_rarg2);
- __ push(c_rarg3);
- __ mov(c_rarg2, rax); // Pass itos
-#ifdef _WIN64
- __ movflt(xmm3, xmm0); // Pass ftos
-#endif
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode),
- c_rarg1, c_rarg2, c_rarg3);
- __ pop(c_rarg3);
- __ pop(c_rarg2);
- __ pop(c_rarg1);
- __ pop(c_rarg0);
- __ pop(state);
- __ ret(0); // return from result handler
-
- return entry;
-}
-
-void TemplateInterpreterGenerator::count_bytecode() {
- __ incrementl(ExternalAddress((address) &BytecodeCounter::_counter_value));
-}
-
-void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
- __ incrementl(ExternalAddress((address) &BytecodeHistogram::_counters[t->bytecode()]));
-}
-
-void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) {
- __ mov32(rbx, ExternalAddress((address) &BytecodePairHistogram::_index));
- __ shrl(rbx, BytecodePairHistogram::log2_number_of_codes);
- __ orl(rbx,
- ((int) t->bytecode()) <<
- BytecodePairHistogram::log2_number_of_codes);
- __ mov32(ExternalAddress((address) &BytecodePairHistogram::_index), rbx);
- __ lea(rscratch1, ExternalAddress((address) BytecodePairHistogram::_counters));
- __ incrementl(Address(rscratch1, rbx, Address::times_4));
-}
-
-
-void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
- // Call a little run-time stub to avoid blow-up for each bytecode.
- // The run-time runtime saves the right registers, depending on
- // the tosca in-state for the given template.
-
- assert(Interpreter::trace_code(t->tos_in()) != NULL,
- "entry must have been generated");
- __ mov(r12, rsp); // remember sp (can only use r12 if not using call_VM)
- __ andptr(rsp, -16); // align stack as required by ABI
- __ call(RuntimeAddress(Interpreter::trace_code(t->tos_in())));
- __ mov(rsp, r12); // restore sp
- __ reinit_heapbase();
-}
-
-
-void TemplateInterpreterGenerator::stop_interpreter_at() {
- Label L;
- __ cmp32(ExternalAddress((address) &BytecodeCounter::_counter_value),
- StopInterpreterAt);
- __ jcc(Assembler::notEqual, L);
- __ int3();
- __ bind(L);
-}
-#endif // !PRODUCT
-#endif // ! CC_INTERP
--- a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -43,8 +43,8 @@
#define __ _masm->
// Global Register Names
-Register rbcp = LP64_ONLY(r13) NOT_LP64(rsi);
-Register rlocals = LP64_ONLY(r14) NOT_LP64(rdi);
+static const Register rbcp = LP64_ONLY(r13) NOT_LP64(rsi);
+static const Register rlocals = LP64_ONLY(r14) NOT_LP64(rdi);
// Platform-dependent initialization
void TemplateTable::pd_initialize() {
--- a/hotspot/src/cpu/zero/vm/interpreter_zero.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/cpu/zero/vm/interpreter_zero.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -38,7 +38,6 @@
#include "prims/jvmtiThreadState.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
@@ -74,7 +73,3 @@
bool AbstractInterpreter::can_be_compiled(methodHandle m) {
return true;
}
-
-void Deoptimization::unwind_callee_save_values(frame* f,
- vframeArray* vframe_array) {
-}
--- a/hotspot/src/os/aix/vm/globals_aix.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/globals_aix.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -29,37 +29,61 @@
//
// Defines Aix specific flags. They are not available on other platforms.
//
+// (Please keep the switches sorted alphabetically.)
#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct, range, constraint) \
\
+ /* Whether to allow the VM to run if EXTSHM=ON. EXTSHM is an environment */ \
+ /* variable used on AIX to activate certain hacks which allow more shm segments */\
+ /* for 32bit processes. For 64bit processes, it is pointless and may have */ \
+ /* harmful side effects (e.g. for some reasonn prevents allocation of 64k pages */\
+ /* via shmctl). */ \
+ /* Per default we quit with an error if that variable is found; for certain */ \
+ /* customer scenarios, we may want to be able to run despite that variable. */ \
+ product(bool, AllowExtshm, false, \
+ "Allow VM to run with EXTSHM=ON.") \
+ \
+ product(intx, AttachListenerTimeout, 1000, \
+ "Timeout in ms the attach listener waits for a request") \
+ range(0, 2147483) \
+ \
+ /* Maximum expected size of the data segment. That correlates with the */ \
+ /* to the maximum C Heap consumption we expect. */ \
+ /* We need to know this because we need to leave "breathing space" for the */ \
+ /* data segment when placing the java heap. If that space is too small, we */ \
+ /* reduce our chance of getting a low heap address (needed for compressed */ \
+ /* Oops). */ \
+ product(uintx, MaxExpectedDataSegmentSize, (SIZE_4G * 2), \
+ "Maximum expected Data Segment Size.") \
+ \
+ /* Use optimized addresses for the polling page. */ \
+ product(bool, OptimizePollingPageLocation, true, \
+ "Optimize the location of the polling page used for Safepoints") \
+ \
/* Use 64K pages for virtual memory (shmat). */ \
product(bool, Use64KPages, true, \
"Use 64K pages if available.") \
\
- /* If UseLargePages == true allow or deny usage of 16M pages. 16M pages are */ \
- /* 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.") \
+ /* If VM uses 64K paged memory (shmat) for virtual memory: threshold below */ \
+ /* which virtual memory allocations are done with 4K memory (mmap). This is */ \
+ /* mainly for test purposes. */ \
+ develop(uintx, Use64KPagesThreshold, 0, \
+ "4K/64K page allocation threshold.") \
\
- /* 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") \
- \
- product_pd(intx, AttachListenerTimeout, \
- "Timeout in ms the attach listener waits for a request") \
- range(0, 2147483) \
+ /* Normally AIX commits memory on touch, but sometimes it is helpful to have */ \
+ /* explicit commit behaviour. This flag, if true, causes the VM to touch */ \
+ /* memory on os::commit_memory() (which normally is a noop). */ \
+ product(bool, UseExplicitCommit, false, \
+ "Explicit commit for virtual memory.") \
\
-// Per default, do not allow 16M pages. 16M pages have to be switched on specifically.
-define_pd_global(bool, Use16MPages, false);
-define_pd_global(bool, OptimizePollingPageLocation, true);
-define_pd_global(intx, AttachListenerTimeout, 1000);
//
// Defines Aix-specific default values. The flags are available on all
// platforms, but they may have different default values on other platforms.
//
+
+// UseLargePages means nothing, for now, on AIX.
+// Use Use64KPages or Use16MPages instead.
define_pd_global(bool, UseLargePages, false);
define_pd_global(bool, UseLargePagesIndividualAllocation, false);
define_pd_global(bool, UseOSErrorReporting, false);
--- a/hotspot/src/os/aix/vm/jvm_aix.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/jvm_aix.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -109,92 +109,3 @@
return JNI_TRUE;
JVM_END
-/*
- All the defined signal names for Linux.
-
- NOTE that not all of these names are accepted by our Java implementation
-
- Via an existing claim by the VM, sigaction restrictions, or
- the "rules of Unix" some of these names will be rejected at runtime.
- For example the VM sets up to handle USR1, sigaction returns EINVAL for
- STOP, and Linux simply doesn't allow catching of KILL.
-
- Here are the names currently accepted by a user of sun.misc.Signal with
- 1.4.1 (ignoring potential interaction with use of chaining, etc):
-
- HUP, INT, TRAP, ABRT, IOT, BUS, USR2, PIPE, ALRM, TERM, STKFLT,
- CLD, CHLD, CONT, TSTP, TTIN, TTOU, URG, XCPU, XFSZ, VTALRM, PROF,
- WINCH, POLL, IO, PWR, SYS
-
-*/
-
-struct siglabel {
- const char *name;
- int number;
-};
-
-struct siglabel siglabels[] = {
- /* derived from /usr/include/bits/signum.h on RH7.2 */
- "HUP", SIGHUP, /* Hangup (POSIX). */
- "INT", SIGINT, /* Interrupt (ANSI). */
- "QUIT", SIGQUIT, /* Quit (POSIX). */
- "ILL", SIGILL, /* Illegal instruction (ANSI). */
- "TRAP", SIGTRAP, /* Trace trap (POSIX). */
- "ABRT", SIGABRT, /* Abort (ANSI). */
- "IOT", SIGIOT, /* IOT trap (4.2 BSD). */
- "BUS", SIGBUS, /* BUS error (4.2 BSD). */
- "FPE", SIGFPE, /* Floating-point exception (ANSI). */
- "KILL", SIGKILL, /* Kill, unblockable (POSIX). */
- "USR1", SIGUSR1, /* User-defined signal 1 (POSIX). */
- "SEGV", SIGSEGV, /* Segmentation violation (ANSI). */
- "USR2", SIGUSR2, /* User-defined signal 2 (POSIX). */
- "PIPE", SIGPIPE, /* Broken pipe (POSIX). */
- "ALRM", SIGALRM, /* Alarm clock (POSIX). */
- "TERM", SIGTERM, /* Termination (ANSI). */
-#ifdef SIGSTKFLT
- "STKFLT", SIGSTKFLT, /* Stack fault. */
-#endif
- "CLD", SIGCLD, /* Same as SIGCHLD (System V). */
- "CHLD", SIGCHLD, /* Child status has changed (POSIX). */
- "CONT", SIGCONT, /* Continue (POSIX). */
- "STOP", SIGSTOP, /* Stop, unblockable (POSIX). */
- "TSTP", SIGTSTP, /* Keyboard stop (POSIX). */
- "TTIN", SIGTTIN, /* Background read from tty (POSIX). */
- "TTOU", SIGTTOU, /* Background write to tty (POSIX). */
- "URG", SIGURG, /* Urgent condition on socket (4.2 BSD). */
- "XCPU", SIGXCPU, /* CPU limit exceeded (4.2 BSD). */
- "XFSZ", SIGXFSZ, /* File size limit exceeded (4.2 BSD). */
- "DANGER", SIGDANGER, /* System crash imminent; free up some page space (AIX). */
- "VTALRM", SIGVTALRM, /* Virtual alarm clock (4.2 BSD). */
- "PROF", SIGPROF, /* Profiling alarm clock (4.2 BSD). */
- "WINCH", SIGWINCH, /* Window size change (4.3 BSD, Sun). */
- "POLL", SIGPOLL, /* Pollable event occurred (System V). */
- "IO", SIGIO, /* I/O now possible (4.2 BSD). */
- "PWR", SIGPWR, /* Power failure restart (System V). */
-#ifdef SIGSYS
- "SYS", SIGSYS /* Bad system call. Only on some Linuxen! */
-#endif
- };
-
-JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name))
-
- /* find and return the named signal's number */
-
- for(uint i=0; i<ARRAY_SIZE(siglabels); i++)
- if(!strcmp(name, siglabels[i].name))
- return siglabels[i].number;
-
- return -1;
-
-JVM_END
-
-// used by os::exception_name()
-extern bool signal_name(int signo, char* buf, size_t len) {
- for(uint i = 0; i < ARRAY_SIZE(siglabels); i++) {
- if (signo == siglabels[i].number) {
- jio_snprintf(buf, len, "SIG%s", siglabels[i].name);
- return true;
- }
- }
- return false;
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/aix/vm/libo4.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012, 2015 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// This is only a stub. Will flesh out later when/if we add further support
+// for PASE.
+
+#include "libo4.hpp"
+
+bool libo4::init() { return false; }
+void libo4::cleanup() {}
+bool libo4::get_memory_info (unsigned long long* p_virt_total, unsigned long long* p_real_total,
+ unsigned long long* p_real_free, unsigned long long* p_pgsp_total, unsigned long long* p_pgsp_free) {
+ return false;
+}
+bool libo4::get_load_avg (double* p_avg1, double* p_avg5, double* p_avg15) { return false; }
+bool libo4::realpath (const char* file_name, char* resolved_name, int resolved_name_len) { return false; }
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/aix/vm/libo4.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2012, 2015 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// A C++ wrapper around the libo4 porting library. The libo4 porting library
+// is a set of bridge functions into native AS/400 functionality.
+
+#ifndef OS_AIX_VM_LIBO4_HPP
+#define OS_AIX_VM_LIBO4_HPP
+
+
+class libo4 {
+public:
+
+ // Initialize the libo4 porting library.
+ // Returns true if succeeded, false if error.
+ static bool init();
+
+ // cleanup of the libo4 porting library.
+ static void cleanup();
+
+ // returns a number of memory statistics from the
+ // AS/400.
+ //
+ // Specify NULL for numbers you are not interested in.
+ //
+ // returns false if an error happened. Activate OsMisc trace for
+ // trace output.
+ //
+ static bool get_memory_info (unsigned long long* p_virt_total, unsigned long long* p_real_total,
+ unsigned long long* p_real_free, unsigned long long* p_pgsp_total, unsigned long long* p_pgsp_free);
+
+ // returns information about system load
+ // (similar to "loadavg()" under other Unices)
+ //
+ // Specify NULL for numbers you are not interested in.
+ //
+ // returns false if an error happened. Activate OsMisc trace for
+ // trace output.
+ //
+ static bool get_load_avg (double* p_avg1, double* p_avg5, double* p_avg15);
+
+ // this is a replacement for the "realpath()" API which does not really work
+ // on PASE
+ //
+ // Specify NULL for numbers you are not interested in.
+ //
+ // returns false if an error happened. Activate OsMisc trace for
+ // trace output.
+ //
+ static bool realpath (const char* file_name,
+ char* resolved_name, int resolved_name_len);
+
+};
+
+#endif // OS_AIX_VM_LIBO4_HPP
+
--- a/hotspot/src/os/aix/vm/libperfstat_aix.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/libperfstat_aix.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,49 +22,50 @@
*
*/
-#include "runtime/arguments.hpp"
#include "libperfstat_aix.hpp"
+#include "misc_aix.hpp"
-// For dlopen and friends
-#include <fcntl.h>
+#include <dlfcn.h>
+#include <sys/systemcfg.h>
-// handle to the libperfstat
+// Handle to the libperfstat.
static void* g_libhandle = NULL;
-// whether initialization worked
-static bool g_initialized = false;
-
-
-typedef int (*fun_perfstat_cpu_total_t) (perfstat_id_t *name, perfstat_cpu_total_t* userbuff,
+typedef int (*fun_perfstat_cpu_total_t) (perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff,
int sizeof_userbuff, int desired_number);
typedef int (*fun_perfstat_memory_total_t) (perfstat_id_t *name, perfstat_memory_total_t* userbuff,
int sizeof_userbuff, int desired_number);
+typedef int (*fun_perfstat_partition_total_t) (perfstat_id_t *name,
+ PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff, int sizeof_userbuff,
+ int desired_number);
+
+typedef int (*fun_perfstat_wpar_total_t) (perfstat_id_wpar_t *name,
+ PERFSTAT_WPAR_TOTAL_T_LATEST* userbuff, int sizeof_userbuff,
+ int desired_number);
+
typedef void (*fun_perfstat_reset_t) ();
+typedef cid_t (*fun_wpar_getcid_t) ();
+
static fun_perfstat_cpu_total_t g_fun_perfstat_cpu_total = NULL;
static fun_perfstat_memory_total_t g_fun_perfstat_memory_total = NULL;
+static fun_perfstat_partition_total_t g_fun_perfstat_partition_total = NULL;
+static fun_perfstat_wpar_total_t g_fun_perfstat_wpar_total = NULL;
static fun_perfstat_reset_t g_fun_perfstat_reset = NULL;
+static fun_wpar_getcid_t g_fun_wpar_getcid = NULL;
bool libperfstat::init() {
- if (g_initialized) {
- return true;
- }
-
- g_initialized = false;
-
- // dynamically load the libperfstat porting library.
+ // Dynamically load the libperfstat porting library.
g_libhandle = dlopen("/usr/lib/libperfstat.a(shr_64.o)", RTLD_MEMBER | RTLD_NOW);
if (!g_libhandle) {
- if (Verbose) {
- fprintf(stderr, "Cannot load libperfstat.a (dlerror: %s)", dlerror());
- }
+ trcVerbose("Cannot load libperfstat.a (dlerror: %s)", dlerror());
return false;
}
- // resolve function pointers
+ // Resolve function pointers
#define RESOLVE_FUN_NO_ERROR(name) \
g_fun_##name = (fun_##name##_t) dlsym(g_libhandle, #name);
@@ -72,26 +73,28 @@
#define RESOLVE_FUN(name) \
RESOLVE_FUN_NO_ERROR(name) \
if (!g_fun_##name) { \
- if (Verbose) { \
- fprintf(stderr, "Cannot resolve " #name "() from libperfstat.a\n" \
+ trcVerbose("Cannot resolve " #name "() from libperfstat.a\n" \
" (dlerror: %s)", dlerror()); \
- } \
return false; \
}
+ // These functions may or may not be there depending on the OS release.
+ RESOLVE_FUN_NO_ERROR(perfstat_partition_total);
+ RESOLVE_FUN_NO_ERROR(perfstat_wpar_total);
+ RESOLVE_FUN_NO_ERROR(wpar_getcid);
+
+ // These functions are required for every release.
RESOLVE_FUN(perfstat_cpu_total);
RESOLVE_FUN(perfstat_memory_total);
RESOLVE_FUN(perfstat_reset);
- g_initialized = true;
+ trcVerbose("libperfstat loaded.");
return true;
}
void libperfstat::cleanup() {
- g_initialized = false;
-
if (g_libhandle) {
dlclose(g_libhandle);
g_libhandle = NULL;
@@ -99,26 +102,250 @@
g_fun_perfstat_cpu_total = NULL;
g_fun_perfstat_memory_total = NULL;
+ g_fun_perfstat_partition_total = NULL;
+ g_fun_perfstat_wpar_total = NULL;
g_fun_perfstat_reset = NULL;
+ g_fun_wpar_getcid = NULL;
+
}
int libperfstat::perfstat_memory_total(perfstat_id_t *name,
perfstat_memory_total_t* userbuff,
int sizeof_userbuff, int desired_number) {
- assert(g_initialized, "libperfstat not initialized");
- assert(g_fun_perfstat_memory_total, "");
+ if (g_fun_perfstat_memory_total == NULL) {
+ return -1;
+ }
return g_fun_perfstat_memory_total(name, userbuff, sizeof_userbuff, desired_number);
}
-int libperfstat::perfstat_cpu_total(perfstat_id_t *name, perfstat_cpu_total_t* userbuff,
+int libperfstat::perfstat_cpu_total(perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff,
int sizeof_userbuff, int desired_number) {
- assert(g_initialized, "libperfstat not initialized");
- assert(g_fun_perfstat_cpu_total, "");
+ if (g_fun_perfstat_cpu_total == NULL) {
+ return -1;
+ }
return g_fun_perfstat_cpu_total(name, userbuff, sizeof_userbuff, desired_number);
}
+int libperfstat::perfstat_partition_total(perfstat_id_t *name, PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff,
+ int sizeof_userbuff, int desired_number) {
+ if (g_fun_perfstat_partition_total == NULL) {
+ return -1;
+ }
+ return g_fun_perfstat_partition_total(name, userbuff, sizeof_userbuff, desired_number);
+}
+
+int libperfstat::perfstat_wpar_total(perfstat_id_wpar_t *name, PERFSTAT_WPAR_TOTAL_T_LATEST* userbuff,
+ int sizeof_userbuff, int desired_number) {
+ if (g_fun_perfstat_wpar_total == NULL) {
+ return -1;
+ }
+ return g_fun_perfstat_wpar_total(name, userbuff, sizeof_userbuff, desired_number);
+}
+
void libperfstat::perfstat_reset() {
- assert(g_initialized, "libperfstat not initialized");
- assert(g_fun_perfstat_reset, "");
- g_fun_perfstat_reset();
+ if (g_fun_perfstat_reset != NULL) {
+ g_fun_perfstat_reset();
+ }
+}
+
+cid_t libperfstat::wpar_getcid() {
+ if (g_fun_wpar_getcid == NULL) {
+ return (cid_t) -1;
+ }
+ return g_fun_wpar_getcid();
+}
+
+
+//////////////////// convenience functions, release-independent /////////////////////////////
+
+// Excerpts from systemcfg.h definitions newer than AIX 5.3 (our oldest build platform)
+
+#define PV_6 0x100000 /* Power PC 6 */
+#define PV_6_1 0x100001 /* Power PC 6 DD1.x */
+#define PV_7 0x200000 /* Power PC 7 */
+#define PV_5_Compat 0x0F8000 /* Power PC 5 */
+#define PV_6_Compat 0x108000 /* Power PC 6 */
+#define PV_7_Compat 0x208000 /* Power PC 7 */
+#define PV_8 0x300000 /* Power PC 8 */
+#define PV_8_Compat 0x308000 /* Power PC 8 */
+
+
+// Retrieve global cpu information.
+bool libperfstat::get_cpuinfo(cpuinfo_t* pci) {
+
+ assert(pci, "get_cpuinfo: invalid parameter");
+ memset(pci, 0, sizeof(cpuinfo_t));
+
+ PERFSTAT_CPU_TOTAL_T_LATEST psct;
+ memset (&psct, '\0', sizeof(psct));
+
+ if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(PERFSTAT_CPU_TOTAL_T_LATEST), 1)) {
+ if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(perfstat_cpu_total_t_61), 1)) {
+ if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(perfstat_cpu_total_t_53), 1)) {
+ trcVerbose("perfstat_cpu_total() failed (errno=%d)", errno);
+ return false;
+ }
+ }
+ }
+
+ // Global cpu information.
+ strcpy (pci->description, psct.description);
+ pci->processorHZ = psct.processorHZ;
+ pci->ncpus = psct.ncpus;
+ for (int i = 0; i < 3; i++) {
+ pci->loadavg[i] = (double) psct.loadavg[i] / (1 << SBITS);
+ }
+
+ pci->user_clock_ticks = psct.user;
+ pci->sys_clock_ticks = psct.sys;
+ pci->idle_clock_ticks = psct.idle;
+ pci->wait_clock_ticks = psct.wait;
+
+ // Get the processor version from _system_configuration.
+ switch (_system_configuration.version) {
+ case PV_8:
+ strcpy(pci->version, "Power PC 8");
+ break;
+ case PV_7:
+ strcpy(pci->version, "Power PC 7");
+ break;
+ case PV_6_1:
+ strcpy(pci->version, "Power PC 6 DD1.x");
+ break;
+ case PV_6:
+ strcpy(pci->version, "Power PC 6");
+ break;
+ case PV_5:
+ strcpy(pci->version, "Power PC 5");
+ break;
+ case PV_5_2:
+ strcpy(pci->version, "Power PC 5_2");
+ break;
+ case PV_5_3:
+ strcpy(pci->version, "Power PC 5_3");
+ break;
+ case PV_5_Compat:
+ strcpy(pci->version, "PV_5_Compat");
+ break;
+ case PV_6_Compat:
+ strcpy(pci->version, "PV_6_Compat");
+ break;
+ case PV_7_Compat:
+ strcpy(pci->version, "PV_7_Compat");
+ break;
+ case PV_8_Compat:
+ strcpy(pci->version, "PV_8_Compat");
+ break;
+ default:
+ strcpy(pci->version, "unknown");
+ }
+
+ return true;
}
+
+// Retrieve partition information.
+bool libperfstat::get_partitioninfo(partitioninfo_t* ppi) {
+
+ assert(ppi, "get_partitioninfo: invalid parameter");
+ memset(ppi, 0, sizeof(partitioninfo_t));
+
+ PERFSTAT_PARTITON_TOTAL_T_LATEST pspt;
+ memset(&pspt, '\0', sizeof(pspt));
+
+ bool ame_details = true;
+
+ if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(PERFSTAT_PARTITON_TOTAL_T_LATEST), 1)) {
+ if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_71), 1)) {
+ ame_details = false;
+ if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_61), 1)) {
+ if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_53), 1)) {
+ if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_53_5), 1)) {
+ trcVerbose("perfstat_partition_total() failed (errno=%d)", errno);
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ // partition type info
+ ppi->shared_enabled = pspt.type.b.shared_enabled;
+ ppi->smt_capable = pspt.type.b.smt_capable;
+ ppi->smt_enabled = pspt.type.b.smt_enabled;
+ ppi->lpar_capable = pspt.type.b.lpar_capable;
+ ppi->lpar_enabled = pspt.type.b.lpar_enabled;
+ ppi->dlpar_capable = pspt.type.b.dlpar_capable;
+ ppi->capped = pspt.type.b.capped;
+ ppi->kernel_is_64 = pspt.type.b.kernel_is_64;
+ ppi->pool_util_authority = pspt.type.b.pool_util_authority;
+ ppi->donate_capable = pspt.type.b.donate_capable;
+ ppi->donate_enabled = pspt.type.b.donate_enabled;
+ ppi->ams_capable = pspt.type.b.ams_capable;
+ ppi->ams_enabled = pspt.type.b.ams_enabled;
+ ppi->power_save = pspt.type.b.power_save;
+ ppi->ame_enabled = pspt.type.b.ame_enabled;
+
+ // partition total info
+ ppi->online_cpus = pspt.online_cpus;
+ ppi->entitled_proc_capacity = pspt.entitled_proc_capacity;
+ ppi->var_proc_capacity_weight = pspt.var_proc_capacity_weight;
+ ppi->phys_cpus_pool = pspt.phys_cpus_pool;
+ ppi->pool_id = pspt.pool_id;
+ ppi->entitled_pool_capacity = pspt.entitled_pool_capacity;
+ strcpy(ppi->name, pspt.name);
+
+ // Added values to ppi that we need for later computation of cpu utilization
+ // ( pool authorization needed for pool_idle_time ??? )
+ ppi->timebase_last = pspt.timebase_last;
+ ppi->pool_idle_time = pspt.pool_idle_time;
+ ppi->pcpu_tics_user = pspt.puser;
+ ppi->pcpu_tics_sys = pspt.psys;
+ ppi->pcpu_tics_idle = pspt.pidle;
+ ppi->pcpu_tics_wait = pspt.pwait;
+
+ // Additional AME information.
+ if (ame_details) {
+ ppi->true_memory = pspt.true_memory * 4096;
+ ppi->expanded_memory = pspt.expanded_memory * 4096;
+ ppi->target_memexp_factr = pspt.target_memexp_factr;
+ ppi->current_memexp_factr = pspt.current_memexp_factr;
+ ppi->cmcs_total_time = pspt.cmcs_total_time;
+ }
+
+ return true;
+}
+
+// Retrieve wpar information.
+bool libperfstat::get_wparinfo(wparinfo_t* pwi) {
+
+ assert(pwi, "get_wparinfo: invalid parameter");
+ memset(pwi, 0, sizeof(wparinfo_t));
+
+ if (libperfstat::wpar_getcid() <= 0) {
+ return false;
+ }
+
+ PERFSTAT_WPAR_TOTAL_T_LATEST pswt;
+ memset (&pswt, '\0', sizeof(pswt));
+
+ if (-1 == libperfstat::perfstat_wpar_total(NULL, &pswt, sizeof(PERFSTAT_WPAR_TOTAL_T_LATEST), 1)) {
+ if (-1 == libperfstat::perfstat_wpar_total(NULL, &pswt, sizeof(perfstat_wpar_total_t_61), 1)) {
+ trcVerbose("perfstat_wpar_total() failed (errno=%d)", errno);
+ return false;
+ }
+ }
+
+ // WPAR type info.
+ pwi->app_wpar = pswt.type.b.app_wpar;
+ pwi->cpu_rset = pswt.type.b.cpu_rset;
+ pwi->cpu_xrset = pswt.type.b.cpu_xrset;
+ pwi->cpu_limits = pswt.type.b.cpu_limits;
+ pwi->mem_limits = pswt.type.b.mem_limits;
+ // WPAR total info.
+ strcpy(pwi->name, pswt.name);
+ pwi->wpar_id = pswt.wpar_id;
+ pwi->cpu_limit = pswt.cpu_limit;
+ pwi->mem_limit = pswt.mem_limit;
+
+ return true;
+}
--- a/hotspot/src/os/aix/vm/libperfstat_aix.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/libperfstat_aix.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -22,7 +22,7 @@
*
*/
-// encapsulates the libperfstat library.
+// Encapsulates the libperfstat library.
//
// The purpose of this code is to dynamically load the libperfstat library
// instead of statically linking against it. The libperfstat library is an
@@ -32,7 +32,732 @@
#ifndef OS_AIX_VM_LIBPERFSTAT_AIX_HPP
#define OS_AIX_VM_LIBPERFSTAT_AIX_HPP
-#include <libperfstat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// These are excerpts from the AIX 5.3, 6.1, 7.1 libperfstat.h -
+// this is all we need from libperfstat.h and I want to avoid having to include <libperfstat.h>
+//
+// Note: I define all structures as if I were to include libperfstat.h on an AIX 5.2
+// build machine.
+//
+// The ratio behind that is that if I would build on an AIX 5.2 build machine,
+// include libperfstat.h and hard-link against libperfstat.a, the program should
+// work without recompilation on all newer AIX versions.
+//
+
+#define IDENTIFIER_LENGTH 64 /* length of strings included in the structures */
+
+
+typedef struct { /* structure element identifier */
+ char name[IDENTIFIER_LENGTH]; /* name of the identifier */
+} perfstat_id_t;
+
+#define CEC_ID_LEN 40 /* CEC identifier length */
+#define MAXCORRALNAMELEN 25 /* length of the wpar name */
+#define FIRST_WPARNAME "" /* pseudo-name for the first WPAR */
+#define FIRST_WPARID -1 /* pseudo-id for the first WPAR */
+
+typedef unsigned short cid_t; /* workload partition identifier */
+
+typedef struct { /* Virtual memory utilization */
+ u_longlong_t virt_total; /* total virtual memory (in 4KB pages) */
+ u_longlong_t real_total; /* total real memory (in 4KB pages) */
+ u_longlong_t real_free; /* free real memory (in 4KB pages) */
+ u_longlong_t real_pinned; /* real memory which is pinned (in 4KB pages) */
+ u_longlong_t real_inuse; /* real memory which is in use (in 4KB pages) */
+ u_longlong_t pgbad; /* number of bad pages */
+ u_longlong_t pgexct; /* number of page faults */
+ u_longlong_t pgins; /* number of pages paged in */
+ u_longlong_t pgouts; /* number of pages paged out */
+ u_longlong_t pgspins; /* number of page ins from paging space */
+ u_longlong_t pgspouts; /* number of page outs from paging space */
+ u_longlong_t scans; /* number of page scans by clock */
+ u_longlong_t cycles; /* number of page replacement cycles */
+ u_longlong_t pgsteals; /* number of page steals */
+ u_longlong_t numperm; /* number of frames used for files (in 4KB pages) */
+ u_longlong_t pgsp_total; /* total paging space (in 4KB pages) */
+ u_longlong_t pgsp_free; /* free paging space (in 4KB pages) */
+ u_longlong_t pgsp_rsvd; /* reserved paging space (in 4KB pages) */
+ u_longlong_t real_system; /* real memory used by system segments (in 4KB pages). This is the sum of all the used pages in segment marked for system usage.
+ * Since segment classifications are not always guaranteed to be accurate, this number is only an approximation. */
+ u_longlong_t real_user; /* real memory used by non-system segments (in 4KB pages). This is the sum of all pages used in segments not marked for system usage.
+ * Since segment classifications are not always guaranteed to be accurate, this number is only an approximation. */
+ u_longlong_t real_process; /* real memory used by process segments (in 4KB pages). This is real_total-real_free-numperm-real_system. Since real_system is an
+ * approximation, this number is too. */
+ u_longlong_t virt_active; /* Active virtual pages. Virtual pages are considered active if they have been accessed */
+
+} perfstat_memory_total_t;
+
+typedef struct { /* global cpu information AIX 5.3 < TL10 */
+ int ncpus; /* number of active logical processors */
+ int ncpus_cfg; /* number of configured processors */
+ char description[IDENTIFIER_LENGTH]; /* processor description (type/official name) */
+ u_longlong_t processorHZ; /* processor speed in Hz */
+ u_longlong_t user; /* raw total number of clock ticks spent in user mode */
+ u_longlong_t sys; /* raw total number of clock ticks spent in system mode */
+ u_longlong_t idle; /* raw total number of clock ticks spent idle */
+ u_longlong_t wait; /* raw total number of clock ticks spent waiting for I/O */
+ u_longlong_t pswitch; /* number of process switches (change in currently running process) */
+ u_longlong_t syscall; /* number of system calls executed */
+ u_longlong_t sysread; /* number of read system calls executed */
+ u_longlong_t syswrite; /* number of write system calls executed */
+ u_longlong_t sysfork; /* number of forks system calls executed */
+ u_longlong_t sysexec; /* number of execs system calls executed */
+ u_longlong_t readch; /* number of characters tranferred with read system call */
+ u_longlong_t writech; /* number of characters tranferred with write system call */
+ u_longlong_t devintrs; /* number of device interrupts */
+ u_longlong_t softintrs; /* number of software interrupts */
+ time_t lbolt; /* number of ticks since last reboot */
+ u_longlong_t loadavg[3]; /* (1<<SBITS) times the average number of runnables processes during the last 1, 5 and 15 minutes.
+ * To calculate the load average, divide the numbers by (1<<SBITS). SBITS is defined in <sys/proc.h>. */
+ u_longlong_t runque; /* length of the run queue (processes ready) */
+ u_longlong_t swpque; /* ength of the swap queue (processes waiting to be paged in) */
+ u_longlong_t bread; /* number of blocks read */
+ u_longlong_t bwrite; /* number of blocks written */
+ u_longlong_t lread; /* number of logical read requests */
+ u_longlong_t lwrite; /* number of logical write requests */
+ u_longlong_t phread; /* number of physical reads (reads on raw devices) */
+ u_longlong_t phwrite; /* number of physical writes (writes on raw devices) */
+ u_longlong_t runocc; /* updated whenever runque is updated, i.e. the runqueue is occupied.
+ * This can be used to compute the simple average of ready processes */
+ u_longlong_t swpocc; /* updated whenever swpque is updated. i.e. the swpqueue is occupied.
+ * This can be used to compute the simple average processes waiting to be paged in */
+ u_longlong_t iget; /* number of inode lookups */
+ u_longlong_t namei; /* number of vnode lookup from a path name */
+ u_longlong_t dirblk; /* number of 512-byte block reads by the directory search routine to locate an entry for a file */
+ u_longlong_t msg; /* number of IPC message operations */
+ u_longlong_t sema; /* number of IPC semaphore operations */
+ u_longlong_t rcvint; /* number of tty receive interrupts */
+ u_longlong_t xmtint; /* number of tyy transmit interrupts */
+ u_longlong_t mdmint; /* number of modem interrupts */
+ u_longlong_t tty_rawinch; /* number of raw input characters */
+ u_longlong_t tty_caninch; /* number of canonical input characters (always zero) */
+ u_longlong_t tty_rawoutch; /* number of raw output characters */
+ u_longlong_t ksched; /* number of kernel processes created */
+ u_longlong_t koverf; /* kernel process creation attempts where:
+ * -the user has forked to their maximum limit
+ * -the configuration limit of processes has been reached */
+ u_longlong_t kexit; /* number of kernel processes that became zombies */
+ u_longlong_t rbread; /* number of remote read requests */
+ u_longlong_t rcread; /* number of cached remote reads */
+ u_longlong_t rbwrt; /* number of remote writes */
+ u_longlong_t rcwrt; /* number of cached remote writes */
+ u_longlong_t traps; /* number of traps */
+ int ncpus_high; /* index of highest processor online */
+ u_longlong_t puser; /* raw number of physical processor tics in user mode */
+ u_longlong_t psys; /* raw number of physical processor tics in system mode */
+ u_longlong_t pidle; /* raw number of physical processor tics idle */
+ u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */
+ u_longlong_t decrintrs; /* number of decrementer tics interrupts */
+ u_longlong_t mpcrintrs; /* number of mpc's received interrupts */
+ u_longlong_t mpcsintrs; /* number of mpc's sent interrupts */
+ u_longlong_t phantintrs; /* number of phantom interrupts */
+ u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */
+ short iowait; /* number of processes that are asleep waiting for buffered I/O */
+ short physio; /* number of processes waiting for raw I/O */
+ longlong_t twait; /* number of threads that are waiting for filesystem direct(cio) */
+ u_longlong_t hpi; /* number of hypervisor page-ins */
+ u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds) */
+} perfstat_cpu_total_t_53;
+
+typedef struct { /* global cpu information AIX 6.1|5.3 > TL09 */
+ int ncpus; /* number of active logical processors */
+ int ncpus_cfg; /* number of configured processors */
+ char description[IDENTIFIER_LENGTH]; /* processor description (type/official name) */
+ u_longlong_t processorHZ; /* processor speed in Hz */
+ u_longlong_t user; /* raw total number of clock ticks spent in user mode */
+ u_longlong_t sys; /* raw total number of clock ticks spent in system mode */
+ u_longlong_t idle; /* raw total number of clock ticks spent idle */
+ u_longlong_t wait; /* raw total number of clock ticks spent waiting for I/O */
+ u_longlong_t pswitch; /* number of process switches (change in currently running process) */
+ u_longlong_t syscall; /* number of system calls executed */
+ u_longlong_t sysread; /* number of read system calls executed */
+ u_longlong_t syswrite; /* number of write system calls executed */
+ u_longlong_t sysfork; /* number of forks system calls executed */
+ u_longlong_t sysexec; /* number of execs system calls executed */
+ u_longlong_t readch; /* number of characters tranferred with read system call */
+ u_longlong_t writech; /* number of characters tranferred with write system call */
+ u_longlong_t devintrs; /* number of device interrupts */
+ u_longlong_t softintrs; /* number of software interrupts */
+ time_t lbolt; /* number of ticks since last reboot */
+ u_longlong_t loadavg[3]; /* (1<<SBITS) times the average number of runnables processes during the last 1, 5 and 15 minutes.
+ * To calculate the load average, divide the numbers by (1<<SBITS). SBITS is defined in <sys/proc.h>. */
+ u_longlong_t runque; /* length of the run queue (processes ready) */
+ u_longlong_t swpque; /* length of the swap queue (processes waiting to be paged in) */
+ u_longlong_t bread; /* number of blocks read */
+ u_longlong_t bwrite; /* number of blocks written */
+ u_longlong_t lread; /* number of logical read requests */
+ u_longlong_t lwrite; /* number of logical write requests */
+ u_longlong_t phread; /* number of physical reads (reads on raw devices) */
+ u_longlong_t phwrite; /* number of physical writes (writes on raw devices) */
+ u_longlong_t runocc; /* updated whenever runque is updated, i.e. the runqueue is occupied.
+ * This can be used to compute the simple average of ready processes */
+ u_longlong_t swpocc; /* updated whenever swpque is updated. i.e. the swpqueue is occupied.
+ * This can be used to compute the simple average processes waiting to be paged in */
+ u_longlong_t iget; /* number of inode lookups */
+ u_longlong_t namei; /* number of vnode lookup from a path name */
+ u_longlong_t dirblk; /* number of 512-byte block reads by the directory search routine to locate an entry for a file */
+ u_longlong_t msg; /* number of IPC message operations */
+ u_longlong_t sema; /* number of IPC semaphore operations */
+ u_longlong_t rcvint; /* number of tty receive interrupts */
+ u_longlong_t xmtint; /* number of tyy transmit interrupts */
+ u_longlong_t mdmint; /* number of modem interrupts */
+ u_longlong_t tty_rawinch; /* number of raw input characters */
+ u_longlong_t tty_caninch; /* number of canonical input characters (always zero) */
+ u_longlong_t tty_rawoutch; /* number of raw output characters */
+ u_longlong_t ksched; /* number of kernel processes created */
+ u_longlong_t koverf; /* kernel process creation attempts where:
+ * -the user has forked to their maximum limit
+ * -the configuration limit of processes has been reached */
+ u_longlong_t kexit; /* number of kernel processes that became zombies */
+ u_longlong_t rbread; /* number of remote read requests */
+ u_longlong_t rcread; /* number of cached remote reads */
+ u_longlong_t rbwrt; /* number of remote writes */
+ u_longlong_t rcwrt; /* number of cached remote writes */
+ u_longlong_t traps; /* number of traps */
+ int ncpus_high; /* index of highest processor online */
+ u_longlong_t puser; /* raw number of physical processor tics in user mode */
+ u_longlong_t psys; /* raw number of physical processor tics in system mode */
+ u_longlong_t pidle; /* raw number of physical processor tics idle */
+ u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */
+ u_longlong_t decrintrs; /* number of decrementer tics interrupts */
+ u_longlong_t mpcrintrs; /* number of mpc's received interrupts */
+ u_longlong_t mpcsintrs; /* number of mpc's sent interrupts */
+ u_longlong_t phantintrs; /* number of phantom interrupts */
+ u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */
+ short iowait; /* number of processes that are asleep waiting for buffered I/O */
+ short physio; /* number of processes waiting for raw I/O */
+ longlong_t twait; /* number of threads that are waiting for filesystem direct(cio) */
+ u_longlong_t hpi; /* number of hypervisor page-ins */
+ u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds) */
+ u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */
+ u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */
+ u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */
+ u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */
+ int spurrflag; /* set if running in spurr mode */
+} perfstat_cpu_total_t_61;
+
+typedef struct { /* global cpu information AIX 7.1 */
+ int ncpus; /* number of active logical processors */
+ int ncpus_cfg; /* number of configured processors */
+ char description[IDENTIFIER_LENGTH]; /* processor description (type/official name) */
+ u_longlong_t processorHZ; /* processor speed in Hz */
+ u_longlong_t user; /* raw total number of clock ticks spent in user mode */
+ u_longlong_t sys; /* raw total number of clock ticks spent in system mode */
+ u_longlong_t idle; /* raw total number of clock ticks spent idle */
+ u_longlong_t wait; /* raw total number of clock ticks spent waiting for I/O */
+ u_longlong_t pswitch; /* number of process switches (change in currently running process) */
+ u_longlong_t syscall; /* number of system calls executed */
+ u_longlong_t sysread; /* number of read system calls executed */
+ u_longlong_t syswrite; /* number of write system calls executed */
+ u_longlong_t sysfork; /* number of forks system calls executed */
+ u_longlong_t sysexec; /* number of execs system calls executed */
+ u_longlong_t readch; /* number of characters tranferred with read system call */
+ u_longlong_t writech; /* number of characters tranferred with write system call */
+ u_longlong_t devintrs; /* number of device interrupts */
+ u_longlong_t softintrs; /* number of software interrupts */
+ time_t lbolt; /* number of ticks since last reboot */
+ u_longlong_t loadavg[3]; /* (1<<SBITS) times the average number of runnables processes during the last 1, 5 and 15 minutes.
+ * To calculate the load average, divide the numbers by (1<<SBITS). SBITS is defined in <sys/proc.h>. */
+ u_longlong_t runque; /* length of the run queue (processes ready) */
+ u_longlong_t swpque; /* ength of the swap queue (processes waiting to be paged in) */
+ u_longlong_t bread; /* number of blocks read */
+ u_longlong_t bwrite; /* number of blocks written */
+ u_longlong_t lread; /* number of logical read requests */
+ u_longlong_t lwrite; /* number of logical write requests */
+ u_longlong_t phread; /* number of physical reads (reads on raw devices) */
+ u_longlong_t phwrite; /* number of physical writes (writes on raw devices) */
+ u_longlong_t runocc; /* updated whenever runque is updated, i.e. the runqueue is occupied.
+ * This can be used to compute the simple average of ready processes */
+ u_longlong_t swpocc; /* updated whenever swpque is updated. i.e. the swpqueue is occupied.
+ * This can be used to compute the simple average processes waiting to be paged in */
+ u_longlong_t iget; /* number of inode lookups */
+ u_longlong_t namei; /* number of vnode lookup from a path name */
+ u_longlong_t dirblk; /* number of 512-byte block reads by the directory search routine to locate an entry for a file */
+ u_longlong_t msg; /* number of IPC message operations */
+ u_longlong_t sema; /* number of IPC semaphore operations */
+ u_longlong_t rcvint; /* number of tty receive interrupts */
+ u_longlong_t xmtint; /* number of tyy transmit interrupts */
+ u_longlong_t mdmint; /* number of modem interrupts */
+ u_longlong_t tty_rawinch; /* number of raw input characters */
+ u_longlong_t tty_caninch; /* number of canonical input characters (always zero) */
+ u_longlong_t tty_rawoutch; /* number of raw output characters */
+ u_longlong_t ksched; /* number of kernel processes created */
+ u_longlong_t koverf; /* kernel process creation attempts where:
+ * -the user has forked to their maximum limit
+ * -the configuration limit of processes has been reached */
+ u_longlong_t kexit; /* number of kernel processes that became zombies */
+ u_longlong_t rbread; /* number of remote read requests */
+ u_longlong_t rcread; /* number of cached remote reads */
+ u_longlong_t rbwrt; /* number of remote writes */
+ u_longlong_t rcwrt; /* number of cached remote writes */
+ u_longlong_t traps; /* number of traps */
+ int ncpus_high; /* index of highest processor online */
+ u_longlong_t puser; /* raw number of physical processor tics in user mode */
+ u_longlong_t psys; /* raw number of physical processor tics in system mode */
+ u_longlong_t pidle; /* raw number of physical processor tics idle */
+ u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */
+ u_longlong_t decrintrs; /* number of decrementer tics interrupts */
+ u_longlong_t mpcrintrs; /* number of mpc's received interrupts */
+ u_longlong_t mpcsintrs; /* number of mpc's sent interrupts */
+ u_longlong_t phantintrs; /* number of phantom interrupts */
+ u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */
+ short iowait; /* number of processes that are asleep waiting for buffered I/O */
+ short physio; /* number of processes waiting for raw I/O */
+ longlong_t twait; /* number of threads that are waiting for filesystem direct(cio) */
+ u_longlong_t hpi; /* number of hypervisor page-ins */
+ u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds) */
+ u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */
+ u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */
+ u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */
+ u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */
+ int spurrflag; /* set if running in spurr mode */
+ u_longlong_t version; /* version number (1, 2, etc.,) */
+/* >>>>> END OF STRUCTURE DEFINITION <<<<< */
+#define CURR_VERSION_CPU_TOTAL 1 /* Incremented by one for every new release *
+ * of perfstat_cpu_total_t data structure */
+} perfstat_cpu_total_t_71;
+
+typedef union {
+ uint w;
+ struct {
+ unsigned smt_capable :1; /* OS supports SMT mode */
+ unsigned smt_enabled :1; /* SMT mode is on */
+ unsigned lpar_capable :1; /* OS supports logical partitioning */
+ unsigned lpar_enabled :1; /* logical partitioning is on */
+ unsigned shared_capable :1; /* OS supports shared processor LPAR */
+ unsigned shared_enabled :1; /* partition runs in shared mode */
+ unsigned dlpar_capable :1; /* OS supports dynamic LPAR */
+ unsigned capped :1; /* partition is capped */
+ unsigned kernel_is_64 :1; /* kernel is 64 bit */
+ unsigned pool_util_authority :1; /* pool utilization available */
+ unsigned donate_capable :1; /* capable of donating cycles */
+ unsigned donate_enabled :1; /* enabled for donating cycles */
+ unsigned ams_capable:1; /* 1 = AMS(Active Memory Sharing) capable, 0 = Not AMS capable */
+ unsigned ams_enabled:1; /* 1 = AMS(Active Memory Sharing) enabled, 0 = Not AMS enabled */
+ unsigned power_save:1; /* 1 = Power saving mode is enabled */
+ unsigned ame_enabled:1; /* Active Memory Expansion is enabled */
+ unsigned shared_extended :1;
+ unsigned spare :15; /* reserved for future usage */
+ } b;
+} perfstat_partition_type_t;
+
+typedef struct { /* partition total information AIX 5.3 < TL6 */
+ char name[IDENTIFIER_LENGTH]; /* name of the logical partition */
+ perfstat_partition_type_t type; /* set of bits describing the partition */
+ int lpar_id; /* logical partition identifier */
+ int group_id; /* identifier of the LPAR group this partition is a member of */
+ int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */
+ int online_cpus; /* number of virtual CPUs currently online on the partition */
+ int max_cpus; /* maximum number of virtual CPUs this parition can ever have */
+ int min_cpus; /* minimum number of virtual CPUs this partition must have */
+ u_longlong_t online_memory; /* amount of memory currently online */
+ u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */
+ u_longlong_t min_memory; /* minimum amount of memory this partition must have */
+ int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */
+ int max_proc_capacity; /* maximum number of processor units this partition can ever have */
+ int min_proc_capacity; /* minimum number of processor units this partition must have */
+ int proc_capacity_increment; /* increment value to the entitled capacity */
+ int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */
+ int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */
+ int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */
+ int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */
+ int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */
+ int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */
+ u_longlong_t puser; /* raw number of physical processor tics in user mode */
+ u_longlong_t psys; /* raw number of physical processor tics in system mode */
+ u_longlong_t pidle; /* raw number of physical processor tics idle */
+ u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */
+ u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */
+ u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */
+ u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */
+ u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */
+ u_longlong_t timebase_last; /* most recently cpu time base */
+ u_longlong_t reserved_pages; /* Currenlty number of 16GB pages. Cannot participate in DR operations */
+ u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */
+} perfstat_partition_total_t_53_5;
+
+typedef struct { /* partition total information AIX 5.3 < TL10 */
+ char name[IDENTIFIER_LENGTH]; /* name of the logical partition */
+ perfstat_partition_type_t type; /* set of bits describing the partition */
+ int lpar_id; /* logical partition identifier */
+ int group_id; /* identifier of the LPAR group this partition is a member of */
+ int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */
+ int online_cpus; /* number of virtual CPUs currently online on the partition */
+ int max_cpus; /* maximum number of virtual CPUs this parition can ever have */
+ int min_cpus; /* minimum number of virtual CPUs this partition must have */
+ u_longlong_t online_memory; /* amount of memory currently online */
+ u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */
+ u_longlong_t min_memory; /* minimum amount of memory this partition must have */
+ int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */
+ int max_proc_capacity; /* maximum number of processor units this partition can ever have */
+ int min_proc_capacity; /* minimum number of processor units this partition must have */
+ int proc_capacity_increment; /* increment value to the entitled capacity */
+ int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */
+ int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */
+ int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */
+ int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */
+ int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */
+ int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */
+ u_longlong_t puser; /* raw number of physical processor tics in user mode */
+ u_longlong_t psys; /* raw number of physical processor tics in system mode */
+ u_longlong_t pidle; /* raw number of physical processor tics idle */
+ u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */
+ u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */
+ u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */
+ u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */
+ u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */
+ u_longlong_t timebase_last; /* most recently cpu time base */
+ u_longlong_t reserved_pages; /* Currenlty number of 16GB pages. Cannot participate in DR operations */
+ u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */
+ u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use */
+ u_longlong_t max_pool_capacity; /* Maximum processor capacity of partitions pool */
+ u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */
+ u_longlong_t pool_max_time; /* Summation of maximum time that could be consumed by the pool (nano seconds) */
+ u_longlong_t pool_busy_time; /* Summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */
+ u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */
+ u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nano seconds) */
+ u_longlong_t shcpu_busy_time; /* Summation of busy (non-idle) time accumulated across all shared processor partitions (nano seconds) */
+ u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nano seconds) */
+ int ams_pool_id; /* AMS pool id of the pool the LPAR belongs to */
+ int var_mem_weight; /* variable memory capacity weight */
+ u_longlong_t iome; /* I/O memory entitlement of the partition in bytes*/
+ u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes*/
+ u_longlong_t hpi; /* number of hypervisor page-ins */
+ u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds)*/
+ u_longlong_t hypv_pagesize; /* Hypervisor page size in KB*/
+} perfstat_partition_total_t_53;
+
+typedef struct { /* partition total information AIX 6.1|5.3 > TL09 */
+ char name[IDENTIFIER_LENGTH]; /* name of the logical partition */
+ perfstat_partition_type_t type; /* set of bits describing the partition */
+ int lpar_id; /* logical partition identifier */
+ int group_id; /* identifier of the LPAR group this partition is a member of */
+ int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */
+ int online_cpus; /* number of virtual CPUs currently online on the partition */
+ int max_cpus; /* maximum number of virtual CPUs this parition can ever have */
+ int min_cpus; /* minimum number of virtual CPUs this partition must have */
+ u_longlong_t online_memory; /* amount of memory currently online */
+ u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */
+ u_longlong_t min_memory; /* minimum amount of memory this partition must have */
+ int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */
+ int max_proc_capacity; /* maximum number of processor units this partition can ever have */
+ int min_proc_capacity; /* minimum number of processor units this partition must have */
+ int proc_capacity_increment; /* increment value to the entitled capacity */
+ int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */
+ int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */
+ int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */
+ int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */
+ int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */
+ int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */
+ u_longlong_t puser; /* raw number of physical processor tics in user mode */
+ u_longlong_t psys; /* raw number of physical processor tics in system mode */
+ u_longlong_t pidle; /* raw number of physical processor tics idle */
+ u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */
+ u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */
+ u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */
+ u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */
+ u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */
+ u_longlong_t timebase_last; /* most recently cpu time base */
+ u_longlong_t reserved_pages; /* Currenlty number of 16GB pages. Cannot participate in DR operations */
+ u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */
+ u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use */
+ u_longlong_t max_pool_capacity; /* Maximum processor capacity of partitions pool */
+ u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */
+ u_longlong_t pool_max_time; /* Summation of maximum time that could be consumed by the pool (nano seconds) */
+ u_longlong_t pool_busy_time; /* Summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */
+ u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */
+ u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nano seconds) */
+ u_longlong_t shcpu_busy_time; /* Summation of busy (non-idle) time accumulated across all shared processor partitions (nano seconds) */
+ u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nano seconds) */
+ int ams_pool_id; /* AMS pool id of the pool the LPAR belongs to */
+ int var_mem_weight; /* variable memory capacity weight */
+ u_longlong_t iome; /* I/O memory entitlement of the partition in bytes*/
+ u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes*/
+ u_longlong_t hpi; /* number of hypervisor page-ins */
+ u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds)*/
+ u_longlong_t hypv_pagesize; /* Hypervisor page size in KB*/
+ uint online_lcpus; /* number of online logical cpus */
+ uint smt_thrds; /* number of hardware threads that are running */
+ u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */
+ u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */
+ u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */
+ u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */
+ int spurrflag; /* set if running in spurr mode */
+} perfstat_partition_total_t_61;
+
+typedef struct { /* partition total information AIX 7.1 */
+ char name[IDENTIFIER_LENGTH]; /* name of the logical partition */
+ perfstat_partition_type_t type; /* set of bits describing the partition */
+ int lpar_id; /* logical partition identifier */
+ int group_id; /* identifier of the LPAR group this partition is a member of */
+ int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */
+ int online_cpus; /* number of virtual CPUs currently online on the partition */
+ int max_cpus; /* maximum number of virtual CPUs this parition can ever have */
+ int min_cpus; /* minimum number of virtual CPUs this partition must have */
+ u_longlong_t online_memory; /* amount of memory currently online */
+ u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */
+ u_longlong_t min_memory; /* minimum amount of memory this partition must have */
+ int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */
+ int max_proc_capacity; /* maximum number of processor units this partition can ever have */
+ int min_proc_capacity; /* minimum number of processor units this partition must have */
+ int proc_capacity_increment; /* increment value to the entitled capacity */
+ int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */
+ int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */
+ int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */
+ int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */
+ int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */
+ int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */
+ u_longlong_t puser; /* raw number of physical processor tics in user mode */
+ u_longlong_t psys; /* raw number of physical processor tics in system mode */
+ u_longlong_t pidle; /* raw number of physical processor tics idle */
+ u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */
+ u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */
+ u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */
+ u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */
+ u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */
+ u_longlong_t timebase_last; /* most recently cpu time base */
+ u_longlong_t reserved_pages; /* Currenlty number of 16GB pages. Cannot participate in DR operations */
+ u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */
+ u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use */
+ u_longlong_t max_pool_capacity; /* Maximum processor capacity of partitions pool */
+ u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */
+ u_longlong_t pool_max_time; /* Summation of maximum time that could be consumed by the pool (nano seconds) */
+ u_longlong_t pool_busy_time; /* Summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */
+ u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */
+ u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nano seconds) */
+ u_longlong_t shcpu_busy_time; /* Summation of busy (non-idle) time accumulated across all shared processor partitions (nano seconds) */
+ u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nano seconds) */
+ int ams_pool_id; /* AMS pool id of the pool the LPAR belongs to */
+ int var_mem_weight; /* variable memory capacity weight */
+ u_longlong_t iome; /* I/O memory entitlement of the partition in bytes*/
+ u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes*/
+ u_longlong_t hpi; /* number of hypervisor page-ins */
+ u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds)*/
+ u_longlong_t hypv_pagesize; /* Hypervisor page size in KB*/
+ uint online_lcpus; /* number of online logical cpus */
+ uint smt_thrds; /* number of hardware threads that are running */
+ u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */
+ u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */
+ u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */
+ u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */
+ int spurrflag; /* set if running in spurr mode */
+ char hardwareid[CEC_ID_LEN]; /* CEC Identifier */
+ uint power_save_mode; /* Power save mode for the LPAR. Introduced through LI 53K PRF : Feature 728 292*/
+ ushort ame_version; /* AME Version */
+ u_longlong_t true_memory; /* True Memory Size in 4KB pages */
+ u_longlong_t expanded_memory; /* Expanded Memory Size in 4KB pages */
+ u_longlong_t target_memexp_factr; /* Target Memory Expansion Factor scaled by 100 */
+ u_longlong_t current_memexp_factr; /* Current Memory Expansion Factor scaled by 100 */
+ u_longlong_t target_cpool_size; /* Target Compressed Pool Size in bytes */
+ u_longlong_t max_cpool_size; /* Max Size of Compressed Pool in bytes */
+ u_longlong_t min_ucpool_size; /* Min Size of Uncompressed Pool in bytes */
+ u_longlong_t ame_deficit_size; /*Deficit memory size in bytes */
+ u_longlong_t version; /* version number (1, 2, etc.,) */
+ u_longlong_t cmcs_total_time; /* Total CPU time spent due to active memory expansion */
+} perfstat_partition_total_t_71;
+
+typedef struct { /* partition total information AIX 7.1 >= TL1*/
+ char name[IDENTIFIER_LENGTH]; /* name of the logical partition */
+ perfstat_partition_type_t type; /* set of bits describing the partition */
+ int lpar_id; /* logical partition identifier */
+ int group_id; /* identifier of the LPAR group this partition is a member of */
+ int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */
+ int online_cpus; /* number of virtual CPUs currently online on the partition */
+ int max_cpus; /* maximum number of virtual CPUs this parition can ever have */
+ int min_cpus; /* minimum number of virtual CPUs this partition must have */
+ u_longlong_t online_memory; /* amount of memory currently online */
+ u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */
+ u_longlong_t min_memory; /* minimum amount of memory this partition must have */
+ int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */
+ int max_proc_capacity; /* maximum number of processor units this partition can ever have */
+ int min_proc_capacity; /* minimum number of processor units this partition must have */
+ int proc_capacity_increment; /* increment value to the entitled capacity */
+ int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */
+ int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */
+ int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */
+ int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */
+ int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */
+ int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */
+ u_longlong_t puser; /* raw number of physical processor tics in user mode */
+ u_longlong_t psys; /* raw number of physical processor tics in system mode */
+ u_longlong_t pidle; /* raw number of physical processor tics idle */
+ u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */
+ u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */
+ u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */
+ u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */
+ u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */
+ u_longlong_t timebase_last; /* most recently cpu time base */
+ u_longlong_t reserved_pages; /* Currenlty number of 16GB pages. Cannot participate in DR operations */
+ u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */
+ u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */
+ u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */
+ u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use */
+ u_longlong_t max_pool_capacity; /* Maximum processor capacity of partitions pool */
+ u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */
+ u_longlong_t pool_max_time; /* Summation of maximum time that could be consumed by the pool (nano seconds) */
+ u_longlong_t pool_busy_time; /* Summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */
+ u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */
+ u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nano seconds) */
+ u_longlong_t shcpu_busy_time; /* Summation of busy (non-idle) time accumulated across all shared processor partitions (nano seconds) */
+ u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nano seconds) */
+ int ams_pool_id; /* AMS pool id of the pool the LPAR belongs to */
+ int var_mem_weight; /* variable memory capacity weight */
+ u_longlong_t iome; /* I/O memory entitlement of the partition in bytes*/
+ u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes*/
+ u_longlong_t hpi; /* number of hypervisor page-ins */
+ u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds)*/
+ u_longlong_t hypv_pagesize; /* Hypervisor page size in KB*/
+ uint online_lcpus; /* number of online logical cpus */
+ uint smt_thrds; /* number of hardware threads that are running */
+ u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */
+ u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */
+ u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */
+ u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */
+ int spurrflag; /* set if running in spurr mode */
+ char hardwareid[CEC_ID_LEN]; /* CEC Identifier */
+ uint power_save_mode; /* Power save mode for the LPAR. Introduced through LI 53K PRF : Feature 728 292*/
+ ushort ame_version; /* AME Version */
+ u_longlong_t true_memory; /* True Memory Size in 4KB pages */
+ u_longlong_t expanded_memory; /* Expanded Memory Size in 4KB pages */
+ u_longlong_t target_memexp_factr; /* Target Memory Expansion Factor scaled by 100 */
+ u_longlong_t current_memexp_factr; /* Current Memory Expansion Factor scaled by 100 */
+ u_longlong_t target_cpool_size; /* Target Compressed Pool Size in bytes */
+ u_longlong_t max_cpool_size; /* Max Size of Compressed Pool in bytes */
+ u_longlong_t min_ucpool_size; /* Min Size of Uncompressed Pool in bytes */
+ u_longlong_t ame_deficit_size; /*Deficit memory size in bytes */
+ u_longlong_t version; /* version number (1, 2, etc.,) */
+ u_longlong_t cmcs_total_time; /* Total CPU time spent due to active memory expansion */
+ u_longlong_t purr_coalescing; /* If the calling partition is authorized to see pool wide statistics then PURR cycles consumed to coalesce data else set to zero.*/
+ u_longlong_t spurr_coalescing; /* If the calling partition is authorized to see pool wide statistics then SPURR cycles consumed to coalesce data else set to zero.*/
+ u_longlong_t MemPoolSize; /* Indicates the memory pool size of the pool that the partition belongs to (in bytes)., mpsz */
+ u_longlong_t IOMemEntInUse; /* I/O memory entitlement of the LPAR in use in bytes. iomu */
+ u_longlong_t IOMemEntFree; /* free I/O memory entitlement in bytes. iomf */
+ u_longlong_t IOHighWaterMark; /* high water mark of I/O memory entitlement usage in bytes. iohwn */
+ u_longlong_t purr_counter; /* number of purr cycles spent in user + kernel mode */
+ u_longlong_t spurr_counter; /* number of spurr cycles spent in user + kernel mode */
+
+ /* Marketing Requirement(MR): MR1124083744 */
+ u_longlong_t real_free; /* free real memory (in 4KB pages) */
+ u_longlong_t real_avail; /* number of pages available for user application (memfree + numperm - minperm - minfree) */
+ /* >>>>> END OF STRUCTURE DEFINITION <<<<< */
+#define CURR_VERSION_PARTITION_TOTAL 5 /* Incremented by one for every new release *
+ * of perfstat_partition_total_t data structure */
+} perfstat_partition_total_t_71_1;
+
+typedef union { /* WPAR Type & Flags */
+ uint w;
+ struct {
+ unsigned app_wpar :1; /* Application WPAR */
+ unsigned cpu_rset :1; /* WPAR restricted to CPU resource set */
+ unsigned cpu_xrset:1; /* WPAR restricted to CPU Exclusive resource set */
+ unsigned cpu_limits :1; /* CPU resource limits enforced */
+ unsigned mem_limits :1; /* Memory resource limits enforced */
+ unsigned spare :27; /* reserved for future usage */
+ } b;
+} perfstat_wpar_type_t;
+
+typedef struct { /* Workload partition Information AIX 5.3 & 6.1*/
+ char name[MAXCORRALNAMELEN+1]; /* name of the Workload Partition */
+ perfstat_wpar_type_t type; /* set of bits describing the wpar */
+ cid_t wpar_id; /* workload partition identifier */
+ uint online_cpus; /* Number of Virtual CPUs in partition rset or number of virtual CPUs currently online on the Global partition*/
+ int cpu_limit; /* CPU limit in 100ths of % - 1..10000 */
+ int mem_limit; /* Memory limit in 100ths of % - 1..10000 */
+ u_longlong_t online_memory; /* amount of memory currently online in Global Partition */
+ int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */
+} perfstat_wpar_total_t_61;
+
+typedef struct { /* Workload partition Information AIX 7.1*/
+ char name[MAXCORRALNAMELEN+1]; /* name of the Workload Partition */
+ perfstat_wpar_type_t type; /* set of bits describing the wpar */
+ cid_t wpar_id; /* workload partition identifier */
+ uint online_cpus; /* Number of Virtual CPUs in partition rset or number of virtual CPUs currently online on the Global partition*/
+ int cpu_limit; /* CPU limit in 100ths of % - 1..10000 */
+ int mem_limit; /* Memory limit in 100ths of % - 1..10000 */
+ u_longlong_t online_memory; /* amount of memory currently online in Global Partition */
+ int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */
+ u_longlong_t version; /* version number (1, 2, etc.,) */
+/* >>>>> END OF STRUCTURE DEFINITION <<<<< */
+#define CURR_VERSION_WPAR_TOTAL 1 /* Incremented by one for every new release *
+ * of perfstat_wpar_total_t data structure */
+} perfstat_wpar_total_t_71;
+
+typedef void * rsethandle_t; /* Type to identify a resource set handle: rsethandle_t */
+
+typedef enum { WPARNAME, WPARID, RSETHANDLE } wparid_specifier; /* Type of wparid_specifier */
+
+typedef struct { /* WPAR identifier */
+ wparid_specifier spec; /* Specifier to choose wpar id or name */
+ union {
+ cid_t wpar_id; /* WPAR ID */
+ rsethandle_t rset; /* Rset Handle */
+ char wparname[MAXCORRALNAMELEN+1]; /* WPAR NAME */
+ } u;
+ char name[IDENTIFIER_LENGTH]; /* name of the structure element identifier */
+} perfstat_id_wpar_t;
+
+
+
+// end: libperfstat.h (AIX 5.2, 5.3, 6.1, 7.1)
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define PERFSTAT_PARTITON_TOTAL_T_LATEST perfstat_partition_total_t_71_1/* latest perfstat_partition_total_t structure */
+#define PERFSTAT_CPU_TOTAL_T_LATEST perfstat_cpu_total_t_71 /* latest perfstat_cpu_total_t structure */
+#define PERFSTAT_WPAR_TOTAL_T_LATEST perfstat_wpar_total_t_71 /* latest perfstat_wpar_total_t structure */
class libperfstat {
@@ -41,19 +766,107 @@
// Load the libperfstat library (must be in LIBPATH).
// Returns true if succeeded, false if error.
static bool init();
-
- // cleanup of the libo4 porting library.
static void cleanup();
- // direct wrappers for the libperfstat functionality. All they do is
+ // Direct wrappers for the libperfstat functionality. All they do is
// to call the functions with the same name via function pointers.
- static int perfstat_cpu_total(perfstat_id_t *name, perfstat_cpu_total_t* userbuff,
+ // Get all available data also on newer AIX versions (PERFSTAT_CPU_TOTAL_T_LATEST).
+ static int perfstat_cpu_total(perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff,
int sizeof_userbuff, int desired_number);
static int perfstat_memory_total(perfstat_id_t *name, perfstat_memory_total_t* userbuff,
int sizeof_userbuff, int desired_number);
+ static int perfstat_partition_total(perfstat_id_t *name, PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff,
+ int sizeof_userbuff, int desired_number);
+
static void perfstat_reset();
+
+ static int perfstat_wpar_total(perfstat_id_wpar_t *name, PERFSTAT_WPAR_TOTAL_T_LATEST* userbuff,
+ int sizeof_userbuff, int desired_number);
+
+ static cid_t wpar_getcid();
+
+
+ ////////////////////////////////////////////////////////////////
+ // The convenience functions get_partitioninfo(), get_cpuinfo(), get_wparinfo() return
+ // information about partition, cpu and wpars, respectivly. They can be used without
+ // regard for which OS release we are on. On older AIX release, some output structure
+ // members will be 0.
+
+ // Result struct for get_partitioninfo().
+ struct partitioninfo_t {
+ // partition type info
+ unsigned smt_capable :1; /* OS supports SMT mode */
+ unsigned smt_enabled :1; /* SMT mode is on */
+ unsigned lpar_capable :1; /* OS supports logical partitioning */
+ unsigned lpar_enabled :1; /* logical partitioning is on */
+ unsigned shared_capable :1; /* OS supports shared processor LPAR */
+ unsigned shared_enabled :1; /* partition runs in shared mode */
+ unsigned dlpar_capable :1; /* OS supports dynamic LPAR */
+ unsigned capped :1; /* partition is capped */
+ unsigned kernel_is_64 :1; /* kernel is 64 bit */
+ unsigned pool_util_authority :1; /* pool utilization available */
+ unsigned donate_capable :1; /* capable of donating cycles */
+ unsigned donate_enabled :1; /* enabled for donating cycles */
+ unsigned ams_capable:1; /* 1 = AMS(Active Memory Sharing) capable, 0 = Not AMS capable */
+ unsigned ams_enabled:1; /* 1 = AMS(Active Memory Sharing) enabled, 0 = Not AMS enabled */
+ unsigned power_save:1; /* 1 = Power saving mode is enabled */
+ unsigned ame_enabled:1; /* Active Memory Expansion is enabled */
+ // partition total info
+ int online_cpus; /* number of virtual CPUs currently online on the partition */
+ int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */
+ int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */
+ int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */
+ int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */
+ u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */
+ char name[IDENTIFIER_LENGTH]; /* name of the logical partition */
+
+ u_longlong_t timebase_last; /* most recently cpu time base (an incremented long int on PowerPC) */
+ u_longlong_t pool_idle_time; /* pool idle time = number of clock tics a processor in the shared pool was idle */
+ u_longlong_t pcpu_tics_user; /* raw number of physical processor tics in user mode */
+ u_longlong_t pcpu_tics_sys; /* raw number of physical processor tics in system mode */
+ u_longlong_t pcpu_tics_idle; /* raw number of physical processor tics idle */
+ u_longlong_t pcpu_tics_wait; /* raw number of physical processor tics waiting for I/O */
+
+ u_longlong_t true_memory; /* True Memory Size in 4KB pages */
+ u_longlong_t expanded_memory; /* Expanded Memory Size in 4KB pages */
+ u_longlong_t target_memexp_factr; /* Target Memory Expansion Factor scaled by 100 */
+ u_longlong_t current_memexp_factr; /* Current Memory Expansion Factor scaled by 100 */
+ u_longlong_t cmcs_total_time; /* Total CPU time spent due to active memory expansion */
+ };
+
+ // Result struct for get_cpuinfo().
+ struct cpuinfo_t {
+ char description[IDENTIFIER_LENGTH]; // processor description (type/official name)
+ u_longlong_t processorHZ; // processor speed in Hz
+ int ncpus; // number of active logical processors
+ double loadavg[3]; // (1<<SBITS) times the average number of runnables processes during the last 1, 5 and 15 minutes.
+ // To calculate the load average, divide the numbers by (1<<SBITS). SBITS is defined in <sys/proc.h>.
+ char version[20]; // processor version from _system_configuration (sys/systemcfg.h)
+ unsigned long long user_clock_ticks; // raw total number of clock ticks spent in user mode
+ unsigned long long sys_clock_ticks; // raw total number of clock ticks spent in system mode
+ unsigned long long idle_clock_ticks; // raw total number of clock ticks spent idle
+ unsigned long long wait_clock_ticks; // raw total number of clock ticks spent waiting for I/O
+ };
+
+ // Result struct for get_wparinfo().
+ struct wparinfo_t {
+ char name[MAXCORRALNAMELEN+1]; /* name of the Workload Partition */
+ unsigned short wpar_id; /* workload partition identifier */
+ unsigned app_wpar :1; /* Application WPAR */
+ unsigned cpu_rset :1; /* WPAR restricted to CPU resource set */
+ unsigned cpu_xrset:1; /* WPAR restricted to CPU Exclusive resource set */
+ unsigned cpu_limits :1; /* CPU resource limits enforced */
+ unsigned mem_limits :1; /* Memory resource limits enforced */
+ int cpu_limit; /* CPU limit in 100ths of % - 1..10000 */
+ int mem_limit; /* Memory limit in 100ths of % - 1..10000 */
+ };
+
+ static bool get_partitioninfo(partitioninfo_t* ppi);
+ static bool get_cpuinfo(cpuinfo_t* pci);
+ static bool get_wparinfo(wparinfo_t* pwi);
+
};
#endif // OS_AIX_VM_LIBPERFSTAT_AIX_HPP
--- a/hotspot/src/os/aix/vm/loadlib_aix.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/loadlib_aix.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@
#endif
#include "loadlib_aix.hpp"
-// for CritSect
#include "misc_aix.hpp"
#include "porting_aix.hpp"
#include "utilities/debug.hpp"
--- a/hotspot/src/os/aix/vm/misc_aix.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/misc_aix.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -26,6 +26,8 @@
#include "runtime/stubRoutines.hpp"
#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
void MiscUtils::init_critsect(MiscUtils::critsect_t* cs) {
const int rc = pthread_mutex_init(cs, NULL);
--- a/hotspot/src/os/aix/vm/misc_aix.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/misc_aix.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -29,6 +29,8 @@
// misc_aix.hpp, misc_aix.cpp: convenience functions needed for the OpenJDK AIX
// port.
#include "utilities/globalDefinitions.hpp"
+#include "runtime/globals.hpp"
+#include "utilities/debug.hpp"
#include <pthread.h>
@@ -40,7 +42,6 @@
} \
}
#define ERRBYE(s) { trcVerbose(s); return -1; }
-#define trc(fmt, ...)
#define assert0(b) assert((b), "")
#define guarantee0(b) guarantee((b), "")
--- a/hotspot/src/os/aix/vm/osThread_aix.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/osThread_aix.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -35,7 +35,7 @@
void OSThread::pd_initialize() {
assert(this != NULL, "check");
_thread_id = 0;
- _pthread_id = 0;
+ _kernel_thread_id = 0;
_siginfo = NULL;
_ucontext = NULL;
_expanding_stack = 0;
--- a/hotspot/src/os/aix/vm/osThread_aix.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/osThread_aix.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -27,7 +27,7 @@
#define OS_AIX_VM_OSTHREAD_AIX_HPP
public:
- typedef pid_t thread_id_t;
+ typedef pthread_t thread_id_t;
private:
int _thread_type;
@@ -43,9 +43,13 @@
private:
- // _pthread_id is the pthread id, which is used by library calls
- // (e.g. pthread_kill).
- pthread_t _pthread_id;
+ // On AIX, we use the pthread id as OSThread::thread_id and keep the kernel thread id
+ // separately for diagnostic purposes.
+ //
+ // Note: this kernel thread id is saved at thread start. Depending on the
+ // AIX scheduling mode, this may not be the current thread id (usually not
+ // a problem though as we run with AIXTHREAD_SCOPE=S).
+ tid_t _kernel_thread_id;
sigset_t _caller_sigmask; // Caller's signal mask
@@ -66,11 +70,16 @@
return false;
}
#endif // ASSERT
- pthread_t pthread_id() const {
- return _pthread_id;
+ tid_t kernel_thread_id() const {
+ return _kernel_thread_id;
}
- void set_pthread_id(pthread_t tid) {
- _pthread_id = tid;
+ void set_kernel_thread_id(tid_t tid) {
+ _kernel_thread_id = tid;
+ }
+
+ pthread_t pthread_id() const {
+ // Here: same as OSThread::thread_id()
+ return _thread_id;
}
// ***************************************************************
--- a/hotspot/src/os/aix/vm/os_aix.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/os_aix.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -36,6 +36,7 @@
#include "compiler/compileBroker.hpp"
#include "interpreter/interpreter.hpp"
#include "jvm_aix.h"
+#include "libo4.hpp"
#include "libperfstat_aix.hpp"
#include "loadlib_aix.hpp"
#include "memory/allocation.inline.hpp"
@@ -108,25 +109,14 @@
#include <sys/vminfo.h>
#include <sys/wait.h>
-// 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
-#define RUSAGE_THREAD (1) /* only the calling thread */
-#endif
-
-// PPC port
-static const uintx Use64KPagesThreshold = 1*M;
-static const uintx MaxExpectedDataSegmentSize = SIZE_4G*2;
-
-// Add missing declarations (should be in procinfo.h but isn't until AIX 6.1).
+// Missing prototypes for various system APIs.
+extern "C"
+int mread_real_time(timebasestruct_t *t, size_t size_of_timebasestruct_t);
+
#if !defined(_AIXVERSION_610)
-extern "C" {
- int getthrds64(pid_t ProcessIdentifier,
- struct thrdentry64* ThreadBuffer,
- int ThreadSize,
- tid64_t* IndexPointer,
- int Count);
-}
+extern "C" int getthrds64(pid_t, struct thrdentry64*, int, tid64_t*, int);
+extern "C" int getprocs64(procentry64*, int, fdsinfo*, int, pid_t*, int);
+extern "C" int getargs (procsinfo*, int, char*, int);
#endif
#define MAX_PATH (2 * K)
@@ -150,18 +140,9 @@
typedef unsigned long stackslot_t;
typedef stackslot_t* stackptr_t;
-// Excerpts from systemcfg.h definitions newer than AIX 5.3.
-#ifndef PV_7
-#define PV_7 0x200000 /* Power PC 7 */
-#define PV_7_Compat 0x208000 /* Power PC 7 */
-#endif
-#ifndef PV_8
-#define PV_8 0x300000 /* Power PC 8 */
-#define PV_8_Compat 0x308000 /* Power PC 8 */
-#endif
-
// Query dimensions of the stack of the calling thread.
static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size);
+static address resolve_function_descriptor_to_code_pointer(address p);
// Function to check a given stack pointer against given stack limits.
inline bool is_valid_stackpointer(stackptr_t sp, stackptr_t stack_base, size_t stack_size) {
@@ -185,7 +166,7 @@
if (((uintptr_t)p) & 0x3) {
return false;
}
- if (!LoadedLibraries::find_for_text_address(p, NULL)) {
+ if (LoadedLibraries::find_for_text_address(p, NULL) == NULL) {
return false;
}
return true;
@@ -203,31 +184,44 @@
CHECK_STACK_PTR(sp, stack_base, stack_size); \
}
+static void vmembk_print_on(outputStream* os);
+
////////////////////////////////////////////////////////////////////////////////
// global variables (for a description see os_aix.hpp)
julong os::Aix::_physical_memory = 0;
+
pthread_t os::Aix::_main_thread = ((pthread_t)0);
int os::Aix::_page_size = -1;
+
+// -1 = uninitialized, 0 if AIX, 1 if OS/400 pase
int os::Aix::_on_pase = -1;
+
+// -1 = uninitialized, otherwise os version in the form 0xMMmm - MM:major, mm:minor
+// E.g. 0x0601 for AIX 6.1 or 0x0504 for OS/400 V5R4
int os::Aix::_os_version = -1;
+
int os::Aix::_stack_page_size = -1;
+
+// -1 = uninitialized, 0 - no, 1 - yes
int os::Aix::_xpg_sus_mode = -1;
+
+// -1 = uninitialized, 0 - no, 1 - yes
int os::Aix::_extshm = -1;
-int os::Aix::_logical_cpus = -1;
////////////////////////////////////////////////////////////////////////////////
// local variables
-static int g_multipage_error = -1; // error analysis for multipage initialization
static jlong initial_time_count = 0;
static int clock_tics_per_sec = 100;
static sigset_t check_signal_done; // For diagnostics to print a message once (see run_periodic_checks)
static bool check_signals = true;
-static pid_t _initial_pid = 0;
static int SR_signum = SIGUSR2; // Signal used to suspend/resume a thread (must be > SIGSEGV, see 4355769)
static sigset_t SR_sigset;
+// Process break recorded at startup.
+static address g_brk_at_startup = NULL;
+
// This describes the state of multipage support of the underlying
// OS. Note that this is of no interest to the outsize world and
// therefore should not be defined in AIX class.
@@ -278,8 +272,9 @@
// a specific wish address, e.g. to place the heap in a
// compressed-oops-friendly way.
static bool is_close_to_brk(address a) {
- address a1 = (address) sbrk(0);
- if (a >= a1 && a < (a1 + MaxExpectedDataSegmentSize)) {
+ assert0(g_brk_at_startup != NULL);
+ if (a >= g_brk_at_startup &&
+ a < (g_brk_at_startup + MaxExpectedDataSegmentSize)) {
return true;
}
return false;
@@ -290,11 +285,15 @@
}
julong os::Aix::available_memory() {
+ // Avoid expensive API call here, as returned value will always be null.
+ if (os::Aix::on_pase()) {
+ return 0x0LL;
+ }
os::Aix::meminfo_t mi;
if (os::Aix::get_meminfo(&mi)) {
return mi.real_free;
} else {
- return 0xFFFFFFFFFFFFFFFFLL;
+ return ULONG_MAX;
}
}
@@ -332,7 +331,7 @@
for (int i = 0; i < numFullDisclaimsNeeded; i ++) {
if (::disclaim(p, maxDisclaimSize, DISCLAIM_ZEROMEM) != 0) {
- trc("Cannot disclaim %p - %p (errno %d)\n", p, p + maxDisclaimSize, errno);
+ trcVerbose("Cannot disclaim %p - %p (errno %d)\n", p, p + maxDisclaimSize, errno);
return false;
}
p += maxDisclaimSize;
@@ -340,7 +339,7 @@
if (lastDisclaimSize > 0) {
if (::disclaim(p, lastDisclaimSize, DISCLAIM_ZEROMEM) != 0) {
- trc("Cannot disclaim %p - %p (errno %d)\n", p, p + lastDisclaimSize, errno);
+ trcVerbose("Cannot disclaim %p - %p (errno %d)\n", p, p + lastDisclaimSize, errno);
return false;
}
}
@@ -357,25 +356,30 @@
#error Add appropriate cpu_arch setting
#endif
+// Wrap the function "vmgetinfo" which is not available on older OS releases.
+static int checked_vmgetinfo(void *out, int command, int arg) {
+ if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) {
+ guarantee(false, "cannot call vmgetinfo on AS/400 older than V6R1");
+ }
+ return ::vmgetinfo(out, command, arg);
+}
// Given an address, returns the size of the page backing that address.
size_t os::Aix::query_pagesize(void* addr) {
+ if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) {
+ // AS/400 older than V6R1: no vmgetinfo here, default to 4K
+ return SIZE_4K;
+ }
+
vm_page_info pi;
pi.addr = (uint64_t)addr;
- if (::vmgetinfo(&pi, VM_PAGE_INFO, sizeof(pi)) == 0) {
+ if (checked_vmgetinfo(&pi, VM_PAGE_INFO, sizeof(pi)) == 0) {
return pi.pagesize;
} else {
- fprintf(stderr, "vmgetinfo failed to retrieve page size for address %p (errno %d).\n", addr, errno);
assert(false, "vmgetinfo failed to retrieve page size");
return SIZE_4K;
}
-
-}
-
-// Returns the kernel thread id of the currently running thread.
-pid_t os::Aix::gettid() {
- return (pid_t) thread_self();
}
void os::Aix::initialize_system_info() {
@@ -387,7 +391,6 @@
// Retrieve total physical storage.
os::Aix::meminfo_t mi;
if (!os::Aix::get_meminfo(&mi)) {
- fprintf(stderr, "os::Aix::get_meminfo failed.\n"); fflush(stderr);
assert(false, "os::Aix::get_meminfo failed.");
}
_physical_memory = (julong) mi.real_total;
@@ -400,7 +403,6 @@
case SIZE_64K: return "64K";
case SIZE_16M: return "16M";
case SIZE_16G: return "16G";
- case -1: return "not set";
default:
assert(false, "surprise");
return "??";
@@ -431,6 +433,8 @@
}
// Query default shm page size (LDR_CNTRL SHMPSIZE).
+ // Note that this is pure curiosity. We do not rely on default page size but set
+ // our own page size after allocated.
{
const int shmid = ::shmget(IPC_PRIVATE, 1, IPC_CREAT | S_IRUSR | S_IWUSR);
guarantee(shmid != -1, "shmget failed");
@@ -447,26 +451,26 @@
// number of reasons so we may just as well guarantee it here.
guarantee0(!os::Aix::is_primordial_thread());
- // Query pthread stack page size.
+ // Query pthread stack page size. Should be the same as data page size because
+ // pthread stacks are allocated from C-Heap.
{
int dummy = 0;
g_multipage_support.pthr_stack_pagesize = os::Aix::query_pagesize(&dummy);
}
// Query default text page size (LDR_CNTRL TEXTPSIZE).
- /* PPC port: so far unused.
{
address any_function =
- (address) resolve_function_descriptor_to_code_pointer((address)describe_pagesize);
+ resolve_function_descriptor_to_code_pointer((address)describe_pagesize);
g_multipage_support.textpsize = os::Aix::query_pagesize(any_function);
}
- */
// Now probe for support of 64K pages and 16M pages.
// Before OS/400 V6R1, there is no support for pages other than 4K.
if (os::Aix::on_pase_V5R4_or_older()) {
- Unimplemented();
+ trcVerbose("OS/400 < V6R1 - no large page support.");
+ g_multipage_support.error = ERROR_MP_OS_TOO_OLD;
goto query_multipage_support_end;
}
@@ -474,10 +478,10 @@
{
const int MAX_PAGE_SIZES = 4;
psize_t sizes[MAX_PAGE_SIZES];
- const int num_psizes = ::vmgetinfo(sizes, VMINFO_GETPSIZES, MAX_PAGE_SIZES);
+ const int num_psizes = checked_vmgetinfo(sizes, VMINFO_GETPSIZES, MAX_PAGE_SIZES);
if (num_psizes == -1) {
- trc("vmgetinfo(VMINFO_GETPSIZES) failed (errno: %d)\n", errno);
- trc("disabling multipage support.\n");
+ trcVerbose("vmgetinfo(VMINFO_GETPSIZES) failed (errno: %d)", errno);
+ trcVerbose("disabling multipage support.");
g_multipage_support.error = ERROR_MP_VMGETINFO_FAILED;
goto query_multipage_support_end;
}
@@ -505,8 +509,8 @@
if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) {
const int en = errno;
::shmctl(shmid, IPC_RMID, NULL); // As early as possible!
- // PPC port trcVerbose("shmctl(SHM_PAGESIZE) failed with %s",
- // PPC port MiscUtils::describe_errno(en));
+ trcVerbose("shmctl(SHM_PAGESIZE) failed with errno=%n",
+ errno);
} else {
// Attach and double check pageisze.
void* p = ::shmat(shmid, NULL, 0);
@@ -532,35 +536,35 @@
query_multipage_support_end:
- trcVerbose("base page size (sysconf _SC_PAGESIZE): %s\n",
+ trcVerbose("base page size (sysconf _SC_PAGESIZE): %s",
describe_pagesize(g_multipage_support.pagesize));
- trcVerbose("Data page size (C-Heap, bss, etc): %s\n",
+ trcVerbose("Data page size (C-Heap, bss, etc): %s",
describe_pagesize(g_multipage_support.datapsize));
- trcVerbose("Text page size: %s\n",
+ trcVerbose("Text page size: %s",
describe_pagesize(g_multipage_support.textpsize));
- trcVerbose("Thread stack page size (pthread): %s\n",
+ trcVerbose("Thread stack page size (pthread): %s",
describe_pagesize(g_multipage_support.pthr_stack_pagesize));
- trcVerbose("Default shared memory page size: %s\n",
+ trcVerbose("Default shared memory page size: %s",
describe_pagesize(g_multipage_support.shmpsize));
- trcVerbose("Can use 64K pages dynamically with shared meory: %s\n",
+ trcVerbose("Can use 64K pages dynamically with shared meory: %s",
(g_multipage_support.can_use_64K_pages ? "yes" :"no"));
- trcVerbose("Can use 16M pages dynamically with shared memory: %s\n",
+ trcVerbose("Can use 16M pages dynamically with shared memory: %s",
(g_multipage_support.can_use_16M_pages ? "yes" :"no"));
- trcVerbose("Multipage error details: %d\n",
+ trcVerbose("Multipage error details: %d",
g_multipage_support.error);
// sanity checks
assert0(g_multipage_support.pagesize == SIZE_4K);
assert0(g_multipage_support.datapsize == SIZE_4K || g_multipage_support.datapsize == SIZE_64K);
- // PPC port: so far unused.assert0(g_multipage_support.textpsize == SIZE_4K || g_multipage_support.textpsize == SIZE_64K);
+ assert0(g_multipage_support.textpsize == SIZE_4K || g_multipage_support.textpsize == SIZE_64K);
assert0(g_multipage_support.pthr_stack_pagesize == g_multipage_support.datapsize);
assert0(g_multipage_support.shmpsize == SIZE_4K || g_multipage_support.shmpsize == SIZE_64K);
-} // end os::Aix::query_multipage_support()
+}
void os::init_system_properties_values() {
-#define DEFAULT_LIBPATH "/usr/lib:/lib"
+#define DEFAULT_LIBPATH "/lib:/usr/lib"
#define EXTENSIONS_DIR "/lib/ext"
// Buffer that fits several sprintfs.
@@ -578,7 +582,10 @@
// Found the full path to libjvm.so.
// Now cut the path to <java_home>/jre if we can.
- *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so.
+ pslash = strrchr(buf, '/');
+ if (pslash != NULL) {
+ *pslash = '\0'; // Get rid of /libjvm.so.
+ }
pslash = strrchr(buf, '/');
if (pslash != NULL) {
*pslash = '\0'; // Get rid of /{client|server|hotspot}.
@@ -753,8 +760,21 @@
memset(pmi, 0, sizeof(meminfo_t));
if (os::Aix::on_pase()) {
-
- Unimplemented();
+ // On PASE, use the libo4 porting library.
+
+ unsigned long long virt_total = 0;
+ unsigned long long real_total = 0;
+ unsigned long long real_free = 0;
+ unsigned long long pgsp_total = 0;
+ unsigned long long pgsp_free = 0;
+ if (libo4::get_memory_info(&virt_total, &real_total, &real_free, &pgsp_total, &pgsp_free)) {
+ pmi->virt_total = virt_total;
+ pmi->real_total = real_total;
+ pmi->real_free = real_free;
+ pmi->pgsp_total = pgsp_total;
+ pmi->pgsp_free = pgsp_free;
+ return true;
+ }
return false;
} else {
@@ -770,7 +790,7 @@
memset (&psmt, '\0', sizeof(psmt));
const int rc = libperfstat::perfstat_memory_total(NULL, &psmt, sizeof(psmt), 1);
if (rc == -1) {
- fprintf(stderr, "perfstat_memory_total() failed (errno=%d)\n", errno);
+ trcVerbose("perfstat_memory_total() failed (errno=%d)", errno);
assert(0, "perfstat_memory_total() failed");
return false;
}
@@ -798,81 +818,6 @@
}
} // end os::Aix::get_meminfo
-// Retrieve global cpu information.
-// Returns false if something went wrong;
-// the content of pci is undefined in this case.
-bool os::Aix::get_cpuinfo(cpuinfo_t* pci) {
- assert(pci, "get_cpuinfo: invalid parameter");
- memset(pci, 0, sizeof(cpuinfo_t));
-
- perfstat_cpu_total_t psct;
- memset (&psct, '\0', sizeof(psct));
-
- if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(perfstat_cpu_total_t), 1)) {
- fprintf(stderr, "perfstat_cpu_total() failed (errno=%d)\n", errno);
- assert(0, "perfstat_cpu_total() failed");
- return false;
- }
-
- // global cpu information
- strcpy (pci->description, psct.description);
- pci->processorHZ = psct.processorHZ;
- pci->ncpus = psct.ncpus;
- os::Aix::_logical_cpus = psct.ncpus;
- for (int i = 0; i < 3; i++) {
- pci->loadavg[i] = (double) psct.loadavg[i] / (1 << SBITS);
- }
-
- // get the processor version from _system_configuration
- switch (_system_configuration.version) {
- case PV_8:
- strcpy(pci->version, "Power PC 8");
- break;
- case PV_7:
- strcpy(pci->version, "Power PC 7");
- break;
- case PV_6_1:
- strcpy(pci->version, "Power PC 6 DD1.x");
- break;
- case PV_6:
- strcpy(pci->version, "Power PC 6");
- break;
- case PV_5:
- strcpy(pci->version, "Power PC 5");
- break;
- case PV_5_2:
- strcpy(pci->version, "Power PC 5_2");
- break;
- case PV_5_3:
- strcpy(pci->version, "Power PC 5_3");
- break;
- case PV_5_Compat:
- strcpy(pci->version, "PV_5_Compat");
- break;
- case PV_6_Compat:
- strcpy(pci->version, "PV_6_Compat");
- break;
- case PV_7_Compat:
- strcpy(pci->version, "PV_7_Compat");
- break;
- case PV_8_Compat:
- strcpy(pci->version, "PV_8_Compat");
- break;
- default:
- strcpy(pci->version, "unknown");
- }
-
- return true;
-
-} //end os::Aix::get_cpuinfo
-
-//////////////////////////////////////////////////////////////////////////////
-// detecting pthread library
-
-void os::Aix::libpthread_init() {
- return;
-}
-
//////////////////////////////////////////////////////////////////////////////
// create new thread
@@ -889,6 +834,26 @@
thread->set_stack_size(size);
}
+ const pthread_t pthread_id = ::pthread_self();
+ const tid_t kernel_thread_id = ::thread_self();
+
+ trcVerbose("newborn Thread : pthread-id %u, ktid " UINT64_FORMAT
+ ", stack %p ... %p, stacksize 0x%IX (%IB)",
+ pthread_id, kernel_thread_id,
+ thread->stack_base() - thread->stack_size(),
+ thread->stack_base(),
+ thread->stack_size(),
+ thread->stack_size());
+
+ // Normally, pthread stacks on AIX live in the data segment (are allocated with malloc()
+ // by the pthread library). In rare cases, this may not be the case, e.g. when third-party
+ // tools hook pthread_create(). In this case, we may run into problems establishing
+ // guard pages on those stacks, because the stacks may reside in memory which is not
+ // protectable (shmated).
+ if (thread->stack_base() > ::sbrk(0)) {
+ trcVerbose("Thread " UINT64_FORMAT ": stack not in data segment.", (uint64_t) pthread_id);
+ }
+
// Do some sanity checks.
CHECK_CURRENT_STACK_PTR(thread->stack_base(), thread->stack_size());
@@ -902,32 +867,35 @@
int pid = os::current_process_id();
alloca(((pid ^ counter++) & 7) * 128);
- ThreadLocalStorage::set_thread(thread);
+ thread->initialize_thread_current();
OSThread* osthread = thread->osthread();
- // thread_id is kernel thread id (similar to Solaris LWP id)
- osthread->set_thread_id(os::Aix::gettid());
-
- // initialize signal mask for this thread
+ // Thread_id is pthread id.
+ osthread->set_thread_id(pthread_id);
+
+ // .. but keep kernel thread id too for diagnostics
+ osthread->set_kernel_thread_id(kernel_thread_id);
+
+ // Initialize signal mask for this thread.
os::Aix::hotspot_sigmask(thread);
- // initialize floating point control register
+ // Initialize floating point control register.
os::Aix::init_thread_fpu_state();
assert(osthread->get_state() == RUNNABLE, "invalid os thread state");
- // call one more level start routine
+ // Call one more level start routine.
thread->run();
+ trcVerbose("Thread finished : pthread-id %u, ktid " UINT64_FORMAT ".",
+ pthread_id, kernel_thread_id);
+
return 0;
}
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
- // We want the whole function to be synchronized.
- ThreadCritical cs;
-
assert(thread->osthread() == NULL, "caller responsible");
// Allocate the OSThread object
@@ -992,8 +960,14 @@
pthread_attr_destroy(&attr);
if (ret == 0) {
- // PPC port traceOsMisc(("Created New Thread : pthread-id %u", tid));
+ trcVerbose("Created New Thread : pthread-id %u", tid);
} else {
+ if (os::Aix::on_pase()) {
+ // QIBM_MULTI_THREADED=Y is needed when the launcher is started on iSeries
+ // using QSH. Otherwise pthread_create fails with errno=11.
+ trcVerbose("(Please make sure you set the environment variable "
+ "QIBM_MULTI_THREADED=Y before running this program.)");
+ }
if (PrintMiscellaneous && (Verbose || WizardMode)) {
perror("pthread_create()");
}
@@ -1003,8 +977,8 @@
return false;
}
- // Store pthread info into the OSThread
- osthread->set_pthread_id(tid);
+ // OSThread::thread_id is the pthread id.
+ osthread->set_thread_id(tid);
return true;
}
@@ -1030,9 +1004,21 @@
return false;
}
- // Store pthread info into the OSThread
- osthread->set_thread_id(os::Aix::gettid());
- osthread->set_pthread_id(::pthread_self());
+ const pthread_t pthread_id = ::pthread_self();
+ const tid_t kernel_thread_id = ::thread_self();
+
+ trcVerbose("attaching Thread : pthread-id %u, ktid " UINT64_FORMAT ", stack %p ... %p, stacksize 0x%IX (%IB)",
+ pthread_id, kernel_thread_id,
+ thread->stack_base() - thread->stack_size(),
+ thread->stack_base(),
+ thread->stack_size(),
+ thread->stack_size());
+
+ // OSThread::thread_id is the pthread id.
+ osthread->set_thread_id(pthread_id);
+
+ // .. but keep kernel thread id too for diagnostics
+ osthread->set_kernel_thread_id(kernel_thread_id);
// initialize floating point control register
os::Aix::init_thread_fpu_state();
@@ -1077,32 +1063,6 @@
delete osthread;
}
-//////////////////////////////////////////////////////////////////////////////
-// thread local storage
-
-int os::allocate_thread_local_storage() {
- pthread_key_t key;
- int rslt = pthread_key_create(&key, NULL);
- assert(rslt == 0, "cannot allocate thread local storage");
- return (int)key;
-}
-
-// Note: This is currently not used by VM, as we don't destroy TLS key
-// on VM exit.
-void os::free_thread_local_storage(int index) {
- int rslt = pthread_key_delete((pthread_key_t)index);
- assert(rslt == 0, "invalid index");
-}
-
-void os::thread_local_storage_at_put(int index, void* value) {
- int rslt = pthread_setspecific((pthread_key_t)index, value);
- assert(rslt == 0, "pthread_setspecific failed");
-}
-
-extern "C" Thread* get_thread() {
- return ThreadLocalStorage::thread();
-}
-
////////////////////////////////////////////////////////////////////////////////
// time support
@@ -1152,17 +1112,15 @@
nanos = jlong(time.tv_usec) * 1000;
}
-
-// We need to manually declare mread_real_time,
-// because IBM didn't provide a prototype in time.h.
-// (they probably only ever tested in C, not C++)
-extern "C"
-int mread_real_time(timebasestruct_t *t, size_t size_of_timebasestruct_t);
-
jlong os::javaTimeNanos() {
if (os::Aix::on_pase()) {
- Unimplemented();
- return 0;
+
+ timeval time;
+ int status = gettimeofday(&time, NULL);
+ assert(status != -1, "PASE error at gettimeofday()");
+ jlong usecs = jlong((unsigned long long) time.tv_sec * (1000 * 1000) + time.tv_usec);
+ return 1000 * usecs;
+
} else {
// On AIX use the precision of processors real time clock
// or time base registers.
@@ -1291,22 +1249,12 @@
return n;
}
-intx os::current_thread_id() { return (intx)pthread_self(); }
+intx os::current_thread_id() {
+ return (intx)pthread_self();
+}
int os::current_process_id() {
-
- // This implementation returns a unique pid, the pid of the
- // launcher thread that starts the vm 'process'.
-
- // Under POSIX, getpid() returns the same pid as the
- // launcher thread rather than a unique pid per thread.
- // Use gettid() if you want the old pre NPTL behaviour.
-
- // if you are looking for the result of a call to getpid() that
- // returns a unique pid for the calling thread, then look at the
- // OSThread::thread_id() method in osThread_linux.hpp file
-
- return (int)(_initial_pid ? _initial_pid : getpid());
+ return getpid();
}
// DLL functions
@@ -1343,6 +1291,9 @@
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
+ if (pelements == NULL) {
+ return false;
+ }
for (int i = 0; i < n; i++) {
// Really shouldn't be NULL, but check can't hurt
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
@@ -1580,62 +1531,98 @@
os::loadavg(loadavg, 3);
st->print("%0.02f %0.02f %0.02f", loadavg[0], loadavg[1], loadavg[2]);
st->cr();
+
+ // print wpar info
+ libperfstat::wparinfo_t wi;
+ if (libperfstat::get_wparinfo(&wi)) {
+ st->print_cr("wpar info");
+ st->print_cr("name: %s", wi.name);
+ st->print_cr("id: %d", wi.wpar_id);
+ st->print_cr("type: %s", (wi.app_wpar ? "application" : "system"));
+ }
+
+ // print partition info
+ libperfstat::partitioninfo_t pi;
+ if (libperfstat::get_partitioninfo(&pi)) {
+ st->print_cr("partition info");
+ st->print_cr(" name: %s", pi.name);
+ }
+
}
void os::print_memory_info(outputStream* st) {
st->print_cr("Memory:");
- st->print_cr(" default page size: %s", describe_pagesize(os::vm_page_size()));
- st->print_cr(" default stack page size: %s", describe_pagesize(os::vm_page_size()));
+ st->print_cr(" Base page size (sysconf _SC_PAGESIZE): %s",
+ describe_pagesize(g_multipage_support.pagesize));
+ st->print_cr(" Data page size (C-Heap, bss, etc): %s",
+ describe_pagesize(g_multipage_support.datapsize));
+ st->print_cr(" Text page size: %s",
+ describe_pagesize(g_multipage_support.textpsize));
+ st->print_cr(" Thread stack page size (pthread): %s",
+ describe_pagesize(g_multipage_support.pthr_stack_pagesize));
st->print_cr(" Default shared memory page size: %s",
describe_pagesize(g_multipage_support.shmpsize));
st->print_cr(" Can use 64K pages dynamically with shared meory: %s",
(g_multipage_support.can_use_64K_pages ? "yes" :"no"));
st->print_cr(" Can use 16M pages dynamically with shared memory: %s",
(g_multipage_support.can_use_16M_pages ? "yes" :"no"));
- if (g_multipage_error != 0) {
- st->print_cr(" multipage error: %d", g_multipage_error);
- }
+ st->print_cr(" Multipage error: %d",
+ g_multipage_support.error);
+ st->cr();
+ st->print_cr(" os::vm_page_size: %s", describe_pagesize(os::vm_page_size()));
+ // not used in OpenJDK st->print_cr(" os::stack_page_size: %s", describe_pagesize(os::stack_page_size()));
// print out LDR_CNTRL because it affects the default page sizes
const char* const ldr_cntrl = ::getenv("LDR_CNTRL");
st->print_cr(" LDR_CNTRL=%s.", ldr_cntrl ? ldr_cntrl : "<unset>");
+ // Print out EXTSHM because it is an unsupported setting.
const char* const extshm = ::getenv("EXTSHM");
st->print_cr(" EXTSHM=%s.", extshm ? extshm : "<unset>");
if ( (strcmp(extshm, "on") == 0) || (strcmp(extshm, "ON") == 0) ) {
st->print_cr(" *** Unsupported! Please remove EXTSHM from your environment! ***");
}
- // Call os::Aix::get_meminfo() to retrieve memory statistics.
+ // Print out AIXTHREAD_GUARDPAGES because it affects the size of pthread stacks.
+ const char* const aixthread_guardpages = ::getenv("AIXTHREAD_GUARDPAGES");
+ st->print_cr(" AIXTHREAD_GUARDPAGES=%s.",
+ aixthread_guardpages ? aixthread_guardpages : "<unset>");
+
os::Aix::meminfo_t mi;
if (os::Aix::get_meminfo(&mi)) {
char buffer[256];
if (os::Aix::on_aix()) {
- jio_snprintf(buffer, sizeof(buffer),
- " physical total : %llu\n"
- " physical free : %llu\n"
- " swap total : %llu\n"
- " swap free : %llu\n",
- mi.real_total,
- mi.real_free,
- mi.pgsp_total,
- mi.pgsp_free);
+ st->print_cr("physical total : " SIZE_FORMAT, mi.real_total);
+ st->print_cr("physical free : " SIZE_FORMAT, mi.real_free);
+ st->print_cr("swap total : " SIZE_FORMAT, mi.pgsp_total);
+ st->print_cr("swap free : " SIZE_FORMAT, mi.pgsp_free);
} else {
- Unimplemented();
+ // PASE - Numbers are result of QWCRSSTS; they mean:
+ // real_total: Sum of all system pools
+ // real_free: always 0
+ // pgsp_total: we take the size of the system ASP
+ // pgsp_free: size of system ASP times percentage of system ASP unused
+ st->print_cr("physical total : " SIZE_FORMAT, mi.real_total);
+ st->print_cr("system asp total : " SIZE_FORMAT, mi.pgsp_total);
+ st->print_cr("%% system asp used : " SIZE_FORMAT,
+ mi.pgsp_total ? (100.0f * (mi.pgsp_total - mi.pgsp_free) / mi.pgsp_total) : -1.0f);
}
st->print_raw(buffer);
- } else {
- st->print_cr(" (no more information available)");
- }
+ }
+ st->cr();
+
+ // Print segments allocated with os::reserve_memory.
+ st->print_cr("internal virtual memory regions used by vm:");
+ vmembk_print_on(st);
}
// Get a string for the cpuinfo that is a summary of the cpu type
void os::get_summary_cpu_info(char* buf, size_t buflen) {
// This looks good
- os::Aix::cpuinfo_t ci;
- if (os::Aix::get_cpuinfo(&ci)) {
+ libperfstat::cpuinfo_t ci;
+ if (libperfstat::get_cpuinfo(&ci)) {
strncpy(buf, ci.version, buflen);
} else {
strncpy(buf, "AIX", buflen);
@@ -1643,10 +1630,15 @@
}
void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
+ st->print("CPU:");
+ st->print("total %d", os::processor_count());
+ // It's not safe to query number of active processors after crash.
+ // st->print("(active %d)", os::active_processor_count());
+ st->print(" %s", VM_Version::cpu_features());
+ st->cr();
}
void os::print_siginfo(outputStream* st, void* siginfo) {
- // Use common posix version.
os::Posix::print_siginfo_brief(st, (const siginfo_t*) siginfo);
st->cr();
}
@@ -1785,21 +1777,75 @@
// a counter for each possible signal value
static volatile jint pending_signals[NSIG+1] = { 0 };
-// Linux(POSIX) specific hand shaking semaphore.
+// Wrapper functions for: sem_init(), sem_post(), sem_wait()
+// On AIX, we use sem_init(), sem_post(), sem_wait()
+// On Pase, we need to use msem_lock() and msem_unlock(), because Posix Semaphores
+// do not seem to work at all on PASE (unimplemented, will cause SIGILL).
+// Note that just using msem_.. APIs for both PASE and AIX is not an option either, as
+// on AIX, msem_..() calls are suspected of causing problems.
static sem_t sig_sem;
+static msemaphore* p_sig_msem = 0;
+
+static void local_sem_init() {
+ if (os::Aix::on_aix()) {
+ int rc = ::sem_init(&sig_sem, 0, 0);
+ guarantee(rc != -1, "sem_init failed");
+ } else {
+ // Memory semaphores must live in shared mem.
+ guarantee0(p_sig_msem == NULL);
+ p_sig_msem = (msemaphore*)os::reserve_memory(sizeof(msemaphore), NULL);
+ guarantee(p_sig_msem, "Cannot allocate memory for memory semaphore");
+ guarantee(::msem_init(p_sig_msem, 0) == p_sig_msem, "msem_init failed");
+ }
+}
+
+static void local_sem_post() {
+ static bool warn_only_once = false;
+ if (os::Aix::on_aix()) {
+ int rc = ::sem_post(&sig_sem);
+ if (rc == -1 && !warn_only_once) {
+ trcVerbose("sem_post failed (errno = %d, %s)", errno, strerror(errno));
+ warn_only_once = true;
+ }
+ } else {
+ guarantee0(p_sig_msem != NULL);
+ int rc = ::msem_unlock(p_sig_msem, 0);
+ if (rc == -1 && !warn_only_once) {
+ trcVerbose("msem_unlock failed (errno = %d, %s)", errno, strerror(errno));
+ warn_only_once = true;
+ }
+ }
+}
+
+static void local_sem_wait() {
+ static bool warn_only_once = false;
+ if (os::Aix::on_aix()) {
+ int rc = ::sem_wait(&sig_sem);
+ if (rc == -1 && !warn_only_once) {
+ trcVerbose("sem_wait failed (errno = %d, %s)", errno, strerror(errno));
+ warn_only_once = true;
+ }
+ } else {
+ guarantee0(p_sig_msem != NULL); // must init before use
+ int rc = ::msem_lock(p_sig_msem, 0);
+ if (rc == -1 && !warn_only_once) {
+ trcVerbose("msem_lock failed (errno = %d, %s)", errno, strerror(errno));
+ warn_only_once = true;
+ }
+ }
+}
void os::signal_init_pd() {
// Initialize signal structures
::memset((void*)pending_signals, 0, sizeof(pending_signals));
// Initialize signal semaphore
- int rc = ::sem_init(&sig_sem, 0, 0);
- guarantee(rc != -1, "sem_init failed");
+ local_sem_init();
}
void os::signal_notify(int sig) {
Atomic::inc(&pending_signals[sig]);
- ::sem_post(&sig_sem);
+ local_sem_post();
}
static int check_pending_signals(bool wait) {
@@ -1822,7 +1868,7 @@
thread->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
- ::sem_wait(&sig_sem);
+ local_sem_wait();
// were we externally suspended while we were waiting?
threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
@@ -1833,7 +1879,8 @@
// while suspended because that would surprise the thread that
// suspended us.
//
- ::sem_post(&sig_sem);
+
+ local_sem_post();
thread->java_suspend_self();
}
@@ -1884,14 +1931,14 @@
// also check that range is fully page aligned to the page size if the block.
void assert_is_valid_subrange(char* p, size_t s) const {
if (!contains_range(p, s)) {
- fprintf(stderr, "[" PTR_FORMAT " - " PTR_FORMAT "] is not a sub "
- "range of [" PTR_FORMAT " - " PTR_FORMAT "].\n",
- p, p + s - 1, addr, addr + size - 1);
+ trcVerbose("[" PTR_FORMAT " - " PTR_FORMAT "] is not a sub "
+ "range of [" PTR_FORMAT " - " PTR_FORMAT "].",
+ p, p + s, addr, addr + size);
guarantee0(false);
}
if (!is_aligned_to(p, pagesize) || !is_aligned_to(p + s, pagesize)) {
- fprintf(stderr, "range [" PTR_FORMAT " - " PTR_FORMAT "] is not"
- " aligned to pagesize (%s)\n", p, p + s);
+ trcVerbose("range [" PTR_FORMAT " - " PTR_FORMAT "] is not"
+ " aligned to pagesize (%lu)", p, p + s, (unsigned long) pagesize);
guarantee0(false);
}
}
@@ -1988,7 +2035,7 @@
// Reserve the shared segment.
int shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | S_IRUSR | S_IWUSR);
if (shmid == -1) {
- trc("shmget(.., " UINTX_FORMAT ", ..) failed (errno: %d).", size, errno);
+ trcVerbose("shmget(.., " UINTX_FORMAT ", ..) failed (errno: %d).", size, errno);
return NULL;
}
@@ -2017,7 +2064,7 @@
// (A) Right after shmat and before handing shmat errors delete the shm segment.
if (::shmctl(shmid, IPC_RMID, NULL) == -1) {
- trc("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno);
+ trcVerbose("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno);
assert(false, "failed to remove shared memory segment!");
}
@@ -2082,6 +2129,8 @@
return true;
}
+//////////////////////////////// mmap-based routines /////////////////////////////////
+
// Reserve memory via mmap.
// If <requested_addr> is given, an attempt is made to attach at the given address.
// Failing that, memory is allocated at any address.
@@ -2227,9 +2276,6 @@
return rc;
}
-// End: shared memory bookkeeping
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
int os::vm_page_size() {
// Seems redundant as all get out.
assert(os::Aix::page_size() != -1, "must call os::init");
@@ -2263,15 +2309,26 @@
bool os::pd_commit_memory(char* addr, size_t size, bool exec) {
- assert0(is_aligned_to(addr, os::vm_page_size()));
- assert0(is_aligned_to(size, os::vm_page_size()));
+ assert(is_aligned_to(addr, os::vm_page_size()),
+ "addr " PTR_FORMAT " not aligned to vm_page_size (" PTR_FORMAT ")",
+ p2i(addr), os::vm_page_size());
+ assert(is_aligned_to(size, os::vm_page_size()),
+ "size " PTR_FORMAT " not aligned to vm_page_size (" PTR_FORMAT ")",
+ size, os::vm_page_size());
vmembk_t* const vmi = vmembk_find(addr);
- assert0(vmi);
+ guarantee0(vmi);
vmi->assert_is_valid_subrange(addr, size);
trcVerbose("commit_memory [" PTR_FORMAT " - " PTR_FORMAT "].", addr, addr + size - 1);
+ if (UseExplicitCommit) {
+ // AIX commits memory on touch. So, touch all pages to be committed.
+ for (char* p = addr; p < (addr + size); p += SIZE_4K) {
+ *p = '\0';
+ }
+ }
+
return true;
}
@@ -2287,12 +2344,16 @@
}
bool os::pd_uncommit_memory(char* addr, size_t size) {
- assert0(is_aligned_to(addr, os::vm_page_size()));
- assert0(is_aligned_to(size, os::vm_page_size()));
+ assert(is_aligned_to(addr, os::vm_page_size()),
+ "addr " PTR_FORMAT " not aligned to vm_page_size (" PTR_FORMAT ")",
+ p2i(addr), os::vm_page_size());
+ assert(is_aligned_to(size, os::vm_page_size()),
+ "size " PTR_FORMAT " not aligned to vm_page_size (" PTR_FORMAT ")",
+ size, os::vm_page_size());
// Dynamically do different things for mmap/shmat.
const vmembk_t* const vmi = vmembk_find(addr);
- assert0(vmi);
+ guarantee0(vmi);
vmi->assert_is_valid_subrange(addr, size);
if (vmi->type == VMEM_SHMATED) {
@@ -2390,7 +2451,7 @@
// Dynamically do different things for mmap/shmat.
vmembk_t* const vmi = vmembk_find(addr);
- assert0(vmi);
+ guarantee0(vmi);
// Always round to os::vm_page_size(), which may be larger than 4K.
size = align_size_up(size, os::vm_page_size());
@@ -2466,11 +2527,31 @@
} else {
rc = read_protected;
}
+
+ if (!rc) {
+ if (os::Aix::on_pase()) {
+ // There is an issue on older PASE systems where mprotect() will return success but the
+ // memory will not be protected.
+ // This has nothing to do with the problem of using mproect() on SPEC1170 incompatible
+ // machines; we only see it rarely, when using mprotect() to protect the guard page of
+ // a stack. It is an OS error.
+ //
+ // A valid strategy is just to try again. This usually works. :-/
+
+ ::usleep(1000);
+ if (::mprotect(addr, size, prot) == 0) {
+ const bool read_protected_2 =
+ (SafeFetch32((int*)addr, 0x12345678) == 0x12345678 &&
+ SafeFetch32((int*)addr, 0x76543210) == 0x76543210) ? true : false;
+ rc = true;
+ }
+ }
+ }
}
}
- if (!rc) {
- assert(false, "mprotect failed.");
- }
+
+ assert(rc == true, "mprotect failed.");
+
return rc;
}
@@ -2507,10 +2588,11 @@
}
char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) {
- // "exec" is passed in but not used. Creating the shared image for
- // the code cache doesn't have an SHM_X executable permission to check.
- Unimplemented();
- return 0;
+ // reserve_memory_special() is used to allocate large paged memory. On AIX, we implement
+ // 64k paged memory reservation using the normal memory allocation paths (os::reserve_memory()),
+ // so this is not needed.
+ assert(false, "should not be called on AIX");
+ return NULL;
}
bool os::release_memory_special(char* base, size_t bytes) {
@@ -2962,7 +3044,9 @@
// getting raised while being blocked.
unblock_program_error_signals();
+ int orig_errno = errno; // Preserve errno value over signal handler.
JVM_handle_aix_signal(sig, info, uc, true);
+ errno = orig_errno;
}
// This boolean allows users to forward their own non-matching signals
@@ -3084,7 +3168,6 @@
void* oldhand = oldAct.sa_sigaction
? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction)
: CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
- // Renamed 'signalHandler' to avoid collision with other shared libs.
if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) &&
oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) &&
oldhand != CAST_FROM_FN_PTR(void*, (sa_sigaction_t)javaSignalHandler)) {
@@ -3108,7 +3191,6 @@
sigAct.sa_handler = SIG_DFL;
sigAct.sa_flags = SA_RESTART;
} else {
- // Renamed 'signalHandler' to avoid collision with other shared libs.
sigAct.sa_sigaction = javaSignalHandler;
sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
}
@@ -3300,7 +3382,7 @@
struct sigaction act;
if (os_sigaction == NULL) {
// only trust the default sigaction, in case it has been interposed
- os_sigaction = (os_sigaction_t)dlsym(RTLD_DEFAULT, "sigaction");
+ os_sigaction = CAST_TO_FN_PTR(os_sigaction_t, dlsym(RTLD_DEFAULT, "sigaction"));
if (os_sigaction == NULL) return;
}
@@ -3317,7 +3399,6 @@
case SIGPIPE:
case SIGILL:
case SIGXFSZ:
- // Renamed 'signalHandler' to avoid collision with other shared libs.
jvmHandler = CAST_FROM_FN_PTR(address, (sa_sigaction_t)javaSignalHandler);
break;
@@ -3350,8 +3431,12 @@
}
} else if (os::Aix::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Aix::get_our_sigflags(sig)) {
tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN));
- tty->print("expected:" PTR32_FORMAT, os::Aix::get_our_sigflags(sig));
- tty->print_cr(" found:" PTR32_FORMAT, act.sa_flags);
+ tty->print("expected:");
+ os::Posix::print_sa_flags(tty, os::Aix::get_our_sigflags(sig));
+ tty->cr();
+ tty->print(" found:");
+ os::Posix::print_sa_flags(tty, act.sa_flags);
+ tty->cr();
// No need to check this sig any longer
sigaddset(&check_signal_done, sig);
}
@@ -3362,20 +3447,6 @@
}
}
-extern bool signal_name(int signo, char* buf, size_t len);
-
-const char* os::exception_name(int exception_code, char* buf, size_t size) {
- if (0 < exception_code && exception_code <= SIGRTMAX) {
- // signal
- if (!signal_name(exception_code, buf, size)) {
- jio_snprintf(buf, size, "SIG%d", exception_code);
- }
- return buf;
- } else {
- return NULL;
- }
-}
-
// To install functions for atexit system call
extern "C" {
static void perfMemory_exit_helper() {
@@ -3389,6 +3460,10 @@
// (Shared memory boundary is supposed to be a 256M aligned.)
assert(SHMLBA == ((uint64_t)0x10000000ULL)/*256M*/, "unexpected");
+ // Record process break at startup.
+ g_brk_at_startup = (address) ::sbrk(0);
+ assert(g_brk_at_startup != (address) -1, "sbrk failed");
+
// First off, we need to know whether we run on AIX or PASE, and
// the OS level we run on.
os::Aix::initialize_os_info();
@@ -3396,7 +3471,7 @@
// Scan environment (SPEC1170 behaviour, etc).
os::Aix::scan_environment();
- // Check which pages are supported by AIX.
+ // Probe multipage support.
query_multipage_support();
// Act like we only have one page size by eliminating corner cases which
@@ -3449,9 +3524,9 @@
}
} else {
// datapsize = 64k. Data segment, thread stacks are 64k paged.
- // This normally means that we can allocate 64k pages dynamically.
- // (There is one special case where this may be false: EXTSHM=on.
- // but we decided to not support that mode).
+ // This normally means that we can allocate 64k pages dynamically.
+ // (There is one special case where this may be false: EXTSHM=on.
+ // but we decided to not support that mode).
assert0(g_multipage_support.can_use_64K_pages);
Aix::_page_size = SIZE_64K;
trcVerbose("64K page mode");
@@ -3467,7 +3542,7 @@
_page_sizes[0] = 0;
// debug trace
- trcVerbose("os::vm_page_size %s\n", describe_pagesize(os::vm_page_size()));
+ trcVerbose("os::vm_page_size %s", describe_pagesize(os::vm_page_size()));
// Next, we need to initialize libo4 and libperfstat libraries.
if (os::Aix::on_pase()) {
@@ -3485,8 +3560,6 @@
// need libperfstat etc.
os::Aix::initialize_system_info();
- _initial_pid = getpid();
-
clock_tics_per_sec = sysconf(_SC_CLK_TCK);
init_random(1234567);
@@ -3511,11 +3584,21 @@
// This is called _after_ the global arguments have been parsed.
jint os::init_2(void) {
+ if (os::Aix::on_pase()) {
+ trcVerbose("Running on PASE.");
+ } else {
+ trcVerbose("Running on AIX (not PASE).");
+ }
+
trcVerbose("processor count: %d", os::_processor_count);
trcVerbose("physical memory: %lu", Aix::_physical_memory);
// Initially build up the loaded dll map.
LoadedLibraries::reload();
+ if (Verbose) {
+ trcVerbose("Loaded Libraries: ");
+ LoadedLibraries::print(tty);
+ }
const int page_size = Aix::page_size();
const int map_size = page_size;
@@ -3553,10 +3636,8 @@
map_size, prot,
flags | MAP_FIXED,
-1, 0);
- if (Verbose) {
- fprintf(stderr, "SafePoint Polling Page address: %p (wish) => %p\n",
- address_wishes[i], map_address + (ssize_t)page_size);
- }
+ trcVerbose("SafePoint Polling Page address: %p (wish) => %p",
+ address_wishes[i], map_address + (ssize_t)page_size);
if (map_address + (ssize_t)page_size == address_wishes[i]) {
// Map succeeded and map_address is at wished address, exit loop.
@@ -3583,11 +3664,9 @@
guarantee(mem_serialize_page != NULL, "mmap Failed for memory serialize page");
os::set_memory_serialize_page(mem_serialize_page);
-#ifndef PRODUCT
- if (Verbose && PrintMiscellaneous) {
- tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", (intptr_t)mem_serialize_page);
- }
-#endif
+ trcVerbose("Memory Serialize Page address: %p - %p, size %IX (%IB)",
+ mem_serialize_page, mem_serialize_page + Aix::page_size(),
+ Aix::page_size(), Aix::page_size());
}
// initialize suspend/resume support - must do this before signal_sets_init()
@@ -3624,7 +3703,10 @@
// Note that this can be 0, if no default stacksize was set.
JavaThread::set_stack_size_at_create(round_to(threadStackSizeInBytes, vm_page_size()));
- Aix::libpthread_init();
+ if (UseNUMA) {
+ UseNUMA = false;
+ warning("NUMA optimizations are not available on this OS.");
+ }
if (MaxFDLimit) {
// Set the number of file descriptors to max. print out error
@@ -3646,7 +3728,7 @@
if (PerfAllowAtExitRegistration) {
// Only register atexit functions if PerfAllowAtExitRegistration is set.
- // Atexit functions can be delayed until process exit time, which
+ // At exit functions can be delayed until process exit time, which
// can be problematic for embedded VM situations. Embedded VMs should
// call DestroyJavaVM() to assure that VM resources are released.
@@ -3746,16 +3828,6 @@
////////////////////////////////////////////////////////////////////////////////
// debug support
-static address same_page(address x, address y) {
- intptr_t page_bits = -os::vm_page_size();
- if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits))
- return x;
- else if (x > y)
- return (address)(intptr_t(y) | ~page_bits) + 1;
- else
- return (address)(intptr_t(y) & page_bits);
-}
-
bool os::find(address addr, outputStream* st) {
st->print(PTR_FORMAT ": ", addr);
@@ -4119,24 +4191,28 @@
// For now just return the system wide load average (no processor sets).
int os::loadavg(double values[], int nelem) {
- // Implemented using libperfstat on AIX.
-
guarantee(nelem >= 0 && nelem <= 3, "argument error");
guarantee(values, "argument error");
if (os::Aix::on_pase()) {
- Unimplemented();
- return -1;
+
+ // AS/400 PASE: use libo4 porting library
+ double v[3] = { 0.0, 0.0, 0.0 };
+
+ if (libo4::get_load_avg(v, v + 1, v + 2)) {
+ for (int i = 0; i < nelem; i ++) {
+ values[i] = v[i];
+ }
+ return nelem;
+ } else {
+ return -1;
+ }
+
} else {
+
// AIX: use libperfstat
- //
- // See also:
- // http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/perfstat_cputot.htm
- // /usr/include/libperfstat.h:
-
- // Use the already AIX version independent get_cpuinfo.
- os::Aix::cpuinfo_t ci;
- if (os::Aix::get_cpuinfo(&ci)) {
+ libperfstat::cpuinfo_t ci;
+ if (libperfstat::get_cpuinfo(&ci)) {
for (int i = 0; i < nelem; i++) {
values[i] = ci.loadavg[i];
}
@@ -4163,8 +4239,7 @@
(void)::poll(NULL, 0, 100);
}
} else {
- jio_fprintf(stderr,
- "Could not open pause file '%s', continuing immediately.\n", filename);
+ trcVerbose("Could not open pause file '%s', continuing immediately.", filename);
}
}
@@ -4186,7 +4261,7 @@
memset(&uts, 0, sizeof(uts));
strcpy(uts.sysname, "?");
if (::uname(&uts) == -1) {
- trc("uname failed (%d)", errno);
+ trcVerbose("uname failed (%d)", errno);
guarantee(0, "Could not determine whether we run on AIX or PASE");
} else {
trcVerbose("uname says: sysname \"%s\" version \"%s\" release \"%s\" "
@@ -4198,15 +4273,22 @@
assert(minor > 0, "invalid OS release");
_os_version = (major << 8) | minor;
if (strcmp(uts.sysname, "OS400") == 0) {
- Unimplemented();
+ // We run on AS/400 PASE. We do not support versions older than V5R4M0.
+ _on_pase = 1;
+ if (_os_version < 0x0504) {
+ trcVerbose("OS/400 releases older than V5R4M0 not supported.");
+ assert(false, "OS/400 release too old.");
+ } else {
+ trcVerbose("We run on OS/400 (pase) V%dR%d", major, minor);
+ }
} else if (strcmp(uts.sysname, "AIX") == 0) {
// We run on AIX. We do not support versions older than AIX 5.3.
_on_pase = 0;
if (_os_version < 0x0503) {
- trc("AIX release older than AIX 5.3 not supported.");
+ trcVerbose("AIX release older than AIX 5.3 not supported.");
assert(false, "AIX release too old.");
} else {
- trcVerbose("We run on AIX %d.%d\n", major, minor);
+ trcVerbose("We run on AIX %d.%d", major, minor);
}
} else {
assert(false, "unknown OS");
@@ -4232,12 +4314,17 @@
// This switch was needed on AIX 32bit, but on AIX 64bit the general
// recommendation is (in OSS notes) to switch it off.
p = ::getenv("EXTSHM");
- if (Verbose) {
- fprintf(stderr, "EXTSHM=%s.\n", p ? p : "<unset>");
- }
+ trcVerbose("EXTSHM=%s.", p ? p : "<unset>");
if (p && strcasecmp(p, "ON") == 0) {
- fprintf(stderr, "Unsupported setting: EXTSHM=ON. Large Page support will be disabled.\n");
_extshm = 1;
+ trcVerbose("*** Unsupported mode! Please remove EXTSHM from your environment! ***");
+ if (!AllowExtshm) {
+ // We allow under certain conditions the user to continue. However, we want this
+ // to be a fatal error by default. On certain AIX systems, leaving EXTSHM=ON means
+ // that the VM is not able to allocate 64k pages for the heap.
+ // We do not want to run with reduced performance.
+ vm_exit_during_initialization("EXTSHM is ON. Please remove EXTSHM from your environment.");
+ }
} else {
_extshm = 0;
}
@@ -4254,7 +4341,7 @@
trcVerbose("XPG_SUS_ENV=%s.", p ? p : "<unset>");
if (p && strcmp(p, "ON") == 0) {
_xpg_sus_mode = 1;
- trc("Unsupported setting: XPG_SUS_ENV=ON");
+ trcVerbose("Unsupported setting: XPG_SUS_ENV=ON");
// This is not supported. Worst of all, it changes behaviour of mmap MAP_FIXED to
// clobber address ranges. If we ever want to support that, we have to do some
// testing first.
@@ -4263,35 +4350,46 @@
_xpg_sus_mode = 0;
}
- // Switch off AIX internal (pthread) guard pages. This has
- // immediate effect for any pthread_create calls which follow.
+ if (os::Aix::on_pase()) {
+ p = ::getenv("QIBM_MULTI_THREADED");
+ trcVerbose("QIBM_MULTI_THREADED=%s.", p ? p : "<unset>");
+ }
+
+ p = ::getenv("LDR_CNTRL");
+ trcVerbose("LDR_CNTRL=%s.", p ? p : "<unset>");
+ if (os::Aix::on_pase() && os::Aix::os_version() == 0x0701) {
+ if (p && ::strstr(p, "TEXTPSIZE")) {
+ trcVerbose("*** WARNING - LDR_CNTRL contains TEXTPSIZE. "
+ "you may experience hangs or crashes on OS/400 V7R1.");
+ }
+ }
+
p = ::getenv("AIXTHREAD_GUARDPAGES");
trcVerbose("AIXTHREAD_GUARDPAGES=%s.", p ? p : "<unset>");
- rc = ::putenv("AIXTHREAD_GUARDPAGES=0");
- guarantee(rc == 0, "");
} // end: os::Aix::scan_environment()
-// PASE: initialize the libo4 library (AS400 PASE porting library).
+// PASE: initialize the libo4 library (PASE porting library).
void os::Aix::initialize_libo4() {
- Unimplemented();
-}
-
-// AIX: initialize the libperfstat library (we load this dynamically
-// because it is only available on AIX.
+ guarantee(os::Aix::on_pase(), "OS/400 only.");
+ if (!libo4::init()) {
+ trcVerbose("libo4 initialization failed.");
+ assert(false, "libo4 initialization failed");
+ } else {
+ trcVerbose("libo4 initialized.");
+ }
+}
+
+// AIX: initialize the libperfstat library.
void os::Aix::initialize_libperfstat() {
-
assert(os::Aix::on_aix(), "AIX only");
-
if (!libperfstat::init()) {
- trc("libperfstat initialization failed.");
+ trcVerbose("libperfstat initialization failed.");
assert(false, "libperfstat initialization failed");
} else {
- if (Verbose) {
- fprintf(stderr, "libperfstat initialized.\n");
- }
- }
-} // end: os::Aix::initialize_libperfstat
+ trcVerbose("libperfstat initialized.");
+ }
+}
/////////////////////////////////////////////////////////////////////////////
// thread stack
@@ -4313,7 +4411,7 @@
pthread_t tid = pthread_self();
struct __pthrdsinfo pinfo;
- char dummy[1]; // We only need this to satisfy the api and to not get E.
+ char dummy[1]; // Just needed to satisfy pthread_getthrds_np.
int dummy_size = sizeof(dummy);
memset(&pinfo, 0, sizeof(pinfo));
@@ -4328,44 +4426,47 @@
}
guarantee0(pinfo.__pi_stackend);
- // The following can happen when invoking pthread_getthrds_np on a pthread running
- // on a user provided stack (when handing down a stack to pthread create, see
- // pthread_attr_setstackaddr).
- // Not sure what to do here - I feel inclined to forbid this use case completely.
+ // The following may happen when invoking pthread_getthrds_np on a pthread
+ // running on a user provided stack (when handing down a stack to pthread
+ // create, see pthread_attr_setstackaddr).
+ // Not sure what to do then.
+
guarantee0(pinfo.__pi_stacksize);
- // Note: the pthread stack on AIX seems to look like this:
- //
- // --------------------- real base ? at page border ?
+ // Note: we get three values from pthread_getthrds_np:
+ // __pi_stackaddr, __pi_stacksize, __pi_stackend
//
- // pthread internal data, like ~2K, see also
- // http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.prftungd/doc/prftungd/thread_supp_tun_params.htm
- //
- // --------------------- __pi_stackend - not page aligned, (xxxxF890)
+ // high addr ---------------------
//
- // stack
- // ....
- //
- // stack
- //
- // --------------------- __pi_stackend - __pi_stacksize
+ // | pthread internal data, like ~2K
+ // |
+ // | --------------------- __pi_stackend (usually not page aligned, (xxxxF890))
+ // |
+ // |
+ // |
+ // |
+ // |
+ // |
+ // | --------------------- (__pi_stackend - __pi_stacksize)
+ // |
+ // | padding to align the following AIX guard pages, if enabled.
+ // |
+ // V --------------------- __pi_stackaddr
//
- // padding due to AIX guard pages (?) see AIXTHREAD_GUARDPAGES
- // --------------------- __pi_stackaddr (page aligned if AIXTHREAD_GUARDPAGES > 0)
- //
- // AIX guard pages (?)
+ // low addr AIX guard pages, if enabled (AIXTHREAD_GUARDPAGES > 0)
//
- // So, the safe thing to do is to use the area from __pi_stackend to __pi_stackaddr;
- // __pi_stackend however is almost never page aligned.
- //
+ address stack_base = (address)(pinfo.__pi_stackend);
+ address stack_low_addr = (address)align_ptr_up(pinfo.__pi_stackaddr,
+ os::vm_page_size());
+ size_t stack_size = stack_base - stack_low_addr;
if (p_stack_base) {
- (*p_stack_base) = (address) (pinfo.__pi_stackend);
+ *p_stack_base = stack_base;
}
if (p_stack_size) {
- (*p_stack_size) = pinfo.__pi_stackend - pinfo.__pi_stackaddr;
+ *p_stack_size = stack_size;
}
return true;
--- a/hotspot/src/os/aix/vm/os_aix.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/os_aix.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -34,9 +34,6 @@
class Aix {
friend class os;
- // Length of strings included in the libperfstat structures.
-#define IDENTIFIER_LENGTH 64
-
static bool libjsig_is_loaded; // libjsig that interposes sigaction(),
// __sigaction(), signal() is loaded
static struct sigaction *(*get_signal_action)(int);
@@ -45,13 +42,15 @@
static void check_signal_handler(int sig);
- protected:
+ private:
static julong _physical_memory;
static pthread_t _main_thread;
static Mutex* _createThread_lock;
static int _page_size;
- static int _logical_cpus;
+
+ // Page size of newly created pthreads.
+ static int _stack_page_size;
// -1 = uninitialized, 0 = AIX, 1 = OS/400 (PASE)
static int _on_pase;
@@ -63,6 +62,9 @@
// for OS/400 e.g. 0x0504 for OS/400 V5R4
static int _os_version;
+ // 4 Byte kernel version: Version, Release, Tech Level, Service Pack.
+ static unsigned int _os_kernel_version;
+
// -1 = uninitialized,
// 0 - SPEC1170 not requested (XPG_SUS_ENV is OFF or not set)
// 1 - SPEC1170 requested (XPG_SUS_ENV is ON)
@@ -73,35 +75,6 @@
// 1 - EXTSHM=ON
static int _extshm;
- // page sizes on AIX.
- //
- // AIX supports four different page sizes - 4K, 64K, 16MB, 16GB. The latter two
- // (16M "large" resp. 16G "huge" pages) require special setup and are normally
- // not available.
- //
- // AIX supports multiple page sizes per process, for:
- // - Stack (of the primordial thread, so not relevant for us)
- // - Data - data, bss, heap, for us also pthread stacks
- // - Text - text code
- // - shared memory
- //
- // Default page sizes can be set via linker options (-bdatapsize, -bstacksize, ...)
- // and via environment variable LDR_CNTRL (DATAPSIZE, STACKPSIZE, ...)
- //
- // For shared memory, page size can be set dynamically via shmctl(). Different shared memory
- // regions can have different page sizes.
- //
- // More information can be found at AIBM info center:
- // http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=/com.ibm.aix.prftungd/doc/prftungd/multiple_page_size_app_support.htm
- //
- // -----
- // We want to support 4K and 64K and, if the machine is set up correctly, 16MB pages.
- //
-
- // page size of the stack of newly created pthreads
- // (should be LDR_CNTRL DATAPSIZE because stack is allocated on heap by pthread lib)
- static int _stack_page_size;
-
static julong available_memory();
static julong physical_memory() { return _physical_memory; }
static void initialize_system_info();
@@ -125,9 +98,6 @@
public:
static void init_thread_fpu_state();
static pthread_t main_thread(void) { return _main_thread; }
- // returns kernel thread id (similar to LWP id on Solaris), which can be
- // used to access /proc
- static pid_t gettid();
static void set_createThread_lock(Mutex* lk) { _createThread_lock = lk; }
static Mutex* createThread_lock(void) { return _createThread_lock; }
static void hotspot_sigmask(Thread* thread);
@@ -215,6 +185,14 @@
return _os_version;
}
+ // Get 4 byte AIX kernel version number:
+ // highest 2 bytes: Version, Release
+ // if available: lowest 2 bytes: Tech Level, Service Pack.
+ static unsigned int os_kernel_version() {
+ if (_os_kernel_version) return _os_kernel_version;
+ return os_version() << 16;
+ }
+
// Convenience method: returns true if running on PASE V5R4 or older.
static bool on_pase_V5R4_or_older() {
return on_pase() && os_version() <= 0x0504;
@@ -257,27 +235,12 @@
};
- // Result struct for get_cpuinfo().
- struct cpuinfo_t {
- char description[IDENTIFIER_LENGTH]; // processor description (type/official name)
- u_longlong_t processorHZ; // processor speed in Hz
- int ncpus; // number of active logical processors
- double loadavg[3]; // (1<<SBITS) times the average number of runnables processes during the last 1, 5 and 15 minutes.
- // To calculate the load average, divide the numbers by (1<<SBITS). SBITS is defined in <sys/proc.h>.
- char version[20]; // processor version from _system_configuration (sys/systemcfg.h)
- };
-
// Functions to retrieve memory information on AIX, PASE.
// (on AIX, using libperfstat, on PASE with libo4.so).
// Returns true if ok, false if error.
static bool get_meminfo(meminfo_t* pmi);
- // Function to retrieve cpu information on AIX
- // (on AIX, using libperfstat)
- // Returns true if ok, false if error.
- static bool get_cpuinfo(cpuinfo_t* pci);
-
-}; // os::Aix class
+};
class PlatformEvent : public CHeapObj<mtInternal> {
--- a/hotspot/src/os/aix/vm/os_aix.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/aix/vm/os_aix.inline.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -36,10 +36,6 @@
#include <sys/ioctl.h>
#include <netdb.h>
-inline void* os::thread_local_storage_at(int index) {
- return pthread_getspecific((pthread_key_t)index);
-}
-
// File names are case-sensitive on windows only.
inline int os::file_name_strcmp(const char* s1, const char* s2) {
return strcmp(s1, s2);
@@ -64,6 +60,8 @@
// On Aix, reservations are made on a page by page basis, nothing to do.
inline void os::pd_split_reserved_memory(char *base, size_t size,
size_t split, bool realloc) {
+ // TODO: Determine whether Sys V memory is split. If yes, we need to treat
+ // this the same way Windows treats its VirtualAlloc allocations.
}
// Bang the shadow pages if they need to be touched to be mapped.
--- a/hotspot/src/os/aix/vm/thread_aix.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_AIX_VM_THREAD_AIX_INLINE_HPP
-#define OS_AIX_VM_THREAD_AIX_INLINE_HPP
-
-#include "runtime/thread.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// Contains inlined functions for class Thread and ThreadLocalStorage
-
-inline void ThreadLocalStorage::pd_invalidate_all() {} // nothing to do
-
-#endif // OS_AIX_VM_THREAD_AIX_INLINE_HPP
--- a/hotspot/src/os/bsd/vm/jvm_bsd.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/bsd/vm/jvm_bsd.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -108,84 +108,3 @@
return JNI_TRUE;
JVM_END
-/*
- All the defined signal names for Bsd.
-
- NOTE that not all of these names are accepted by our Java implementation
-
- Via an existing claim by the VM, sigaction restrictions, or
- the "rules of Unix" some of these names will be rejected at runtime.
- For example the VM sets up to handle USR1, sigaction returns EINVAL for
- STOP, and Bsd simply doesn't allow catching of KILL.
-
- Here are the names currently accepted by a user of sun.misc.Signal with
- 1.4.1 (ignoring potential interaction with use of chaining, etc):
-
- HUP, INT, TRAP, ABRT, IOT, BUS, USR2, PIPE, ALRM, TERM, STKFLT,
- CLD, CHLD, CONT, TSTP, TTIN, TTOU, URG, XCPU, XFSZ, VTALRM, PROF,
- WINCH, POLL, IO, PWR, SYS
-
-*/
-
-struct siglabel {
- const char *name;
- int number;
-};
-
-struct siglabel siglabels[] = {
- /* derived from /usr/include/bits/signum.h on RH7.2 */
- "HUP", SIGHUP, /* Hangup (POSIX). */
- "INT", SIGINT, /* Interrupt (ANSI). */
- "QUIT", SIGQUIT, /* Quit (POSIX). */
- "ILL", SIGILL, /* Illegal instruction (ANSI). */
- "TRAP", SIGTRAP, /* Trace trap (POSIX). */
- "ABRT", SIGABRT, /* Abort (ANSI). */
- "EMT", SIGEMT, /* EMT trap */
- "FPE", SIGFPE, /* Floating-point exception (ANSI). */
- "KILL", SIGKILL, /* Kill, unblockable (POSIX). */
- "BUS", SIGBUS, /* BUS error (4.2 BSD). */
- "SEGV", SIGSEGV, /* Segmentation violation (ANSI). */
- "SYS", SIGSYS, /* Bad system call. Only on some Bsden! */
- "PIPE", SIGPIPE, /* Broken pipe (POSIX). */
- "ALRM", SIGALRM, /* Alarm clock (POSIX). */
- "TERM", SIGTERM, /* Termination (ANSI). */
- "URG", SIGURG, /* Urgent condition on socket (4.2 BSD). */
- "STOP", SIGSTOP, /* Stop, unblockable (POSIX). */
- "TSTP", SIGTSTP, /* Keyboard stop (POSIX). */
- "CONT", SIGCONT, /* Continue (POSIX). */
- "CHLD", SIGCHLD, /* Child status has changed (POSIX). */
- "TTIN", SIGTTIN, /* Background read from tty (POSIX). */
- "TTOU", SIGTTOU, /* Background write to tty (POSIX). */
- "IO", SIGIO, /* I/O now possible (4.2 BSD). */
- "XCPU", SIGXCPU, /* CPU limit exceeded (4.2 BSD). */
- "XFSZ", SIGXFSZ, /* File size limit exceeded (4.2 BSD). */
- "VTALRM", SIGVTALRM, /* Virtual alarm clock (4.2 BSD). */
- "PROF", SIGPROF, /* Profiling alarm clock (4.2 BSD). */
- "WINCH", SIGWINCH, /* Window size change (4.3 BSD, Sun). */
- "INFO", SIGINFO, /* Information request. */
- "USR1", SIGUSR1, /* User-defined signal 1 (POSIX). */
- "USR2", SIGUSR2 /* User-defined signal 2 (POSIX). */
- };
-
-JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name))
-
- /* find and return the named signal's number */
-
- for(uint i=0; i<ARRAY_SIZE(siglabels); i++)
- if(!strcmp(name, siglabels[i].name))
- return siglabels[i].number;
-
- return -1;
-
-JVM_END
-
-// used by os::exception_name()
-extern bool signal_name(int signo, char* buf, size_t len) {
- for(uint i = 0; i < ARRAY_SIZE(siglabels); i++) {
- if (signo == siglabels[i].number) {
- jio_snprintf(buf, len, "SIG%s", siglabels[i].name);
- return true;
- }
- }
- return false;
-}
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -674,7 +674,7 @@
int pid = os::current_process_id();
alloca(((pid ^ counter++) & 7) * 128);
- ThreadLocalStorage::set_thread(thread);
+ thread->initialize_thread_current();
OSThread* osthread = thread->osthread();
Monitor* sync = osthread->startThread_lock();
@@ -882,44 +882,6 @@
delete osthread;
}
-//////////////////////////////////////////////////////////////////////////////
-// thread local storage
-
-// Restore the thread pointer if the destructor is called. This is in case
-// someone from JNI code sets up a destructor with pthread_key_create to run
-// detachCurrentThread on thread death. Unless we restore the thread pointer we
-// will hang or crash. When detachCurrentThread is called the key will be set
-// to null and we will not be called again. If detachCurrentThread is never
-// called we could loop forever depending on the pthread implementation.
-static void restore_thread_pointer(void* p) {
- Thread* thread = (Thread*) p;
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
-}
-
-int os::allocate_thread_local_storage() {
- pthread_key_t key;
- int rslt = pthread_key_create(&key, restore_thread_pointer);
- assert(rslt == 0, "cannot allocate thread local storage");
- return (int)key;
-}
-
-// Note: This is currently not used by VM, as we don't destroy TLS key
-// on VM exit.
-void os::free_thread_local_storage(int index) {
- int rslt = pthread_key_delete((pthread_key_t)index);
- assert(rslt == 0, "invalid index");
-}
-
-void os::thread_local_storage_at_put(int index, void* value) {
- int rslt = pthread_setspecific((pthread_key_t)index, value);
- assert(rslt == 0, "pthread_setspecific failed");
-}
-
-extern "C" Thread* get_thread() {
- return ThreadLocalStorage::thread();
-}
-
-
////////////////////////////////////////////////////////////////////////////////
// time support
@@ -3420,8 +3382,12 @@
}
} else if(os::Bsd::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Bsd::get_our_sigflags(sig)) {
tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN));
- tty->print("expected:" PTR32_FORMAT, os::Bsd::get_our_sigflags(sig));
- tty->print_cr(" found:" PTR32_FORMAT, act.sa_flags);
+ tty->print("expected:");
+ os::Posix::print_sa_flags(tty, os::Bsd::get_our_sigflags(sig));
+ tty->cr();
+ tty->print(" found:");
+ os::Posix::print_sa_flags(tty, act.sa_flags);
+ tty->cr();
// No need to check this sig any longer
sigaddset(&check_signal_done, sig);
}
@@ -3435,20 +3401,6 @@
extern void report_error(char* file_name, int line_no, char* title,
char* format, ...);
-extern bool signal_name(int signo, char* buf, size_t len);
-
-const char* os::exception_name(int exception_code, char* buf, size_t size) {
- if (0 < exception_code && exception_code <= SIGRTMAX) {
- // signal
- if (!signal_name(exception_code, buf, size)) {
- jio_snprintf(buf, size, "SIG%d", exception_code);
- }
- return buf;
- } else {
- return NULL;
- }
-}
-
// this is called _before_ the most of global arguments have been parsed
void os::init(void) {
char dummy; // used to get a guess on initial stack address
--- a/hotspot/src/os/bsd/vm/os_bsd.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/bsd/vm/os_bsd.inline.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -34,10 +34,6 @@
#include <sys/poll.h>
#include <netdb.h>
-inline void* os::thread_local_storage_at(int index) {
- return pthread_getspecific((pthread_key_t)index);
-}
-
// File names are case-sensitive on windows only
inline int os::file_name_strcmp(const char* s1, const char* s2) {
return strcmp(s1, s2);
--- a/hotspot/src/os/bsd/vm/thread_bsd.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2002, 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 OS_BSD_VM_THREAD_BSD_INLINE_HPP
-#define OS_BSD_VM_THREAD_BSD_INLINE_HPP
-
-#ifndef SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
-#error "This file should only be included from thread.inline.hpp"
-#endif
-
-#include "runtime/thread.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// Contains inlined functions for class Thread and ThreadLocalStorage
-
-inline void ThreadLocalStorage::pd_invalidate_all() {} // nothing to do
-
-#endif // OS_BSD_VM_THREAD_BSD_INLINE_HPP
--- a/hotspot/src/os/linux/vm/jvm_linux.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/linux/vm/jvm_linux.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -108,91 +108,3 @@
return JNI_TRUE;
JVM_END
-/*
- All the defined signal names for Linux.
-
- NOTE that not all of these names are accepted by our Java implementation
-
- Via an existing claim by the VM, sigaction restrictions, or
- the "rules of Unix" some of these names will be rejected at runtime.
- For example the VM sets up to handle USR1, sigaction returns EINVAL for
- STOP, and Linux simply doesn't allow catching of KILL.
-
- Here are the names currently accepted by a user of sun.misc.Signal with
- 1.4.1 (ignoring potential interaction with use of chaining, etc):
-
- HUP, INT, TRAP, ABRT, IOT, BUS, USR2, PIPE, ALRM, TERM, STKFLT,
- CLD, CHLD, CONT, TSTP, TTIN, TTOU, URG, XCPU, XFSZ, VTALRM, PROF,
- WINCH, POLL, IO, PWR, SYS
-
-*/
-
-struct siglabel {
- const char *name;
- int number;
-};
-
-struct siglabel siglabels[] = {
- /* derived from /usr/include/bits/signum.h on RH7.2 */
- "HUP", SIGHUP, /* Hangup (POSIX). */
- "INT", SIGINT, /* Interrupt (ANSI). */
- "QUIT", SIGQUIT, /* Quit (POSIX). */
- "ILL", SIGILL, /* Illegal instruction (ANSI). */
- "TRAP", SIGTRAP, /* Trace trap (POSIX). */
- "ABRT", SIGABRT, /* Abort (ANSI). */
- "IOT", SIGIOT, /* IOT trap (4.2 BSD). */
- "BUS", SIGBUS, /* BUS error (4.2 BSD). */
- "FPE", SIGFPE, /* Floating-point exception (ANSI). */
- "KILL", SIGKILL, /* Kill, unblockable (POSIX). */
- "USR1", SIGUSR1, /* User-defined signal 1 (POSIX). */
- "SEGV", SIGSEGV, /* Segmentation violation (ANSI). */
- "USR2", SIGUSR2, /* User-defined signal 2 (POSIX). */
- "PIPE", SIGPIPE, /* Broken pipe (POSIX). */
- "ALRM", SIGALRM, /* Alarm clock (POSIX). */
- "TERM", SIGTERM, /* Termination (ANSI). */
-#ifdef SIGSTKFLT
- "STKFLT", SIGSTKFLT, /* Stack fault. */
-#endif
- "CLD", SIGCLD, /* Same as SIGCHLD (System V). */
- "CHLD", SIGCHLD, /* Child status has changed (POSIX). */
- "CONT", SIGCONT, /* Continue (POSIX). */
- "STOP", SIGSTOP, /* Stop, unblockable (POSIX). */
- "TSTP", SIGTSTP, /* Keyboard stop (POSIX). */
- "TTIN", SIGTTIN, /* Background read from tty (POSIX). */
- "TTOU", SIGTTOU, /* Background write to tty (POSIX). */
- "URG", SIGURG, /* Urgent condition on socket (4.2 BSD). */
- "XCPU", SIGXCPU, /* CPU limit exceeded (4.2 BSD). */
- "XFSZ", SIGXFSZ, /* File size limit exceeded (4.2 BSD). */
- "VTALRM", SIGVTALRM, /* Virtual alarm clock (4.2 BSD). */
- "PROF", SIGPROF, /* Profiling alarm clock (4.2 BSD). */
- "WINCH", SIGWINCH, /* Window size change (4.3 BSD, Sun). */
- "POLL", SIGPOLL, /* Pollable event occurred (System V). */
- "IO", SIGIO, /* I/O now possible (4.2 BSD). */
- "PWR", SIGPWR, /* Power failure restart (System V). */
-#ifdef SIGSYS
- "SYS", SIGSYS /* Bad system call. Only on some Linuxen! */
-#endif
- };
-
-JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name))
-
- /* find and return the named signal's number */
-
- for(uint i=0; i<ARRAY_SIZE(siglabels); i++)
- if(!strcmp(name, siglabels[i].name))
- return siglabels[i].number;
-
- return -1;
-
-JVM_END
-
-// used by os::exception_name()
-extern bool signal_name(int signo, char* buf, size_t len) {
- for(uint i = 0; i < ARRAY_SIZE(siglabels); i++) {
- if (signo == siglabels[i].number) {
- jio_snprintf(buf, len, "SIG%s", siglabels[i].name);
- return true;
- }
- }
- return false;
-}
--- a/hotspot/src/os/linux/vm/os_linux.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -646,7 +646,7 @@
int pid = os::current_process_id();
alloca(((pid ^ counter++) & 7) * 128);
- ThreadLocalStorage::set_thread(thread);
+ thread->initialize_thread_current();
OSThread* osthread = thread->osthread();
Monitor* sync = osthread->startThread_lock();
@@ -874,43 +874,6 @@
}
//////////////////////////////////////////////////////////////////////////////
-// thread local storage
-
-// Restore the thread pointer if the destructor is called. This is in case
-// someone from JNI code sets up a destructor with pthread_key_create to run
-// detachCurrentThread on thread death. Unless we restore the thread pointer we
-// will hang or crash. When detachCurrentThread is called the key will be set
-// to null and we will not be called again. If detachCurrentThread is never
-// called we could loop forever depending on the pthread implementation.
-static void restore_thread_pointer(void* p) {
- Thread* thread = (Thread*) p;
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
-}
-
-int os::allocate_thread_local_storage() {
- pthread_key_t key;
- int rslt = pthread_key_create(&key, restore_thread_pointer);
- assert(rslt == 0, "cannot allocate thread local storage");
- return (int)key;
-}
-
-// Note: This is currently not used by VM, as we don't destroy TLS key
-// on VM exit.
-void os::free_thread_local_storage(int index) {
- int rslt = pthread_key_delete((pthread_key_t)index);
- assert(rslt == 0, "invalid index");
-}
-
-void os::thread_local_storage_at_put(int index, void* value) {
- int rslt = pthread_setspecific((pthread_key_t)index, value);
- assert(rslt == 0, "pthread_setspecific failed");
-}
-
-extern "C" Thread* get_thread() {
- return ThreadLocalStorage::thread();
-}
-
-//////////////////////////////////////////////////////////////////////////////
// initial thread
// Check if current thread is the initial thread, similar to Solaris thr_main.
@@ -4570,8 +4533,12 @@
}
} else if(os::Linux::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Linux::get_our_sigflags(sig)) {
tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN));
- tty->print("expected:" PTR32_FORMAT, os::Linux::get_our_sigflags(sig));
- tty->print_cr(" found:" PTR32_FORMAT, act.sa_flags);
+ tty->print("expected:");
+ os::Posix::print_sa_flags(tty, os::Linux::get_our_sigflags(sig));
+ tty->cr();
+ tty->print(" found:");
+ os::Posix::print_sa_flags(tty, act.sa_flags);
+ tty->cr();
// No need to check this sig any longer
sigaddset(&check_signal_done, sig);
}
@@ -4585,20 +4552,6 @@
extern void report_error(char* file_name, int line_no, char* title,
char* format, ...);
-extern bool signal_name(int signo, char* buf, size_t len);
-
-const char* os::exception_name(int exception_code, char* buf, size_t size) {
- if (0 < exception_code && exception_code <= SIGRTMAX) {
- // signal
- if (!signal_name(exception_code, buf, size)) {
- jio_snprintf(buf, size, "SIG%d", exception_code);
- }
- return buf;
- } else {
- return NULL;
- }
-}
-
// this is called _before_ the most of global arguments have been parsed
void os::init(void) {
char dummy; // used to get a guess on initial stack address
--- a/hotspot/src/os/linux/vm/os_linux.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/linux/vm/os_linux.inline.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -34,10 +34,6 @@
#include <sys/poll.h>
#include <netdb.h>
-inline void* os::thread_local_storage_at(int index) {
- return pthread_getspecific((pthread_key_t)index);
-}
-
// File names are case-sensitive on windows only
inline int os::file_name_strcmp(const char* s1, const char* s2) {
return strcmp(s1, s2);
--- a/hotspot/src/os/linux/vm/thread_linux.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2002, 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 OS_LINUX_VM_THREAD_LINUX_INLINE_HPP
-#define OS_LINUX_VM_THREAD_LINUX_INLINE_HPP
-
-#ifndef SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
-#error "This file should only be included from thread.inline.hpp"
-#endif
-
-#include "runtime/thread.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// Contains inlined functions for class Thread and ThreadLocalStorage
-
-inline void ThreadLocalStorage::pd_invalidate_all() {} // nothing to do
-
-#endif // OS_LINUX_VM_THREAD_LINUX_INLINE_HPP
--- a/hotspot/src/os/posix/vm/os_posix.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/posix/vm/os_posix.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -493,166 +493,171 @@
return interrupted;
}
-// Returned string is a constant. For unknown signals "UNKNOWN" is returned.
-const char* os::Posix::get_signal_name(int sig, char* out, size_t outlen) {
+
- static const struct {
- int sig; const char* name;
- }
- info[] =
+static const struct {
+ int sig; const char* name;
+}
+ g_signal_info[] =
{
- { SIGABRT, "SIGABRT" },
+ { SIGABRT, "SIGABRT" },
#ifdef SIGAIO
- { SIGAIO, "SIGAIO" },
+ { SIGAIO, "SIGAIO" },
#endif
- { SIGALRM, "SIGALRM" },
+ { SIGALRM, "SIGALRM" },
#ifdef SIGALRM1
- { SIGALRM1, "SIGALRM1" },
+ { SIGALRM1, "SIGALRM1" },
#endif
- { SIGBUS, "SIGBUS" },
+ { SIGBUS, "SIGBUS" },
#ifdef SIGCANCEL
- { SIGCANCEL, "SIGCANCEL" },
+ { SIGCANCEL, "SIGCANCEL" },
#endif
- { SIGCHLD, "SIGCHLD" },
+ { SIGCHLD, "SIGCHLD" },
#ifdef SIGCLD
- { SIGCLD, "SIGCLD" },
+ { SIGCLD, "SIGCLD" },
#endif
- { SIGCONT, "SIGCONT" },
+ { SIGCONT, "SIGCONT" },
#ifdef SIGCPUFAIL
- { SIGCPUFAIL, "SIGCPUFAIL" },
+ { SIGCPUFAIL, "SIGCPUFAIL" },
#endif
#ifdef SIGDANGER
- { SIGDANGER, "SIGDANGER" },
+ { SIGDANGER, "SIGDANGER" },
#endif
#ifdef SIGDIL
- { SIGDIL, "SIGDIL" },
+ { SIGDIL, "SIGDIL" },
#endif
#ifdef SIGEMT
- { SIGEMT, "SIGEMT" },
+ { SIGEMT, "SIGEMT" },
#endif
- { SIGFPE, "SIGFPE" },
+ { SIGFPE, "SIGFPE" },
#ifdef SIGFREEZE
- { SIGFREEZE, "SIGFREEZE" },
+ { SIGFREEZE, "SIGFREEZE" },
#endif
#ifdef SIGGFAULT
- { SIGGFAULT, "SIGGFAULT" },
+ { SIGGFAULT, "SIGGFAULT" },
#endif
#ifdef SIGGRANT
- { SIGGRANT, "SIGGRANT" },
+ { SIGGRANT, "SIGGRANT" },
#endif
- { SIGHUP, "SIGHUP" },
- { SIGILL, "SIGILL" },
- { SIGINT, "SIGINT" },
+ { SIGHUP, "SIGHUP" },
+ { SIGILL, "SIGILL" },
+ { SIGINT, "SIGINT" },
#ifdef SIGIO
- { SIGIO, "SIGIO" },
+ { SIGIO, "SIGIO" },
#endif
#ifdef SIGIOINT
- { SIGIOINT, "SIGIOINT" },
+ { SIGIOINT, "SIGIOINT" },
#endif
#ifdef SIGIOT
- // SIGIOT is there for BSD compatibility, but on most Unices just a
- // synonym for SIGABRT. The result should be "SIGABRT", not
- // "SIGIOT".
- #if (SIGIOT != SIGABRT )
- { SIGIOT, "SIGIOT" },
- #endif
+// SIGIOT is there for BSD compatibility, but on most Unices just a
+// synonym for SIGABRT. The result should be "SIGABRT", not
+// "SIGIOT".
+#if (SIGIOT != SIGABRT )
+ { SIGIOT, "SIGIOT" },
+#endif
#endif
#ifdef SIGKAP
- { SIGKAP, "SIGKAP" },
+ { SIGKAP, "SIGKAP" },
#endif
- { SIGKILL, "SIGKILL" },
+ { SIGKILL, "SIGKILL" },
#ifdef SIGLOST
- { SIGLOST, "SIGLOST" },
+ { SIGLOST, "SIGLOST" },
#endif
#ifdef SIGLWP
- { SIGLWP, "SIGLWP" },
+ { SIGLWP, "SIGLWP" },
#endif
#ifdef SIGLWPTIMER
- { SIGLWPTIMER, "SIGLWPTIMER" },
+ { SIGLWPTIMER, "SIGLWPTIMER" },
#endif
#ifdef SIGMIGRATE
- { SIGMIGRATE, "SIGMIGRATE" },
+ { SIGMIGRATE, "SIGMIGRATE" },
#endif
#ifdef SIGMSG
- { SIGMSG, "SIGMSG" },
+ { SIGMSG, "SIGMSG" },
#endif
- { SIGPIPE, "SIGPIPE" },
+ { SIGPIPE, "SIGPIPE" },
#ifdef SIGPOLL
- { SIGPOLL, "SIGPOLL" },
+ { SIGPOLL, "SIGPOLL" },
#endif
#ifdef SIGPRE
- { SIGPRE, "SIGPRE" },
+ { SIGPRE, "SIGPRE" },
#endif
- { SIGPROF, "SIGPROF" },
+ { SIGPROF, "SIGPROF" },
#ifdef SIGPTY
- { SIGPTY, "SIGPTY" },
+ { SIGPTY, "SIGPTY" },
#endif
#ifdef SIGPWR
- { SIGPWR, "SIGPWR" },
+ { SIGPWR, "SIGPWR" },
#endif
- { SIGQUIT, "SIGQUIT" },
+ { SIGQUIT, "SIGQUIT" },
#ifdef SIGRECONFIG
- { SIGRECONFIG, "SIGRECONFIG" },
+ { SIGRECONFIG, "SIGRECONFIG" },
#endif
#ifdef SIGRECOVERY
- { SIGRECOVERY, "SIGRECOVERY" },
+ { SIGRECOVERY, "SIGRECOVERY" },
#endif
#ifdef SIGRESERVE
- { SIGRESERVE, "SIGRESERVE" },
+ { SIGRESERVE, "SIGRESERVE" },
#endif
#ifdef SIGRETRACT
- { SIGRETRACT, "SIGRETRACT" },
+ { SIGRETRACT, "SIGRETRACT" },
#endif
#ifdef SIGSAK
- { SIGSAK, "SIGSAK" },
+ { SIGSAK, "SIGSAK" },
#endif
- { SIGSEGV, "SIGSEGV" },
+ { SIGSEGV, "SIGSEGV" },
#ifdef SIGSOUND
- { SIGSOUND, "SIGSOUND" },
+ { SIGSOUND, "SIGSOUND" },
+#endif
+#ifdef SIGSTKFLT
+ { SIGSTKFLT, "SIGSTKFLT" },
#endif
- { SIGSTOP, "SIGSTOP" },
- { SIGSYS, "SIGSYS" },
+ { SIGSTOP, "SIGSTOP" },
+ { SIGSYS, "SIGSYS" },
#ifdef SIGSYSERROR
- { SIGSYSERROR, "SIGSYSERROR" },
+ { SIGSYSERROR, "SIGSYSERROR" },
#endif
#ifdef SIGTALRM
- { SIGTALRM, "SIGTALRM" },
+ { SIGTALRM, "SIGTALRM" },
#endif
- { SIGTERM, "SIGTERM" },
+ { SIGTERM, "SIGTERM" },
#ifdef SIGTHAW
- { SIGTHAW, "SIGTHAW" },
+ { SIGTHAW, "SIGTHAW" },
#endif
- { SIGTRAP, "SIGTRAP" },
+ { SIGTRAP, "SIGTRAP" },
#ifdef SIGTSTP
- { SIGTSTP, "SIGTSTP" },
+ { SIGTSTP, "SIGTSTP" },
#endif
- { SIGTTIN, "SIGTTIN" },
- { SIGTTOU, "SIGTTOU" },
+ { SIGTTIN, "SIGTTIN" },
+ { SIGTTOU, "SIGTTOU" },
#ifdef SIGURG
- { SIGURG, "SIGURG" },
+ { SIGURG, "SIGURG" },
#endif
- { SIGUSR1, "SIGUSR1" },
- { SIGUSR2, "SIGUSR2" },
+ { SIGUSR1, "SIGUSR1" },
+ { SIGUSR2, "SIGUSR2" },
#ifdef SIGVIRT
- { SIGVIRT, "SIGVIRT" },
+ { SIGVIRT, "SIGVIRT" },
#endif
- { SIGVTALRM, "SIGVTALRM" },
+ { SIGVTALRM, "SIGVTALRM" },
#ifdef SIGWAITING
- { SIGWAITING, "SIGWAITING" },
+ { SIGWAITING, "SIGWAITING" },
#endif
#ifdef SIGWINCH
- { SIGWINCH, "SIGWINCH" },
+ { SIGWINCH, "SIGWINCH" },
#endif
#ifdef SIGWINDOW
- { SIGWINDOW, "SIGWINDOW" },
+ { SIGWINDOW, "SIGWINDOW" },
#endif
- { SIGXCPU, "SIGXCPU" },
- { SIGXFSZ, "SIGXFSZ" },
+ { SIGXCPU, "SIGXCPU" },
+ { SIGXFSZ, "SIGXFSZ" },
#ifdef SIGXRES
- { SIGXRES, "SIGXRES" },
+ { SIGXRES, "SIGXRES" },
#endif
- { -1, NULL }
- };
+ { -1, NULL }
+};
+
+// Returned string is a constant. For unknown signals "UNKNOWN" is returned.
+const char* os::Posix::get_signal_name(int sig, char* out, size_t outlen) {
const char* ret = NULL;
@@ -670,9 +675,9 @@
#endif
if (sig > 0) {
- for (int idx = 0; info[idx].sig != -1; idx ++) {
- if (info[idx].sig == sig) {
- ret = info[idx].name;
+ for (int idx = 0; g_signal_info[idx].sig != -1; idx ++) {
+ if (g_signal_info[idx].sig == sig) {
+ ret = g_signal_info[idx].name;
break;
}
}
@@ -693,6 +698,25 @@
return out;
}
+int os::Posix::get_signal_number(const char* signal_name) {
+ char tmp[30];
+ const char* s = signal_name;
+ if (s[0] != 'S' || s[1] != 'I' || s[2] != 'G') {
+ jio_snprintf(tmp, sizeof(tmp), "SIG%s", signal_name);
+ s = tmp;
+ }
+ for (int idx = 0; g_signal_info[idx].sig != -1; idx ++) {
+ if (strcmp(g_signal_info[idx].name, s) == 0) {
+ return g_signal_info[idx].sig;
+ }
+ }
+ return -1;
+}
+
+int os::get_signal_number(const char* signal_name) {
+ return os::Posix::get_signal_number(signal_name);
+}
+
// Returns true if signal number is valid.
bool os::Posix::is_valid_signal(int sig) {
// MacOS not really POSIX compliant: sigaddset does not return
@@ -711,6 +735,21 @@
#endif
}
+// Returns:
+// "invalid (<num>)" for an invalid signal number
+// "SIG<num>" for a valid but unknown signal number
+// signal name otherwise.
+const char* os::exception_name(int sig, char* buf, size_t size) {
+ if (!os::Posix::is_valid_signal(sig)) {
+ jio_snprintf(buf, size, "invalid (%d)", sig);
+ }
+ const char* const name = os::Posix::get_signal_name(sig, buf, size);
+ if (strcmp(name, "UNKNOWN") == 0) {
+ jio_snprintf(buf, size, "SIG%d", sig);
+ }
+ return buf;
+}
+
#define NUM_IMPORTANT_SIGS 32
// Returns one-line short description of a signal set in a user provided buffer.
const char* os::Posix::describe_signal_set_short(const sigset_t* set, char* buffer, size_t buf_size) {
--- a/hotspot/src/os/posix/vm/os_posix.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/posix/vm/os_posix.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -51,6 +51,12 @@
// Returned string is a constant. For unknown signals "UNKNOWN" is returned.
static const char* get_signal_name(int sig, char* out, size_t outlen);
+ // Helper function, returns a signal number for a given signal name, e.g. 11
+ // for "SIGSEGV". Name can be given with or without "SIG" prefix, so both
+ // "SEGV" or "SIGSEGV" work. Name must be uppercase.
+ // Returns -1 for an unknown signal name.
+ static int get_signal_number(const char* signal_name);
+
// Returns one-line short description of a signal set in a user provided buffer.
static const char* describe_signal_set_short(const sigset_t* set, char* buffer, size_t size);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/posix/vm/threadLocalStorage_posix.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -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 "runtime/threadLocalStorage.hpp"
+#include <pthread.h>
+
+static pthread_key_t _thread_key;
+static bool _initialized = false;
+
+// Restore the thread pointer if the destructor is called. This is in case
+// someone from JNI code sets up a destructor with pthread_key_create to run
+// detachCurrentThread on thread death. Unless we restore the thread pointer we
+// will hang or crash. When detachCurrentThread is called the key will be set
+// to null and we will not be called again. If detachCurrentThread is never
+// called we could loop forever depending on the pthread implementation.
+extern "C" void restore_thread_pointer(void* p) {
+ ThreadLocalStorage::set_thread((Thread*) p);
+}
+
+void ThreadLocalStorage::init() {
+ assert(!_initialized, "initializing TLS more than once!");
+ int rslt = pthread_key_create(&_thread_key, restore_thread_pointer);
+ // If this assert fails we will get a recursive assertion failure
+ // and not see the actual error message or get a hs_err file
+ assert_status(rslt == 0, rslt, "pthread_key_create");
+ _initialized = true;
+}
+
+bool ThreadLocalStorage::is_initialized() {
+ return _initialized;
+}
+
+Thread* ThreadLocalStorage::thread() {
+ // If this assert fails we will get a recursive assertion failure
+ // and not see the actual error message or get a hs_err file.
+ // Which most likely indicates we have taken an error path early in
+ // the initialization process, which is using Thread::current without
+ // checking TLS is initialized - see java.cpp vm_exit
+ assert(_initialized, "TLS not initialized yet!");
+ return (Thread*) pthread_getspecific(_thread_key); // may be NULL
+}
+
+void ThreadLocalStorage::set_thread(Thread* current) {
+ assert(_initialized, "TLS not initialized yet!");
+ int rslt = pthread_setspecific(_thread_key, current);
+ assert_status(rslt == 0, rslt, "pthread_setspecific");
+}
--- a/hotspot/src/os/solaris/vm/jvm_solaris.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/solaris/vm/jvm_solaris.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -106,40 +106,3 @@
return JNI_TRUE;
JVM_END
-
-/*
- All the defined signal names for Solaris are defined by str2sig().
-
- NOTE that not all of these names are accepted by our Java implementation
-
- Via an existing claim by the VM, sigaction restrictions, or
- the "rules of Unix" some of these names will be rejected at runtime.
- For example the VM sets up to handle USR1, sigaction returns EINVAL for
- CANCEL, and Solaris simply doesn't allow catching of KILL.
-
- Here are the names currently accepted by a user of sun.misc.Signal with
- 1.4.1 (ignoring potential interaction with use of chaining, etc):
-
- HUP, INT, TRAP, IOT, ABRT, EMT, BUS, SYS, PIPE, ALRM, TERM, USR2,
- CLD, CHLD, PWR, WINCH, URG, POLL, IO, TSTP, CONT, TTIN, TTOU, VTALRM,
- PROF, XCPU, XFSZ, FREEZE, THAW, LOST
-*/
-
-JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name))
-
- int sig;
-
- /* return the named signal's number */
-
- if(str2sig(name, &sig))
- return -1;
- else
- return sig;
-
-JVM_END
-
-
-//Reconciliation History
-// 1.4 98/10/07 13:39:41 jvm_win32.cpp
-// 1.6 99/06/22 16:39:00 jvm_win32.cpp
-//End
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -728,6 +728,9 @@
int prio;
Thread* thread = (Thread*)thread_addr;
+
+ thread->initialize_thread_current();
+
OSThread* osthr = thread->osthread();
osthr->set_lwp_id(_lwp_self()); // Store lwp in case we are bound
@@ -4055,8 +4058,12 @@
}
} else if(os::Solaris::get_our_sigflags(sig) != 0 && act.sa_flags != os::Solaris::get_our_sigflags(sig)) {
tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN));
- tty->print("expected:" PTR32_FORMAT, os::Solaris::get_our_sigflags(sig));
- tty->print_cr(" found:" PTR32_FORMAT, act.sa_flags);
+ tty->print("expected:");
+ os::Posix::print_sa_flags(tty, os::Solaris::get_our_sigflags(sig));
+ tty->cr();
+ tty->print(" found:");
+ os::Posix::print_sa_flags(tty, act.sa_flags);
+ tty->cr();
// No need to check this sig any longer
sigaddset(&check_signal_done, sig);
}
@@ -4144,32 +4151,6 @@
void report_error(const char* file_name, int line_no, const char* title,
const char* format, ...);
-const char * signames[] = {
- "SIG0",
- "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP",
- "SIGABRT", "SIGEMT", "SIGFPE", "SIGKILL", "SIGBUS",
- "SIGSEGV", "SIGSYS", "SIGPIPE", "SIGALRM", "SIGTERM",
- "SIGUSR1", "SIGUSR2", "SIGCLD", "SIGPWR", "SIGWINCH",
- "SIGURG", "SIGPOLL", "SIGSTOP", "SIGTSTP", "SIGCONT",
- "SIGTTIN", "SIGTTOU", "SIGVTALRM", "SIGPROF", "SIGXCPU",
- "SIGXFSZ", "SIGWAITING", "SIGLWP", "SIGFREEZE", "SIGTHAW",
- "SIGCANCEL", "SIGLOST"
-};
-
-const char* os::exception_name(int exception_code, char* buf, size_t size) {
- if (0 < exception_code && exception_code <= SIGRTMAX) {
- // signal
- if (exception_code < sizeof(signames)/sizeof(const char*)) {
- jio_snprintf(buf, size, "%s", signames[exception_code]);
- } else {
- jio_snprintf(buf, size, "SIG%d", exception_code);
- }
- return buf;
- } else {
- return NULL;
- }
-}
-
// (Static) wrapper for getisax(2) call.
os::Solaris::getisax_func_t os::Solaris::_getisax = 0;
@@ -5605,7 +5586,7 @@
// fork is async-safe, fork1 is not so can't use in signal handler
pid_t pid;
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null_safe();
if (t != NULL && t->is_inside_signal_handler()) {
pid = fork();
} else {
--- a/hotspot/src/os/solaris/vm/thread_solaris.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_THREAD_SOLARIS_INLINE_HPP
-#define OS_SOLARIS_VM_THREAD_SOLARIS_INLINE_HPP
-
-#ifndef SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
-#error "This file should only be included from thread.inline.hpp"
-#endif
-
-#include "runtime/thread.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// Thread::current is "hot" it's called > 128K times in the 1st 500 msecs of
-// startup.
-// ThreadLocalStorage::thread is warm -- it's called > 16K times in the same
-// period. Thread::current() now calls ThreadLocalStorage::thread() directly.
-// For SPARC, to avoid excessive register window spill-fill faults,
-// we aggressively inline these routines.
-
-inline void ThreadLocalStorage::set_thread(Thread* thread) {
- _thr_current = thread;
-}
-
-inline Thread* ThreadLocalStorage::thread() {
- return _thr_current;
-}
-
-#endif // OS_SOLARIS_VM_THREAD_SOLARIS_INLINE_HPP
--- a/hotspot/src/os/windows/vm/jvm_windows.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/windows/vm/jvm_windows.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -89,39 +89,3 @@
JVM_END
-/*
- All the defined signal names for Windows.
-
- NOTE that not all of these names are accepted by FindSignal!
-
- For various reasons some of these may be rejected at runtime.
-
- Here are the names currently accepted by a user of sun.misc.Signal with
- 1.4.1 (ignoring potential interaction with use of chaining, etc):
-
- (LIST TBD)
-
-*/
-struct siglabel {
- char *name;
- int number;
-};
-
-struct siglabel siglabels[] =
- /* derived from version 6.0 VC98/include/signal.h */
- {"ABRT", SIGABRT, /* abnormal termination triggered by abort cl */
- "FPE", SIGFPE, /* floating point exception */
- "SEGV", SIGSEGV, /* segment violation */
- "INT", SIGINT, /* interrupt */
- "TERM", SIGTERM, /* software term signal from kill */
- "BREAK", SIGBREAK, /* Ctrl-Break sequence */
- "ILL", SIGILL}; /* illegal instruction */
-
-JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name))
- /* find and return the named signal's number */
-
- for(int i=0;i<sizeof(siglabels)/sizeof(struct siglabel);i++)
- if(!strcmp(name, siglabels[i].name))
- return siglabels[i].number;
- return -1;
-JVM_END
--- a/hotspot/src/os/windows/vm/os_windows.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -419,6 +419,8 @@
int pid = os::current_process_id();
_alloca(((pid ^ counter++) & 7) * 128);
+ thread->initialize_thread_current();
+
OSThread* osthr = thread->osthread();
assert(osthr->get_state() == RUNNABLE, "invalid os thread state");
@@ -1799,24 +1801,32 @@
void os::print_siginfo(outputStream *st, void *siginfo) {
EXCEPTION_RECORD* er = (EXCEPTION_RECORD*)siginfo;
st->print("siginfo:");
- st->print(" ExceptionCode=0x%x", er->ExceptionCode);
-
- if (er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
- er->NumberParameters >= 2) {
+
+ char tmp[64];
+ if (os::exception_name(er->ExceptionCode, tmp, sizeof(tmp)) == NULL) {
+ strcpy(tmp, "EXCEPTION_??");
+ }
+ st->print(" %s (0x%x)", tmp, er->ExceptionCode);
+
+ if ((er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
+ er->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) &&
+ er->NumberParameters >= 2) {
switch (er->ExceptionInformation[0]) {
case 0: st->print(", reading address"); break;
case 1: st->print(", writing address"); break;
+ case 8: st->print(", data execution prevention violation at address"); break;
default: st->print(", ExceptionInformation=" INTPTR_FORMAT,
er->ExceptionInformation[0]);
}
st->print(" " INTPTR_FORMAT, er->ExceptionInformation[1]);
- } else if (er->ExceptionCode == EXCEPTION_IN_PAGE_ERROR &&
- er->NumberParameters >= 2 && UseSharedSpaces) {
- FileMapInfo* mapinfo = FileMapInfo::current_info();
- if (mapinfo->is_in_shared_space((void*)er->ExceptionInformation[1])) {
- st->print("\n\nError accessing class data sharing archive." \
- " Mapped file inaccessible during execution, " \
- " possible disk/network problem.");
+
+ if (er->ExceptionCode == EXCEPTION_IN_PAGE_ERROR && UseSharedSpaces) {
+ FileMapInfo* mapinfo = FileMapInfo::current_info();
+ if (mapinfo->is_in_shared_space((void*)er->ExceptionInformation[1])) {
+ st->print("\n\nError accessing class data sharing archive." \
+ " Mapped file inaccessible during execution, " \
+ " possible disk/network problem.");
+ }
}
} else {
int num = er->NumberParameters;
@@ -2146,7 +2156,7 @@
LONG Handle_Exception(struct _EXCEPTION_POINTERS* exceptionInfo,
address handler) {
- JavaThread* thread = JavaThread::current();
+ JavaThread* thread = (JavaThread*) Thread::current_or_null();
// Save pc in thread
#ifdef _M_IA64
// Do not blow up if no thread info available.
@@ -2384,7 +2394,7 @@
address pc = (address) exceptionInfo->ContextRecord->Eip;
#endif
#endif
- Thread* t = ThreadLocalStorage::get_thread_slow(); // slow & steady
+ Thread* t = Thread::current_or_null_safe();
// Handle SafeFetch32 and SafeFetchN exceptions.
if (StubRoutines::is_safefetch_fault(pc)) {
@@ -4011,27 +4021,6 @@
return result == IDYES;
}
-int os::allocate_thread_local_storage() {
- return TlsAlloc();
-}
-
-
-void os::free_thread_local_storage(int index) {
- TlsFree(index);
-}
-
-
-void os::thread_local_storage_at_put(int index, void* value) {
- TlsSetValue(index, value);
- assert(thread_local_storage_at(index) == value, "Just checking");
-}
-
-
-void* os::thread_local_storage_at(int index) {
- return TlsGetValue(index);
-}
-
-
#ifndef PRODUCT
#ifndef _WIN64
// Helpers to check whether NX protection is enabled
@@ -4079,6 +4068,9 @@
fatal("DuplicateHandle failed\n");
}
main_thread_id = (int) GetCurrentThreadId();
+
+ // initialize fast thread access - only used for 32-bit
+ win32::initialize_thread_ptr_offset();
}
// To install functions for atexit processing
@@ -5177,9 +5169,7 @@
}
}
- JavaThread* thread = (JavaThread*)(Thread::current());
- assert(thread->is_Java_thread(), "Must be JavaThread");
- JavaThread *jt = (JavaThread *)thread;
+ JavaThread* thread = JavaThread::current();
// Don't wait if interrupted or already triggered
if (Thread::is_interrupted(thread, false) ||
@@ -5187,16 +5177,16 @@
ResetEvent(_ParkEvent);
return;
} else {
- ThreadBlockInVM tbivm(jt);
+ ThreadBlockInVM tbivm(thread);
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
- jt->set_suspend_equivalent();
+ thread->set_suspend_equivalent();
WaitForSingleObject(_ParkEvent, time);
ResetEvent(_ParkEvent);
// If externally suspended while waiting, re-suspend
- if (jt->handle_special_suspend_equivalent_condition()) {
- jt->java_suspend_self();
+ if (thread->handle_special_suspend_equivalent_condition()) {
+ thread->java_suspend_self();
}
}
}
@@ -5299,7 +5289,7 @@
DWORD exception_code = e->ExceptionRecord->ExceptionCode;
if (exception_code == EXCEPTION_ACCESS_VIOLATION) {
- JavaThread* thread = (JavaThread*)ThreadLocalStorage::get_thread_slow();
+ JavaThread* thread = JavaThread::current();
PEXCEPTION_RECORD exceptionRecord = e->ExceptionRecord;
address addr = (address) exceptionRecord->ExceptionInformation[1];
@@ -6033,3 +6023,48 @@
UseNUMAInterleaving = old_use_numa_interleaving;
}
#endif // PRODUCT
+
+/*
+ All the defined signal names for Windows.
+
+ NOTE that not all of these names are accepted by FindSignal!
+
+ For various reasons some of these may be rejected at runtime.
+
+ Here are the names currently accepted by a user of sun.misc.Signal with
+ 1.4.1 (ignoring potential interaction with use of chaining, etc):
+
+ (LIST TBD)
+
+*/
+int os::get_signal_number(const char* name) {
+ static const struct {
+ char* name;
+ int number;
+ } siglabels [] =
+ // derived from version 6.0 VC98/include/signal.h
+ {"ABRT", SIGABRT, // abnormal termination triggered by abort cl
+ "FPE", SIGFPE, // floating point exception
+ "SEGV", SIGSEGV, // segment violation
+ "INT", SIGINT, // interrupt
+ "TERM", SIGTERM, // software term signal from kill
+ "BREAK", SIGBREAK, // Ctrl-Break sequence
+ "ILL", SIGILL}; // illegal instruction
+ for(int i=0;i<sizeof(siglabels)/sizeof(struct siglabel);i++)
+ if(!strcmp(name, siglabels[i].name))
+ return siglabels[i].number;
+ return -1;
+}
+
+// Fast current thread access
+
+int os::win32::_thread_ptr_offset = 0;
+
+static void call_wrapper_dummy() {}
+
+// We need to call the os_exception_wrapper once so that it sets
+// up the offset from FS of the thread pointer.
+void os::win32::initialize_thread_ptr_offset() {
+ os::os_exception_wrapper((java_call_t)call_wrapper_dummy,
+ NULL, NULL, NULL, NULL);
+}
--- a/hotspot/src/os/windows/vm/os_windows.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os/windows/vm/os_windows.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -117,6 +117,17 @@
// filter function to ignore faults on serializations page
static LONG WINAPI serialize_fault_filter(struct _EXCEPTION_POINTERS* e);
+
+ // Fast access to current thread
+protected:
+ static int _thread_ptr_offset;
+private:
+ static void initialize_thread_ptr_offset();
+public:
+ static inline void set_thread_ptr_offset(int offset) {
+ _thread_ptr_offset = offset;
+ }
+ static inline int get_thread_ptr_offset() { return _thread_ptr_offset; }
};
/*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/windows/vm/threadLocalStorage_windows.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/threadLocalStorage.hpp"
+#include <windows.h>
+
+static DWORD _thread_key;
+static bool _initialized = false;
+
+
+void ThreadLocalStorage::init() {
+ assert(!_initialized, "initializing TLS more than once!");
+ _thread_key = TlsAlloc();
+ // If this assert fails we will get a recursive assertion failure
+ // and not see the actual error message or get a hs_err file
+ assert(_thread_key != TLS_OUT_OF_INDEXES, "TlsAlloc failed: out of indices");
+ _initialized = true;
+}
+
+bool ThreadLocalStorage::is_initialized() {
+ return _initialized;
+}
+
+Thread* ThreadLocalStorage::thread() {
+ // If this assert fails we will get a recursive assertion failure
+ // and not see the actual error message or get a hs_err file.
+ // Which most likely indicates we have taken an error path early in
+ // the initialization process, which is using Thread::current without
+ // checking TLS is initialized - see java.cpp vm_exit
+ assert(_initialized, "TLS not initialized yet!");
+ Thread* current = (Thread*) TlsGetValue(_thread_key);
+ assert(current != 0 || GetLastError() == ERROR_SUCCESS,
+ "TlsGetValue failed with error code: %lu", GetLastError());
+ return current;
+}
+
+void ThreadLocalStorage::set_thread(Thread* current) {
+ assert(_initialized, "TLS not initialized yet!");
+ BOOL res = TlsSetValue(_thread_key, current);
+ assert(res, "TlsSetValue failed with error code: %lu", GetLastError());
+}
--- a/hotspot/src/os/windows/vm/thread_windows.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_THREAD_WINDOWS_INLINE_HPP
-#define OS_WINDOWS_VM_THREAD_WINDOWS_INLINE_HPP
-
-#ifndef SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
-#error "This file should only be included from thread.inline.hpp"
-#endif
-
-#include "runtime/thread.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// Contains inlined functions for class Thread and ThreadLocalStorage
-
-inline void ThreadLocalStorage::pd_invalidate_all() { return; }
-
-#endif // OS_WINDOWS_VM_THREAD_WINDOWS_INLINE_HPP
--- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -28,6 +28,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
@@ -167,7 +168,7 @@
ucontext_t* uc = (ucontext_t*) ucVoid;
- Thread* t = ThreadLocalStorage::get_thread_slow(); // slow & steady
+ Thread* t = Thread::current_or_null_safe();
SignalHandlerMark shm(t);
--- a/hotspot/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2014 SAP AG. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "runtime/threadLocalStorage.hpp"
-#include "runtime/thread.hpp"
-
-void ThreadLocalStorage::generate_code_for_get_thread() {
- // Nothing we can do here for user-level thread.
-}
-
-void ThreadLocalStorage::pd_init() {
- // Nothing to do.
-}
-
-void ThreadLocalStorage::pd_set_thread(Thread* thread) {
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
-}
--- a/hotspot/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_AIX_PPC_VM_THREADLS_AIX_PPC_HPP
-#define OS_CPU_AIX_PPC_VM_THREADLS_AIX_PPC_HPP
-
- // Processor dependent parts of ThreadLocalStorage
-
-public:
- static Thread* thread() {
- return (Thread *) os::thread_local_storage_at(thread_index());
- }
-
-#endif // OS_CPU_AIX_PPC_VM_THREADLS_AIX_PPC_HPP
--- a/hotspot/src/os_cpu/aix_ppc/vm/vmStructs_aix_ppc.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/aix_ppc/vm/vmStructs_aix_ppc.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -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.
* Copyright 2012, 2013 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -35,8 +35,7 @@
/******************************/ \
/* Threads (NOTE: incomplete) */ \
/******************************/ \
- nonstatic_field(OSThread, _thread_id, pid_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t)
+ nonstatic_field(OSThread, _thread_id, pthread_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) \
@@ -45,7 +44,6 @@
/* Posix Thread IDs */ \
/**********************/ \
\
- declare_integer_type(pid_t) \
declare_unsigned_integer_type(pthread_t)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
--- a/hotspot/src/os_cpu/bsd_x86/vm/assembler_bsd_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/bsd_x86/vm/assembler_bsd_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, 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
@@ -26,62 +26,7 @@
#include "asm/macroAssembler.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "runtime/os.hpp"
-#include "runtime/threadLocalStorage.hpp"
-#ifndef _LP64
-void MacroAssembler::int3() {
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint)));
-}
-
-void MacroAssembler::get_thread(Register thread) {
- movl(thread, rsp);
- shrl(thread, PAGE_SHIFT);
-
- ExternalAddress tls_base((address)ThreadLocalStorage::sp_map_addr());
- Address index(noreg, thread, Address::times_4);
- ArrayAddress tls(tls_base, index);
-
- movptr(thread, tls);
-}
-#else
void MacroAssembler::int3() {
call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint)));
}
-
-void MacroAssembler::get_thread(Register thread) {
- // call pthread_getspecific
- // void * pthread_getspecific(pthread_key_t key);
- if (thread != rax) {
- push(rax);
- }
- push(rdi);
- push(rsi);
- push(rdx);
- push(rcx);
- push(r8);
- push(r9);
- push(r10);
- // XXX
- mov(r10, rsp);
- andq(rsp, -16);
- push(r10);
- push(r11);
-
- movl(rdi, ThreadLocalStorage::thread_index());
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, pthread_getspecific)));
-
- pop(r11);
- pop(rsp);
- pop(r10);
- pop(r9);
- pop(r8);
- pop(rcx);
- pop(rdx);
- pop(rsi);
- pop(rdi);
- if (thread != rax) {
- mov(thread, rax);
- pop(rax);
- }
-}
-#endif
--- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -27,6 +27,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
@@ -405,7 +406,7 @@
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null_safe();
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run)
--- a/hotspot/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/thread.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// Map stack pointer (%esp) to thread pointer for faster TLS access
-//
-// Here we use a flat table for better performance. Getting current thread
-// is down to one memory access (read _sp_map[%esp>>12]) in generated code
-// and two in runtime code (-fPIC code needs an extra load for _sp_map).
-//
-// This code assumes stack page is not shared by different threads. It works
-// in 32-bit VM when page size is 4K (or a multiple of 4K, if that matters).
-//
-// Notice that _sp_map is allocated in the bss segment, which is ZFOD
-// (zero-fill-on-demand). While it reserves 4M address space upfront,
-// actual memory pages are committed on demand.
-//
-// If an application creates and destroys a lot of threads, usually the
-// stack space freed by a thread will soon get reused by new thread
-// (this is especially true in NPTL or BsdThreads in fixed-stack mode).
-// No memory page in _sp_map is wasted.
-//
-// However, it's still possible that we might end up populating &
-// committing a large fraction of the 4M table over time, but the actual
-// amount of live data in the table could be quite small. The max wastage
-// is less than 4M bytes. If it becomes an issue, we could use madvise()
-// with MADV_DONTNEED to reclaim unused (i.e. all-zero) pages in _sp_map.
-// MADV_DONTNEED on Bsd keeps the virtual memory mapping, but zaps the
-// physical memory page (i.e. similar to MADV_FREE on Solaris).
-
-#ifndef AMD64
-Thread* ThreadLocalStorage::_sp_map[1UL << (SP_BITLENGTH - PAGE_SHIFT)];
-#endif // !AMD64
-
-void ThreadLocalStorage::generate_code_for_get_thread() {
- // nothing we can do here for user-level thread
-}
-
-void ThreadLocalStorage::pd_init() {
-#ifndef AMD64
- assert(align_size_down(os::vm_page_size(), PAGE_SIZE) == os::vm_page_size(),
- "page size must be multiple of PAGE_SIZE");
-#endif // !AMD64
-}
-
-void ThreadLocalStorage::pd_set_thread(Thread* thread) {
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
-
-#ifndef AMD64
- address stack_top = os::current_stack_base();
- size_t stack_size = os::current_stack_size();
-
- for (address p = stack_top - stack_size; p < stack_top; p += PAGE_SIZE) {
- // pd_set_thread() is called with non-NULL value when a new thread is
- // created/attached, or with NULL value when a thread is about to exit.
- // If both "thread" and the corresponding _sp_map[] entry are non-NULL,
- // they should have the same value. Otherwise it might indicate that the
- // stack page is shared by multiple threads. However, a more likely cause
- // for this assertion to fail is that an attached thread exited without
- // detaching itself from VM, which is a program error and could cause VM
- // to crash.
- assert(thread == NULL || _sp_map[(uintptr_t)p >> PAGE_SHIFT] == NULL ||
- thread == _sp_map[(uintptr_t)p >> PAGE_SHIFT],
- "thread exited without detaching from VM??");
- _sp_map[(uintptr_t)p >> PAGE_SHIFT] = thread;
- }
-#endif // !AMD64
-}
--- a/hotspot/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_CPU_BSD_X86_VM_THREADLS_BSD_X86_HPP
-#define OS_CPU_BSD_X86_VM_THREADLS_BSD_X86_HPP
-
- // Processor dependent parts of ThreadLocalStorage
-
-#ifndef AMD64
- // map stack pointer to thread pointer - see notes in threadLS_bsd_x86.cpp
- #define SP_BITLENGTH 32
-#ifndef PAGE_SHIFT
- #define PAGE_SHIFT 12
- #define PAGE_SIZE (1UL << PAGE_SHIFT)
-#endif
- static Thread* _sp_map[1UL << (SP_BITLENGTH - PAGE_SHIFT)];
-#endif // !AMD64
-
-public:
-
-#ifndef AMD64
- static Thread** sp_map_addr() { return _sp_map; }
-#endif // !AMD64
-
- static Thread* thread() {
-#ifdef AMD64
- return (Thread*) os::thread_local_storage_at(thread_index());
-#else
- uintptr_t sp;
- __asm__ volatile ("movl %%esp, %0" : "=r" (sp));
- return _sp_map[sp >> PAGE_SHIFT];
-#endif // AMD64
- }
-
-#endif // OS_CPU_BSD_X86_VM_THREADLS_BSD_X86_HPP
--- a/hotspot/src/os_cpu/bsd_zero/vm/assembler_bsd_zero.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/bsd_zero/vm/assembler_bsd_zero.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright 2009 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -23,10 +23,4 @@
*
*/
-#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_zero.inline.hpp"
-#include "runtime/os.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
// This file is intentionally empty
--- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -134,7 +134,7 @@
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null_safe();
SignalHandlerMark shm(t);
--- a/hotspot/src/os_cpu/bsd_zero/vm/threadLS_bsd_zero.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2007 Red Hat, Inc.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/thread.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-void ThreadLocalStorage::generate_code_for_get_thread() {
- // nothing to do
-}
-
-void ThreadLocalStorage::pd_init() {
- // nothing to do
-}
-
-void ThreadLocalStorage::pd_set_thread(Thread* thread) {
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
-}
--- a/hotspot/src/os_cpu/bsd_zero/vm/threadLS_bsd_zero.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_CPU_BSD_ZERO_VM_THREADLS_BSD_ZERO_HPP
-#define OS_CPU_BSD_ZERO_VM_THREADLS_BSD_ZERO_HPP
-
-// Processor dependent parts of ThreadLocalStorage
-
- public:
- static Thread* thread() {
- return (Thread*) os::thread_local_storage_at(thread_index());
- }
-
-#endif // OS_CPU_BSD_ZERO_VM_THREADLS_BSD_ZERO_HPP
--- a/hotspot/src/os_cpu/linux_aarch64/vm/assembler_linux_aarch64.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/assembler_linux_aarch64.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -23,32 +23,6 @@
*
*/
-#include "precompiled.hpp"
-#include "asm/macroAssembler.hpp"
-#include "asm/macroAssembler.inline.hpp"
-#include "runtime/os.hpp"
-#include "runtime/threadLocalStorage.hpp"
+// nothing required here
-// get_thread can be called anywhere inside generated code so we need
-// to save whatever non-callee save context might get clobbered by the
-// call to the C thread_local lookup call or, indeed, the call setup
-// code. x86 appears to save C arg registers.
-
-void MacroAssembler::get_thread(Register dst) {
- // call pthread_getspecific
- // void * pthread_getspecific(pthread_key_t key);
-
- // Save all call-clobbered regs except dst, plus r19 and r20.
- RegSet saved_regs = RegSet::range(r0, r20) + lr - dst;
- push(saved_regs, sp);
- mov(c_rarg0, ThreadLocalStorage::thread_index());
- mov(r19, CAST_FROM_FN_PTR(address, pthread_getspecific));
- blrt(r19, 1, 0, 1);
- if (dst != c_rarg0) {
- mov(dst, c_rarg0);
- }
- // restore pushed registers
- pop(saved_regs, sp);
-}
-
--- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -28,6 +28,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "code/nativeInst.hpp"
@@ -249,7 +250,7 @@
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null_safe();
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run)
--- a/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, Red Hat Inc. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/threadLocalStorage.hpp"
-#include "runtime/thread.inline.hpp"
-
-void ThreadLocalStorage::generate_code_for_get_thread() {
- // nothing we can do here for user-level thread
-}
-
-void ThreadLocalStorage::pd_init() {
-}
-
-__thread Thread *aarch64_currentThread;
-
-void ThreadLocalStorage::pd_set_thread(Thread* thread) {
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
- aarch64_currentThread = thread;
-}
--- a/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, Red Hat Inc. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_CPU_LINUX_AARCH64_VM_THREADLS_LINUX_AARCH64_HPP
-#define OS_CPU_LINUX_AARCH64_VM_THREADLS_LINUX_AARCH64_HPP
-
- // Processor dependent parts of ThreadLocalStorage
-
-public:
-
- static Thread *thread() {
- return aarch64_currentThread;
- }
-
-#endif // OS_CPU_LINUX_AARCH64_VM_THREADLS_LINUX_AARCH64_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.s Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,44 @@
+// Copyright (c) 2015, Red Hat Inc. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+
+ // JavaThread::aarch64_get_thread_helper()
+ //
+ // Return the current thread pointer in x0.
+ // Clobber x1, flags.
+ // All other registers are preserved,
+
+ .global _ZN10JavaThread25aarch64_get_thread_helperEv
+ .type _ZN10JavaThread25aarch64_get_thread_helperEv, %function
+
+_ZN10JavaThread25aarch64_get_thread_helperEv:
+ stp x29, x30, [sp, -16]!
+ adrp x0, :tlsdesc:_ZN6Thread12_thr_currentE
+ ldr x1, [x0, #:tlsdesc_lo12:_ZN6Thread12_thr_currentE]
+ add x0, x0, :tlsdesc_lo12:_ZN6Thread12_thr_currentE
+ .tlsdesccall _ZN6Thread12_thr_currentE
+ blr x1
+ mrs x1, tpidr_el0
+ add x0, x1, x0
+ ldr x0, [x0]
+ ldp x29, x30, [sp], 16
+ ret
+
+ .size _ZN10JavaThread25aarch64_get_thread_helperEv, .-_ZN10JavaThread25aarch64_get_thread_helperEv
--- a/hotspot/src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -77,6 +77,8 @@
bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava);
public:
+ static Thread *aarch64_get_thread_helper();
+
// These routines are only used on cpu architectures that
// have separate register stacks (Itanium).
static bool register_stack_overflow() { return false; }
--- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -28,6 +28,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
@@ -182,7 +183,7 @@
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null_safe();
SignalHandlerMark shm(t);
--- a/hotspot/src/os_cpu/linux_ppc/vm/threadLS_linux_ppc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-void ThreadLocalStorage::generate_code_for_get_thread() {
- // nothing we can do here for user-level thread
-}
-
-void ThreadLocalStorage::pd_init() {
- // Nothing to do
-}
-
-void ThreadLocalStorage::pd_set_thread(Thread* thread) {
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
-}
--- a/hotspot/src/os_cpu/linux_ppc/vm/threadLS_linux_ppc.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_LINUX_PPC_VM_THREADLS_LINUX_PPC_HPP
-#define OS_CPU_LINUX_PPC_VM_THREADLS_LINUX_PPC_HPP
-
- // Processor dependent parts of ThreadLocalStorage
-
-public:
- static Thread* thread() {
- return (Thread *) os::thread_local_storage_at(thread_index());
- }
-
-#endif // OS_CPU_LINUX_PPC_VM_THREADLS_LINUX_PPC_HPP
--- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -27,6 +27,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
@@ -347,9 +348,9 @@
}
void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) {
- sigcontext_t* ctx = (sigcontext_t*) uc;
- SIG_PC(ctx) = (intptr_t)addr;
- SIG_NPC(ctx) = (intptr_t)(addr+4);
+ sigcontext* ctx = (sigcontext*) uc;
+ SIG_PC(ctx) = (intptr_t)pc;
+ SIG_NPC(ctx) = (intptr_t)(pc+4);
}
intptr_t* os::Linux::ucontext_get_sp(ucontext_t *uc) {
@@ -541,7 +542,7 @@
ucontext_t* ucFake = (ucontext_t*) ucVoid;
sigcontext* uc = (sigcontext*)ucVoid;
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null_safe();
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run)
@@ -695,6 +696,7 @@
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
+ return false;
}
void os::Linux::init_thread_fpu_state(void) {
--- a/hotspot/src/os_cpu/linux_sparc/vm/threadLS_linux_sparc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/thread.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-void ThreadLocalStorage::generate_code_for_get_thread() {
-}
-
-void ThreadLocalStorage::pd_init() {
- // Nothing to do
-}
-
-void ThreadLocalStorage::pd_set_thread(Thread* thread) {
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
-}
--- a/hotspot/src/os_cpu/linux_sparc/vm/threadLS_linux_sparc.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_CPU_LINUX_SPARC_VM_THREADLS_LINUX_SPARC_HPP
-#define OS_CPU_LINUX_SPARC_VM_THREADLS_LINUX_SPARC_HPP
-
-public:
- static Thread* thread() {
- return (Thread*) os::thread_local_storage_at(thread_index());
- }
-
-#endif // OS_CPU_LINUX_SPARC_VM_THREADLS_LINUX_SPARC_HPP
--- a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, 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
@@ -26,85 +26,7 @@
#include "asm/macroAssembler.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "runtime/os.hpp"
-#include "runtime/threadLocalStorage.hpp"
-#ifndef _LP64
void MacroAssembler::int3() {
call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint)));
}
-
-#ifdef MINIMIZE_RAM_USAGE
-
-void MacroAssembler::get_thread(Register thread) {
- // call pthread_getspecific
- // void * pthread_getspecific(pthread_key_t key);
- if (thread != rax) push(rax);
- push(rcx);
- push(rdx);
-
- push(ThreadLocalStorage::thread_index());
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, pthread_getspecific)));
- increment(rsp, wordSize);
-
- pop(rdx);
- pop(rcx);
- if (thread != rax) {
- mov(thread, rax);
- pop(rax);
- }
-}
-
-#else
-void MacroAssembler::get_thread(Register thread) {
- movl(thread, rsp);
- shrl(thread, PAGE_SHIFT);
-
- ExternalAddress tls_base((address)ThreadLocalStorage::sp_map_addr());
- Address index(noreg, thread, Address::times_4);
- ArrayAddress tls(tls_base, index);
-
- movptr(thread, tls);
-}
-#endif // MINIMIZE_RAM_USAGE
-#else
-void MacroAssembler::int3() {
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint)));
-}
-
-void MacroAssembler::get_thread(Register thread) {
- // call pthread_getspecific
- // void * pthread_getspecific(pthread_key_t key);
- if (thread != rax) {
- push(rax);
- }
- push(rdi);
- push(rsi);
- push(rdx);
- push(rcx);
- push(r8);
- push(r9);
- push(r10);
- // XXX
- mov(r10, rsp);
- andq(rsp, -16);
- push(r10);
- push(r11);
-
- movl(rdi, ThreadLocalStorage::thread_index());
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, pthread_getspecific)));
-
- pop(r11);
- pop(rsp);
- pop(r10);
- pop(r9);
- pop(r8);
- pop(rcx);
- pop(rdx);
- pop(rsi);
- pop(rdi);
- if (thread != rax) {
- mov(thread, rax);
- pop(rax);
- }
-}
-#endif
--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -27,6 +27,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
@@ -221,7 +222,7 @@
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null_safe();
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run)
--- a/hotspot/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/thread.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// Map stack pointer (%esp) to thread pointer for faster TLS access
-//
-// Here we use a flat table for better performance. Getting current thread
-// is down to one memory access (read _sp_map[%esp>>12]) in generated code
-// and two in runtime code (-fPIC code needs an extra load for _sp_map).
-//
-// This code assumes stack page is not shared by different threads. It works
-// in 32-bit VM when page size is 4K (or a multiple of 4K, if that matters).
-//
-// Notice that _sp_map is allocated in the bss segment, which is ZFOD
-// (zero-fill-on-demand). While it reserves 4M address space upfront,
-// actual memory pages are committed on demand.
-//
-// If an application creates and destroys a lot of threads, usually the
-// stack space freed by a thread will soon get reused by new thread.
-// No memory page in _sp_map is wasted.
-//
-// However, it's still possible that we might end up populating &
-// committing a large fraction of the 4M table over time, but the actual
-// amount of live data in the table could be quite small. The max wastage
-// is less than 4M bytes. If it becomes an issue, we could use madvise()
-// with MADV_DONTNEED to reclaim unused (i.e. all-zero) pages in _sp_map.
-// MADV_DONTNEED on Linux keeps the virtual memory mapping, but zaps the
-// physical memory page (i.e. similar to MADV_FREE on Solaris).
-
-#if !defined(AMD64) && !defined(MINIMIZE_RAM_USAGE)
-Thread* ThreadLocalStorage::_sp_map[1UL << (SP_BITLENGTH - PAGE_SHIFT)];
-
-void ThreadLocalStorage::generate_code_for_get_thread() {
- // nothing we can do here for user-level thread
-}
-
-void ThreadLocalStorage::pd_init() {
- assert(align_size_down(os::vm_page_size(), PAGE_SIZE) == os::vm_page_size(),
- "page size must be multiple of PAGE_SIZE");
-}
-
-void ThreadLocalStorage::pd_set_thread(Thread* thread) {
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
- address stack_top = os::current_stack_base();
- size_t stack_size = os::current_stack_size();
-
- for (address p = stack_top - stack_size; p < stack_top; p += PAGE_SIZE) {
- // pd_set_thread() is called with non-NULL value when a new thread is
- // created/attached, or with NULL value when a thread is about to exit.
- // If both "thread" and the corresponding _sp_map[] entry are non-NULL,
- // they should have the same value. Otherwise it might indicate that the
- // stack page is shared by multiple threads. However, a more likely cause
- // for this assertion to fail is that an attached thread exited without
- // detaching itself from VM, which is a program error and could cause VM
- // to crash.
- assert(thread == NULL || _sp_map[(uintptr_t)p >> PAGE_SHIFT] == NULL ||
- thread == _sp_map[(uintptr_t)p >> PAGE_SHIFT],
- "thread exited without detaching from VM??");
- _sp_map[(uintptr_t)p >> PAGE_SHIFT] = thread;
- }
-}
-#else
-
-void ThreadLocalStorage::generate_code_for_get_thread() {
- // nothing we can do here for user-level thread
-}
-
-void ThreadLocalStorage::pd_init() {
-}
-
-void ThreadLocalStorage::pd_set_thread(Thread* thread) {
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
-}
-#endif // !AMD64 && !MINIMIZE_RAM_USAGE
--- a/hotspot/src/os_cpu/linux_x86/vm/threadLS_linux_x86.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_CPU_LINUX_X86_VM_THREADLS_LINUX_X86_HPP
-#define OS_CPU_LINUX_X86_VM_THREADLS_LINUX_X86_HPP
-
- // Processor dependent parts of ThreadLocalStorage
-
-#if !defined(AMD64) && !defined(MINIMIZE_RAM_USAGE)
-
- // map stack pointer to thread pointer - see notes in threadLS_linux_x86.cpp
- #define SP_BITLENGTH 32
- #define PAGE_SHIFT 12
- #define PAGE_SIZE (1UL << PAGE_SHIFT)
- static Thread* _sp_map[1UL << (SP_BITLENGTH - PAGE_SHIFT)];
-
-public:
-
- static Thread** sp_map_addr() { return _sp_map; }
-
- static Thread* thread() {
- uintptr_t sp;
- __asm__ volatile ("movl %%esp, %0" : "=r" (sp));
- return _sp_map[sp >> PAGE_SHIFT];
- }
-
-#else
-
-public:
-
- static Thread* thread() {
- return (Thread*) os::thread_local_storage_at(thread_index());
- }
-
-#endif // AMD64 || MINIMIZE_RAM_USAGE
-
-#endif // OS_CPU_LINUX_X86_VM_THREADLS_LINUX_X86_HPP
--- a/hotspot/src/os_cpu/linux_zero/vm/assembler_linux_zero.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/linux_zero/vm/assembler_linux_zero.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright 2009 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -23,10 +23,4 @@
*
*/
-#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_zero.inline.hpp"
-#include "runtime/os.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
// This file is intentionally empty
--- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -125,7 +125,7 @@
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null_safe();
SignalHandlerMark shm(t);
--- a/hotspot/src/os_cpu/linux_zero/vm/threadLS_linux_zero.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2007 Red Hat, Inc.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/thread.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-void ThreadLocalStorage::generate_code_for_get_thread() {
- // nothing to do
-}
-
-void ThreadLocalStorage::pd_init() {
- // nothing to do
-}
-
-void ThreadLocalStorage::pd_set_thread(Thread* thread) {
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
-}
--- a/hotspot/src/os_cpu/linux_zero/vm/threadLS_linux_zero.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_CPU_LINUX_ZERO_VM_THREADLS_LINUX_ZERO_HPP
-#define OS_CPU_LINUX_ZERO_VM_THREADLS_LINUX_ZERO_HPP
-
-// Processor dependent parts of ThreadLocalStorage
-
- public:
- static Thread* thread() {
- return (Thread*) os::thread_local_storage_at(thread_index());
- }
-
-#endif // OS_CPU_LINUX_ZERO_VM_THREADLS_LINUX_ZERO_HPP
--- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -290,7 +290,7 @@
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null_safe();
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run)
@@ -551,6 +551,7 @@
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
+ return false;
}
void os::print_context(outputStream *st, void *context) {
--- a/hotspot/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/thread.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// True thread-local variable
-__thread Thread * ThreadLocalStorage::_thr_current = NULL;
-
-// Implementations needed to support the shared API
-
-void ThreadLocalStorage::pd_invalidate_all() {} // nothing to do
-
-bool ThreadLocalStorage::_initialized = false;
-
-void ThreadLocalStorage::init() {
- _initialized = true;
-}
-
-bool ThreadLocalStorage::is_initialized() {
- return _initialized;
-}
-
-Thread* ThreadLocalStorage::get_thread_slow() {
- return thread();
-}
-
-extern "C" Thread* get_thread() {
- return ThreadLocalStorage::thread();
-}
--- a/hotspot/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_CPU_SOLARIS_SPARC_VM_THREADLS_SOLARIS_SPARC_HPP
-#define OS_CPU_SOLARIS_SPARC_VM_THREADLS_SOLARIS_SPARC_HPP
-
-// Solaris specific implementation involves simple, direct use
-// of a compiler-based thread-local variable
-
-private:
- static __thread Thread * _thr_current;
-
- static bool _initialized; // needed for shared API
-
-public:
- static inline Thread* thread();
-
-#endif // OS_CPU_SOLARIS_SPARC_VM_THREADLS_SOLARIS_SPARC_HPP
--- a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -25,8 +25,6 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "runtime/os.hpp"
-#include "runtime/threadLocalStorage.hpp"
-#include "runtime/thread.inline.hpp"
void MacroAssembler::int3() {
push(rax);
@@ -37,33 +35,3 @@
pop(rdx);
pop(rax);
}
-
-// This is simply a call to ThreadLocalStorage::thread()
-void MacroAssembler::get_thread(Register thread) {
- if (thread != rax) {
- push(rax);
- }
- push(rdi);
- push(rsi);
- push(rdx);
- push(rcx);
- push(r8);
- push(r9);
- push(r10);
- push(r11);
-
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, ThreadLocalStorage::thread)));
-
- pop(r11);
- pop(r10);
- pop(r9);
- pop(r8);
- pop(rcx);
- pop(rdx);
- pop(rsi);
- pop(rdi);
- if (thread != rax) {
- movl(thread, rax);
- pop(rax);
- }
-}
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -27,6 +27,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
@@ -346,7 +347,7 @@
}
#endif // !AMD64
- Thread* t = ThreadLocalStorage::get_thread_slow(); // slow & steady
+ Thread* t = Thread::current_or_null_safe();
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run)
--- a/hotspot/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/thread.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// True thread-local variable
-__thread Thread * ThreadLocalStorage::_thr_current = NULL;
-
-// Implementations needed to support the shared API
-
-void ThreadLocalStorage::pd_invalidate_all() {} // nothing to do
-
-bool ThreadLocalStorage::_initialized = false;
-
-void ThreadLocalStorage::init() {
- _initialized = true;
-}
-
-bool ThreadLocalStorage::is_initialized() {
- return _initialized;
-}
-
-Thread* ThreadLocalStorage::get_thread_slow() {
- return thread();
-}
-
-extern "C" Thread* get_thread() {
- return ThreadLocalStorage::thread();
-}
--- a/hotspot/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_CPU_SOLARIS_X86_VM_THREADLS_SOLARIS_X86_HPP
-#define OS_CPU_SOLARIS_X86_VM_THREADLS_SOLARIS_X86_HPP
-
-// Solaris specific implementation involves simple, direct use
-// of a compiler-based thread-local variable
-
-private:
- static __thread Thread * _thr_current;
-
- static bool _initialized; // needed for shared API
-
-public:
- static inline Thread* thread();
-
-#endif // OS_CPU_SOLARIS_X86_VM_THREADLS_SOLARIS_X86_HPP
--- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, 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
@@ -26,8 +26,6 @@
#include "asm/macroAssembler.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "runtime/os.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
void MacroAssembler::int3() {
emit_int8((unsigned char)0xCC);
@@ -58,44 +56,11 @@
prefix(FS_segment);
movptr(thread, null);
- assert(ThreadLocalStorage::get_thread_ptr_offset() != 0,
+ assert(os::win32::get_thread_ptr_offset() != 0,
"Thread Pointer Offset has not been initialized");
- movl(thread, Address(thread, ThreadLocalStorage::get_thread_ptr_offset()));
+ movl(thread, Address(thread, os::win32::get_thread_ptr_offset()));
}
-#else
-// call (Thread*)TlsGetValue(thread_index());
-void MacroAssembler::get_thread(Register thread) {
- if (thread != rax) {
- push(rax);
- }
- push(rdi);
- push(rsi);
- push(rdx);
- push(rcx);
- push(r8);
- push(r9);
- push(r10);
- // XXX
- mov(r10, rsp);
- andq(rsp, -16);
- push(r10);
- push(r11);
- movl(c_rarg0, ThreadLocalStorage::thread_index());
- call(RuntimeAddress((address)TlsGetValue));
+// #else - use shared x86 implementation in cpu/x86/vm/macroAssembler_x86.cpp
- pop(r11);
- pop(rsp);
- pop(r10);
- pop(r9);
- pop(r8);
- pop(rcx);
- pop(rdx);
- pop(rsi);
- pop(rdi);
- if (thread != rax) {
- mov(thread, rax);
- pop(rax);
- }
-}
#endif
--- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -85,14 +85,14 @@
//
volatile Thread* wrapperthread = thread;
- if ( ThreadLocalStorage::get_thread_ptr_offset() == 0 ) {
+ if (os::win32::get_thread_ptr_offset() == 0) {
int thread_ptr_offset;
__asm {
lea eax, dword ptr wrapperthread;
sub eax, dword ptr FS:[0H];
mov thread_ptr_offset, eax
};
- ThreadLocalStorage::set_thread_ptr_offset(thread_ptr_offset);
+ os::win32::set_thread_ptr_offset(thread_ptr_offset);
}
#ifdef ASSERT
// Verify that the offset hasn't changed since we initally captured
@@ -105,7 +105,7 @@
sub eax, dword ptr FS:[0H];
mov test_thread_ptr_offset, eax
};
- assert(test_thread_ptr_offset == ThreadLocalStorage::get_thread_ptr_offset(),
+ assert(test_thread_ptr_offset == os::win32::get_thread_ptr_offset(),
"thread pointer offset from SEH changed");
}
#endif // ASSERT
--- a/hotspot/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/thread.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// Provides an entry point we can link against and
-// a buffer we can emit code into. The buffer is
-// filled by ThreadLocalStorage::generate_code_for_get_thread
-// and called from ThreadLocalStorage::thread()
-
-int ThreadLocalStorage::_thread_ptr_offset = 0;
-
-static void call_wrapper_dummy() {}
-
-// We need to call the os_exception_wrapper once so that it sets
-// up the offset from FS of the thread pointer.
-void ThreadLocalStorage::generate_code_for_get_thread() {
- os::os_exception_wrapper( (java_call_t)call_wrapper_dummy,
- NULL, NULL, NULL, NULL);
-}
-
-void ThreadLocalStorage::pd_init() { }
-
-void ThreadLocalStorage::pd_set_thread(Thread* thread) {
- os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
-}
--- a/hotspot/src/os_cpu/windows_x86/vm/threadLS_windows_x86.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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_CPU_WINDOWS_X86_VM_THREADLS_WINDOWS_X86_HPP
-#define OS_CPU_WINDOWS_X86_VM_THREADLS_WINDOWS_X86_HPP
-
-// Processor dependent parts of ThreadLocalStorage
-
-protected:
-
- static int _thread_ptr_offset;
-
-public:
-
- // Java Thread
- static inline Thread* thread() {
- return (Thread*)TlsGetValue(thread_index());
- }
-
- static inline Thread* get_thread() {
- return (Thread*)TlsGetValue(thread_index());
- }
-
- static inline void set_thread_ptr_offset( int offset ) { _thread_ptr_offset = offset; }
-
- static inline int get_thread_ptr_offset() { return _thread_ptr_offset; }
-
-#endif // OS_CPU_WINDOWS_X86_VM_THREADLS_WINDOWS_X86_HPP
--- a/hotspot/src/share/vm/classfile/classFileError.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/classFileError.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -33,28 +33,39 @@
PRAGMA_DIAG_PUSH
PRAGMA_FORMAT_NONLITERAL_IGNORED
-void ClassFileParser::classfile_parse_error(const char* msg, TRAPS) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
- msg, _class_name->as_C_string());
+void ClassFileParser::classfile_parse_error(const char* msg, TRAPS) const {
+ assert(_class_name != NULL, "invariant");
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
+ msg, _class_name->as_C_string());
+}
+
+void ClassFileParser::classfile_parse_error(const char* msg,
+ int index,
+ TRAPS) const {
+ assert(_class_name != NULL, "invariant");
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
+ msg, index, _class_name->as_C_string());
}
-void ClassFileParser::classfile_parse_error(const char* msg, int index, TRAPS) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
- msg, index, _class_name->as_C_string());
+void ClassFileParser::classfile_parse_error(const char* msg,
+ const char* name,
+ TRAPS) const {
+ assert(_class_name != NULL, "invariant");
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
+ msg, name, _class_name->as_C_string());
}
-void ClassFileParser::classfile_parse_error(const char* msg, const char *name, TRAPS) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
- msg, name, _class_name->as_C_string());
-}
-
-void ClassFileParser::classfile_parse_error(const char* msg, int index, const char *name, TRAPS) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
- msg, index, name, _class_name->as_C_string());
+void ClassFileParser::classfile_parse_error(const char* msg,
+ int index,
+ const char* name,
+ TRAPS) const {
+ assert(_class_name != NULL, "invariant");
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
+ msg, index, name, _class_name->as_C_string());
}
PRAGMA_DIAG_POP
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -21,9 +21,9 @@
* questions.
*
*/
-
#include "precompiled.hpp"
#include "classfile/classFileParser.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/defaultMethods.hpp"
@@ -37,16 +37,17 @@
#include "memory/allocation.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/oopFactory.hpp"
-#include "memory/referenceType.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp"
-#include "oops/constantPool.hpp"
+#include "oops/annotations.hpp"
#include "oops/fieldStreams.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/klass.inline.hpp"
#include "oops/klassVtable.hpp"
+#include "oops/metadata.hpp"
#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "prims/jvm.h"
#include "prims/jvmtiExport.hpp"
@@ -58,6 +59,7 @@
#include "runtime/timer.hpp"
#include "services/classLoadingService.hpp"
#include "services/threadService.hpp"
+#include "trace/traceMacros.hpp"
#include "utilities/array.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/globalDefinitions.hpp"
@@ -98,20 +100,25 @@
// Extension method support.
#define JAVA_8_VERSION 52
-void ClassFileParser::parse_constant_pool_entries(int length, TRAPS) {
+enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names
+
+void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const stream,
+ ConstantPool* cp,
+ const int length,
+ TRAPS) {
+ assert(stream != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+
// Use a local copy of ClassFileStream. It helps the C++ compiler to optimize
// this function (_current can be allocated in a register, with scalar
// replacement of aggregates). The _current pointer is copied back to
// stream() when this function returns. DON'T call another method within
// this method that uses stream().
- ClassFileStream* cfs0 = stream();
- ClassFileStream cfs1 = *cfs0;
- ClassFileStream* cfs = &cfs1;
-#ifdef ASSERT
- assert(cfs->allocated_on_stack(),"should be local");
- u1* old_current = cfs0->current();
-#endif
- Handle class_loader(THREAD, _loader_data->class_loader());
+ const ClassFileStream cfs1 = *stream;
+ const ClassFileStream* const cfs = &cfs1;
+
+ assert(cfs->allocated_on_stack(), "should be local");
+ debug_only(const u1* const old_current = stream->current();)
// Used for batching symbol allocations.
const char* names[SymbolTable::symbol_alloc_batch_size];
@@ -125,48 +132,43 @@
// Each of the following case guarantees one more byte in the stream
// for the following tag or the access_flags following constant pool,
// so we don't need bounds-check for reading tag.
- u1 tag = cfs->get_u1_fast();
+ const u1 tag = cfs->get_u1_fast();
switch (tag) {
- case JVM_CONSTANT_Class :
- {
- cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags
- u2 name_index = cfs->get_u2_fast();
- _cp->klass_index_at_put(index, name_index);
- }
+ case JVM_CONSTANT_Class : {
+ cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags
+ const u2 name_index = cfs->get_u2_fast();
+ cp->klass_index_at_put(index, name_index);
break;
- case JVM_CONSTANT_Fieldref :
- {
- cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
- u2 class_index = cfs->get_u2_fast();
- u2 name_and_type_index = cfs->get_u2_fast();
- _cp->field_at_put(index, class_index, name_and_type_index);
- }
+ }
+ case JVM_CONSTANT_Fieldref: {
+ cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
+ const u2 class_index = cfs->get_u2_fast();
+ const u2 name_and_type_index = cfs->get_u2_fast();
+ cp->field_at_put(index, class_index, name_and_type_index);
break;
- case JVM_CONSTANT_Methodref :
- {
- cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
- u2 class_index = cfs->get_u2_fast();
- u2 name_and_type_index = cfs->get_u2_fast();
- _cp->method_at_put(index, class_index, name_and_type_index);
- }
+ }
+ case JVM_CONSTANT_Methodref: {
+ cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
+ const u2 class_index = cfs->get_u2_fast();
+ const u2 name_and_type_index = cfs->get_u2_fast();
+ cp->method_at_put(index, class_index, name_and_type_index);
break;
- case JVM_CONSTANT_InterfaceMethodref :
- {
- cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
- u2 class_index = cfs->get_u2_fast();
- u2 name_and_type_index = cfs->get_u2_fast();
- _cp->interface_method_at_put(index, class_index, name_and_type_index);
- }
+ }
+ case JVM_CONSTANT_InterfaceMethodref: {
+ cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
+ const u2 class_index = cfs->get_u2_fast();
+ const u2 name_and_type_index = cfs->get_u2_fast();
+ cp->interface_method_at_put(index, class_index, name_and_type_index);
break;
- case JVM_CONSTANT_String :
- {
- cfs->guarantee_more(3, CHECK); // string_index, tag/access_flags
- u2 string_index = cfs->get_u2_fast();
- _cp->string_index_at_put(index, string_index);
- }
+ }
+ case JVM_CONSTANT_String : {
+ cfs->guarantee_more(3, CHECK); // string_index, tag/access_flags
+ const u2 string_index = cfs->get_u2_fast();
+ cp->string_index_at_put(index, string_index);
break;
+ }
case JVM_CONSTANT_MethodHandle :
- case JVM_CONSTANT_MethodType :
+ case JVM_CONSTANT_MethodType: {
if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
classfile_parse_error(
"Class file version does not support constant tag %u in class file %s",
@@ -174,379 +176,401 @@
}
if (tag == JVM_CONSTANT_MethodHandle) {
cfs->guarantee_more(4, CHECK); // ref_kind, method_index, tag/access_flags
- u1 ref_kind = cfs->get_u1_fast();
- u2 method_index = cfs->get_u2_fast();
- _cp->method_handle_index_at_put(index, ref_kind, method_index);
- } else if (tag == JVM_CONSTANT_MethodType) {
+ const u1 ref_kind = cfs->get_u1_fast();
+ const u2 method_index = cfs->get_u2_fast();
+ cp->method_handle_index_at_put(index, ref_kind, method_index);
+ }
+ else if (tag == JVM_CONSTANT_MethodType) {
cfs->guarantee_more(3, CHECK); // signature_index, tag/access_flags
- u2 signature_index = cfs->get_u2_fast();
- _cp->method_type_index_at_put(index, signature_index);
- } else {
+ const u2 signature_index = cfs->get_u2_fast();
+ cp->method_type_index_at_put(index, signature_index);
+ }
+ else {
ShouldNotReachHere();
}
break;
- case JVM_CONSTANT_InvokeDynamic :
- {
- if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
- classfile_parse_error(
+ }
+ case JVM_CONSTANT_InvokeDynamic : {
+ if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
+ classfile_parse_error(
"Class file version does not support constant tag %u in class file %s",
tag, CHECK);
- }
- cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags
- u2 bootstrap_specifier_index = cfs->get_u2_fast();
- u2 name_and_type_index = cfs->get_u2_fast();
- if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index)
- _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later
- _cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index);
+ }
+ cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags
+ const u2 bootstrap_specifier_index = cfs->get_u2_fast();
+ const u2 name_and_type_index = cfs->get_u2_fast();
+ if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) {
+ _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later
}
+ cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index);
break;
- case JVM_CONSTANT_Integer :
- {
- cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags
- u4 bytes = cfs->get_u4_fast();
- _cp->int_at_put(index, (jint) bytes);
- }
+ }
+ case JVM_CONSTANT_Integer: {
+ cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags
+ const u4 bytes = cfs->get_u4_fast();
+ cp->int_at_put(index, (jint)bytes);
break;
- case JVM_CONSTANT_Float :
- {
- cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags
- u4 bytes = cfs->get_u4_fast();
- _cp->float_at_put(index, *(jfloat*)&bytes);
- }
+ }
+ case JVM_CONSTANT_Float: {
+ cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags
+ const u4 bytes = cfs->get_u4_fast();
+ cp->float_at_put(index, *(jfloat*)&bytes);
break;
- case JVM_CONSTANT_Long :
+ }
+ case JVM_CONSTANT_Long: {
// A mangled type might cause you to overrun allocated memory
- guarantee_property(index+1 < length,
+ guarantee_property(index + 1 < length,
"Invalid constant pool entry %u in class file %s",
- index, CHECK);
- {
- cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags
- u8 bytes = cfs->get_u8_fast();
- _cp->long_at_put(index, bytes);
- }
+ index,
+ CHECK);
+ cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags
+ const u8 bytes = cfs->get_u8_fast();
+ cp->long_at_put(index, bytes);
index++; // Skip entry following eigth-byte constant, see JVM book p. 98
break;
- case JVM_CONSTANT_Double :
+ }
+ case JVM_CONSTANT_Double: {
// A mangled type might cause you to overrun allocated memory
guarantee_property(index+1 < length,
"Invalid constant pool entry %u in class file %s",
- index, CHECK);
- {
- cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags
- u8 bytes = cfs->get_u8_fast();
- _cp->double_at_put(index, *(jdouble*)&bytes);
- }
+ index,
+ CHECK);
+ cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags
+ const u8 bytes = cfs->get_u8_fast();
+ cp->double_at_put(index, *(jdouble*)&bytes);
index++; // Skip entry following eigth-byte constant, see JVM book p. 98
break;
- case JVM_CONSTANT_NameAndType :
- {
- cfs->guarantee_more(5, CHECK); // name_index, signature_index, tag/access_flags
- u2 name_index = cfs->get_u2_fast();
- u2 signature_index = cfs->get_u2_fast();
- _cp->name_and_type_at_put(index, name_index, signature_index);
+ }
+ case JVM_CONSTANT_NameAndType: {
+ cfs->guarantee_more(5, CHECK); // name_index, signature_index, tag/access_flags
+ const u2 name_index = cfs->get_u2_fast();
+ const u2 signature_index = cfs->get_u2_fast();
+ cp->name_and_type_at_put(index, name_index, signature_index);
+ break;
+ }
+ case JVM_CONSTANT_Utf8 : {
+ cfs->guarantee_more(2, CHECK); // utf8_length
+ u2 utf8_length = cfs->get_u2_fast();
+ const u1* utf8_buffer = cfs->get_u1_buffer();
+ assert(utf8_buffer != NULL, "null utf8 buffer");
+ // Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward.
+ cfs->guarantee_more(utf8_length+1, CHECK); // utf8 string, tag/access_flags
+ cfs->skip_u1_fast(utf8_length);
+
+ // Before storing the symbol, make sure it's legal
+ if (_need_verify) {
+ verify_legal_utf8(utf8_buffer, utf8_length, CHECK);
+ }
+
+ if (has_cp_patch_at(index)) {
+ Handle patch = clear_cp_patch_at(index);
+ guarantee_property(java_lang_String::is_instance(patch()),
+ "Illegal utf8 patch at %d in class file %s",
+ index,
+ CHECK);
+ const char* const str = java_lang_String::as_utf8_string(patch());
+ // (could use java_lang_String::as_symbol instead, but might as well batch them)
+ utf8_buffer = (const u1*) str;
+ utf8_length = (int) strlen(str);
+ }
+
+ unsigned int hash;
+ Symbol* const result = SymbolTable::lookup_only((const char*)utf8_buffer,
+ utf8_length,
+ hash);
+ if (result == NULL) {
+ names[names_count] = (const char*)utf8_buffer;
+ lengths[names_count] = utf8_length;
+ indices[names_count] = index;
+ hashValues[names_count++] = hash;
+ if (names_count == SymbolTable::symbol_alloc_batch_size) {
+ SymbolTable::new_symbols(_loader_data,
+ cp,
+ names_count,
+ names,
+ lengths,
+ indices,
+ hashValues,
+ CHECK);
+ names_count = 0;
+ }
+ } else {
+ cp->symbol_at_put(index, result);
}
break;
- case JVM_CONSTANT_Utf8 :
- {
- cfs->guarantee_more(2, CHECK); // utf8_length
- u2 utf8_length = cfs->get_u2_fast();
- u1* utf8_buffer = cfs->get_u1_buffer();
- assert(utf8_buffer != NULL, "null utf8 buffer");
- // Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward.
- cfs->guarantee_more(utf8_length+1, CHECK); // utf8 string, tag/access_flags
- cfs->skip_u1_fast(utf8_length);
-
- // Before storing the symbol, make sure it's legal
- if (_need_verify) {
- verify_legal_utf8((unsigned char*)utf8_buffer, utf8_length, CHECK);
- }
-
- if (has_cp_patch_at(index)) {
- Handle patch = clear_cp_patch_at(index);
- guarantee_property(java_lang_String::is_instance(patch()),
- "Illegal utf8 patch at %d in class file %s",
- index, CHECK);
- char* str = java_lang_String::as_utf8_string(patch());
- // (could use java_lang_String::as_symbol instead, but might as well batch them)
- utf8_buffer = (u1*) str;
- utf8_length = (int) strlen(str);
- }
-
- unsigned int hash;
- Symbol* result = SymbolTable::lookup_only((char*)utf8_buffer, utf8_length, hash);
- if (result == NULL) {
- names[names_count] = (char*)utf8_buffer;
- lengths[names_count] = utf8_length;
- indices[names_count] = index;
- hashValues[names_count++] = hash;
- if (names_count == SymbolTable::symbol_alloc_batch_size) {
- SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK);
- names_count = 0;
- }
- } else {
- _cp->symbol_at_put(index, result);
- }
- }
+ }
+ default: {
+ classfile_parse_error("Unknown constant tag %u in class file %s",
+ tag,
+ CHECK);
break;
- default:
- classfile_parse_error(
- "Unknown constant tag %u in class file %s", tag, CHECK);
- break;
- }
- }
+ }
+ } // end of switch(tag)
+ } // end of for
// Allocate the remaining symbols
if (names_count > 0) {
- SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK);
+ SymbolTable::new_symbols(_loader_data,
+ cp,
+ names_count,
+ names,
+ lengths,
+ indices,
+ hashValues,
+ CHECK);
}
- // Copy _current pointer of local copy back to stream().
-#ifdef ASSERT
- assert(cfs0->current() == old_current, "non-exclusive use of stream()");
-#endif
- cfs0->set_current(cfs1.current());
+ // Copy _current pointer of local copy back to stream.
+ assert(stream->current() == old_current, "non-exclusive use of stream");
+ stream->set_current(cfs1.current());
+
}
-bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); }
-
-inline Symbol* check_symbol_at(constantPoolHandle cp, int index) {
- if (valid_cp_range(index, cp->length()) && cp->tag_at(index).is_utf8())
+static inline bool valid_cp_range(int index, int length) {
+ return (index > 0 && index < length);
+}
+
+static inline Symbol* check_symbol_at(const ConstantPool* cp, int index) {
+ assert(cp != NULL, "invariant");
+ if (valid_cp_range(index, cp->length()) && cp->tag_at(index).is_utf8()) {
return cp->symbol_at(index);
- else
- return NULL;
+ }
+ return NULL;
}
#ifdef ASSERT
PRAGMA_DIAG_PUSH
PRAGMA_FORMAT_NONLITERAL_IGNORED
-void ClassFileParser::report_assert_property_failure(const char* msg, TRAPS) {
+void ClassFileParser::report_assert_property_failure(const char* msg, TRAPS) const {
ResourceMark rm(THREAD);
fatal(msg, _class_name->as_C_string());
}
-void ClassFileParser::report_assert_property_failure(const char* msg, int index, TRAPS) {
+void ClassFileParser::report_assert_property_failure(const char* msg,
+ int index,
+ TRAPS) const {
ResourceMark rm(THREAD);
fatal(msg, index, _class_name->as_C_string());
}
PRAGMA_DIAG_POP
#endif
-constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
- ClassFileStream* cfs = stream();
- constantPoolHandle nullHandle;
-
- cfs->guarantee_more(3, CHECK_(nullHandle)); // length, first cp tag
- u2 length = cfs->get_u2_fast();
- guarantee_property(
- length >= 1, "Illegal constant pool size %u in class file %s",
- length, CHECK_(nullHandle));
- ConstantPool* constant_pool = ConstantPool::allocate(_loader_data, length,
- CHECK_(nullHandle));
- _cp = constant_pool; // save in case of errors
- constantPoolHandle cp (THREAD, constant_pool);
+void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
+ ConstantPool* const cp,
+ const int length,
+ TRAPS) {
+ assert(cp != NULL, "invariant");
+ assert(stream != NULL, "invariant");
// parsing constant pool entries
- parse_constant_pool_entries(length, CHECK_(nullHandle));
+ parse_constant_pool_entries(stream, cp, length, CHECK);
int index = 1; // declared outside of loops for portability
- // first verification pass - validate cross references and fixup class and string constants
+ // first verification pass - validate cross references
+ // and fixup class and string constants
for (index = 1; index < length; index++) { // Index 0 is unused
- jbyte tag = cp->tag_at(index).value();
+ const jbyte tag = cp->tag_at(index).value();
switch (tag) {
- case JVM_CONSTANT_Class :
+ case JVM_CONSTANT_Class: {
ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present
break;
- case JVM_CONSTANT_Fieldref :
+ }
+ case JVM_CONSTANT_Fieldref:
// fall through
- case JVM_CONSTANT_Methodref :
+ case JVM_CONSTANT_Methodref:
// fall through
- case JVM_CONSTANT_InterfaceMethodref : {
+ case JVM_CONSTANT_InterfaceMethodref: {
if (!_need_verify) break;
- int klass_ref_index = cp->klass_ref_index_at(index);
- int name_and_type_ref_index = cp->name_and_type_ref_index_at(index);
+ const int klass_ref_index = cp->klass_ref_index_at(index);
+ const int name_and_type_ref_index = cp->name_and_type_ref_index_at(index);
check_property(valid_klass_reference_at(klass_ref_index),
"Invalid constant pool index %u in class file %s",
- klass_ref_index,
- CHECK_(nullHandle));
+ klass_ref_index, CHECK);
check_property(valid_cp_range(name_and_type_ref_index, length) &&
- cp->tag_at(name_and_type_ref_index).is_name_and_type(),
- "Invalid constant pool index %u in class file %s",
- name_and_type_ref_index,
- CHECK_(nullHandle));
+ cp->tag_at(name_and_type_ref_index).is_name_and_type(),
+ "Invalid constant pool index %u in class file %s",
+ name_and_type_ref_index, CHECK);
break;
}
- case JVM_CONSTANT_String :
+ case JVM_CONSTANT_String: {
ShouldNotReachHere(); // Only JVM_CONSTANT_StringIndex should be present
break;
- case JVM_CONSTANT_Integer :
+ }
+ case JVM_CONSTANT_Integer:
break;
- case JVM_CONSTANT_Float :
+ case JVM_CONSTANT_Float:
break;
- case JVM_CONSTANT_Long :
- case JVM_CONSTANT_Double :
+ case JVM_CONSTANT_Long:
+ case JVM_CONSTANT_Double: {
index++;
check_property(
(index < length && cp->tag_at(index).is_invalid()),
"Improper constant pool long/double index %u in class file %s",
- index, CHECK_(nullHandle));
- break;
- case JVM_CONSTANT_NameAndType : {
- if (!_need_verify) break;
- int name_ref_index = cp->name_ref_index_at(index);
- int signature_ref_index = cp->signature_ref_index_at(index);
- check_property(valid_symbol_at(name_ref_index),
- "Invalid constant pool index %u in class file %s",
- name_ref_index, CHECK_(nullHandle));
- check_property(valid_symbol_at(signature_ref_index),
- "Invalid constant pool index %u in class file %s",
- signature_ref_index, CHECK_(nullHandle));
+ index, CHECK);
break;
}
- case JVM_CONSTANT_Utf8 :
+ case JVM_CONSTANT_NameAndType: {
+ if (!_need_verify) break;
+ const int name_ref_index = cp->name_ref_index_at(index);
+ const int signature_ref_index = cp->signature_ref_index_at(index);
+ check_property(valid_symbol_at(name_ref_index),
+ "Invalid constant pool index %u in class file %s",
+ name_ref_index, CHECK);
+ check_property(valid_symbol_at(signature_ref_index),
+ "Invalid constant pool index %u in class file %s",
+ signature_ref_index, CHECK);
break;
- case JVM_CONSTANT_UnresolvedClass : // fall-through
- case JVM_CONSTANT_UnresolvedClassInError:
+ }
+ case JVM_CONSTANT_Utf8:
+ break;
+ case JVM_CONSTANT_UnresolvedClass: // fall-through
+ case JVM_CONSTANT_UnresolvedClassInError: {
ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present
break;
- case JVM_CONSTANT_ClassIndex :
- {
- int class_index = cp->klass_index_at(index);
- check_property(valid_symbol_at(class_index),
- "Invalid constant pool index %u in class file %s",
- class_index, CHECK_(nullHandle));
- cp->unresolved_klass_at_put(index, cp->symbol_at(class_index));
- }
+ }
+ case JVM_CONSTANT_ClassIndex: {
+ const int class_index = cp->klass_index_at(index);
+ check_property(valid_symbol_at(class_index),
+ "Invalid constant pool index %u in class file %s",
+ class_index, CHECK);
+ cp->unresolved_klass_at_put(index, cp->symbol_at(class_index));
break;
- case JVM_CONSTANT_StringIndex :
- {
- int string_index = cp->string_index_at(index);
- check_property(valid_symbol_at(string_index),
- "Invalid constant pool index %u in class file %s",
- string_index, CHECK_(nullHandle));
- Symbol* sym = cp->symbol_at(string_index);
- cp->unresolved_string_at_put(index, sym);
- }
+ }
+ case JVM_CONSTANT_StringIndex: {
+ const int string_index = cp->string_index_at(index);
+ check_property(valid_symbol_at(string_index),
+ "Invalid constant pool index %u in class file %s",
+ string_index, CHECK);
+ Symbol* const sym = cp->symbol_at(string_index);
+ cp->unresolved_string_at_put(index, sym);
break;
- case JVM_CONSTANT_MethodHandle :
- {
- int ref_index = cp->method_handle_index_at(index);
- check_property(
- valid_cp_range(ref_index, length),
- "Invalid constant pool index %u in class file %s",
- ref_index, CHECK_(nullHandle));
- constantTag tag = cp->tag_at(ref_index);
- int ref_kind = cp->method_handle_ref_kind_at(index);
- switch (ref_kind) {
+ }
+ case JVM_CONSTANT_MethodHandle: {
+ const int ref_index = cp->method_handle_index_at(index);
+ check_property(valid_cp_range(ref_index, length),
+ "Invalid constant pool index %u in class file %s",
+ ref_index, CHECK);
+ const constantTag tag = cp->tag_at(ref_index);
+ const int ref_kind = cp->method_handle_ref_kind_at(index);
+
+ switch (ref_kind) {
case JVM_REF_getField:
case JVM_REF_getStatic:
case JVM_REF_putField:
- case JVM_REF_putStatic:
+ case JVM_REF_putStatic: {
check_property(
tag.is_field(),
"Invalid constant pool index %u in class file %s (not a field)",
- ref_index, CHECK_(nullHandle));
+ ref_index, CHECK);
break;
+ }
case JVM_REF_invokeVirtual:
- case JVM_REF_newInvokeSpecial:
+ case JVM_REF_newInvokeSpecial: {
check_property(
tag.is_method(),
"Invalid constant pool index %u in class file %s (not a method)",
- ref_index, CHECK_(nullHandle));
+ ref_index, CHECK);
break;
+ }
case JVM_REF_invokeStatic:
- case JVM_REF_invokeSpecial:
- check_property(tag.is_method() ||
- ((_major_version >= JAVA_8_VERSION) && tag.is_interface_method()),
- "Invalid constant pool index %u in class file %s (not a method)",
- ref_index, CHECK_(nullHandle));
- break;
- case JVM_REF_invokeInterface:
+ case JVM_REF_invokeSpecial: {
+ check_property(
+ tag.is_method() ||
+ ((_major_version >= JAVA_8_VERSION) && tag.is_interface_method()),
+ "Invalid constant pool index %u in class file %s (not a method)",
+ ref_index, CHECK);
+ break;
+ }
+ case JVM_REF_invokeInterface: {
check_property(
tag.is_interface_method(),
"Invalid constant pool index %u in class file %s (not an interface method)",
- ref_index, CHECK_(nullHandle));
+ ref_index, CHECK);
break;
- default:
+ }
+ default: {
classfile_parse_error(
"Bad method handle kind at constant pool index %u in class file %s",
- index, CHECK_(nullHandle));
+ index, CHECK);
}
- // Keep the ref_index unchanged. It will be indirected at link-time.
- }
+ } // switch(refkind)
+ // Keep the ref_index unchanged. It will be indirected at link-time.
break;
- case JVM_CONSTANT_MethodType :
- {
- int ref_index = cp->method_type_index_at(index);
- check_property(valid_symbol_at(ref_index),
- "Invalid constant pool index %u in class file %s",
- ref_index, CHECK_(nullHandle));
- }
+ } // case MethodHandle
+ case JVM_CONSTANT_MethodType: {
+ const int ref_index = cp->method_type_index_at(index);
+ check_property(valid_symbol_at(ref_index),
+ "Invalid constant pool index %u in class file %s",
+ ref_index, CHECK);
break;
- case JVM_CONSTANT_InvokeDynamic :
- {
- int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index);
- check_property(valid_cp_range(name_and_type_ref_index, length) &&
- cp->tag_at(name_and_type_ref_index).is_name_and_type(),
- "Invalid constant pool index %u in class file %s",
- name_and_type_ref_index,
- CHECK_(nullHandle));
- // bootstrap specifier index must be checked later, when BootstrapMethods attr is available
- break;
- }
- default:
+ }
+ case JVM_CONSTANT_InvokeDynamic: {
+ const int name_and_type_ref_index =
+ cp->invoke_dynamic_name_and_type_ref_index_at(index);
+
+ check_property(valid_cp_range(name_and_type_ref_index, length) &&
+ cp->tag_at(name_and_type_ref_index).is_name_and_type(),
+ "Invalid constant pool index %u in class file %s",
+ name_and_type_ref_index, CHECK);
+ // bootstrap specifier index must be checked later,
+ // when BootstrapMethods attr is available
+ break;
+ }
+ default: {
fatal("bad constant pool tag value %u", cp->tag_at(index).value());
ShouldNotReachHere();
break;
- } // end of switch
+ }
+ } // switch(tag)
} // end of for
if (_cp_patches != NULL) {
// need to treat this_class specially...
int this_class_index;
{
- cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len
- u1* mark = cfs->current();
- u2 flags = cfs->get_u2_fast();
- this_class_index = cfs->get_u2_fast();
- cfs->set_current(mark); // revert to mark
+ stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len
+ const u1* const mark = stream->current();
+ stream->skip_u2_fast(1); // skip flags
+ this_class_index = stream->get_u2_fast();
+ stream->set_current(mark); // revert to mark
}
for (index = 1; index < length; index++) { // Index 0 is unused
if (has_cp_patch_at(index)) {
guarantee_property(index != this_class_index,
- "Illegal constant pool patch to self at %d in class file %s",
- index, CHECK_(nullHandle));
- patch_constant_pool(cp, index, cp_patch_at(index), CHECK_(nullHandle));
+ "Illegal constant pool patch to self at %d in class file %s",
+ index, CHECK);
+ patch_constant_pool(cp, index, cp_patch_at(index), CHECK);
}
}
}
if (!_need_verify) {
- return cp;
+ return;
}
// second verification pass - checks the strings are of the right format.
// but not yet to the other entries
for (index = 1; index < length; index++) {
- jbyte tag = cp->tag_at(index).value();
+ const jbyte tag = cp->tag_at(index).value();
switch (tag) {
case JVM_CONSTANT_UnresolvedClass: {
- Symbol* class_name = cp->klass_name_at(index);
+ const Symbol* const class_name = cp->klass_name_at(index);
// check the name, even if _cp_patches will overwrite it
- verify_legal_class_name(class_name, CHECK_(nullHandle));
+ verify_legal_class_name(class_name, CHECK);
break;
}
case JVM_CONSTANT_NameAndType: {
if (_need_verify && _major_version >= JAVA_7_VERSION) {
- int sig_index = cp->signature_ref_index_at(index);
- int name_index = cp->name_ref_index_at(index);
- Symbol* name = cp->symbol_at(name_index);
- Symbol* sig = cp->symbol_at(sig_index);
+ const int sig_index = cp->signature_ref_index_at(index);
+ const int name_index = cp->name_ref_index_at(index);
+ const Symbol* const name = cp->symbol_at(name_index);
+ const Symbol* const sig = cp->symbol_at(sig_index);
if (sig->byte_at(0) == JVM_SIGNATURE_FUNC) {
- verify_legal_method_signature(name, sig, CHECK_(nullHandle));
+ verify_legal_method_signature(name, sig, CHECK);
} else {
- verify_legal_field_signature(name, sig, CHECK_(nullHandle));
+ verify_legal_field_signature(name, sig, CHECK);
}
}
break;
@@ -555,47 +579,50 @@
case JVM_CONSTANT_Fieldref:
case JVM_CONSTANT_Methodref:
case JVM_CONSTANT_InterfaceMethodref: {
- int name_and_type_ref_index = cp->name_and_type_ref_index_at(index);
+ const int name_and_type_ref_index =
+ cp->name_and_type_ref_index_at(index);
// already verified to be utf8
- int name_ref_index = cp->name_ref_index_at(name_and_type_ref_index);
+ const int name_ref_index =
+ cp->name_ref_index_at(name_and_type_ref_index);
// already verified to be utf8
- int signature_ref_index = cp->signature_ref_index_at(name_and_type_ref_index);
- Symbol* name = cp->symbol_at(name_ref_index);
- Symbol* signature = cp->symbol_at(signature_ref_index);
+ const int signature_ref_index =
+ cp->signature_ref_index_at(name_and_type_ref_index);
+ const Symbol* const name = cp->symbol_at(name_ref_index);
+ const Symbol* const signature = cp->symbol_at(signature_ref_index);
if (tag == JVM_CONSTANT_Fieldref) {
- verify_legal_field_name(name, CHECK_(nullHandle));
+ verify_legal_field_name(name, CHECK);
if (_need_verify && _major_version >= JAVA_7_VERSION) {
// Signature is verified above, when iterating NameAndType_info.
// Need only to be sure it's the right type.
if (signature->byte_at(0) == JVM_SIGNATURE_FUNC) {
throwIllegalSignature(
- "Field", name, signature, CHECK_(nullHandle));
+ "Field", name, signature, CHECK);
}
} else {
- verify_legal_field_signature(name, signature, CHECK_(nullHandle));
+ verify_legal_field_signature(name, signature, CHECK);
}
} else {
- verify_legal_method_name(name, CHECK_(nullHandle));
+ verify_legal_method_name(name, CHECK);
if (_need_verify && _major_version >= JAVA_7_VERSION) {
// Signature is verified above, when iterating NameAndType_info.
// Need only to be sure it's the right type.
if (signature->byte_at(0) != JVM_SIGNATURE_FUNC) {
throwIllegalSignature(
- "Method", name, signature, CHECK_(nullHandle));
+ "Method", name, signature, CHECK);
}
} else {
- verify_legal_method_signature(name, signature, CHECK_(nullHandle));
+ verify_legal_method_signature(name, signature, CHECK);
}
if (tag == JVM_CONSTANT_Methodref) {
// 4509014: If a class method name begins with '<', it must be "<init>".
assert(name != NULL, "method name in constant pool is null");
- unsigned int name_len = name->utf8_length();
+ const unsigned int name_len = name->utf8_length();
assert(name_len > 0, "bad method name"); // already verified as legal name
if (name->byte_at(0) == '<') {
if (name != vmSymbols::object_initializer_name()) {
classfile_parse_error(
"Bad method name at constant pool index %u in class file %s",
- name_ref_index, CHECK_(nullHandle));
+ name_ref_index, CHECK);
}
}
}
@@ -603,84 +630,88 @@
break;
}
case JVM_CONSTANT_MethodHandle: {
- int ref_index = cp->method_handle_index_at(index);
- int ref_kind = cp->method_handle_ref_kind_at(index);
+ const int ref_index = cp->method_handle_index_at(index);
+ const int ref_kind = cp->method_handle_ref_kind_at(index);
switch (ref_kind) {
- case JVM_REF_invokeVirtual:
- case JVM_REF_invokeStatic:
- case JVM_REF_invokeSpecial:
- case JVM_REF_newInvokeSpecial:
- {
- int name_and_type_ref_index = cp->name_and_type_ref_index_at(ref_index);
- int name_ref_index = cp->name_ref_index_at(name_and_type_ref_index);
- Symbol* name = cp->symbol_at(name_ref_index);
+ case JVM_REF_invokeVirtual:
+ case JVM_REF_invokeStatic:
+ case JVM_REF_invokeSpecial:
+ case JVM_REF_newInvokeSpecial: {
+ const int name_and_type_ref_index =
+ cp->name_and_type_ref_index_at(ref_index);
+ const int name_ref_index =
+ cp->name_ref_index_at(name_and_type_ref_index);
+ const Symbol* const name = cp->symbol_at(name_ref_index);
if (ref_kind == JVM_REF_newInvokeSpecial) {
if (name != vmSymbols::object_initializer_name()) {
classfile_parse_error(
"Bad constructor name at constant pool index %u in class file %s",
- name_ref_index, CHECK_(nullHandle));
+ name_ref_index, CHECK);
}
} else {
if (name == vmSymbols::object_initializer_name()) {
classfile_parse_error(
"Bad method name at constant pool index %u in class file %s",
- name_ref_index, CHECK_(nullHandle));
+ name_ref_index, CHECK);
}
}
+ break;
}
- break;
// Other ref_kinds are already fully checked in previous pass.
- }
+ } // switch(ref_kind)
break;
}
case JVM_CONSTANT_MethodType: {
- Symbol* no_name = vmSymbols::type_name(); // place holder
- Symbol* signature = cp->method_type_signature_at(index);
- verify_legal_method_signature(no_name, signature, CHECK_(nullHandle));
+ const Symbol* const no_name = vmSymbols::type_name(); // place holder
+ const Symbol* const signature = cp->method_type_signature_at(index);
+ verify_legal_method_signature(no_name, signature, CHECK);
break;
}
case JVM_CONSTANT_Utf8: {
assert(cp->symbol_at(index)->refcount() != 0, "count corrupted");
}
- } // end of switch
+ } // switch(tag)
} // end of for
-
- return cp;
}
-
-void ClassFileParser::patch_constant_pool(const constantPoolHandle& cp, int index, Handle patch, TRAPS) {
+void ClassFileParser::patch_constant_pool(ConstantPool* cp,
+ int index,
+ Handle patch,
+ TRAPS) {
+ assert(cp != NULL, "invariant");
+
BasicType patch_type = T_VOID;
switch (cp->tag_at(index).value()) {
- case JVM_CONSTANT_UnresolvedClass :
- // Patching a class means pre-resolving it.
- // The name in the constant pool is ignored.
- if (java_lang_Class::is_instance(patch())) {
- guarantee_property(!java_lang_Class::is_primitive(patch()),
- "Illegal class patch at %d in class file %s",
- index, CHECK);
- cp->klass_at_put(index, java_lang_Class::as_Klass(patch()));
- } else {
- guarantee_property(java_lang_String::is_instance(patch()),
- "Illegal class patch at %d in class file %s",
- index, CHECK);
- Symbol* name = java_lang_String::as_symbol(patch(), CHECK);
- cp->unresolved_klass_at_put(index, name);
+ case JVM_CONSTANT_UnresolvedClass: {
+ // Patching a class means pre-resolving it.
+ // The name in the constant pool is ignored.
+ if (java_lang_Class::is_instance(patch())) {
+ guarantee_property(!java_lang_Class::is_primitive(patch()),
+ "Illegal class patch at %d in class file %s",
+ index, CHECK);
+ cp->klass_at_put(index, java_lang_Class::as_Klass(patch()));
+ } else {
+ guarantee_property(java_lang_String::is_instance(patch()),
+ "Illegal class patch at %d in class file %s",
+ index, CHECK);
+ Symbol* const name = java_lang_String::as_symbol(patch(), CHECK);
+ cp->unresolved_klass_at_put(index, name);
+ }
+ break;
}
- break;
-
- case JVM_CONSTANT_String :
- // skip this patch and don't clear it. Needs the oop array for resolved
- // references to be created first.
- return;
-
- case JVM_CONSTANT_Integer : patch_type = T_INT; goto patch_prim;
- case JVM_CONSTANT_Float : patch_type = T_FLOAT; goto patch_prim;
- case JVM_CONSTANT_Long : patch_type = T_LONG; goto patch_prim;
- case JVM_CONSTANT_Double : patch_type = T_DOUBLE; goto patch_prim;
- patch_prim:
+
+ case JVM_CONSTANT_String: {
+ // skip this patch and don't clear it. Needs the oop array for resolved
+ // references to be created first.
+ return;
+ }
+ case JVM_CONSTANT_Integer: patch_type = T_INT; goto patch_prim;
+ case JVM_CONSTANT_Float: patch_type = T_FLOAT; goto patch_prim;
+ case JVM_CONSTANT_Long: patch_type = T_LONG; goto patch_prim;
+ case JVM_CONSTANT_Double: patch_type = T_DOUBLE; goto patch_prim;
+ patch_prim:
{
jvalue value;
BasicType value_type = java_lang_boxing_object::get_value(patch(), &value);
@@ -688,39 +719,37 @@
"Illegal primitive patch at %d in class file %s",
index, CHECK);
switch (value_type) {
- case T_INT: cp->int_at_put(index, value.i); break;
- case T_FLOAT: cp->float_at_put(index, value.f); break;
- case T_LONG: cp->long_at_put(index, value.j); break;
- case T_DOUBLE: cp->double_at_put(index, value.d); break;
- default: assert(false, "");
+ case T_INT: cp->int_at_put(index, value.i); break;
+ case T_FLOAT: cp->float_at_put(index, value.f); break;
+ case T_LONG: cp->long_at_put(index, value.j); break;
+ case T_DOUBLE: cp->double_at_put(index, value.d); break;
+ default: assert(false, "");
}
- }
+ } // end patch_prim label
break;
- default:
- // %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc.
- guarantee_property(!has_cp_patch_at(index),
- "Illegal unexpected patch at %d in class file %s",
- index, CHECK);
- return;
- }
+ default: {
+ // %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc.
+ guarantee_property(!has_cp_patch_at(index),
+ "Illegal unexpected patch at %d in class file %s",
+ index, CHECK);
+ return;
+ }
+ } // end of switch(tag)
// On fall-through, mark the patch as used.
clear_cp_patch_at(index);
}
-
-
class NameSigHash: public ResourceObj {
public:
- Symbol* _name; // name
- Symbol* _sig; // signature
- NameSigHash* _next; // Next entry in hash table
+ const Symbol* _name; // name
+ const Symbol* _sig; // signature
+ NameSigHash* _next; // Next entry in hash table
};
-
-#define HASH_ROW_SIZE 256
-
-unsigned int hash(Symbol* name, Symbol* sig) {
+static const int HASH_ROW_SIZE = 256;
+
+static unsigned int hash(const Symbol* name, const Symbol* sig) {
unsigned int raw_hash = 0;
raw_hash += ((unsigned int)(uintptr_t)name) >> (LogHeapWordSize + 2);
raw_hash += ((unsigned int)(uintptr_t)sig) >> LogHeapWordSize;
@@ -729,16 +758,15 @@
}
-void initialize_hashtable(NameSigHash** table) {
+static void initialize_hashtable(NameSigHash** table) {
memset((void*)table, 0, sizeof(NameSigHash*) * HASH_ROW_SIZE);
}
-
// Return false if the name/sig combination is found in table.
// Return true if no duplicate is found. And name/sig is added as a new entry in table.
// The old format checker uses heap sort to find duplicates.
// NOTE: caller should guarantee that GC doesn't happen during the life cycle
// of table since we don't expect Symbol*'s to move.
-bool put_after_lookup(Symbol* name, Symbol* sig, NameSigHash** table) {
+static bool put_after_lookup(const Symbol* name, const Symbol* sig, NameSigHash** table) {
assert(name != NULL, "name in constant pool is NULL");
// First lookup for duplicates
@@ -763,69 +791,78 @@
return true;
}
-
-Array<Klass*>* ClassFileParser::parse_interfaces(int length,
- Handle protection_domain,
- Symbol* class_name,
- bool* has_default_methods,
- TRAPS) {
- if (length == 0) {
+// Side-effects: populates the _local_interfaces field
+void ClassFileParser::parse_interfaces(const ClassFileStream* const stream,
+ const int itfs_len,
+ ConstantPool* const cp,
+ bool* const has_default_methods,
+ TRAPS) {
+ assert(stream != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+ assert(has_default_methods != NULL, "invariant");
+
+ if (itfs_len == 0) {
_local_interfaces = Universe::the_empty_klass_array();
} else {
- ClassFileStream* cfs = stream();
- assert(length > 0, "only called for length>0");
- _local_interfaces = MetadataFactory::new_array<Klass*>(_loader_data, length, NULL, CHECK_NULL);
+ assert(itfs_len > 0, "only called for len>0");
+ _local_interfaces = MetadataFactory::new_array<Klass*>(_loader_data, itfs_len, NULL, CHECK);
int index;
- for (index = 0; index < length; index++) {
- u2 interface_index = cfs->get_u2(CHECK_NULL);
+ for (index = 0; index < itfs_len; index++) {
+ const u2 interface_index = stream->get_u2(CHECK);
KlassHandle interf;
check_property(
valid_klass_reference_at(interface_index),
"Interface name has bad constant pool index %u in class file %s",
- interface_index, CHECK_NULL);
- if (_cp->tag_at(interface_index).is_klass()) {
- interf = KlassHandle(THREAD, _cp->resolved_klass_at(interface_index));
+ interface_index, CHECK);
+ if (cp->tag_at(interface_index).is_klass()) {
+ interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index));
} else {
- Symbol* unresolved_klass = _cp->klass_name_at(interface_index);
+ Symbol* const unresolved_klass = cp->klass_name_at(interface_index);
// Don't need to check legal name because it's checked when parsing constant pool.
// But need to make sure it's not an array type.
guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY,
- "Bad interface name in class file %s", CHECK_NULL);
- Handle class_loader(THREAD, _loader_data->class_loader());
+ "Bad interface name in class file %s", CHECK);
// Call resolve_super so classcircularity is checked
- Klass* k = SystemDictionary::resolve_super_or_fail(class_name,
- unresolved_klass, class_loader, protection_domain,
- false, CHECK_NULL);
+ const Klass* const k =
+ SystemDictionary::resolve_super_or_fail(_class_name,
+ unresolved_klass,
+ _loader_data->class_loader(),
+ _protection_domain,
+ false,
+ CHECK);
interf = KlassHandle(THREAD, k);
}
if (!interf()->is_interface()) {
- THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL);
+ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(),
+ "Implementing class");
}
+
if (InstanceKlass::cast(interf())->has_default_methods()) {
*has_default_methods = true;
}
_local_interfaces->at_put(index, interf());
}
- if (!_need_verify || length <= 1) {
- return _local_interfaces;
+ if (!_need_verify || itfs_len <= 1) {
+ return;
}
// Check if there's any duplicates in interfaces
ResourceMark rm(THREAD);
- NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, NameSigHash*, HASH_ROW_SIZE);
+ NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD,
+ NameSigHash*,
+ HASH_ROW_SIZE);
initialize_hashtable(interface_names);
bool dup = false;
{
debug_only(No_Safepoint_Verifier nsv;)
- for (index = 0; index < length; index++) {
- Klass* k = _local_interfaces->at(index);
- Symbol* name = k->name();
+ for (index = 0; index < itfs_len; index++) {
+ const Klass* const k = _local_interfaces->at(index);
+ const Symbol* const name = InstanceKlass::cast(k)->name();
// If no duplicates, add (name, NULL) in hashtable interface_names.
if (!put_after_lookup(name, NULL, interface_names)) {
dup = true;
@@ -834,79 +871,339 @@
}
}
if (dup) {
- classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL);
+ classfile_parse_error("Duplicate interface name in class file %s", CHECK);
}
}
- return _local_interfaces;
}
-
-void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, TRAPS) {
+void ClassFileParser::verify_constantvalue(const ConstantPool* const cp,
+ int constantvalue_index,
+ int signature_index,
+ TRAPS) const {
// Make sure the constant pool entry is of a type appropriate to this field
guarantee_property(
(constantvalue_index > 0 &&
- constantvalue_index < _cp->length()),
+ constantvalue_index < cp->length()),
"Bad initial value index %u in ConstantValue attribute in class file %s",
constantvalue_index, CHECK);
- constantTag value_type = _cp->tag_at(constantvalue_index);
- switch ( _cp->basic_type_for_signature_at(signature_index) ) {
- case T_LONG:
- guarantee_property(value_type.is_long(), "Inconsistent constant value type in class file %s", CHECK);
+
+ const constantTag value_type = cp->tag_at(constantvalue_index);
+ switch(cp->basic_type_for_signature_at(signature_index)) {
+ case T_LONG: {
+ guarantee_property(value_type.is_long(),
+ "Inconsistent constant value type in class file %s",
+ CHECK);
+ break;
+ }
+ case T_FLOAT: {
+ guarantee_property(value_type.is_float(),
+ "Inconsistent constant value type in class file %s",
+ CHECK);
break;
- case T_FLOAT:
- guarantee_property(value_type.is_float(), "Inconsistent constant value type in class file %s", CHECK);
+ }
+ case T_DOUBLE: {
+ guarantee_property(value_type.is_double(),
+ "Inconsistent constant value type in class file %s",
+ CHECK);
+ break;
+ }
+ case T_BYTE:
+ case T_CHAR:
+ case T_SHORT:
+ case T_BOOLEAN:
+ case T_INT: {
+ guarantee_property(value_type.is_int(),
+ "Inconsistent constant value type in class file %s",
+ CHECK);
+ break;
+ }
+ case T_OBJECT: {
+ guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;")
+ && value_type.is_string()),
+ "Bad string initial value in class file %s",
+ CHECK);
break;
- case T_DOUBLE:
- guarantee_property(value_type.is_double(), "Inconsistent constant value type in class file %s", CHECK);
+ }
+ default: {
+ classfile_parse_error("Unable to set initial value %u in class file %s",
+ constantvalue_index,
+ CHECK);
+ }
+ }
+}
+
+class AnnotationCollector : public ResourceObj{
+public:
+ enum Location { _in_field, _in_method, _in_class };
+ enum ID {
+ _unknown = 0,
+ _method_CallerSensitive,
+ _method_ForceInline,
+ _method_DontInline,
+ _method_InjectedProfile,
+ _method_LambdaForm_Compiled,
+ _method_LambdaForm_Hidden,
+ _method_HotSpotIntrinsicCandidate,
+ _jdk_internal_vm_annotation_Contended,
+ _field_Stable,
+ _annotation_LIMIT
+ };
+ const Location _location;
+ int _annotations_present;
+ u2 _contended_group;
+
+ AnnotationCollector(Location location)
+ : _location(location), _annotations_present(0)
+ {
+ assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
+ }
+ // If this annotation name has an ID, report it (or _none).
+ ID annotation_index(const ClassLoaderData* loader_data, const Symbol* name);
+ // Set the annotation name:
+ void set_annotation(ID id) {
+ assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
+ _annotations_present |= nth_bit((int)id);
+ }
+
+ void remove_annotation(ID id) {
+ assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
+ _annotations_present &= ~nth_bit((int)id);
+ }
+
+ // Report if the annotation is present.
+ bool has_any_annotations() const { return _annotations_present != 0; }
+ bool has_annotation(ID id) const { return (nth_bit((int)id) & _annotations_present) != 0; }
+
+ void set_contended_group(u2 group) { _contended_group = group; }
+ u2 contended_group() const { return _contended_group; }
+
+ bool is_contended() const { return has_annotation(_jdk_internal_vm_annotation_Contended); }
+
+ void set_stable(bool stable) { set_annotation(_field_Stable); }
+ bool is_stable() const { return has_annotation(_field_Stable); }
+};
+
+// This class also doubles as a holder for metadata cleanup.
+class ClassFileParser::FieldAnnotationCollector : public AnnotationCollector {
+private:
+ ClassLoaderData* _loader_data;
+ AnnotationArray* _field_annotations;
+ AnnotationArray* _field_type_annotations;
+public:
+ FieldAnnotationCollector(ClassLoaderData* loader_data) :
+ AnnotationCollector(_in_field),
+ _loader_data(loader_data),
+ _field_annotations(NULL),
+ _field_type_annotations(NULL) {}
+ ~FieldAnnotationCollector();
+ void apply_to(FieldInfo* f);
+ AnnotationArray* field_annotations() { return _field_annotations; }
+ AnnotationArray* field_type_annotations() { return _field_type_annotations; }
+
+ void set_field_annotations(AnnotationArray* a) { _field_annotations = a; }
+ void set_field_type_annotations(AnnotationArray* a) { _field_type_annotations = a; }
+};
+
+class MethodAnnotationCollector : public AnnotationCollector{
+public:
+ MethodAnnotationCollector() : AnnotationCollector(_in_method) { }
+ void apply_to(methodHandle m);
+};
+
+class ClassFileParser::ClassAnnotationCollector : public AnnotationCollector{
+public:
+ ClassAnnotationCollector() : AnnotationCollector(_in_class) { }
+ void apply_to(InstanceKlass* ik);
+};
+
+
+static int skip_annotation_value(const u1*, int, int); // fwd decl
+
+// Skip an annotation. Return >=limit if there is any problem.
+static int skip_annotation(const u1* buffer, int limit, int index) {
+ assert(buffer != NULL, "invariant");
+ // annotation := atype:u2 do(nmem:u2) {member:u2 value}
+ // value := switch (tag:u1) { ... }
+ index += 2; // skip atype
+ if ((index += 2) >= limit) return limit; // read nmem
+ int nmem = Bytes::get_Java_u2((address)buffer + index - 2);
+ while (--nmem >= 0 && index < limit) {
+ index += 2; // skip member
+ index = skip_annotation_value(buffer, limit, index);
+ }
+ return index;
+}
+
+// Skip an annotation value. Return >=limit if there is any problem.
+static int skip_annotation_value(const u1* buffer, int limit, int index) {
+ assert(buffer != NULL, "invariant");
+
+ // value := switch (tag:u1) {
+ // case B, C, I, S, Z, D, F, J, c: con:u2;
+ // case e: e_class:u2 e_name:u2;
+ // case s: s_con:u2;
+ // case [: do(nval:u2) {value};
+ // case @: annotation;
+ // case s: s_con:u2;
+ // }
+ if ((index += 1) >= limit) return limit; // read tag
+ const u1 tag = buffer[index - 1];
+ switch (tag) {
+ case 'B':
+ case 'C':
+ case 'I':
+ case 'S':
+ case 'Z':
+ case 'D':
+ case 'F':
+ case 'J':
+ case 'c':
+ case 's':
+ index += 2; // skip con or s_con
break;
- case T_BYTE: case T_CHAR: case T_SHORT: case T_BOOLEAN: case T_INT:
- guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s", CHECK);
+ case 'e':
+ index += 4; // skip e_class, e_name
break;
- case T_OBJECT:
- guarantee_property((_cp->symbol_at(signature_index)->equals("Ljava/lang/String;")
- && value_type.is_string()),
- "Bad string initial value in class file %s", CHECK);
+ case '[':
+ {
+ if ((index += 2) >= limit) return limit; // read nval
+ int nval = Bytes::get_Java_u2((address)buffer + index - 2);
+ while (--nval >= 0 && index < limit) {
+ index = skip_annotation_value(buffer, limit, index);
+ }
+ }
+ break;
+ case '@':
+ index = skip_annotation(buffer, limit, index);
break;
default:
- classfile_parse_error(
- "Unable to set initial value %u in class file %s",
- constantvalue_index, CHECK);
+ return limit; // bad tag byte
+ }
+ return index;
+}
+
+// Sift through annotations, looking for those significant to the VM:
+static void parse_annotations(const ConstantPool* const cp,
+ const u1* buffer, int limit,
+ AnnotationCollector* coll,
+ ClassLoaderData* loader_data,
+ TRAPS) {
+
+ assert(cp != NULL, "invariant");
+ assert(buffer != NULL, "invariant");
+ assert(coll != NULL, "invariant");
+ assert(loader_data != NULL, "invariant");
+
+ // annotations := do(nann:u2) {annotation}
+ int index = 0;
+ if ((index += 2) >= limit) return; // read nann
+ int nann = Bytes::get_Java_u2((address)buffer + index - 2);
+ enum { // initial annotation layout
+ atype_off = 0, // utf8 such as 'Ljava/lang/annotation/Retention;'
+ count_off = 2, // u2 such as 1 (one value)
+ member_off = 4, // utf8 such as 'value'
+ tag_off = 6, // u1 such as 'c' (type) or 'e' (enum)
+ e_tag_val = 'e',
+ e_type_off = 7, // utf8 such as 'Ljava/lang/annotation/RetentionPolicy;'
+ e_con_off = 9, // utf8 payload, such as 'SOURCE', 'CLASS', 'RUNTIME'
+ e_size = 11, // end of 'e' annotation
+ c_tag_val = 'c', // payload is type
+ c_con_off = 7, // utf8 payload, such as 'I'
+ c_size = 9, // end of 'c' annotation
+ s_tag_val = 's', // payload is String
+ s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;'
+ s_size = 9,
+ min_size = 6 // smallest possible size (zero members)
+ };
+ while ((--nann) >= 0 && (index - 2 + min_size <= limit)) {
+ int index0 = index;
+ index = skip_annotation(buffer, limit, index);
+ const u1* const abase = buffer + index0;
+ const int atype = Bytes::get_Java_u2((address)abase + atype_off);
+ const int count = Bytes::get_Java_u2((address)abase + count_off);
+ const Symbol* const aname = check_symbol_at(cp, atype);
+ if (aname == NULL) break; // invalid annotation name
+ const Symbol* member = NULL;
+ if (count >= 1) {
+ const int member_index = Bytes::get_Java_u2((address)abase + member_off);
+ member = check_symbol_at(cp, member_index);
+ if (member == NULL) break; // invalid member name
+ }
+
+ // Here is where parsing particular annotations will take place.
+ AnnotationCollector::ID id = coll->annotation_index(loader_data, aname);
+ if (AnnotationCollector::_unknown == id) continue;
+ coll->set_annotation(id);
+
+ if (AnnotationCollector::_jdk_internal_vm_annotation_Contended == id) {
+ // @Contended can optionally specify the contention group.
+ //
+ // Contended group defines the equivalence class over the fields:
+ // the fields within the same contended group are not treated distinct.
+ // The only exception is default group, which does not incur the
+ // equivalence. Naturally, contention group for classes is meaningless.
+ //
+ // While the contention group is specified as String, annotation
+ // values are already interned, and we might as well use the constant
+ // pool index as the group tag.
+ //
+ u2 group_index = 0; // default contended group
+ if (count == 1
+ && s_size == (index - index0) // match size
+ && s_tag_val == *(abase + tag_off)
+ && member == vmSymbols::value_name()) {
+ group_index = Bytes::get_Java_u2((address)abase + s_con_off);
+ if (cp->symbol_at(group_index)->utf8_length() == 0) {
+ group_index = 0; // default contended group
+ }
+ }
+ coll->set_contended_group(group_index);
+ }
}
}
// Parse attributes for a field.
-void ClassFileParser::parse_field_attributes(u2 attributes_count,
+void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
+ u2 attributes_count,
bool is_static, u2 signature_index,
- u2* constantvalue_index_addr,
- bool* is_synthetic_addr,
- u2* generic_signature_index_addr,
+ u2* const constantvalue_index_addr,
+ bool* const is_synthetic_addr,
+ u2* const generic_signature_index_addr,
ClassFileParser::FieldAnnotationCollector* parsed_annotations,
TRAPS) {
- ClassFileStream* cfs = stream();
- assert(attributes_count > 0, "length should be greater than 0");
+ assert(cfs != NULL, "invariant");
+ assert(constantvalue_index_addr != NULL, "invariant");
+ assert(is_synthetic_addr != NULL, "invariant");
+ assert(generic_signature_index_addr != NULL, "invariant");
+ assert(parsed_annotations != NULL, "invariant");
+ assert(attributes_count > 0, "attributes_count should be greater than 0");
+
u2 constantvalue_index = 0;
u2 generic_signature_index = 0;
bool is_synthetic = false;
- u1* runtime_visible_annotations = NULL;
+ const u1* runtime_visible_annotations = NULL;
int runtime_visible_annotations_length = 0;
- u1* runtime_invisible_annotations = NULL;
+ const u1* runtime_invisible_annotations = NULL;
int runtime_invisible_annotations_length = 0;
- u1* runtime_visible_type_annotations = NULL;
+ const u1* runtime_visible_type_annotations = NULL;
int runtime_visible_type_annotations_length = 0;
- u1* runtime_invisible_type_annotations = NULL;
+ const u1* runtime_invisible_type_annotations = NULL;
int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_annotations_exists = false;
bool runtime_invisible_type_annotations_exists = false;
+ const ConstantPool* const cp = _cp;
+
while (attributes_count--) {
cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length
- u2 attribute_name_index = cfs->get_u2_fast();
- u4 attribute_length = cfs->get_u4_fast();
+ const u2 attribute_name_index = cfs->get_u2_fast();
+ const u4 attribute_length = cfs->get_u4_fast();
check_property(valid_symbol_at(attribute_name_index),
"Invalid field attribute index %u in class file %s",
attribute_name_index,
CHECK);
- Symbol* attribute_name = _cp->symbol_at(attribute_name_index);
+
+ const Symbol* const attribute_name = cp->symbol_at(attribute_name_index);
if (is_static && attribute_name == vmSymbols::tag_constant_value()) {
// ignore if non-static
if (constantvalue_index != 0) {
@@ -916,9 +1213,10 @@
attribute_length == 2,
"Invalid ConstantValue field attribute length %u in class file %s",
attribute_length, CHECK);
+
constantvalue_index = cfs->get_u2(CHECK);
if (_need_verify) {
- verify_constantvalue(constantvalue_index, signature_index, CHECK);
+ verify_constantvalue(cp, constantvalue_index, signature_index, CHECK);
}
} else if (attribute_name == vmSymbols::tag_synthetic()) {
if (attribute_length != 0) {
@@ -940,7 +1238,7 @@
"Wrong size %u for field's Signature attribute in class file %s",
attribute_length, CHECK);
}
- generic_signature_index = parse_generic_signature_attribute(CHECK);
+ generic_signature_index = parse_generic_signature_attribute(cfs, CHECK);
} else if (attribute_name == vmSymbols::tag_runtime_visible_annotations()) {
if (runtime_visible_annotations != NULL) {
classfile_parse_error(
@@ -949,9 +1247,12 @@
runtime_visible_annotations_length = attribute_length;
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
- parse_annotations(runtime_visible_annotations,
+ parse_annotations(cp,
+ runtime_visible_annotations,
runtime_visible_annotations_length,
- parsed_annotations);
+ parsed_annotations,
+ _loader_data,
+ CHECK);
cfs->skip_u1(runtime_visible_annotations_length, CHECK);
} else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
@@ -1081,7 +1382,7 @@
return result;
}
-class FieldAllocationCount: public ResourceObj {
+class ClassFileParser::FieldAllocationCount : public ResourceObj {
public:
u2 count[MAX_FIELD_ALLOCATION_TYPE];
@@ -1100,18 +1401,33 @@
}
};
-Array<u2>* ClassFileParser::parse_fields(Symbol* class_name,
- bool is_interface,
- FieldAllocationCount *fac,
- u2* java_fields_count_ptr, TRAPS) {
- ClassFileStream* cfs = stream();
- cfs->guarantee_more(2, CHECK_NULL); // length
- u2 length = cfs->get_u2_fast();
+// Side-effects: populates the _fields, _fields_annotations,
+// _fields_type_annotations fields
+void ClassFileParser::parse_fields(const ClassFileStream* const cfs,
+ bool is_interface,
+ FieldAllocationCount* const fac,
+ ConstantPool* cp,
+ const int cp_size,
+ u2* const java_fields_count_ptr,
+ TRAPS) {
+
+ assert(cfs != NULL, "invariant");
+ assert(fac != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+ assert(java_fields_count_ptr != NULL, "invariant");
+
+ assert(NULL == _fields, "invariant");
+ assert(NULL == _fields_annotations, "invariant");
+ assert(NULL == _fields_type_annotations, "invariant");
+
+ cfs->guarantee_more(2, CHECK); // length
+ const u2 length = cfs->get_u2_fast();
*java_fields_count_ptr = length;
int num_injected = 0;
- InjectedField* injected = JavaClasses::get_injected(class_name, &num_injected);
- int total_fields = length + num_injected;
+ const InjectedField* const injected = JavaClasses::get_injected(_class_name,
+ &num_injected);
+ const int total_fields = length + num_injected;
// The field array starts with tuples of shorts
// [access, name index, sig index, initial value index, byte offset].
@@ -1134,62 +1450,70 @@
// index. After parsing all fields, the data are copied to a permanent
// array and any unused slots will be discarded.
ResourceMark rm(THREAD);
- u2* fa = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, u2, total_fields * (FieldInfo::field_slots + 1));
+ u2* const fa = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD,
+ u2,
+ total_fields * (FieldInfo::field_slots + 1));
// The generic signature slots start after all other fields' data.
int generic_signature_slot = total_fields * FieldInfo::field_slots;
int num_generic_signature = 0;
for (int n = 0; n < length; n++) {
- cfs->guarantee_more(8, CHECK_NULL); // access_flags, name_index, descriptor_index, attributes_count
+ // access_flags, name_index, descriptor_index, attributes_count
+ cfs->guarantee_more(8, CHECK);
AccessFlags access_flags;
- jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS;
- verify_legal_field_modifiers(flags, is_interface, CHECK_NULL);
+ const jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS;
+ verify_legal_field_modifiers(flags, is_interface, CHECK);
access_flags.set_flags(flags);
- u2 name_index = cfs->get_u2_fast();
- int cp_size = _cp->length();
+ const u2 name_index = cfs->get_u2_fast();
check_property(valid_symbol_at(name_index),
"Invalid constant pool index %u for field name in class file %s",
- name_index,
- CHECK_NULL);
- Symbol* name = _cp->symbol_at(name_index);
- verify_legal_field_name(name, CHECK_NULL);
-
- u2 signature_index = cfs->get_u2_fast();
+ name_index, CHECK);
+ const Symbol* const name = cp->symbol_at(name_index);
+ verify_legal_field_name(name, CHECK);
+
+ const u2 signature_index = cfs->get_u2_fast();
check_property(valid_symbol_at(signature_index),
"Invalid constant pool index %u for field signature in class file %s",
- signature_index, CHECK_NULL);
- Symbol* sig = _cp->symbol_at(signature_index);
- verify_legal_field_signature(name, sig, CHECK_NULL);
+ signature_index, CHECK);
+ const Symbol* const sig = cp->symbol_at(signature_index);
+ verify_legal_field_signature(name, sig, CHECK);
u2 constantvalue_index = 0;
bool is_synthetic = false;
u2 generic_signature_index = 0;
- bool is_static = access_flags.is_static();
+ const bool is_static = access_flags.is_static();
FieldAnnotationCollector parsed_annotations(_loader_data);
- u2 attributes_count = cfs->get_u2_fast();
+ const u2 attributes_count = cfs->get_u2_fast();
if (attributes_count > 0) {
- parse_field_attributes(attributes_count, is_static, signature_index,
- &constantvalue_index, &is_synthetic,
- &generic_signature_index, &parsed_annotations,
- CHECK_NULL);
+ parse_field_attributes(cfs,
+ attributes_count,
+ is_static,
+ signature_index,
+ &constantvalue_index,
+ &is_synthetic,
+ &generic_signature_index,
+ &parsed_annotations,
+ CHECK);
+
if (parsed_annotations.field_annotations() != NULL) {
if (_fields_annotations == NULL) {
_fields_annotations = MetadataFactory::new_array<AnnotationArray*>(
_loader_data, length, NULL,
- CHECK_NULL);
+ CHECK);
}
_fields_annotations->at_put(n, parsed_annotations.field_annotations());
parsed_annotations.set_field_annotations(NULL);
}
if (parsed_annotations.field_type_annotations() != NULL) {
if (_fields_type_annotations == NULL) {
- _fields_type_annotations = MetadataFactory::new_array<AnnotationArray*>(
- _loader_data, length, NULL,
- CHECK_NULL);
+ _fields_type_annotations =
+ MetadataFactory::new_array<AnnotationArray*>(_loader_data,
+ length,
+ NULL,
+ CHECK);
}
_fields_type_annotations->at_put(n, parsed_annotations.field_type_annotations());
parsed_annotations.set_field_type_annotations(NULL);
@@ -1206,15 +1530,15 @@
}
}
- FieldInfo* field = FieldInfo::from_field_array(fa, n);
+ FieldInfo* const field = FieldInfo::from_field_array(fa, n);
field->initialize(access_flags.as_short(),
name_index,
signature_index,
constantvalue_index);
- BasicType type = _cp->basic_type_for_signature_at(signature_index);
+ const BasicType type = cp->basic_type_for_signature_at(signature_index);
// Remember how many oops we encountered and compute allocation type
- FieldAllocationType atype = fac->update(is_static, type);
+ const FieldAllocationType atype = fac->update(is_static, type);
field->set_allocation_type(atype);
// After field is initialized with type, we can augment it with aux info
@@ -1227,13 +1551,13 @@
for (int n = 0; n < num_injected; n++) {
// Check for duplicates
if (injected[n].may_be_java) {
- Symbol* name = injected[n].name();
- Symbol* signature = injected[n].signature();
+ const Symbol* const name = injected[n].name();
+ const Symbol* const signature = injected[n].signature();
bool duplicate = false;
for (int i = 0; i < length; i++) {
- FieldInfo* f = FieldInfo::from_field_array(fa, i);
- if (name == _cp->symbol_at(f->name_index()) &&
- signature == _cp->symbol_at(f->signature_index())) {
+ const FieldInfo* const f = FieldInfo::from_field_array(fa, i);
+ if (name == cp->symbol_at(f->name_index()) &&
+ signature == cp->symbol_at(f->signature_index())) {
// Symbol is desclared in Java so skip this one
duplicate = true;
break;
@@ -1246,40 +1570,41 @@
}
// Injected field
- FieldInfo* field = FieldInfo::from_field_array(fa, index);
+ FieldInfo* const field = FieldInfo::from_field_array(fa, index);
field->initialize(JVM_ACC_FIELD_INTERNAL,
injected[n].name_index,
injected[n].signature_index,
0);
- BasicType type = FieldType::basic_type(injected[n].signature());
+ const BasicType type = FieldType::basic_type(injected[n].signature());
// Remember how many oops we encountered and compute allocation type
- FieldAllocationType atype = fac->update(false, type);
+ const FieldAllocationType atype = fac->update(false, type);
field->set_allocation_type(atype);
index++;
}
}
- // Now copy the fields' data from the temporary resource array.
+ assert(NULL == _fields, "invariant");
+
+ _fields =
+ MetadataFactory::new_array<u2>(_loader_data,
+ index * FieldInfo::field_slots + num_generic_signature,
+ CHECK);
// Sometimes injected fields already exist in the Java source so
// the fields array could be too long. In that case the
// fields array is trimed. Also unused slots that were reserved
// for generic signature indexes are discarded.
- Array<u2>* fields = MetadataFactory::new_array<u2>(
- _loader_data, index * FieldInfo::field_slots + num_generic_signature,
- CHECK_NULL);
- _fields = fields; // save in case of error
{
int i = 0;
for (; i < index * FieldInfo::field_slots; i++) {
- fields->at_put(i, fa[i]);
+ _fields->at_put(i, fa[i]);
}
for (int j = total_fields * FieldInfo::field_slots;
j < generic_signature_slot; j++) {
- fields->at_put(i++, fa[j]);
+ _fields->at_put(i++, fa[j]);
}
- assert(i == fields->length(), "");
+ assert(_fields->length() == i, "");
}
if (_need_verify && length > 1) {
@@ -1291,9 +1616,9 @@
bool dup = false;
{
debug_only(No_Safepoint_Verifier nsv;)
- for (AllFieldStream fs(fields, _cp); !fs.done(); fs.next()) {
- Symbol* name = fs.name();
- Symbol* sig = fs.signature();
+ for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
+ const Symbol* const name = fs.name();
+ const Symbol* const sig = fs.signature();
// If no duplicates, add name/signature in hashtable names_and_sigs.
if (!put_after_lookup(name, sig, names_and_sigs)) {
dup = true;
@@ -1303,36 +1628,39 @@
}
if (dup) {
classfile_parse_error("Duplicate field name&signature in class file %s",
- CHECK_NULL);
+ CHECK);
}
}
-
- return fields;
}
-static void copy_u2_with_conversion(u2* dest, u2* src, int length) {
+static void copy_u2_with_conversion(u2* dest, const u2* src, int length) {
while (length-- > 0) {
*dest++ = Bytes::get_Java_u2((u1*) (src++));
}
}
-
-u2* ClassFileParser::parse_exception_table(u4 code_length,
- u4 exception_table_length,
- TRAPS) {
- ClassFileStream* cfs = stream();
-
- u2* exception_table_start = cfs->get_u2_buffer();
+const u2* ClassFileParser::parse_exception_table(const ClassFileStream* const cfs,
+ u4 code_length,
+ u4 exception_table_length,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+
+ const u2* const exception_table_start = cfs->get_u2_buffer();
assert(exception_table_start != NULL, "null exception table");
- cfs->guarantee_more(8 * exception_table_length, CHECK_NULL); // start_pc, end_pc, handler_pc, catch_type_index
+
+ cfs->guarantee_more(8 * exception_table_length, CHECK_NULL); // start_pc,
+ // end_pc,
+ // handler_pc,
+ // catch_type_index
+
// Will check legal target after parsing code array in verifier.
if (_need_verify) {
for (unsigned int i = 0; i < exception_table_length; i++) {
- u2 start_pc = cfs->get_u2_fast();
- u2 end_pc = cfs->get_u2_fast();
- u2 handler_pc = cfs->get_u2_fast();
- u2 catch_type_index = cfs->get_u2_fast();
+ const u2 start_pc = cfs->get_u2_fast();
+ const u2 end_pc = cfs->get_u2_fast();
+ const u2 handler_pc = cfs->get_u2_fast();
+ const u2 catch_type_index = cfs->get_u2_fast();
guarantee_property((start_pc < end_pc) && (end_pc <= code_length),
"Illegal exception table range in class file %s",
CHECK_NULL);
@@ -1350,14 +1678,16 @@
return exception_table_start;
}
-void ClassFileParser::parse_linenumber_table(
- u4 code_attribute_length, u4 code_length,
- CompressedLineNumberWriteStream** write_stream, TRAPS) {
- ClassFileStream* cfs = stream();
+void ClassFileParser::parse_linenumber_table(u4 code_attribute_length,
+ u4 code_length,
+ CompressedLineNumberWriteStream**const write_stream,
+ TRAPS) {
+
+ const ClassFileStream* const cfs = _stream;
unsigned int num_entries = cfs->get_u2(CHECK);
// Each entry is a u2 start_pc, and a u2 line_number
- unsigned int length_in_bytes = num_entries * (sizeof(u2) + sizeof(u2));
+ const unsigned int length_in_bytes = num_entries * (sizeof(u2) * 2);
// Verify line number attribute and table length
check_property(
@@ -1371,13 +1701,13 @@
(*write_stream) = new CompressedLineNumberWriteStream(length_in_bytes);
} else {
(*write_stream) = new CompressedLineNumberWriteStream(
- linenumbertable_buffer, fixed_buffer_size);
+ _linenumbertable_buffer, fixed_buffer_size);
}
}
while (num_entries-- > 0) {
- u2 bci = cfs->get_u2_fast(); // start_pc
- u2 line = cfs->get_u2_fast(); // line_number
+ const u2 bci = cfs->get_u2_fast(); // start_pc
+ const u2 line = cfs->get_u2_fast(); // line_number
guarantee_property(bci < code_length,
"Invalid pc in LineNumberTable in class file %s", CHECK);
(*write_stream)->write_pair(bci, line);
@@ -1422,7 +1752,8 @@
u2 slot;
};
-void copy_lvt_element(Classfile_LVT_Element *src, LocalVariableTableElement *lvt) {
+static void copy_lvt_element(const Classfile_LVT_Element* const src,
+ LocalVariableTableElement* const lvt) {
lvt->start_bci = Bytes::get_Java_u2((u1*) &src->start_bci);
lvt->length = Bytes::get_Java_u2((u1*) &src->length);
lvt->name_cp_index = Bytes::get_Java_u2((u1*) &src->name_cp_index);
@@ -1432,36 +1763,41 @@
}
// Function is used to parse both attributes:
-// LocalVariableTable (LVT) and LocalVariableTypeTable (LVTT)
-u2* ClassFileParser::parse_localvariable_table(u4 code_length,
- u2 max_locals,
- u4 code_attribute_length,
- u2* localvariable_table_length,
- bool isLVTT,
- TRAPS) {
- ClassFileStream* cfs = stream();
- const char * tbl_name = (isLVTT) ? "LocalVariableTypeTable" : "LocalVariableTable";
+// LocalVariableTable (LVT) and LocalVariableTypeTable (LVTT)
+const u2* ClassFileParser::parse_localvariable_table(const ClassFileStream* cfs,
+ u4 code_length,
+ u2 max_locals,
+ u4 code_attribute_length,
+ u2* const localvariable_table_length,
+ bool isLVTT,
+ TRAPS) {
+ const char* const tbl_name = (isLVTT) ? "LocalVariableTypeTable" : "LocalVariableTable";
*localvariable_table_length = cfs->get_u2(CHECK_NULL);
- unsigned int size = (*localvariable_table_length) * sizeof(Classfile_LVT_Element) / sizeof(u2);
+ const unsigned int size =
+ (*localvariable_table_length) * sizeof(Classfile_LVT_Element) / sizeof(u2);
+
+ const ConstantPool* const cp = _cp;
+
// Verify local variable table attribute has right length
if (_need_verify) {
guarantee_property(code_attribute_length == (sizeof(*localvariable_table_length) + size * sizeof(u2)),
"%s has wrong length in class file %s", tbl_name, CHECK_NULL);
}
- u2* localvariable_table_start = cfs->get_u2_buffer();
+
+ const u2* const localvariable_table_start = cfs->get_u2_buffer();
assert(localvariable_table_start != NULL, "null local variable table");
if (!_need_verify) {
cfs->skip_u2_fast(size);
} else {
cfs->guarantee_more(size * 2, CHECK_NULL);
for(int i = 0; i < (*localvariable_table_length); i++) {
- u2 start_pc = cfs->get_u2_fast();
- u2 length = cfs->get_u2_fast();
- u2 name_index = cfs->get_u2_fast();
- u2 descriptor_index = cfs->get_u2_fast();
- u2 index = cfs->get_u2_fast();
+ const u2 start_pc = cfs->get_u2_fast();
+ const u2 length = cfs->get_u2_fast();
+ const u2 name_index = cfs->get_u2_fast();
+ const u2 descriptor_index = cfs->get_u2_fast();
+ const u2 index = cfs->get_u2_fast();
// Assign to a u4 to avoid overflow
- u4 end_pc = (u4)start_pc + (u4)length;
+ const u4 end_pc = (u4)start_pc + (u4)length;
if (start_pc >= code_length) {
classfile_parse_error(
@@ -1473,7 +1809,7 @@
"Invalid length %u in %s in class file %s",
length, tbl_name, CHECK_NULL);
}
- int cp_size = _cp->length();
+ const int cp_size = cp->length();
guarantee_property(valid_symbol_at(name_index),
"Name index %u in %s has bad constant type in class file %s",
name_index, tbl_name, CHECK_NULL);
@@ -1481,8 +1817,8 @@
"Signature index %u in %s has bad constant type in class file %s",
descriptor_index, tbl_name, CHECK_NULL);
- Symbol* name = _cp->symbol_at(name_index);
- Symbol* sig = _cp->symbol_at(descriptor_index);
+ const Symbol* const name = cp->symbol_at(name_index);
+ const Symbol* const sig = cp->symbol_at(descriptor_index);
verify_legal_field_name(name, CHECK_NULL);
u2 extra_slot = 0;
if (!isLVTT) {
@@ -1503,24 +1839,29 @@
}
-void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index,
- u1* u1_array, u2* u2_array, TRAPS) {
- ClassFileStream* cfs = stream();
+void ClassFileParser::parse_type_array(u2 array_length,
+ u4 code_length,
+ u4* const u1_index,
+ u4* const u2_index,
+ u1* const u1_array,
+ u2* const u2_array,
+ TRAPS) {
+ const ClassFileStream* const cfs = _stream;
u2 index = 0; // index in the array with long/double occupying two slots
u4 i1 = *u1_index;
u4 i2 = *u2_index + 1;
for(int i = 0; i < array_length; i++) {
- u1 tag = u1_array[i1++] = cfs->get_u1(CHECK);
+ const u1 tag = u1_array[i1++] = cfs->get_u1(CHECK);
index++;
if (tag == ITEM_Long || tag == ITEM_Double) {
index++;
} else if (tag == ITEM_Object) {
- u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK);
+ const u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK);
guarantee_property(valid_klass_reference_at(class_index),
"Bad class index %u in StackMap in class file %s",
class_index, CHECK);
} else if (tag == ITEM_Uninitialized) {
- u2 offset = u2_array[i2++] = cfs->get_u2(CHECK);
+ const u2 offset = u2_array[i2++] = cfs->get_u2(CHECK);
guarantee_property(
offset < code_length,
"Bad uninitialized type offset %u in StackMap in class file %s",
@@ -1537,39 +1878,47 @@
*u2_index = i2;
}
-u1* ClassFileParser::parse_stackmap_table(
- u4 code_attribute_length, TRAPS) {
- if (code_attribute_length == 0)
+static const u1* parse_stackmap_table(const ClassFileStream* const cfs,
+ u4 code_attribute_length,
+ bool need_verify,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+
+ if (0 == code_attribute_length) {
return NULL;
-
- ClassFileStream* cfs = stream();
- u1* stackmap_table_start = cfs->get_u1_buffer();
+ }
+
+ const u1* const stackmap_table_start = cfs->get_u1_buffer();
assert(stackmap_table_start != NULL, "null stackmap table");
// check code_attribute_length first
- stream()->skip_u1(code_attribute_length, CHECK_NULL);
-
- if (!_need_verify && !DumpSharedSpaces) {
+ cfs->skip_u1(code_attribute_length, CHECK_NULL);
+
+ if (!need_verify && !DumpSharedSpaces) {
return NULL;
}
return stackmap_table_start;
}
-u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length,
- u4 method_attribute_length,
- TRAPS) {
- ClassFileStream* cfs = stream();
+const u2* ClassFileParser::parse_checked_exceptions(const ClassFileStream* const cfs,
+ u2* const checked_exceptions_length,
+ u4 method_attribute_length,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+ assert(checked_exceptions_length != NULL, "invariant");
+
cfs->guarantee_more(2, CHECK_NULL); // checked_exceptions_length
*checked_exceptions_length = cfs->get_u2_fast();
- unsigned int size = (*checked_exceptions_length) * sizeof(CheckedExceptionElement) / sizeof(u2);
- u2* checked_exceptions_start = cfs->get_u2_buffer();
+ const unsigned int size =
+ (*checked_exceptions_length) * sizeof(CheckedExceptionElement) / sizeof(u2);
+ const u2* const checked_exceptions_start = cfs->get_u2_buffer();
assert(checked_exceptions_start != NULL, "null checked exceptions");
if (!_need_verify) {
cfs->skip_u2_fast(size);
} else {
// Verify each value in the checked exception table
u2 checked_exception;
- u2 len = *checked_exceptions_length;
+ const u2 len = *checked_exceptions_length;
cfs->guarantee_more(2 * len, CHECK_NULL);
for (int i = 0; i < len; i++) {
checked_exception = cfs->get_u2_fast();
@@ -1588,8 +1937,13 @@
return checked_exceptions_start;
}
-void ClassFileParser::throwIllegalSignature(
- const char* type, Symbol* name, Symbol* sig, TRAPS) {
+void ClassFileParser::throwIllegalSignature(const char* type,
+ const Symbol* name,
+ const Symbol* sig,
+ TRAPS) const {
+ assert(name != NULL, "invariant");
+ assert(sig != NULL, "invariant");
+
ResourceMark rm(THREAD);
Exceptions::fthrow(THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -1597,181 +1951,74 @@
name->as_C_string(), _class_name->as_C_string(), sig->as_C_string());
}
-// Skip an annotation. Return >=limit if there is any problem.
-int ClassFileParser::skip_annotation(u1* buffer, int limit, int index) {
- // annotation := atype:u2 do(nmem:u2) {member:u2 value}
- // value := switch (tag:u1) { ... }
- index += 2; // skip atype
- if ((index += 2) >= limit) return limit; // read nmem
- int nmem = Bytes::get_Java_u2(buffer+index-2);
- while (--nmem >= 0 && index < limit) {
- index += 2; // skip member
- index = skip_annotation_value(buffer, limit, index);
- }
- return index;
-}
-
-// Skip an annotation value. Return >=limit if there is any problem.
-int ClassFileParser::skip_annotation_value(u1* buffer, int limit, int index) {
- // value := switch (tag:u1) {
- // case B, C, I, S, Z, D, F, J, c: con:u2;
- // case e: e_class:u2 e_name:u2;
- // case s: s_con:u2;
- // case [: do(nval:u2) {value};
- // case @: annotation;
- // case s: s_con:u2;
- // }
- if ((index += 1) >= limit) return limit; // read tag
- u1 tag = buffer[index-1];
- switch (tag) {
- case 'B': case 'C': case 'I': case 'S': case 'Z':
- case 'D': case 'F': case 'J': case 'c': case 's':
- index += 2; // skip con or s_con
- break;
- case 'e':
- index += 4; // skip e_class, e_name
- break;
- case '[':
- {
- if ((index += 2) >= limit) return limit; // read nval
- int nval = Bytes::get_Java_u2(buffer+index-2);
- while (--nval >= 0 && index < limit) {
- index = skip_annotation_value(buffer, limit, index);
- }
- }
- break;
- case '@':
- index = skip_annotation(buffer, limit, index);
- break;
- default:
- return limit; // bad tag byte
- }
- return index;
-}
-
-// Sift through annotations, looking for those significant to the VM:
-void ClassFileParser::parse_annotations(u1* buffer, int limit,
- ClassFileParser::AnnotationCollector* coll) {
- // annotations := do(nann:u2) {annotation}
- int index = 0;
- if ((index += 2) >= limit) return; // read nann
- int nann = Bytes::get_Java_u2(buffer+index-2);
- enum { // initial annotation layout
- atype_off = 0, // utf8 such as 'Ljava/lang/annotation/Retention;'
- count_off = 2, // u2 such as 1 (one value)
- member_off = 4, // utf8 such as 'value'
- tag_off = 6, // u1 such as 'c' (type) or 'e' (enum)
- e_tag_val = 'e',
- e_type_off = 7, // utf8 such as 'Ljava/lang/annotation/RetentionPolicy;'
- e_con_off = 9, // utf8 payload, such as 'SOURCE', 'CLASS', 'RUNTIME'
- e_size = 11, // end of 'e' annotation
- c_tag_val = 'c', // payload is type
- c_con_off = 7, // utf8 payload, such as 'I'
- c_size = 9, // end of 'c' annotation
- s_tag_val = 's', // payload is String
- s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;'
- s_size = 9,
- min_size = 6 // smallest possible size (zero members)
- };
- while ((--nann) >= 0 && (index-2 + min_size <= limit)) {
- int index0 = index;
- index = skip_annotation(buffer, limit, index);
- u1* abase = buffer + index0;
- int atype = Bytes::get_Java_u2(abase + atype_off);
- int count = Bytes::get_Java_u2(abase + count_off);
- Symbol* aname = check_symbol_at(_cp, atype);
- if (aname == NULL) break; // invalid annotation name
- Symbol* member = NULL;
- if (count >= 1) {
- int member_index = Bytes::get_Java_u2(abase + member_off);
- member = check_symbol_at(_cp, member_index);
- if (member == NULL) break; // invalid member name
- }
-
- // Here is where parsing particular annotations will take place.
- AnnotationCollector::ID id = coll->annotation_index(_loader_data, aname);
- if (id == AnnotationCollector::_unknown) continue;
- coll->set_annotation(id);
-
- if (id == AnnotationCollector::_jdk_internal_vm_annotation_Contended) {
- // @Contended can optionally specify the contention group.
- //
- // Contended group defines the equivalence class over the fields:
- // the fields within the same contended group are not treated distinct.
- // The only exception is default group, which does not incur the
- // equivalence. Naturally, contention group for classes is meaningless.
- //
- // While the contention group is specified as String, annotation
- // values are already interned, and we might as well use the constant
- // pool index as the group tag.
- //
- u2 group_index = 0; // default contended group
- if (count == 1
- && s_size == (index - index0) // match size
- && s_tag_val == *(abase + tag_off)
- && member == vmSymbols::value_name()) {
- group_index = Bytes::get_Java_u2(abase + s_con_off);
- if (_cp->symbol_at(group_index)->utf8_length() == 0) {
- group_index = 0; // default contended group
- }
- }
- coll->set_contended_group(group_index);
- }
- }
-}
-
-ClassFileParser::AnnotationCollector::ID
-ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_data,
- Symbol* name) {
- vmSymbols::SID sid = vmSymbols::find_sid(name);
+AnnotationCollector::ID
+AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
+ const Symbol* name) {
+ const vmSymbols::SID sid = vmSymbols::find_sid(name);
// Privileged code can use all annotations. Other code silently drops some.
const bool privileged = loader_data->is_the_null_class_loader_data() ||
loader_data->is_ext_class_loader_data() ||
loader_data->is_anonymous();
switch (sid) {
- case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_reflect_CallerSensitive_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_CallerSensitive;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_ForceInline;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_DontInline;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_InjectedProfile_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_InjectedProfile;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_LambdaForm_Compiled;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Hidden_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_LambdaForm_Hidden;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_HotSpotIntrinsicCandidate_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_HotSpotIntrinsicCandidate;
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_reflect_CallerSensitive_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_CallerSensitive;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_ForceInline;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_DontInline;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_InjectedProfile_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_InjectedProfile;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_LambdaForm_Compiled;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Hidden_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_LambdaForm_Hidden;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_HotSpotIntrinsicCandidate_signature): {
+ 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;
+ 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
- return _field_Stable;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Contended_signature):
- if (_location != _in_field && _location != _in_class) break; // only allow for fields and classes
- if (!EnableContended || (RestrictContended && !privileged)) break; // honor privileges
- return _jdk_internal_vm_annotation_Contended;
- default: break;
+ 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
+ return _field_Stable;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Contended_signature): {
+ if (_location != _in_field && _location != _in_class) {
+ break; // only allow for fields and classes
+ }
+ if (!EnableContended || (RestrictContended && !privileged)) {
+ break; // honor privileges
+ }
+ return _jdk_internal_vm_annotation_Contended;
+ }
+ default: {
+ break;
+ }
}
return AnnotationCollector::_unknown;
}
@@ -1789,7 +2036,7 @@
MetadataFactory::free_array<u1>(_loader_data, _field_type_annotations);
}
-void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) {
+void MethodAnnotationCollector::apply_to(methodHandle m) {
if (has_annotation(_method_CallerSensitive))
m->set_caller_sensitive(true);
if (has_annotation(_method_ForceInline))
@@ -1806,11 +2053,11 @@
m->set_intrinsic_candidate(true);
}
-void ClassFileParser::ClassAnnotationCollector::apply_to(instanceKlassHandle k) {
- k->set_is_contended(is_contended());
+void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) {
+ assert(ik != NULL, "invariant");
+ ik->set_is_contended(is_contended());
}
-
#define MAX_ARGS_SIZE 255
#define MAX_CODE_SIZE 65535
#define INITIAL_MAX_LVT_NUMBER 256
@@ -1828,13 +2075,13 @@
* Each LVTT entry has to match some LVT entry.
* - HotSpot internal LVT keeps natural ordering of class file LVT entries.
*/
-void ClassFileParser::copy_localvariable_table(ConstMethod* cm,
+void ClassFileParser::copy_localvariable_table(const ConstMethod* cm,
int lvt_cnt,
- u2* localvariable_table_length,
- u2** localvariable_table_start,
+ u2* const localvariable_table_length,
+ const u2**const localvariable_table_start,
int lvtt_cnt,
- u2* localvariable_type_table_length,
- u2** localvariable_type_table_start,
+ u2* const localvariable_type_table_length,
+ const u2**const localvariable_type_table_start,
TRAPS) {
ResourceMark rm(THREAD);
@@ -1842,10 +2089,10 @@
typedef ResourceHashtable<LocalVariableTableElement, LocalVariableTableElement*,
&LVT_Hash::hash, &LVT_Hash::equals> LVT_HashTable;
- LVT_HashTable* table = new LVT_HashTable();
+ LVT_HashTable* const table = new LVT_HashTable();
// To fill LocalVariableTable in
- Classfile_LVT_Element* cf_lvt;
+ const Classfile_LVT_Element* cf_lvt;
LocalVariableTableElement* lvt = cm->localvariable_table_start();
for (int tbl_no = 0; tbl_no < lvt_cnt; tbl_no++) {
@@ -1865,7 +2112,7 @@
}
// To merge LocalVariableTable and LocalVariableTypeTable
- Classfile_LVT_Element* cf_lvtt;
+ const Classfile_LVT_Element* cf_lvtt;
LocalVariableTableElement lvtt_elem;
for (int tbl_no = 0; tbl_no < lvtt_cnt; tbl_no++) {
@@ -1895,19 +2142,19 @@
void ClassFileParser::copy_method_annotations(ConstMethod* cm,
- u1* runtime_visible_annotations,
+ const u1* runtime_visible_annotations,
int runtime_visible_annotations_length,
- u1* runtime_invisible_annotations,
+ const u1* runtime_invisible_annotations,
int runtime_invisible_annotations_length,
- u1* runtime_visible_parameter_annotations,
+ const u1* runtime_visible_parameter_annotations,
int runtime_visible_parameter_annotations_length,
- u1* runtime_invisible_parameter_annotations,
+ const u1* runtime_invisible_parameter_annotations,
int runtime_invisible_parameter_annotations_length,
- u1* runtime_visible_type_annotations,
+ const u1* runtime_visible_type_annotations,
int runtime_visible_type_annotations_length,
- u1* runtime_invisible_type_annotations,
+ const u1* runtime_invisible_type_annotations,
int runtime_invisible_type_annotations_length,
- u1* annotation_default,
+ const u1* annotation_default,
int annotation_default_length,
TRAPS) {
@@ -1963,33 +2210,37 @@
// from the method back up to the containing klass. These flag values
// are added to klass's access_flags.
-methodHandle ClassFileParser::parse_method(bool is_interface,
- AccessFlags *promoted_flags,
- TRAPS) {
- ClassFileStream* cfs = stream();
- methodHandle nullHandle;
+Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
+ bool is_interface,
+ const ConstantPool* cp,
+ AccessFlags* const promoted_flags,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+ assert(promoted_flags != NULL, "invariant");
+
ResourceMark rm(THREAD);
- // Parse fixed parts
- cfs->guarantee_more(8, CHECK_(nullHandle)); // access_flags, name_index, descriptor_index, attributes_count
+ // Parse fixed parts:
+ // access_flags, name_index, descriptor_index, attributes_count
+ cfs->guarantee_more(8, CHECK_NULL);
int flags = cfs->get_u2_fast();
- u2 name_index = cfs->get_u2_fast();
- int cp_size = _cp->length();
+ const u2 name_index = cfs->get_u2_fast();
+ const int cp_size = cp->length();
check_property(
valid_symbol_at(name_index),
"Illegal constant pool index %u for method name in class file %s",
- name_index, CHECK_(nullHandle));
- Symbol* name = _cp->symbol_at(name_index);
- verify_legal_method_name(name, CHECK_(nullHandle));
-
- u2 signature_index = cfs->get_u2_fast();
+ name_index, CHECK_NULL);
+ const Symbol* const name = cp->symbol_at(name_index);
+ verify_legal_method_name(name, CHECK_NULL);
+
+ const u2 signature_index = cfs->get_u2_fast();
guarantee_property(
valid_symbol_at(signature_index),
"Illegal constant pool index %u for method signature in class file %s",
- signature_index, CHECK_(nullHandle));
- Symbol* signature = _cp->symbol_at(signature_index);
-
- AccessFlags access_flags;
+ signature_index, CHECK_NULL);
+ const Symbol* const signature = cp->symbol_at(signature_index);
+
if (name == vmSymbols::class_initializer_name()) {
// We ignore the other access flags for a valid class initializer.
// (JVM Spec 2nd ed., chapter 4.6)
@@ -1998,37 +2249,37 @@
} else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) {
flags &= JVM_ACC_STATIC | JVM_ACC_STRICT;
} else {
- classfile_parse_error("Method <clinit> is not static in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Method <clinit> is not static in class file %s", CHECK_NULL);
}
} else {
- verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
+ verify_legal_method_modifiers(flags, is_interface, name, CHECK_NULL);
}
if (name == vmSymbols::object_initializer_name() && is_interface) {
- classfile_parse_error("Interface cannot have a method named <init>, class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Interface cannot have a method named <init>, class file %s", CHECK_NULL);
}
int args_size = -1; // only used when _need_verify is true
if (_need_verify) {
args_size = ((flags & JVM_ACC_STATIC) ? 0 : 1) +
- verify_legal_method_signature(name, signature, CHECK_(nullHandle));
+ verify_legal_method_signature(name, signature, CHECK_NULL);
if (args_size > MAX_ARGS_SIZE) {
- classfile_parse_error("Too many arguments in method signature in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Too many arguments in method signature in class file %s", CHECK_NULL);
}
}
- access_flags.set_flags(flags & JVM_RECOGNIZED_METHOD_MODIFIERS);
+ AccessFlags access_flags(flags & JVM_RECOGNIZED_METHOD_MODIFIERS);
// Default values for code and exceptions attribute elements
u2 max_stack = 0;
u2 max_locals = 0;
u4 code_length = 0;
- u1* code_start = 0;
+ const u1* code_start = 0;
u2 exception_table_length = 0;
- u2* exception_table_start = NULL;
+ const u2* exception_table_start = NULL;
Array<int>* exception_handlers = Universe::the_empty_int_array();
u2 checked_exceptions_length = 0;
- u2* checked_exceptions_start = NULL;
+ const u2* checked_exceptions_start = NULL;
CompressedLineNumberWriteStream* linenumber_table = NULL;
int linenumber_table_length = 0;
int total_lvt_length = 0;
@@ -2038,98 +2289,102 @@
u2 max_lvt_cnt = INITIAL_MAX_LVT_NUMBER;
u2 max_lvtt_cnt = INITIAL_MAX_LVT_NUMBER;
u2* localvariable_table_length = NULL;
- u2** localvariable_table_start = NULL;
+ const u2** localvariable_table_start = NULL;
u2* localvariable_type_table_length = NULL;
- u2** localvariable_type_table_start = NULL;
+ const u2** localvariable_type_table_start = NULL;
int method_parameters_length = -1;
- u1* method_parameters_data = NULL;
+ const u1* method_parameters_data = NULL;
bool method_parameters_seen = false;
bool parsed_code_attribute = false;
bool parsed_checked_exceptions_attribute = false;
bool parsed_stackmap_attribute = false;
// stackmap attribute - JDK1.5
- u1* stackmap_data = NULL;
+ const u1* stackmap_data = NULL;
int stackmap_data_length = 0;
u2 generic_signature_index = 0;
MethodAnnotationCollector parsed_annotations;
- u1* runtime_visible_annotations = NULL;
+ const u1* runtime_visible_annotations = NULL;
int runtime_visible_annotations_length = 0;
- u1* runtime_invisible_annotations = NULL;
+ const u1* runtime_invisible_annotations = NULL;
int runtime_invisible_annotations_length = 0;
- u1* runtime_visible_parameter_annotations = NULL;
+ const u1* runtime_visible_parameter_annotations = NULL;
int runtime_visible_parameter_annotations_length = 0;
- u1* runtime_invisible_parameter_annotations = NULL;
+ const u1* runtime_invisible_parameter_annotations = NULL;
int runtime_invisible_parameter_annotations_length = 0;
- u1* runtime_visible_type_annotations = NULL;
+ const u1* runtime_visible_type_annotations = NULL;
int runtime_visible_type_annotations_length = 0;
- u1* runtime_invisible_type_annotations = NULL;
+ const u1* runtime_invisible_type_annotations = NULL;
int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_annotations_exists = false;
bool runtime_invisible_type_annotations_exists = false;
bool runtime_invisible_parameter_annotations_exists = false;
- u1* annotation_default = NULL;
+ const u1* annotation_default = NULL;
int annotation_default_length = 0;
// Parse code and exceptions attribute
u2 method_attributes_count = cfs->get_u2_fast();
while (method_attributes_count--) {
- cfs->guarantee_more(6, CHECK_(nullHandle)); // method_attribute_name_index, method_attribute_length
- u2 method_attribute_name_index = cfs->get_u2_fast();
- u4 method_attribute_length = cfs->get_u4_fast();
+ cfs->guarantee_more(6, CHECK_NULL); // method_attribute_name_index, method_attribute_length
+ const u2 method_attribute_name_index = cfs->get_u2_fast();
+ const u4 method_attribute_length = cfs->get_u4_fast();
check_property(
valid_symbol_at(method_attribute_name_index),
"Invalid method attribute name index %u in class file %s",
- method_attribute_name_index, CHECK_(nullHandle));
-
- Symbol* method_attribute_name = _cp->symbol_at(method_attribute_name_index);
+ method_attribute_name_index, CHECK_NULL);
+
+ const Symbol* const method_attribute_name = cp->symbol_at(method_attribute_name_index);
if (method_attribute_name == vmSymbols::tag_code()) {
// Parse Code attribute
if (_need_verify) {
guarantee_property(
!access_flags.is_native() && !access_flags.is_abstract(),
"Code attribute in native or abstract methods in class file %s",
- CHECK_(nullHandle));
+ CHECK_NULL);
}
if (parsed_code_attribute) {
- classfile_parse_error("Multiple Code attributes in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Multiple Code attributes in class file %s",
+ CHECK_NULL);
}
parsed_code_attribute = true;
// Stack size, locals size, and code size
if (_major_version == 45 && _minor_version <= 2) {
- cfs->guarantee_more(4, CHECK_(nullHandle));
+ cfs->guarantee_more(4, CHECK_NULL);
max_stack = cfs->get_u1_fast();
max_locals = cfs->get_u1_fast();
code_length = cfs->get_u2_fast();
} else {
- cfs->guarantee_more(8, CHECK_(nullHandle));
+ cfs->guarantee_more(8, CHECK_NULL);
max_stack = cfs->get_u2_fast();
max_locals = cfs->get_u2_fast();
code_length = cfs->get_u4_fast();
}
if (_need_verify) {
guarantee_property(args_size <= max_locals,
- "Arguments can't fit into locals in class file %s", CHECK_(nullHandle));
+ "Arguments can't fit into locals in class file %s",
+ CHECK_NULL);
guarantee_property(code_length > 0 && code_length <= MAX_CODE_SIZE,
"Invalid method Code length %u in class file %s",
- code_length, CHECK_(nullHandle));
+ code_length, CHECK_NULL);
}
// Code pointer
code_start = cfs->get_u1_buffer();
assert(code_start != NULL, "null code start");
- cfs->guarantee_more(code_length, CHECK_(nullHandle));
+ cfs->guarantee_more(code_length, CHECK_NULL);
cfs->skip_u1_fast(code_length);
// Exception handler table
- cfs->guarantee_more(2, CHECK_(nullHandle)); // exception_table_length
+ cfs->guarantee_more(2, CHECK_NULL); // exception_table_length
exception_table_length = cfs->get_u2_fast();
if (exception_table_length > 0) {
- exception_table_start =
- parse_exception_table(code_length, exception_table_length, CHECK_(nullHandle));
+ exception_table_start = parse_exception_table(cfs,
+ code_length,
+ exception_table_length,
+ CHECK_NULL);
}
// Parse additional attributes in code attribute
- cfs->guarantee_more(2, CHECK_(nullHandle)); // code_attributes_count
+ cfs->guarantee_more(2, CHECK_NULL); // code_attributes_count
u2 code_attributes_count = cfs->get_u2_fast();
unsigned int calculated_attribute_length = 0;
@@ -2152,111 +2407,119 @@
sizeof(u2) ); // catch_type_index
while (code_attributes_count--) {
- cfs->guarantee_more(6, CHECK_(nullHandle)); // code_attribute_name_index, code_attribute_length
- u2 code_attribute_name_index = cfs->get_u2_fast();
- u4 code_attribute_length = cfs->get_u4_fast();
+ cfs->guarantee_more(6, CHECK_NULL); // code_attribute_name_index, code_attribute_length
+ const u2 code_attribute_name_index = cfs->get_u2_fast();
+ const u4 code_attribute_length = cfs->get_u4_fast();
calculated_attribute_length += code_attribute_length +
sizeof(code_attribute_name_index) +
sizeof(code_attribute_length);
check_property(valid_symbol_at(code_attribute_name_index),
"Invalid code attribute name index %u in class file %s",
code_attribute_name_index,
- CHECK_(nullHandle));
+ CHECK_NULL);
if (LoadLineNumberTables &&
- _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) {
+ cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) {
// Parse and compress line number table
- parse_linenumber_table(code_attribute_length, code_length,
- &linenumber_table, CHECK_(nullHandle));
+ parse_linenumber_table(code_attribute_length,
+ code_length,
+ &linenumber_table,
+ CHECK_NULL);
} else if (LoadLocalVariableTables &&
- _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) {
+ cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) {
// Parse local variable table
if (!lvt_allocated) {
localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
lvt_allocated = true;
}
if (lvt_cnt == max_lvt_cnt) {
max_lvt_cnt <<= 1;
localvariable_table_length = REALLOC_RESOURCE_ARRAY(u2, localvariable_table_length, lvt_cnt, max_lvt_cnt);
- localvariable_table_start = REALLOC_RESOURCE_ARRAY(u2*, localvariable_table_start, lvt_cnt, max_lvt_cnt);
+ localvariable_table_start = REALLOC_RESOURCE_ARRAY(const u2*, localvariable_table_start, lvt_cnt, max_lvt_cnt);
}
localvariable_table_start[lvt_cnt] =
- parse_localvariable_table(code_length,
+ parse_localvariable_table(cfs,
+ code_length,
max_locals,
code_attribute_length,
&localvariable_table_length[lvt_cnt],
false, // is not LVTT
- CHECK_(nullHandle));
+ CHECK_NULL);
total_lvt_length += localvariable_table_length[lvt_cnt];
lvt_cnt++;
} else if (LoadLocalVariableTypeTables &&
_major_version >= JAVA_1_5_VERSION &&
- _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) {
+ cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) {
if (!lvt_allocated) {
localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
lvt_allocated = true;
}
// Parse local variable type table
if (lvtt_cnt == max_lvtt_cnt) {
max_lvtt_cnt <<= 1;
localvariable_type_table_length = REALLOC_RESOURCE_ARRAY(u2, localvariable_type_table_length, lvtt_cnt, max_lvtt_cnt);
- localvariable_type_table_start = REALLOC_RESOURCE_ARRAY(u2*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt);
+ localvariable_type_table_start = REALLOC_RESOURCE_ARRAY(const u2*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt);
}
localvariable_type_table_start[lvtt_cnt] =
- parse_localvariable_table(code_length,
+ parse_localvariable_table(cfs,
+ code_length,
max_locals,
code_attribute_length,
&localvariable_type_table_length[lvtt_cnt],
true, // is LVTT
- CHECK_(nullHandle));
+ CHECK_NULL);
lvtt_cnt++;
} else if (_major_version >= Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION &&
- _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) {
+ cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) {
// Stack map is only needed by the new verifier in JDK1.5.
if (parsed_stackmap_attribute) {
- classfile_parse_error("Multiple StackMapTable attributes in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Multiple StackMapTable attributes in class file %s", CHECK_NULL);
}
- stackmap_data = parse_stackmap_table(code_attribute_length, CHECK_(nullHandle));
+ stackmap_data = parse_stackmap_table(cfs, code_attribute_length, _need_verify, CHECK_NULL);
stackmap_data_length = code_attribute_length;
parsed_stackmap_attribute = true;
} else {
// Skip unknown attributes
- cfs->skip_u1(code_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(code_attribute_length, CHECK_NULL);
}
}
// check method attribute length
if (_need_verify) {
guarantee_property(method_attribute_length == calculated_attribute_length,
- "Code segment has wrong length in class file %s", CHECK_(nullHandle));
+ "Code segment has wrong length in class file %s",
+ CHECK_NULL);
}
} else if (method_attribute_name == vmSymbols::tag_exceptions()) {
// Parse Exceptions attribute
if (parsed_checked_exceptions_attribute) {
- classfile_parse_error("Multiple Exceptions attributes in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Multiple Exceptions attributes in class file %s",
+ CHECK_NULL);
}
parsed_checked_exceptions_attribute = true;
checked_exceptions_start =
- parse_checked_exceptions(&checked_exceptions_length,
+ parse_checked_exceptions(cfs,
+ &checked_exceptions_length,
method_attribute_length,
- CHECK_(nullHandle));
+ CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_method_parameters()) {
// reject multiple method parameters
if (method_parameters_seen) {
- classfile_parse_error("Multiple MethodParameters attributes in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Multiple MethodParameters attributes in class file %s",
+ CHECK_NULL);
}
method_parameters_seen = true;
method_parameters_length = cfs->get_u1_fast();
@@ -2264,7 +2527,7 @@
if (method_attribute_length != real_length) {
classfile_parse_error(
"Invalid MethodParameters method attribute length %u in class file",
- method_attribute_length, CHECK_(nullHandle));
+ method_attribute_length, CHECK_NULL);
}
method_parameters_data = cfs->get_u1_buffer();
cfs->skip_u2_fast(method_parameters_length);
@@ -2276,7 +2539,7 @@
if (method_attribute_length != 0) {
classfile_parse_error(
"Invalid Synthetic method attribute length %u in class file %s",
- method_attribute_length, CHECK_(nullHandle));
+ method_attribute_length, CHECK_NULL);
}
// Should we check that there hasn't already been a synthetic attribute?
access_flags.set_is_synthetic();
@@ -2284,31 +2547,37 @@
if (method_attribute_length != 0) {
classfile_parse_error(
"Invalid Deprecated method attribute length %u in class file %s",
- method_attribute_length, CHECK_(nullHandle));
+ method_attribute_length, CHECK_NULL);
}
} else if (_major_version >= JAVA_1_5_VERSION) {
if (method_attribute_name == vmSymbols::tag_signature()) {
if (method_attribute_length != 2) {
classfile_parse_error(
"Invalid Signature attribute length %u in class file %s",
- method_attribute_length, CHECK_(nullHandle));
+ method_attribute_length, CHECK_NULL);
}
- generic_signature_index = parse_generic_signature_attribute(CHECK_(nullHandle));
+ generic_signature_index = parse_generic_signature_attribute(cfs, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_annotations()) {
if (runtime_visible_annotations != NULL) {
classfile_parse_error(
- "Multiple RuntimeVisibleAnnotations attributes for method in class file %s", CHECK_(nullHandle));
+ "Multiple RuntimeVisibleAnnotations attributes for method in class file %s",
+ CHECK_NULL);
}
runtime_visible_annotations_length = method_attribute_length;
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
- parse_annotations(runtime_visible_annotations,
- runtime_visible_annotations_length, &parsed_annotations);
- cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle));
+ parse_annotations(cp,
+ runtime_visible_annotations,
+ runtime_visible_annotations_length,
+ &parsed_annotations,
+ _loader_data,
+ CHECK_NULL);
+ cfs->skip_u1(runtime_visible_annotations_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
classfile_parse_error(
- "Multiple RuntimeInvisibleAnnotations attributes for method in class file %s", CHECK_(nullHandle));
+ "Multiple RuntimeInvisibleAnnotations attributes for method in class file %s",
+ CHECK_NULL);
}
runtime_invisible_annotations_exists = true;
if (PreserveAllAnnotations) {
@@ -2316,54 +2585,57 @@
runtime_invisible_annotations = cfs->get_u1_buffer();
assert(runtime_invisible_annotations != NULL, "null invisible annotations");
}
- cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_parameter_annotations()) {
if (runtime_visible_parameter_annotations != NULL) {
classfile_parse_error(
- "Multiple RuntimeVisibleParameterAnnotations attributes for method in class file %s", CHECK_(nullHandle));
+ "Multiple RuntimeVisibleParameterAnnotations attributes for method in class file %s",
+ CHECK_NULL);
}
runtime_visible_parameter_annotations_length = method_attribute_length;
runtime_visible_parameter_annotations = cfs->get_u1_buffer();
assert(runtime_visible_parameter_annotations != NULL, "null visible parameter annotations");
- cfs->skip_u1(runtime_visible_parameter_annotations_length, CHECK_(nullHandle));
+ cfs->skip_u1(runtime_visible_parameter_annotations_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_invisible_parameter_annotations()) {
if (runtime_invisible_parameter_annotations_exists) {
classfile_parse_error(
- "Multiple RuntimeInvisibleParameterAnnotations attributes for method in class file %s", CHECK_(nullHandle));
+ "Multiple RuntimeInvisibleParameterAnnotations attributes for method in class file %s",
+ CHECK_NULL);
}
runtime_invisible_parameter_annotations_exists = true;
if (PreserveAllAnnotations) {
runtime_invisible_parameter_annotations_length = method_attribute_length;
runtime_invisible_parameter_annotations = cfs->get_u1_buffer();
- assert(runtime_invisible_parameter_annotations != NULL, "null invisible parameter annotations");
+ assert(runtime_invisible_parameter_annotations != NULL,
+ "null invisible parameter annotations");
}
- cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_annotation_default()) {
if (annotation_default != NULL) {
classfile_parse_error(
"Multiple AnnotationDefault attributes for method in class file %s",
- CHECK_(nullHandle));
+ CHECK_NULL);
}
annotation_default_length = method_attribute_length;
annotation_default = cfs->get_u1_buffer();
assert(annotation_default != NULL, "null annotation default");
- cfs->skip_u1(annotation_default_length, CHECK_(nullHandle));
+ cfs->skip_u1(annotation_default_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
if (runtime_visible_type_annotations != NULL) {
classfile_parse_error(
"Multiple RuntimeVisibleTypeAnnotations attributes for method in class file %s",
- CHECK_(nullHandle));
+ CHECK_NULL);
}
runtime_visible_type_annotations_length = method_attribute_length;
runtime_visible_type_annotations = cfs->get_u1_buffer();
assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
// No need for the VM to parse Type annotations
- cfs->skip_u1(runtime_visible_type_annotations_length, CHECK_(nullHandle));
+ cfs->skip_u1(runtime_visible_type_annotations_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
if (runtime_invisible_type_annotations_exists) {
classfile_parse_error(
"Multiple RuntimeInvisibleTypeAnnotations attributes for method in class file %s",
- CHECK_(nullHandle));
+ CHECK_NULL);
} else {
runtime_invisible_type_annotations_exists = true;
}
@@ -2372,14 +2644,14 @@
runtime_invisible_type_annotations = cfs->get_u1_buffer();
assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
}
- cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else {
// Skip unknown attributes
- cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(method_attribute_length, CHECK_NULL);
}
} else {
// Skip unknown attributes
- cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(method_attribute_length, CHECK_NULL);
}
}
@@ -2390,8 +2662,11 @@
// Make sure there's at least one Code attribute in non-native/non-abstract method
if (_need_verify) {
- guarantee_property(access_flags.is_native() || access_flags.is_abstract() || parsed_code_attribute,
- "Absent Code attribute in method that is not native or abstract in class file %s", CHECK_(nullHandle));
+ guarantee_property(access_flags.is_native() ||
+ access_flags.is_abstract() ||
+ parsed_code_attribute,
+ "Absent Code attribute in method that is not native or abstract in class file %s",
+ CHECK_NULL);
}
// All sizing information for a Method* is finally available, now create it
@@ -2411,9 +2686,12 @@
annotation_default_length,
0);
- Method* m = Method::allocate(
- _loader_data, code_length, access_flags, &sizes,
- ConstMethod::NORMAL, CHECK_(nullHandle));
+ Method* const m = Method::allocate(_loader_data,
+ code_length,
+ access_flags,
+ &sizes,
+ ConstMethod::NORMAL,
+ CHECK_NULL);
ClassLoadingService::add_class_method_size(m->size()*HeapWordSize);
@@ -2423,7 +2701,7 @@
m->set_signature_index(signature_index);
#ifdef CC_INTERP
// hmm is there a gc issue here??
- ResultTypeFinder rtf(_cp->symbol_at(signature_index));
+ ResultTypeFinder rtf(cp->symbol_at(signature_index));
m->set_result_index(rtf.type());
#endif
@@ -2443,17 +2721,20 @@
m->set_max_stack(max_stack);
m->set_max_locals(max_locals);
if (stackmap_data != NULL) {
- m->constMethod()->copy_stackmap_data(_loader_data, stackmap_data,
- stackmap_data_length, CHECK_NULL);
+ m->constMethod()->copy_stackmap_data(_loader_data,
+ (u1*)stackmap_data,
+ stackmap_data_length,
+ CHECK_NULL);
}
// Copy byte codes
- m->set_code(code_start);
+ m->set_code((u1*)code_start);
// Copy line number table
if (linenumber_table != NULL) {
memcpy(m->compressed_linenumber_table(),
- linenumber_table->buffer(), linenumber_table_length);
+ linenumber_table->buffer(),
+ linenumber_table_length);
}
// Copy exception table
@@ -2461,35 +2742,40 @@
int size =
exception_table_length * sizeof(ExceptionTableElement) / sizeof(u2);
copy_u2_with_conversion((u2*) m->exception_table_start(),
- exception_table_start, size);
+ exception_table_start, size);
}
// Copy method parameters
if (method_parameters_length > 0) {
MethodParametersElement* elem = m->constMethod()->method_parameters_start();
for (int i = 0; i < method_parameters_length; i++) {
- elem[i].name_cp_index = Bytes::get_Java_u2(method_parameters_data);
+ elem[i].name_cp_index = Bytes::get_Java_u2((address)method_parameters_data);
method_parameters_data += 2;
- elem[i].flags = Bytes::get_Java_u2(method_parameters_data);
+ elem[i].flags = Bytes::get_Java_u2((address)method_parameters_data);
method_parameters_data += 2;
}
}
// Copy checked exceptions
if (checked_exceptions_length > 0) {
- int size = checked_exceptions_length * sizeof(CheckedExceptionElement) / sizeof(u2);
- copy_u2_with_conversion((u2*) m->checked_exceptions_start(), checked_exceptions_start, size);
+ const int size =
+ checked_exceptions_length * sizeof(CheckedExceptionElement) / sizeof(u2);
+ copy_u2_with_conversion((u2*) m->checked_exceptions_start(),
+ checked_exceptions_start,
+ size);
}
// Copy class file LVT's/LVTT's into the HotSpot internal LVT.
if (total_lvt_length > 0) {
promoted_flags->set_has_localvariable_table();
- copy_localvariable_table(m->constMethod(), lvt_cnt,
+ copy_localvariable_table(m->constMethod(),
+ lvt_cnt,
localvariable_table_length,
localvariable_table_start,
lvtt_cnt,
localvariable_type_table_length,
- localvariable_type_table_start, CHECK_NULL);
+ localvariable_type_table_start,
+ CHECK_NULL);
}
if (parsed_annotations.has_any_annotations())
@@ -2535,25 +2821,37 @@
// The promoted_flags parameter is used to pass relevant access_flags
// from the methods back up to the containing klass. These flag values
// are added to klass's access_flags.
-
-Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
- AccessFlags* promoted_flags,
- bool* has_final_method,
- bool* declares_default_methods,
- TRAPS) {
- ClassFileStream* cfs = stream();
- cfs->guarantee_more(2, CHECK_NULL); // length
- u2 length = cfs->get_u2_fast();
+// Side-effects: populates the _methods field in the parser
+void ClassFileParser::parse_methods(const ClassFileStream* const cfs,
+ bool is_interface,
+ AccessFlags* promoted_flags,
+ bool* has_final_method,
+ bool* declares_default_methods,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+ assert(promoted_flags != NULL, "invariant");
+ assert(has_final_method != NULL, "invariant");
+ assert(declares_default_methods != NULL, "invariant");
+
+ assert(NULL == _methods, "invariant");
+
+ cfs->guarantee_more(2, CHECK); // length
+ const u2 length = cfs->get_u2_fast();
if (length == 0) {
_methods = Universe::the_empty_method_array();
} else {
- _methods = MetadataFactory::new_array<Method*>(_loader_data, length, NULL, CHECK_NULL);
+ _methods = MetadataFactory::new_array<Method*>(_loader_data,
+ length,
+ NULL,
+ CHECK);
HandleMark hm(THREAD);
for (int index = 0; index < length; index++) {
- methodHandle method = parse_method(is_interface,
- promoted_flags,
- CHECK_NULL);
+ Method* method = parse_method(cfs,
+ is_interface,
+ _cp,
+ promoted_flags,
+ CHECK);
if (method->is_final()) {
*has_final_method = true;
@@ -2564,7 +2862,7 @@
&& !method->is_abstract() && !method->is_static()) {
*declares_default_methods = true;
}
- _methods->at_put(index, method());
+ _methods->at_put(index, method);
}
if (_need_verify && length > 1) {
@@ -2577,7 +2875,7 @@
{
debug_only(No_Safepoint_Verifier nsv;)
for (int i = 0; i < length; i++) {
- Method* m = _methods->at(i);
+ const Method* const m = _methods->at(i);
// If no duplicates, add name/signature in hashtable names_and_sigs.
if (!put_after_lookup(m->name(), m->signature(), names_and_sigs)) {
dup = true;
@@ -2587,16 +2885,14 @@
}
if (dup) {
classfile_parse_error("Duplicate method name&signature in class file %s",
- CHECK_NULL);
+ CHECK);
}
}
}
- return _methods;
}
-
-intArray* ClassFileParser::sort_methods(Array<Method*>* methods) {
- int length = methods->length();
+static const intArray* sort_methods(Array<Method*>* methods) {
+ const int length = methods->length();
// If JVMTI original method ordering or sharing is enabled we have to
// remember the original class file ordering.
// We temporarily use the vtable_index field in the Method* to store the
@@ -2604,7 +2900,7 @@
// Put the method ordering in the shared archive.
if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) {
for (int index = 0; index < length; index++) {
- Method* m = methods->at(index);
+ Method* const m = methods->at(index);
assert(!m->valid_vtable_index(), "vtable index should not be set");
m->set_vtable_index(index);
}
@@ -2619,8 +2915,8 @@
if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) {
method_ordering = new intArray(length);
for (int index = 0; index < length; index++) {
- Method* m = methods->at(index);
- int old_index = m->vtable_index();
+ Method* const m = methods->at(index);
+ const int old_index = m->vtable_index();
assert(old_index >= 0 && old_index < length, "invalid method index");
method_ordering->at_put(index, old_index);
m->set_vtable_index(Method::invalid_vtable_index);
@@ -2630,10 +2926,12 @@
}
// Parse generic_signature attribute for methods and fields
-u2 ClassFileParser::parse_generic_signature_attribute(TRAPS) {
- ClassFileStream* cfs = stream();
+u2 ClassFileParser::parse_generic_signature_attribute(const ClassFileStream* const cfs,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+
cfs->guarantee_more(2, CHECK_0); // generic_signature_index
- u2 generic_signature_index = cfs->get_u2_fast();
+ const u2 generic_signature_index = cfs->get_u2_fast();
check_property(
valid_symbol_at(generic_signature_index),
"Invalid Signature attribute at constant pool index %u in class file %s",
@@ -2641,10 +2939,13 @@
return generic_signature_index;
}
-void ClassFileParser::parse_classfile_sourcefile_attribute(TRAPS) {
- ClassFileStream* cfs = stream();
+void ClassFileParser::parse_classfile_sourcefile_attribute(const ClassFileStream* const cfs,
+ TRAPS) {
+
+ assert(cfs != NULL, "invariant");
+
cfs->guarantee_more(2, CHECK); // sourcefile_index
- u2 sourcefile_index = cfs->get_u2_fast();
+ const u2 sourcefile_index = cfs->get_u2_fast();
check_property(
valid_symbol_at(sourcefile_index),
"Invalid SourceFile attribute at constant pool index %u in class file %s",
@@ -2652,22 +2953,23 @@
set_class_sourcefile_index(sourcefile_index);
}
-
-
-void ClassFileParser::parse_classfile_source_debug_extension_attribute(int length, TRAPS) {
- ClassFileStream* cfs = stream();
- u1* sde_buffer = cfs->get_u1_buffer();
+void ClassFileParser::parse_classfile_source_debug_extension_attribute(const ClassFileStream* const cfs,
+ int length,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+
+ const u1* const sde_buffer = cfs->get_u1_buffer();
assert(sde_buffer != NULL, "null sde buffer");
// Don't bother storing it if there is no way to retrieve it
if (JvmtiExport::can_get_source_debug_extension()) {
assert((length+1) > length, "Overflow checking");
- u1* sde = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, u1, length+1);
+ u1* const sde = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, u1, length+1);
for (int i = 0; i < length; i++) {
sde[i] = sde_buffer[i];
}
sde[length] = '\0';
- set_class_sde_buffer((char*)sde, length);
+ set_class_sde_buffer((const char*)sde, length);
}
// Got utf8 string, set stream position forward
cfs->skip_u1(length, CHECK);
@@ -2675,16 +2977,20 @@
// Inner classes can be static, private or protected (classic VM does this)
-#define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC)
+#define RECOGNIZED_INNER_CLASS_MODIFIERS ( JVM_RECOGNIZED_CLASS_MODIFIERS | \
+ JVM_ACC_PRIVATE | \
+ JVM_ACC_PROTECTED | \
+ JVM_ACC_STATIC \
+ )
// Return number of classes in the inner classes attribute table
-u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start,
+u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStream* const cfs,
+ const u1* const inner_classes_attribute_start,
bool parsed_enclosingmethod_attribute,
u2 enclosing_method_class_index,
u2 enclosing_method_method_index,
TRAPS) {
- ClassFileStream* cfs = stream();
- u1* current_mark = cfs->current();
+ const u1* const current_mark = cfs->current();
u2 length = 0;
if (inner_classes_attribute_start != NULL) {
cfs->set_current(inner_classes_attribute_start);
@@ -2701,29 +3007,29 @@
// ...
// enclosing_method_class_index,
// enclosing_method_method_index]
- int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0);
- Array<u2>* inner_classes = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0);
+ const int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0);
+ Array<u2>* const inner_classes = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0);
_inner_classes = inner_classes;
int index = 0;
- int cp_size = _cp->length();
+ const int cp_size = _cp->length();
cfs->guarantee_more(8 * length, CHECK_0); // 4-tuples of u2
for (int n = 0; n < length; n++) {
// Inner class index
- u2 inner_class_info_index = cfs->get_u2_fast();
+ const u2 inner_class_info_index = cfs->get_u2_fast();
check_property(
valid_klass_reference_at(inner_class_info_index),
"inner_class_info_index %u has bad constant type in class file %s",
inner_class_info_index, CHECK_0);
// Outer class index
- u2 outer_class_info_index = cfs->get_u2_fast();
+ const u2 outer_class_info_index = cfs->get_u2_fast();
check_property(
outer_class_info_index == 0 ||
valid_klass_reference_at(outer_class_info_index),
"outer_class_info_index %u has bad constant type in class file %s",
outer_class_info_index, CHECK_0);
// Inner class name
- u2 inner_name_index = cfs->get_u2_fast();
+ const u2 inner_name_index = cfs->get_u2_fast();
check_property(
inner_name_index == 0 || valid_symbol_at(inner_name_index),
"inner_name_index %u has bad constant type in class file %s",
@@ -2733,14 +3039,13 @@
"Class is both outer and inner class in class file %s", CHECK_0);
}
// Access flags
- AccessFlags inner_access_flags;
jint flags = cfs->get_u2_fast() & RECOGNIZED_INNER_CLASS_MODIFIERS;
if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
// Set abstract bit for old class files for backward compatibility
flags |= JVM_ACC_ABSTRACT;
}
verify_legal_class_modifiers(flags, CHECK_0);
- inner_access_flags.set_flags(flags);
+ AccessFlags inner_access_flags(flags);
inner_classes->at_put(index++, inner_class_info_index);
inner_classes->at_put(index++, outer_class_info_index);
@@ -2779,9 +3084,10 @@
set_class_synthetic_flag(true);
}
-void ClassFileParser::parse_classfile_signature_attribute(TRAPS) {
- ClassFileStream* cfs = stream();
- u2 signature_index = cfs->get_u2(CHECK);
+void ClassFileParser::parse_classfile_signature_attribute(const ClassFileStream* const cfs, TRAPS) {
+ assert(cfs != NULL, "invariant");
+
+ const u2 signature_index = cfs->get_u2(CHECK);
check_property(
valid_symbol_at(signature_index),
"Invalid constant pool index %u in Signature attribute in class file %s",
@@ -2789,9 +3095,14 @@
set_class_generic_signature_index(signature_index);
}
-void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_byte_length, TRAPS) {
- ClassFileStream* cfs = stream();
- u1* current_start = cfs->current();
+void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFileStream* const cfs,
+ ConstantPool* cp,
+ u4 attribute_byte_length,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+
+ const u1* const current_start = cfs->current();
guarantee_property(attribute_byte_length >= sizeof(u2),
"Invalid BootstrapMethods attribute length %u in class file %s",
@@ -2800,7 +3111,7 @@
cfs->guarantee_more(attribute_byte_length, CHECK);
- int attribute_array_length = cfs->get_u2_fast();
+ const int attribute_array_length = cfs->get_u2_fast();
guarantee_property(_max_bootstrap_specifier_index < attribute_array_length,
"Short length on BootstrapMethods in class file %s",
@@ -2810,21 +3121,22 @@
// The attribute contains a counted array of counted tuples of shorts,
// represending bootstrap specifiers:
// length*{bootstrap_method_index, argument_count*{argument_index}}
- int operand_count = (attribute_byte_length - sizeof(u2)) / sizeof(u2);
+ const int operand_count = (attribute_byte_length - sizeof(u2)) / sizeof(u2);
// operand_count = number of shorts in attr, except for leading length
// The attribute is copied into a short[] array.
// The array begins with a series of short[2] pairs, one for each tuple.
- int index_size = (attribute_array_length * 2);
-
- Array<u2>* operands = MetadataFactory::new_array<u2>(_loader_data, index_size + operand_count, CHECK);
+ const int index_size = (attribute_array_length * 2);
+
+ Array<u2>* const operands =
+ MetadataFactory::new_array<u2>(_loader_data, index_size + operand_count, CHECK);
// Eagerly assign operands so they will be deallocated with the constant
// pool if there is an error.
- _cp->set_operands(operands);
+ cp->set_operands(operands);
int operand_fill_index = index_size;
- int cp_size = _cp->length();
+ const int cp_size = cp->length();
for (int n = 0; n < attribute_array_length; n++) {
// Store a 32-bit offset into the header of the operand array.
@@ -2832,11 +3144,11 @@
// Read a bootstrap specifier.
cfs->guarantee_more(sizeof(u2) * 2, CHECK); // bsm, argc
- u2 bootstrap_method_index = cfs->get_u2_fast();
- u2 argument_count = cfs->get_u2_fast();
+ const u2 bootstrap_method_index = cfs->get_u2_fast();
+ const u2 argument_count = cfs->get_u2_fast();
check_property(
valid_cp_range(bootstrap_method_index, cp_size) &&
- _cp->tag_at(bootstrap_method_index).is_method_handle(),
+ cp->tag_at(bootstrap_method_index).is_method_handle(),
"bootstrap_method_index %u has bad constant type in class file %s",
bootstrap_method_index,
CHECK);
@@ -2850,26 +3162,29 @@
cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc]
for (int j = 0; j < argument_count; j++) {
- u2 argument_index = cfs->get_u2_fast();
+ const u2 argument_index = cfs->get_u2_fast();
check_property(
valid_cp_range(argument_index, cp_size) &&
- _cp->tag_at(argument_index).is_loadable_constant(),
+ cp->tag_at(argument_index).is_loadable_constant(),
"argument_index %u has bad constant type in class file %s",
argument_index,
CHECK);
operands->at_put(operand_fill_index++, argument_index);
}
}
-
- u1* current_end = cfs->current();
- guarantee_property(current_end == current_start + attribute_byte_length,
+ guarantee_property(current_start + attribute_byte_length == cfs->current(),
"Bad length on BootstrapMethods in class file %s",
CHECK);
}
-void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotationCollector* parsed_annotations,
+void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
+ ConstantPool* cp,
+ ClassFileParser::ClassAnnotationCollector* parsed_annotations,
TRAPS) {
- ClassFileStream* cfs = stream();
+ assert(cfs != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+ assert(parsed_annotations != NULL, "invariant");
+
// Set inner classes attribute to default sentinel
_inner_classes = Universe::the_empty_short_array();
cfs->guarantee_more(2, CHECK); // attributes_count
@@ -2878,31 +3193,31 @@
bool parsed_innerclasses_attribute = false;
bool parsed_enclosingmethod_attribute = false;
bool parsed_bootstrap_methods_attribute = false;
- u1* runtime_visible_annotations = NULL;
+ const u1* runtime_visible_annotations = NULL;
int runtime_visible_annotations_length = 0;
- u1* runtime_invisible_annotations = NULL;
+ const u1* runtime_invisible_annotations = NULL;
int runtime_invisible_annotations_length = 0;
- u1* runtime_visible_type_annotations = NULL;
+ const u1* runtime_visible_type_annotations = NULL;
int runtime_visible_type_annotations_length = 0;
- u1* runtime_invisible_type_annotations = NULL;
+ const u1* runtime_invisible_type_annotations = NULL;
int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_type_annotations_exists = false;
bool runtime_invisible_annotations_exists = false;
bool parsed_source_debug_ext_annotations_exist = false;
- u1* inner_classes_attribute_start = NULL;
+ const u1* inner_classes_attribute_start = NULL;
u4 inner_classes_attribute_length = 0;
u2 enclosing_method_class_index = 0;
u2 enclosing_method_method_index = 0;
// Iterate over attributes
while (attributes_count--) {
cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length
- u2 attribute_name_index = cfs->get_u2_fast();
- u4 attribute_length = cfs->get_u4_fast();
+ const u2 attribute_name_index = cfs->get_u2_fast();
+ const u4 attribute_length = cfs->get_u4_fast();
check_property(
valid_symbol_at(attribute_name_index),
"Attribute name has bad constant pool index %u in class file %s",
attribute_name_index, CHECK);
- Symbol* tag = _cp->symbol_at(attribute_name_index);
+ const Symbol* const tag = cp->symbol_at(attribute_name_index);
if (tag == vmSymbols::tag_source_file()) {
// Check for SourceFile tag
if (_need_verify) {
@@ -2913,7 +3228,7 @@
} else {
parsed_sourcefile_attribute = true;
}
- parse_classfile_sourcefile_attribute(CHECK);
+ parse_classfile_sourcefile_attribute(cfs, CHECK);
} else if (tag == vmSymbols::tag_source_debug_extension()) {
// Check for SourceDebugExtension tag
if (parsed_source_debug_ext_annotations_exist) {
@@ -2921,7 +3236,7 @@
"Multiple SourceDebugExtension attributes in class file %s", CHECK);
}
parsed_source_debug_ext_annotations_exist = true;
- parse_classfile_source_debug_extension_attribute((int)attribute_length, CHECK);
+ parse_classfile_source_debug_extension_attribute(cfs, (int)attribute_length, CHECK);
} else if (tag == vmSymbols::tag_inner_classes()) {
// Check for InnerClasses tag
if (parsed_innerclasses_attribute) {
@@ -2955,7 +3270,7 @@
"Wrong Signature attribute length %u in class file %s",
attribute_length, CHECK);
}
- parse_classfile_signature_attribute(CHECK);
+ parse_classfile_signature_attribute(cfs, CHECK);
} else if (tag == vmSymbols::tag_runtime_visible_annotations()) {
if (runtime_visible_annotations != NULL) {
classfile_parse_error(
@@ -2964,9 +3279,12 @@
runtime_visible_annotations_length = attribute_length;
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
- parse_annotations(runtime_visible_annotations,
+ parse_annotations(cp,
+ runtime_visible_annotations,
runtime_visible_annotations_length,
- parsed_annotations);
+ parsed_annotations,
+ _loader_data,
+ CHECK);
cfs->skip_u1(runtime_visible_annotations_length, CHECK);
} else if (tag == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
@@ -2999,8 +3317,8 @@
check_property(valid_klass_reference_at(enclosing_method_class_index),
"Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK);
if (enclosing_method_method_index != 0 &&
- (!_cp->is_within_bounds(enclosing_method_method_index) ||
- !_cp->tag_at(enclosing_method_method_index).is_name_and_type())) {
+ (!cp->is_within_bounds(enclosing_method_method_index) ||
+ !cp->tag_at(enclosing_method_method_index).is_name_and_type())) {
classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK);
}
} else if (tag == vmSymbols::tag_bootstrap_methods() &&
@@ -3008,7 +3326,7 @@
if (parsed_bootstrap_methods_attribute)
classfile_parse_error("Multiple BootstrapMethods attributes in class file %s", CHECK);
parsed_bootstrap_methods_attribute = true;
- parse_classfile_bootstrap_methods_attribute(attribute_length, CHECK);
+ parse_classfile_bootstrap_methods_attribute(cfs, cp, attribute_length, CHECK);
} else if (tag == vmSymbols::tag_runtime_visible_type_annotations()) {
if (runtime_visible_type_annotations != NULL) {
classfile_parse_error(
@@ -3053,7 +3371,8 @@
CHECK);
if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) {
- u2 num_of_classes = parse_classfile_inner_classes_attribute(
+ const u2 num_of_classes = parse_classfile_inner_classes_attribute(
+ cfs,
inner_classes_attribute_start,
parsed_innerclasses_attribute,
enclosing_method_class_index,
@@ -3072,7 +3391,9 @@
}
}
-void ClassFileParser::apply_parsed_class_attributes(instanceKlassHandle k) {
+void ClassFileParser::apply_parsed_class_attributes(InstanceKlass* k) {
+ assert(k != NULL, "invariant");
+
if (_synthetic_flag)
k->set_is_synthetic();
if (_sourcefile_index != 0) {
@@ -3097,7 +3418,7 @@
return;
}
- Annotations* annotations = Annotations::allocate(_loader_data, CHECK);
+ Annotations* const annotations = Annotations::allocate(_loader_data, CHECK);
annotations->set_class_annotations(_annotations);
annotations->set_class_type_annotations(_type_annotations);
annotations->set_fields_annotations(_fields_annotations);
@@ -3117,9 +3438,11 @@
// Transfer ownership of metadata allocated to the InstanceKlass.
void ClassFileParser::apply_parsed_class_metadata(
- instanceKlassHandle this_klass,
+ InstanceKlass* this_klass,
int java_fields_count, TRAPS) {
- _cp->set_pool_holder(this_klass());
+ assert(this_klass != NULL, "invariant");
+
+ _cp->set_pool_holder(this_klass);
this_klass->set_constants(_cp);
this_klass->set_fields(_fields, java_fields_count);
this_klass->set_methods(_methods);
@@ -3132,10 +3455,11 @@
clear_class_metadata();
}
-AnnotationArray* ClassFileParser::assemble_annotations(u1* runtime_visible_annotations,
+AnnotationArray* ClassFileParser::assemble_annotations(const u1* const runtime_visible_annotations,
int runtime_visible_annotations_length,
- u1* runtime_invisible_annotations,
- int runtime_invisible_annotations_length, TRAPS) {
+ const u1* const runtime_invisible_annotations,
+ int runtime_invisible_annotations_length,
+ TRAPS) {
AnnotationArray* annotations = NULL;
if (runtime_visible_annotations != NULL ||
runtime_invisible_annotations != NULL) {
@@ -3158,9 +3482,13 @@
return annotations;
}
-instanceKlassHandle ClassFileParser::parse_super_class(int super_class_index,
- TRAPS) {
- instanceKlassHandle super_klass;
+const InstanceKlass* ClassFileParser::parse_super_class(ConstantPool* const cp,
+ const int super_class_index,
+ const bool need_verify,
+ TRAPS) {
+ assert(cp != NULL, "invariant");
+ const InstanceKlass* super_klass = NULL;
+
if (super_class_index == 0) {
check_property(_class_name == vmSymbols::java_lang_Object(),
"Invalid superclass index %u in class file %s",
@@ -3174,15 +3502,14 @@
// The class name should be legal because it is checked when parsing constant pool.
// However, make sure it is not an array type.
bool is_array = false;
- if (_cp->tag_at(super_class_index).is_klass()) {
- super_klass = instanceKlassHandle(THREAD, _cp->resolved_klass_at(super_class_index));
- if (_need_verify) {
+ if (cp->tag_at(super_class_index).is_klass()) {
+ super_klass = InstanceKlass::cast(cp->resolved_klass_at(super_class_index));
+ if (need_verify)
is_array = super_klass->is_array_klass();
- }
- } else if (_need_verify) {
- is_array = (_cp->klass_name_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY);
+ } else if (need_verify) {
+ is_array = (cp->klass_name_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY);
}
- if (_need_verify) {
+ if (need_verify) {
guarantee_property(!is_array,
"Bad superclass name in class file %s", CHECK_NULL);
}
@@ -3190,9 +3517,78 @@
return super_klass;
}
+static unsigned int compute_oop_map_count(const InstanceKlass* super,
+ unsigned int nonstatic_oop_map_count,
+ int first_nonstatic_oop_offset) {
+
+ unsigned int map_count =
+ NULL == super ? 0 : super->nonstatic_oop_map_count();
+ if (nonstatic_oop_map_count > 0) {
+ // We have oops to add to map
+ if (map_count == 0) {
+ map_count = nonstatic_oop_map_count;
+ }
+ else {
+ // Check whether we should add a new map block or whether the last one can
+ // be extended
+ const OopMapBlock* const first_map = super->start_of_nonstatic_oop_maps();
+ const OopMapBlock* const last_map = first_map + map_count - 1;
+
+ const int next_offset = last_map->offset() + last_map->count() * heapOopSize;
+ if (next_offset == first_nonstatic_oop_offset) {
+ // There is no gap bettwen superklass's last oop field and first
+ // local oop field, merge maps.
+ nonstatic_oop_map_count -= 1;
+ }
+ else {
+ // Superklass didn't end with a oop field, add extra maps
+ assert(next_offset < first_nonstatic_oop_offset, "just checking");
+ }
+ map_count += nonstatic_oop_map_count;
+ }
+ }
+ return map_count;
+}
+
+#ifndef PRODUCT
+static void print_field_layout(const Symbol* name,
+ Array<u2>* fields,
+ constantPoolHandle cp,
+ int instance_size,
+ int instance_fields_start,
+ int instance_fields_end,
+ int static_fields_end) {
+
+ assert(name != NULL, "invariant");
+
+ tty->print("%s: field layout\n", name->as_klass_external_name());
+ tty->print(" @%3d %s\n", instance_fields_start, "--- instance fields start ---");
+ for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+ if (!fs.access_flags().is_static()) {
+ tty->print(" @%3d \"%s\" %s\n",
+ fs.offset(),
+ fs.name()->as_klass_external_name(),
+ fs.signature()->as_klass_external_name());
+ }
+ }
+ tty->print(" @%3d %s\n", instance_fields_end, "--- instance fields end ---");
+ tty->print(" @%3d %s\n", instance_size * wordSize, "--- instance ends ---");
+ tty->print(" @%3d %s\n", InstanceMirrorKlass::offset_of_static_fields(), "--- static fields start ---");
+ for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+ if (fs.access_flags().is_static()) {
+ tty->print(" @%3d \"%s\" %s\n",
+ fs.offset(),
+ fs.name()->as_klass_external_name(),
+ fs.signature()->as_klass_external_name());
+ }
+ }
+ tty->print(" @%3d %s\n", static_fields_end, "--- static fields end ---");
+ tty->print("\n");
+}
+#endif
// Values needed for oopmap and InstanceKlass creation
-class FieldLayoutInfo : public StackObj {
+class ClassFileParser::FieldLayoutInfo : public ResourceObj {
public:
int* nonstatic_oop_offsets;
unsigned int* nonstatic_oop_counts;
@@ -3205,27 +3601,17 @@
};
// Layout fields and fill in FieldLayoutInfo. Could use more refactoring!
-void ClassFileParser::layout_fields(Handle class_loader,
- FieldAllocationCount* fac,
- ClassAnnotationCollector* parsed_annotations,
+void ClassFileParser::layout_fields(ConstantPool* cp,
+ const FieldAllocationCount* fac,
+ const ClassAnnotationCollector* parsed_annotations,
FieldLayoutInfo* info,
TRAPS) {
+ assert(cp != NULL, "invariant");
+
// Field size and offset computation
- int nonstatic_field_size = _super_klass() == NULL ? 0 : _super_klass()->nonstatic_field_size();
- int next_static_oop_offset = 0;
- int next_static_double_offset = 0;
- int next_static_word_offset = 0;
- int next_static_short_offset = 0;
- int next_static_byte_offset = 0;
- int next_nonstatic_oop_offset = 0;
- int next_nonstatic_double_offset = 0;
- int next_nonstatic_word_offset = 0;
- int next_nonstatic_short_offset = 0;
- int next_nonstatic_byte_offset = 0;
- int first_nonstatic_oop_offset = 0;
- int next_nonstatic_field_offset = 0;
- int next_nonstatic_padded_offset = 0;
+ int nonstatic_field_size = _super_klass == NULL ? 0 :
+ _super_klass->nonstatic_field_size();
// Count the contended fields by type.
//
@@ -3233,7 +3619,7 @@
// The layout code below will also ignore the static fields.
int nonstatic_contended_count = 0;
FieldAllocationCount fac_contended;
- for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
+ for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
FieldAllocationType atype = (FieldAllocationType) fs.allocation_type();
if (fs.is_contended()) {
fac_contended.count[atype]++;
@@ -3245,28 +3631,28 @@
// Calculate the starting byte offsets
- next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields();
- next_static_double_offset = next_static_oop_offset +
- ((fac->count[STATIC_OOP]) * heapOopSize);
+ int next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields();
+ int next_static_double_offset = next_static_oop_offset +
+ ((fac->count[STATIC_OOP]) * heapOopSize);
if ( fac->count[STATIC_DOUBLE] &&
(Universe::field_type_should_be_aligned(T_DOUBLE) ||
Universe::field_type_should_be_aligned(T_LONG)) ) {
next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong);
}
- next_static_word_offset = next_static_double_offset +
- ((fac->count[STATIC_DOUBLE]) * BytesPerLong);
- next_static_short_offset = next_static_word_offset +
- ((fac->count[STATIC_WORD]) * BytesPerInt);
- next_static_byte_offset = next_static_short_offset +
- ((fac->count[STATIC_SHORT]) * BytesPerShort);
+ int next_static_word_offset = next_static_double_offset +
+ ((fac->count[STATIC_DOUBLE]) * BytesPerLong);
+ int next_static_short_offset = next_static_word_offset +
+ ((fac->count[STATIC_WORD]) * BytesPerInt);
+ int next_static_byte_offset = next_static_short_offset +
+ ((fac->count[STATIC_SHORT]) * BytesPerShort);
int nonstatic_fields_start = instanceOopDesc::base_offset_in_bytes() +
nonstatic_field_size * heapOopSize;
- next_nonstatic_field_offset = nonstatic_fields_start;
-
- bool is_contended_class = parsed_annotations->is_contended();
+ int next_nonstatic_field_offset = nonstatic_fields_start;
+
+ const bool is_contended_class = parsed_annotations->is_contended();
// Class is contended, pad before all the fields
if (is_contended_class) {
@@ -3288,9 +3674,10 @@
fac->count[NONSTATIC_SHORT] + fac->count[NONSTATIC_BYTE] +
fac->count[NONSTATIC_OOP];
- bool super_has_nonstatic_fields =
- (_super_klass() != NULL && _super_klass->has_nonstatic_fields());
- bool has_nonstatic_fields = super_has_nonstatic_fields || (nonstatic_fields_count != 0);
+ const bool super_has_nonstatic_fields =
+ (_super_klass != NULL && _super_klass->has_nonstatic_fields());
+ const bool has_nonstatic_fields =
+ super_has_nonstatic_fields || (nonstatic_fields_count != 0);
// Prepare list of oops for oop map generation.
@@ -3303,20 +3690,18 @@
//
// TODO: We add +1 to always allocate non-zero resource arrays; we need
// to figure out if we still need to do this.
- int* nonstatic_oop_offsets;
- unsigned int* nonstatic_oop_counts;
unsigned int nonstatic_oop_map_count = 0;
unsigned int max_nonstatic_oop_maps = fac->count[NONSTATIC_OOP] + 1;
- nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD(
+ int* nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, int, max_nonstatic_oop_maps);
- nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD(
+ unsigned int* const nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, unsigned int, max_nonstatic_oop_maps);
- first_nonstatic_oop_offset = 0; // will be set for first oop field
+ int first_nonstatic_oop_offset = 0; // will be set for first oop field
bool compact_fields = CompactFields;
- int allocation_style = FieldsAllocationStyle;
+ int allocation_style = FieldsAllocationStyle;
if( allocation_style < 0 || allocation_style > 2 ) { // Out of range?
assert(false, "0 <= FieldsAllocationStyle <= 2");
allocation_style = 1; // Optimistic
@@ -3325,7 +3710,7 @@
// The next classes have predefined hard-coded fields offsets
// (see in JavaClasses::compute_hard_coded_offsets()).
// Use default fields allocation order for them.
- if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() &&
+ if( (allocation_style != 0 || compact_fields ) && _loader_data->class_loader() == NULL &&
(_class_name == vmSymbols::java_lang_AssertionStatusDirectives() ||
_class_name == vmSymbols::java_lang_Class() ||
_class_name == vmSymbols::java_lang_ClassLoader() ||
@@ -3346,6 +3731,9 @@
compact_fields = false; // Don't compact fields
}
+ int next_nonstatic_oop_offset = 0;
+ int next_nonstatic_double_offset = 0;
+
// Rearrange fields for a given allocation style
if( allocation_style == 0 ) {
// Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields
@@ -3357,12 +3745,12 @@
next_nonstatic_double_offset = next_nonstatic_field_offset;
} else if( allocation_style == 2 ) {
// Fields allocation: oops fields in super and sub classes are together.
- if( nonstatic_field_size > 0 && _super_klass() != NULL &&
+ if( nonstatic_field_size > 0 && _super_klass != NULL &&
_super_klass->nonstatic_oop_map_size() > 0 ) {
- unsigned int map_count = _super_klass->nonstatic_oop_map_count();
- OopMapBlock* first_map = _super_klass->start_of_nonstatic_oop_maps();
- OopMapBlock* last_map = first_map + map_count - 1;
- int next_offset = last_map->offset() + (last_map->count() * heapOopSize);
+ const unsigned int map_count = _super_klass->nonstatic_oop_map_count();
+ const OopMapBlock* const first_map = _super_klass->start_of_nonstatic_oop_maps();
+ const OopMapBlock* const last_map = first_map + map_count - 1;
+ const int next_offset = last_map->offset() + (last_map->count() * heapOopSize);
if (next_offset == next_nonstatic_field_offset) {
allocation_style = 0; // allocate oops first
next_nonstatic_oop_offset = next_nonstatic_field_offset;
@@ -3378,48 +3766,48 @@
ShouldNotReachHere();
}
- int nonstatic_oop_space_count = 0;
- int nonstatic_word_space_count = 0;
- int nonstatic_short_space_count = 0;
- int nonstatic_byte_space_count = 0;
- int nonstatic_oop_space_offset = 0;
- int nonstatic_word_space_offset = 0;
+ int nonstatic_oop_space_count = 0;
+ int nonstatic_word_space_count = 0;
+ int nonstatic_short_space_count = 0;
+ int nonstatic_byte_space_count = 0;
+ int nonstatic_oop_space_offset = 0;
+ int nonstatic_word_space_offset = 0;
int nonstatic_short_space_offset = 0;
- int nonstatic_byte_space_offset = 0;
+ int nonstatic_byte_space_offset = 0;
// Try to squeeze some of the fields into the gaps due to
// long/double alignment.
- if( nonstatic_double_count > 0 ) {
+ if (nonstatic_double_count > 0) {
int offset = next_nonstatic_double_offset;
next_nonstatic_double_offset = align_size_up(offset, BytesPerLong);
- if( compact_fields && offset != next_nonstatic_double_offset ) {
+ if (compact_fields && offset != next_nonstatic_double_offset) {
// Allocate available fields into the gap before double field.
int length = next_nonstatic_double_offset - offset;
assert(length == BytesPerInt, "");
nonstatic_word_space_offset = offset;
- if( nonstatic_word_count > 0 ) {
+ if (nonstatic_word_count > 0) {
nonstatic_word_count -= 1;
nonstatic_word_space_count = 1; // Only one will fit
length -= BytesPerInt;
offset += BytesPerInt;
}
nonstatic_short_space_offset = offset;
- while( length >= BytesPerShort && nonstatic_short_count > 0 ) {
+ while (length >= BytesPerShort && nonstatic_short_count > 0) {
nonstatic_short_count -= 1;
nonstatic_short_space_count += 1;
length -= BytesPerShort;
offset += BytesPerShort;
}
nonstatic_byte_space_offset = offset;
- while( length > 0 && nonstatic_byte_count > 0 ) {
+ while (length > 0 && nonstatic_byte_count > 0) {
nonstatic_byte_count -= 1;
nonstatic_byte_space_count += 1;
length -= 1;
}
// Allocate oop field in the gap if there are no other fields for that.
nonstatic_oop_space_offset = offset;
- if( length >= heapOopSize && nonstatic_oop_count > 0 &&
- allocation_style != 0 ) { // when oop fields not first
+ if (length >= heapOopSize && nonstatic_oop_count > 0 &&
+ allocation_style != 0) { // when oop fields not first
nonstatic_oop_count -= 1;
nonstatic_oop_space_count = 1; // Only one will fit
length -= heapOopSize;
@@ -3428,14 +3816,14 @@
}
}
- next_nonstatic_word_offset = next_nonstatic_double_offset +
- (nonstatic_double_count * BytesPerLong);
- next_nonstatic_short_offset = next_nonstatic_word_offset +
- (nonstatic_word_count * BytesPerInt);
- next_nonstatic_byte_offset = next_nonstatic_short_offset +
- (nonstatic_short_count * BytesPerShort);
- next_nonstatic_padded_offset = next_nonstatic_byte_offset +
- nonstatic_byte_count;
+ int next_nonstatic_word_offset = next_nonstatic_double_offset +
+ (nonstatic_double_count * BytesPerLong);
+ int next_nonstatic_short_offset = next_nonstatic_word_offset +
+ (nonstatic_word_count * BytesPerInt);
+ int next_nonstatic_byte_offset = next_nonstatic_short_offset +
+ (nonstatic_short_count * BytesPerShort);
+ int next_nonstatic_padded_offset = next_nonstatic_byte_offset +
+ nonstatic_byte_count;
// let oops jump before padding with this allocation style
if( allocation_style == 1 ) {
@@ -3449,7 +3837,7 @@
// Iterate over fields again and compute correct offsets.
// The field allocation type was temporarily stored in the offset slot.
// oop fields are located before non-oop fields (static and non-static).
- for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
+ for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
// skip already laid out fields
if (fs.is_offset_set()) continue;
@@ -3458,7 +3846,7 @@
if (fs.is_contended() && !fs.access_flags().is_static()) continue;
int real_offset = 0;
- FieldAllocationType atype = (FieldAllocationType) fs.allocation_type();
+ const FieldAllocationType atype = (const FieldAllocationType) fs.allocation_type();
// pack the rest of the fields
switch (atype) {
@@ -3567,8 +3955,8 @@
next_nonstatic_padded_offset += ContendedPaddingWidth;
// collect all contended groups
- BitMap bm(_cp->size());
- for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
+ BitMap bm(cp->size());
+ for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
// skip already laid out fields
if (fs.is_offset_set()) continue;
@@ -3580,7 +3968,7 @@
int current_group = -1;
while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) {
- for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
+ for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
// skip already laid out fields
if (fs.is_offset_set()) continue;
@@ -3714,7 +4102,7 @@
if (PrintFieldLayout) {
print_field_layout(_class_name,
_fields,
- _cp,
+ cp,
instance_size,
nonstatic_fields_start,
nonstatic_fields_end,
@@ -3733,751 +4121,13 @@
info->has_nonstatic_fields = has_nonstatic_fields;
}
-
-instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
- ClassLoaderData* loader_data,
- Handle protection_domain,
- KlassHandle host_klass,
- GrowableArray<Handle>* cp_patches,
- TempNewSymbol& parsed_name,
- bool verify,
- TRAPS) {
-
- // When a retransformable agent is attached, JVMTI caches the
- // class bytes that existed before the first retransformation.
- // If RedefineClasses() was used before the retransformable
- // agent attached, then the cached class bytes may not be the
- // original class bytes.
- JvmtiCachedClassFileData *cached_class_file = NULL;
- Handle class_loader(THREAD, loader_data->class_loader());
- bool has_default_methods = false;
- bool declares_default_methods = false;
- ResourceMark rm(THREAD);
-
- ClassFileStream* cfs = stream();
- // Timing
- assert(THREAD->is_Java_thread(), "must be a JavaThread");
- JavaThread* jt = (JavaThread*) THREAD;
-
- PerfClassTraceTime ctimer(ClassLoader::perf_class_parse_time(),
- ClassLoader::perf_class_parse_selftime(),
- NULL,
- jt->get_thread_stat()->perf_recursion_counts_addr(),
- jt->get_thread_stat()->perf_timers_addr(),
- PerfClassTraceTime::PARSE_CLASS);
-
- init_parsed_class_attributes(loader_data);
-
- if (JvmtiExport::should_post_class_file_load_hook()) {
- // Get the cached class file bytes (if any) from the class that
- // is being redefined or retransformed. We use jvmti_thread_state()
- // instead of JvmtiThreadState::state_for(jt) so we don't allocate
- // a JvmtiThreadState any earlier than necessary. This will help
- // avoid the bug described by 7126851.
- JvmtiThreadState *state = jt->jvmti_thread_state();
- if (state != NULL) {
- KlassHandle *h_class_being_redefined =
- state->get_class_being_redefined();
- if (h_class_being_redefined != NULL) {
- instanceKlassHandle ikh_class_being_redefined =
- instanceKlassHandle(THREAD, (*h_class_being_redefined)());
- cached_class_file = ikh_class_being_redefined->get_cached_class_file();
- }
- }
-
- unsigned char* ptr = cfs->buffer();
- unsigned char* end_ptr = cfs->buffer() + cfs->length();
-
- JvmtiExport::post_class_file_load_hook(name, class_loader(), protection_domain,
- &ptr, &end_ptr, &cached_class_file);
-
- if (ptr != cfs->buffer()) {
- // JVMTI agent has modified class file data.
- // Set new class file stream using JVMTI agent modified
- // class file data.
- cfs = new ClassFileStream(ptr, end_ptr - ptr, cfs->source());
- set_stream(cfs);
- }
- }
-
- _host_klass = host_klass;
- _cp_patches = cp_patches;
-
- instanceKlassHandle nullHandle;
-
- // Figure out whether we can skip format checking (matching classic VM behavior)
- if (DumpSharedSpaces) {
- // verify == true means it's a 'remote' class (i.e., non-boot class)
- // Verification decision is based on BytecodeVerificationRemote flag
- // for those classes.
- _need_verify = (verify) ? BytecodeVerificationRemote :
- BytecodeVerificationLocal;
- } else {
- _need_verify = Verifier::should_verify_for(class_loader(), verify);
- }
-
- // Set the verify flag in stream
- cfs->set_verify(_need_verify);
-
- // Save the class file name for easier error message printing.
- _class_name = (name != NULL) ? name : vmSymbols::unknown_class_name();
-
- cfs->guarantee_more(8, CHECK_(nullHandle)); // magic, major, minor
- // Magic value
- u4 magic = cfs->get_u4_fast();
- guarantee_property(magic == JAVA_CLASSFILE_MAGIC,
- "Incompatible magic value %u in class file %s",
- magic, CHECK_(nullHandle));
-
- // Version numbers
- u2 minor_version = cfs->get_u2_fast();
- u2 major_version = cfs->get_u2_fast();
-
- if (DumpSharedSpaces && major_version < JAVA_1_5_VERSION) {
- ResourceMark rm;
- warning("Pre JDK 1.5 class not supported by CDS: %u.%u %s",
- major_version, minor_version, name->as_C_string());
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_UnsupportedClassVersionError(),
- "Unsupported major.minor version for dump time %u.%u",
- major_version,
- minor_version);
- }
-
- // Check version numbers - we check this even with verifier off
- if (!is_supported_version(major_version, minor_version)) {
- if (name == NULL) {
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_UnsupportedClassVersionError(),
- "Unsupported class file version %u.%u, "
- "this version of the Java Runtime only recognizes class file versions up to %u.%u",
- major_version,
- minor_version,
- JAVA_MAX_SUPPORTED_VERSION,
- JAVA_MAX_SUPPORTED_MINOR_VERSION);
- } else {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_UnsupportedClassVersionError(),
- "%s has been compiled by a more recent version of the Java Runtime (class file version %u.%u), "
- "this version of the Java Runtime only recognizes class file versions up to %u.%u",
- name->as_C_string(),
- major_version,
- minor_version,
- JAVA_MAX_SUPPORTED_VERSION,
- JAVA_MAX_SUPPORTED_MINOR_VERSION);
- }
- return nullHandle;
- }
-
- _major_version = major_version;
- _minor_version = minor_version;
-
-
- // Check if verification needs to be relaxed for this class file
- // Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376)
- _relax_verify = Verifier::relax_verify_for(class_loader());
-
- // Constant pool
- constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle));
-
- int cp_size = cp->length();
-
- cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len
-
- // Access flags
- AccessFlags access_flags;
- jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
-
- if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
- // Set abstract bit for old class files for backward compatibility
- flags |= JVM_ACC_ABSTRACT;
- }
- verify_legal_class_modifiers(flags, CHECK_(nullHandle));
- access_flags.set_flags(flags);
-
- // This class and superclass
- u2 this_class_index = cfs->get_u2_fast();
- check_property(
- valid_cp_range(this_class_index, cp_size) &&
- cp->tag_at(this_class_index).is_unresolved_klass(),
- "Invalid this class index %u in constant pool in class file %s",
- this_class_index, CHECK_(nullHandle));
-
- Symbol* class_name = cp->klass_name_at(this_class_index);
- assert(class_name != NULL, "class_name can't be null");
-
- // It's important to set parsed_name *before* resolving the super class.
- // (it's used for cleanup by the caller if parsing fails)
- parsed_name = class_name;
- // parsed_name is returned and can be used if there's an error, so add to
- // its reference count. Caller will decrement the refcount.
- parsed_name->increment_refcount();
-
- // Update _class_name which could be null previously to be class_name
- _class_name = class_name;
-
- // Don't need to check whether this class name is legal or not.
- // It has been checked when constant pool is parsed.
- // However, make sure it is not an array type.
- if (_need_verify) {
- guarantee_property(class_name->byte_at(0) != JVM_SIGNATURE_ARRAY,
- "Bad class name in class file %s",
- CHECK_(nullHandle));
- }
-
- Klass* preserve_this_klass; // for storing result across HandleMark
-
- // release all handles when parsing is done
- { HandleMark hm(THREAD);
-
- // Checks if name in class file matches requested name
- if (name != NULL && class_name != name) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_NoClassDefFoundError(),
- "%s (wrong name: %s)",
- name->as_C_string(),
- class_name->as_C_string()
- );
- return nullHandle;
- }
-
- if (TraceClassLoadingPreorder) {
- tty->print("[Loading %s", (name != NULL) ? name->as_klass_external_name() : "NoName");
- if (cfs->source() != NULL) tty->print(" from %s", cfs->source());
- tty->print_cr("]");
- }
-#if INCLUDE_CDS
- if (DumpLoadedClassList != NULL && cfs->source() != NULL && classlist_file->is_open()) {
- // Only dump the classes that can be stored into CDS archive
- if (SystemDictionaryShared::is_sharing_possible(loader_data)) {
- if (name != NULL) {
- ResourceMark rm(THREAD);
- classlist_file->print_cr("%s", name->as_C_string());
- classlist_file->flush();
- }
- }
- }
-#endif
-
- u2 super_class_index = cfs->get_u2_fast();
- instanceKlassHandle super_klass = parse_super_class(super_class_index,
- CHECK_NULL);
-
- // Interfaces
- u2 itfs_len = cfs->get_u2_fast();
- Array<Klass*>* local_interfaces =
- parse_interfaces(itfs_len, protection_domain, _class_name,
- &has_default_methods, CHECK_(nullHandle));
-
- u2 java_fields_count = 0;
- // Fields (offsets are filled in later)
- FieldAllocationCount fac;
- Array<u2>* fields = parse_fields(class_name,
- access_flags.is_interface(),
- &fac, &java_fields_count,
- CHECK_(nullHandle));
- // Methods
- bool has_final_method = false;
- AccessFlags promoted_flags;
- promoted_flags.set_flags(0);
- Array<Method*>* methods = parse_methods(access_flags.is_interface(),
- &promoted_flags,
- &has_final_method,
- &declares_default_methods,
- CHECK_(nullHandle));
-
- if (declares_default_methods) {
- has_default_methods = true;
- }
-
- // Additional attributes
- ClassAnnotationCollector parsed_annotations;
- parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle));
-
- // Finalize the Annotations metadata object,
- // now that all annotation arrays have been created.
- create_combined_annotations(CHECK_(nullHandle));
-
- // Make sure this is the end of class file stream
- guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle));
-
- // We check super class after class file is parsed and format is checked
- if (super_class_index > 0 && super_klass.is_null()) {
- Symbol* sk = cp->klass_name_at(super_class_index);
- if (access_flags.is_interface()) {
- // Before attempting to resolve the superclass, check for class format
- // errors not checked yet.
- guarantee_property(sk == vmSymbols::java_lang_Object(),
- "Interfaces must have java.lang.Object as superclass in class file %s",
- CHECK_(nullHandle));
- }
- Klass* k = SystemDictionary::resolve_super_or_fail(class_name, sk,
- class_loader,
- protection_domain,
- true,
- CHECK_(nullHandle));
-
- KlassHandle kh (THREAD, k);
- super_klass = instanceKlassHandle(THREAD, kh());
- }
- if (super_klass.not_null()) {
-
- if (super_klass->has_default_methods()) {
- has_default_methods = true;
- }
-
- if (super_klass->is_interface()) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_IncompatibleClassChangeError(),
- "class %s has interface %s as super class",
- class_name->as_klass_external_name(),
- super_klass->external_name()
- );
- return nullHandle;
- }
- // Make sure super class is not final
- if (super_klass->is_final()) {
- THROW_MSG_(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class", nullHandle);
- }
- }
-
- // save super klass for error handling.
- _super_klass = super_klass;
-
- // Compute the transitive list of all unique interfaces implemented by this class
- _transitive_interfaces =
- compute_transitive_interfaces(super_klass, local_interfaces, CHECK_(nullHandle));
-
- // sort methods
- intArray* method_ordering = sort_methods(methods);
-
- // promote flags from parse_methods() to the klass' flags
- access_flags.add_promoted_flags(promoted_flags.as_int());
-
- // Size of Java vtable (in words)
- int vtable_size = 0;
- int itable_size = 0;
- int num_miranda_methods = 0;
-
- GrowableArray<Method*> all_mirandas(20);
-
- klassVtable::compute_vtable_size_and_num_mirandas(
- &vtable_size, &num_miranda_methods, &all_mirandas, super_klass(), methods,
- access_flags, class_loader, class_name, local_interfaces,
- CHECK_(nullHandle));
-
- // Size of Java itable (in words)
- itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces);
-
- FieldLayoutInfo info;
- layout_fields(class_loader, &fac, &parsed_annotations, &info, CHECK_NULL);
-
- int total_oop_map_size2 =
- InstanceKlass::nonstatic_oop_map_size(info.total_oop_map_count);
-
- // Compute reference type
- ReferenceType rt;
- if (super_klass() == NULL) {
- rt = REF_NONE;
- } else {
- rt = super_klass->reference_type();
- }
-
- // We can now create the basic Klass* for this klass
- _klass = InstanceKlass::allocate_instance_klass(loader_data,
- vtable_size,
- itable_size,
- info.static_field_size,
- total_oop_map_size2,
- rt,
- access_flags,
- name,
- super_klass(),
- !host_klass.is_null(),
- CHECK_(nullHandle));
- instanceKlassHandle this_klass (THREAD, _klass);
-
- assert(this_klass->static_field_size() == info.static_field_size, "sanity");
- assert(this_klass->nonstatic_oop_map_count() == info.total_oop_map_count,
- "sanity");
-
- // Fill in information already parsed
- this_klass->set_should_verify_class(verify);
- jint lh = Klass::instance_layout_helper(info.instance_size, false);
- this_klass->set_layout_helper(lh);
- assert(this_klass->is_instance_klass(), "layout is correct");
- assert(this_klass->size_helper() == info.instance_size, "correct size_helper");
- // Not yet: supers are done below to support the new subtype-checking fields
- //this_klass->set_super(super_klass());
- this_klass->set_class_loader_data(loader_data);
- this_klass->set_nonstatic_field_size(info.nonstatic_field_size);
- this_klass->set_has_nonstatic_fields(info.has_nonstatic_fields);
- this_klass->set_static_oop_field_count(fac.count[STATIC_OOP]);
-
- apply_parsed_class_metadata(this_klass, java_fields_count, CHECK_NULL);
-
- if (has_final_method) {
- this_klass->set_has_final_method();
- }
- this_klass->copy_method_ordering(method_ordering, CHECK_NULL);
- // The InstanceKlass::_methods_jmethod_ids cache
- // is managed on the assumption that the initial cache
- // size is equal to the number of methods in the class. If
- // that changes, then InstanceKlass::idnum_can_increment()
- // has to be changed accordingly.
- this_klass->set_initial_method_idnum(methods->length());
- this_klass->set_name(cp->klass_name_at(this_class_index));
- if (is_anonymous()) // I am well known to myself
- cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
-
- this_klass->set_minor_version(minor_version);
- this_klass->set_major_version(major_version);
- this_klass->set_has_default_methods(has_default_methods);
- this_klass->set_declares_default_methods(declares_default_methods);
-
- if (!host_klass.is_null()) {
- assert (this_klass->is_anonymous(), "should be the same");
- this_klass->set_host_klass(host_klass());
- }
-
- // Set up Method*::intrinsic_id as soon as we know the names of methods.
- // (We used to do this lazily, but now we query it in Rewriter,
- // which is eagerly done for every method, so we might as well do it now,
- // when everything is fresh in memory.)
- vmSymbols::SID klass_id = Method::klass_id_for_intrinsics(this_klass());
- if (klass_id != vmSymbols::NO_SID) {
- for (int j = 0; j < methods->length(); j++) {
- Method* method = methods->at(j);
- method->init_intrinsic_id();
-
- if (CheckIntrinsics) {
- // Check if an intrinsic is defined for method 'method',
- // but the method is not annotated with @HotSpotIntrinsicCandidate.
- if (method->intrinsic_id() != vmIntrinsics::_none &&
- !method->intrinsic_candidate()) {
- tty->print("Compiler intrinsic is defined for method [%s], "
- "but the method is not annotated with @HotSpotIntrinsicCandidate.%s",
- method->name_and_sig_as_C_string(),
- NOT_DEBUG(" Method will not be inlined.") DEBUG_ONLY(" Exiting.")
- );
- tty->cr();
- DEBUG_ONLY(vm_exit(1));
- }
- // Check is the method 'method' is annotated with @HotSpotIntrinsicCandidate,
- // but there is no intrinsic available for it.
- if (method->intrinsic_candidate() &&
- method->intrinsic_id() == vmIntrinsics::_none) {
- tty->print("Method [%s] is annotated with @HotSpotIntrinsicCandidate, "
- "but no compiler intrinsic is defined for the method.%s",
- method->name_and_sig_as_C_string(),
- NOT_DEBUG("") DEBUG_ONLY(" Exiting.")
- );
- tty->cr();
- DEBUG_ONLY(vm_exit(1));
- }
- }
- }
-
-#ifdef ASSERT
- if (CheckIntrinsics) {
- // Check for orphan methods in the current class. A method m
- // of a class C is orphan if an intrinsic is defined for method m,
- // but class C does not declare m.
- // The check is potentially expensive, therefore it is available
- // only in debug builds.
-
- for (int id = vmIntrinsics::FIRST_ID; id < (int)vmIntrinsics::ID_LIMIT; id++) {
- if (id == vmIntrinsics::_compiledLambdaForm) {
- // The _compiledLamdbdaForm intrinsic is a special marker for bytecode
- // generated for the JVM from a LambdaForm and therefore no method
- // is defined for it.
- continue;
- }
-
- if (vmIntrinsics::class_for(vmIntrinsics::ID_from(id)) == klass_id) {
- // Check if the current class contains a method with the same
- // name, flags, signature.
- bool match = false;
- for (int j = 0; j < methods->length(); j++) {
- Method* method = methods->at(j);
- if (id == method->intrinsic_id()) {
- match = true;
- break;
- }
- }
-
- if (!match) {
- char buf[1000];
- tty->print("Compiler intrinsic is defined for method [%s], "
- "but the method is not available in class [%s].%s",
- vmIntrinsics::short_name_as_C_string(vmIntrinsics::ID_from(id), buf, sizeof(buf)),
- this_klass->name()->as_C_string(),
- NOT_DEBUG("") DEBUG_ONLY(" Exiting.")
- );
- tty->cr();
- DEBUG_ONLY(vm_exit(1));
- }
- }
- }
- }
-#endif // ASSERT
- }
-
-
- if (cached_class_file != NULL) {
- // JVMTI: we have an InstanceKlass now, tell it about the cached bytes
- this_klass->set_cached_class_file(cached_class_file);
- }
-
- // Fill in field values obtained by parse_classfile_attributes
- if (parsed_annotations.has_any_annotations())
- parsed_annotations.apply_to(this_klass);
- apply_parsed_class_attributes(this_klass);
-
- // Miranda methods
- if ((num_miranda_methods > 0) ||
- // if this class introduced new miranda methods or
- (super_klass.not_null() && (super_klass->has_miranda_methods()))
- // super class exists and this class inherited miranda methods
- ) {
- this_klass->set_has_miranda_methods(); // then set a flag
- }
-
- // Fill in information needed to compute superclasses.
- this_klass->initialize_supers(super_klass(), CHECK_(nullHandle));
-
- // Initialize itable offset tables
- klassItable::setup_itable_offset_table(this_klass);
-
- // Compute transitive closure of interfaces this class implements
- // Do final class setup
- fill_oop_maps(this_klass, info.nonstatic_oop_map_count, info.nonstatic_oop_offsets, info.nonstatic_oop_counts);
-
- // Fill in has_finalizer, has_vanilla_constructor, and layout_helper
- set_precomputed_flags(this_klass);
-
- // reinitialize modifiers, using the InnerClasses attribute
- int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle));
- this_klass->set_modifier_flags(computed_modifiers);
-
- // check if this class can access its super class
- check_super_class_access(this_klass, CHECK_(nullHandle));
-
- // check if this class can access its superinterfaces
- check_super_interface_access(this_klass, CHECK_(nullHandle));
-
- // check if this class overrides any final method
- check_final_method_override(this_klass, CHECK_(nullHandle));
-
- // check that if this class is an interface then it doesn't have static methods
- if (this_klass->is_interface()) {
- /* An interface in a JAVA 8 classfile can be static */
- if (_major_version < JAVA_8_VERSION) {
- check_illegal_static_method(this_klass, CHECK_(nullHandle));
- }
- }
-
- // Allocate mirror and initialize static fields
- java_lang_Class::create_mirror(this_klass, class_loader, protection_domain,
- CHECK_(nullHandle));
-
- // Generate any default methods - default methods are interface methods
- // that have a default implementation. This is new with Lambda project.
- if (has_default_methods ) {
- DefaultMethods::generate_default_methods(
- this_klass(), &all_mirandas, CHECK_(nullHandle));
- }
-
- // Update the loader_data graph.
- record_defined_class_dependencies(this_klass, CHECK_NULL);
-
- ClassLoadingService::notify_class_loaded(InstanceKlass::cast(this_klass()),
- false /* not shared class */);
-
- if (TraceClassLoading) {
- ResourceMark rm;
- // print in a single call to reduce interleaving of output
- if (cfs->source() != NULL) {
- tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
- cfs->source());
- } else if (class_loader.is_null()) {
- Klass* caller =
- THREAD->is_Java_thread()
- ? ((JavaThread*)THREAD)->security_get_caller_class(1)
- : NULL;
- // caller can be NULL, for example, during a JVMTI VM_Init hook
- if (caller != NULL) {
- tty->print("[Loaded %s by instance of %s]\n",
- this_klass->external_name(),
- caller->external_name());
- } else {
- tty->print("[Loaded %s]\n", this_klass->external_name());
- }
- } else {
- tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
- class_loader->klass()->external_name());
- }
- }
-
- if (TraceClassResolution) {
- ResourceMark rm;
- // print out the superclass.
- const char * from = this_klass()->external_name();
- if (this_klass->java_super() != NULL) {
- tty->print("RESOLVE %s %s (super)\n", from, this_klass->java_super()->external_name());
- }
- // print out each of the interface classes referred to by this class.
- Array<Klass*>* local_interfaces = this_klass->local_interfaces();
- if (local_interfaces != NULL) {
- int length = local_interfaces->length();
- for (int i = 0; i < length; i++) {
- Klass* k = local_interfaces->at(i);
- const char * to = k->external_name();
- tty->print("RESOLVE %s %s (interface)\n", from, to);
- }
- }
- }
-
- // preserve result across HandleMark
- preserve_this_klass = this_klass();
- }
-
- // Create new handle outside HandleMark (might be needed for
- // Extended Class Redefinition)
- instanceKlassHandle this_klass (THREAD, preserve_this_klass);
- debug_only(this_klass->verify();)
-
- // Clear class if no error has occurred so destructor doesn't deallocate it
- _klass = NULL;
- return this_klass;
-}
-
-// Destructor to clean up if there's an error
-ClassFileParser::~ClassFileParser() {
- MetadataFactory::free_metadata(_loader_data, _cp);
- MetadataFactory::free_array<u2>(_loader_data, _fields);
-
- // Free methods
- InstanceKlass::deallocate_methods(_loader_data, _methods);
-
- // beware of the Universe::empty_blah_array!!
- if (_inner_classes != Universe::the_empty_short_array()) {
- MetadataFactory::free_array<u2>(_loader_data, _inner_classes);
- }
-
- // Free interfaces
- InstanceKlass::deallocate_interfaces(_loader_data, _super_klass(),
- _local_interfaces, _transitive_interfaces);
-
- if (_combined_annotations != NULL) {
- // After all annotations arrays have been created, they are installed into the
- // Annotations object that will be assigned to the InstanceKlass being created.
-
- // Deallocate the Annotations object and the installed annotations arrays.
- _combined_annotations->deallocate_contents(_loader_data);
-
- // If the _combined_annotations pointer is non-NULL,
- // then the other annotations fields should have been cleared.
- assert(_annotations == NULL, "Should have been cleared");
- assert(_type_annotations == NULL, "Should have been cleared");
- assert(_fields_annotations == NULL, "Should have been cleared");
- assert(_fields_type_annotations == NULL, "Should have been cleared");
- } else {
- // If the annotations arrays were not installed into the Annotations object,
- // then they have to be deallocated explicitly.
- MetadataFactory::free_array<u1>(_loader_data, _annotations);
- MetadataFactory::free_array<u1>(_loader_data, _type_annotations);
- Annotations::free_contents(_loader_data, _fields_annotations);
- Annotations::free_contents(_loader_data, _fields_type_annotations);
- }
-
- clear_class_metadata();
-
- // deallocate the klass if already created. Don't directly deallocate, but add
- // to the deallocate list so that the klass is removed from the CLD::_klasses list
- // at a safepoint.
- if (_klass != NULL) {
- _loader_data->add_to_deallocate_list(_klass);
- }
- _klass = NULL;
-}
-
-void ClassFileParser::print_field_layout(Symbol* name,
- Array<u2>* fields,
- const constantPoolHandle& cp,
- int instance_size,
- int instance_fields_start,
- int instance_fields_end,
- int static_fields_end) {
- tty->print("%s: field layout\n", name->as_klass_external_name());
- tty->print(" @%3d %s\n", instance_fields_start, "--- instance fields start ---");
- for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
- if (!fs.access_flags().is_static()) {
- tty->print(" @%3d \"%s\" %s\n",
- fs.offset(),
- fs.name()->as_klass_external_name(),
- fs.signature()->as_klass_external_name());
- }
- }
- tty->print(" @%3d %s\n", instance_fields_end, "--- instance fields end ---");
- tty->print(" @%3d %s\n", instance_size * wordSize, "--- instance ends ---");
- tty->print(" @%3d %s\n", InstanceMirrorKlass::offset_of_static_fields(), "--- static fields start ---");
- for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
- if (fs.access_flags().is_static()) {
- tty->print(" @%3d \"%s\" %s\n",
- fs.offset(),
- fs.name()->as_klass_external_name(),
- fs.signature()->as_klass_external_name());
- }
- }
- tty->print(" @%3d %s\n", static_fields_end, "--- static fields end ---");
- tty->print("\n");
-}
-
-unsigned int
-ClassFileParser::compute_oop_map_count(instanceKlassHandle super,
- unsigned int nonstatic_oop_map_count,
- int first_nonstatic_oop_offset) {
- unsigned int map_count =
- super.is_null() ? 0 : super->nonstatic_oop_map_count();
- if (nonstatic_oop_map_count > 0) {
- // We have oops to add to map
- if (map_count == 0) {
- map_count = nonstatic_oop_map_count;
- } else {
- // Check whether we should add a new map block or whether the last one can
- // be extended
- OopMapBlock* const first_map = super->start_of_nonstatic_oop_maps();
- OopMapBlock* const last_map = first_map + map_count - 1;
-
- int next_offset = last_map->offset() + last_map->count() * heapOopSize;
- if (next_offset == first_nonstatic_oop_offset) {
- // There is no gap bettwen superklass's last oop field and first
- // local oop field, merge maps.
- nonstatic_oop_map_count -= 1;
- } else {
- // Superklass didn't end with a oop field, add extra maps
- assert(next_offset < first_nonstatic_oop_offset, "just checking");
- }
- map_count += nonstatic_oop_map_count;
- }
- }
- return map_count;
-}
-
-
-void ClassFileParser::fill_oop_maps(instanceKlassHandle k,
- unsigned int nonstatic_oop_map_count,
- int* nonstatic_oop_offsets,
- unsigned int* nonstatic_oop_counts) {
+static void fill_oop_maps(const InstanceKlass* k,
+ unsigned int nonstatic_oop_map_count,
+ const int* nonstatic_oop_offsets,
+ const unsigned int* nonstatic_oop_counts) {
+
+ assert(k != NULL, "invariant");
+
OopMapBlock* this_oop_map = k->start_of_nonstatic_oop_maps();
const InstanceKlass* const super = k->superklass();
const unsigned int super_count = super ? super->nonstatic_oop_map_count() : 0;
@@ -4513,22 +4163,24 @@
}
-void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) {
- Klass* super = k->super();
+void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) {
+ assert(ik != NULL, "invariant");
+
+ const Klass* const super = ik->super();
// Check if this klass has an empty finalize method (i.e. one with return bytecode only),
// in which case we don't have to register objects as finalizable
if (!_has_empty_finalizer) {
if (_has_finalizer ||
(super != NULL && super->has_finalizer())) {
- k->set_has_finalizer();
+ ik->set_has_finalizer();
}
}
#ifdef ASSERT
bool f = false;
- Method* m = k->lookup_method(vmSymbols::finalize_method_name(),
- vmSymbols::void_method_signature());
+ const Method* const m = ik->lookup_method(vmSymbols::finalize_method_name(),
+ vmSymbols::void_method_signature());
if (m != NULL && !m->is_empty_method()) {
f = true;
}
@@ -4536,70 +4188,74 @@
// Spec doesn't prevent agent from redefinition of empty finalizer.
// Despite the fact that it's generally bad idea and redefined finalizer
// will not work as expected we shouldn't abort vm in this case
- if (!k->has_redefined_this_or_super()) {
- assert(f == k->has_finalizer(), "inconsistent has_finalizer");
+ if (!ik->has_redefined_this_or_super()) {
+ assert(ik->has_finalizer() == f, "inconsistent has_finalizer");
}
#endif
// Check if this klass supports the java.lang.Cloneable interface
if (SystemDictionary::Cloneable_klass_loaded()) {
- if (k->is_subtype_of(SystemDictionary::Cloneable_klass())) {
- k->set_is_cloneable();
+ if (ik->is_subtype_of(SystemDictionary::Cloneable_klass())) {
+ ik->set_is_cloneable();
}
}
// Check if this klass has a vanilla default constructor
if (super == NULL) {
// java.lang.Object has empty default constructor
- k->set_has_vanilla_constructor();
+ ik->set_has_vanilla_constructor();
} else {
if (super->has_vanilla_constructor() &&
_has_vanilla_constructor) {
- k->set_has_vanilla_constructor();
+ ik->set_has_vanilla_constructor();
}
#ifdef ASSERT
bool v = false;
if (super->has_vanilla_constructor()) {
- Method* constructor = k->find_method(vmSymbols::object_initializer_name(
-), vmSymbols::void_method_signature());
+ const Method* const constructor =
+ ik->find_method(vmSymbols::object_initializer_name(),
+ vmSymbols::void_method_signature());
if (constructor != NULL && constructor->is_vanilla_constructor()) {
v = true;
}
}
- assert(v == k->has_vanilla_constructor(), "inconsistent has_vanilla_constructor");
+ assert(v == ik->has_vanilla_constructor(), "inconsistent has_vanilla_constructor");
#endif
}
// If it cannot be fast-path allocated, set a bit in the layout helper.
// See documentation of InstanceKlass::can_be_fastpath_allocated().
- assert(k->size_helper() > 0, "layout_helper is initialized");
- if ((!RegisterFinalizersAtInit && k->has_finalizer())
- || k->is_abstract() || k->is_interface()
- || (k->name() == vmSymbols::java_lang_Class() && k->class_loader() == NULL)
- || k->size_helper() >= FastAllocateSizeLimit) {
+ assert(ik->size_helper() > 0, "layout_helper is initialized");
+ if ((!RegisterFinalizersAtInit && ik->has_finalizer())
+ || ik->is_abstract() || ik->is_interface()
+ || (ik->name() == vmSymbols::java_lang_Class() && ik->class_loader() == NULL)
+ || ik->size_helper() >= FastAllocateSizeLimit) {
// Forbid fast-path allocation.
- jint lh = Klass::instance_layout_helper(k->size_helper(), true);
- k->set_layout_helper(lh);
+ const jint lh = Klass::instance_layout_helper(ik->size_helper(), true);
+ ik->set_layout_helper(lh);
}
}
// Attach super classes and interface classes to class loader data
-void ClassFileParser::record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS) {
- ClassLoaderData * defining_loader_data = defined_klass->class_loader_data();
+static void record_defined_class_dependencies(const InstanceKlass* defined_klass,
+ TRAPS) {
+ assert(defined_klass != NULL, "invariant");
+
+ ClassLoaderData* const defining_loader_data = defined_klass->class_loader_data();
if (defining_loader_data->is_the_null_class_loader_data()) {
// Dependencies to null class loader data are implicit.
return;
} else {
// add super class dependency
- Klass* super = defined_klass->super();
+ Klass* const super = defined_klass->super();
if (super != NULL) {
defining_loader_data->record_dependency(super, CHECK);
}
// add super interface dependencies
- Array<Klass*>* local_interfaces = defined_klass->local_interfaces();
+ const Array<Klass*>* const local_interfaces = defined_klass->local_interfaces();
if (local_interfaces != NULL) {
- int length = local_interfaces->length();
+ const int length = local_interfaces->length();
for (int i = 0; i < length; i++) {
defining_loader_data->record_dependency(local_interfaces->at(i), CHECK);
}
@@ -4609,31 +4265,36 @@
// utility methods for appending an array with check for duplicates
-void append_interfaces(GrowableArray<Klass*>* result, Array<Klass*>* ifs) {
+static void append_interfaces(GrowableArray<Klass*>* result,
+ const Array<Klass*>* const ifs) {
// iterate over new interfaces
for (int i = 0; i < ifs->length(); i++) {
- Klass* e = ifs->at(i);
+ Klass* const e = ifs->at(i);
assert(e->is_klass() && InstanceKlass::cast(e)->is_interface(), "just checking");
// add new interface
result->append_if_missing(e);
}
}
-Array<Klass*>* ClassFileParser::compute_transitive_interfaces(
- instanceKlassHandle super,
- Array<Klass*>* local_ifs, TRAPS) {
+static Array<Klass*>* compute_transitive_interfaces(const InstanceKlass* super,
+ Array<Klass*>* local_ifs,
+ ClassLoaderData* loader_data,
+ TRAPS) {
+ assert(local_ifs != NULL, "invariant");
+ assert(loader_data != NULL, "invariant");
+
// Compute maximum size for transitive interfaces
int max_transitive_size = 0;
int super_size = 0;
// Add superclass transitive interfaces size
- if (super.not_null()) {
+ if (super != NULL) {
super_size = super->transitive_interfaces()->length();
max_transitive_size += super_size;
}
// Add local interfaces' super interfaces
- int local_size = local_ifs->length();
+ const int local_size = local_ifs->length();
for (int i = 0; i < local_size; i++) {
- Klass* l = local_ifs->at(i);
+ Klass* const l = local_ifs->at(i);
max_transitive_size += InstanceKlass::cast(l)->transitive_interfaces()->length();
}
// Finally add local interfaces
@@ -4650,38 +4311,40 @@
return local_ifs;
} else {
ResourceMark rm;
- GrowableArray<Klass*>* result = new GrowableArray<Klass*>(max_transitive_size);
+ GrowableArray<Klass*>* const result = new GrowableArray<Klass*>(max_transitive_size);
// Copy down from superclass
- if (super.not_null()) {
+ if (super != NULL) {
append_interfaces(result, super->transitive_interfaces());
}
// Copy down from local interfaces' superinterfaces
- for (int i = 0; i < local_ifs->length(); i++) {
- Klass* l = local_ifs->at(i);
+ for (int i = 0; i < local_size; i++) {
+ Klass* const l = local_ifs->at(i);
append_interfaces(result, InstanceKlass::cast(l)->transitive_interfaces());
}
// Finally add local interfaces
append_interfaces(result, local_ifs);
// length will be less than the max_transitive_size if duplicates were removed
- int length = result->length();
+ const int length = result->length();
assert(length <= max_transitive_size, "just checking");
- Array<Klass*>* new_result = MetadataFactory::new_array<Klass*>(_loader_data, length, CHECK_NULL);
+ Array<Klass*>* const new_result =
+ MetadataFactory::new_array<Klass*>(loader_data, length, CHECK_NULL);
for (int i = 0; i < length; i++) {
- Klass* e = result->at(i);
- assert(e != NULL, "just checking");
+ Klass* const e = result->at(i);
+ assert(e != NULL, "just checking");
new_result->at_put(i, e);
}
return new_result;
}
}
-void ClassFileParser::check_super_class_access(instanceKlassHandle this_klass, TRAPS) {
- Klass* super = this_klass->super();
+static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
+ assert(this_klass != NULL, "invariant");
+ const Klass* const super = this_klass->super();
if ((super != NULL) &&
- (!Reflection::verify_class_access(this_klass(), super, false))) {
+ (!Reflection::verify_class_access(this_klass, super, false))) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
@@ -4695,13 +4358,14 @@
}
-void ClassFileParser::check_super_interface_access(instanceKlassHandle this_klass, TRAPS) {
- Array<Klass*>* local_interfaces = this_klass->local_interfaces();
- int lng = local_interfaces->length();
+static void check_super_interface_access(const InstanceKlass* this_klass, TRAPS) {
+ assert(this_klass != NULL, "invariant");
+ const Array<Klass*>* const local_interfaces = this_klass->local_interfaces();
+ const int lng = local_interfaces->length();
for (int i = lng - 1; i >= 0; i--) {
- Klass* k = local_interfaces->at(i);
+ Klass* const k = local_interfaces->at(i);
assert (k != NULL && k->is_interface(), "invalid interface");
- if (!Reflection::verify_class_access(this_klass(), k, false)) {
+ if (!Reflection::verify_class_access(this_klass, k, false)) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
@@ -4716,22 +4380,23 @@
}
-void ClassFileParser::check_final_method_override(instanceKlassHandle this_klass, TRAPS) {
- Array<Method*>* methods = this_klass->methods();
- int num_methods = methods->length();
+static void check_final_method_override(const InstanceKlass* this_klass, TRAPS) {
+ assert(this_klass != NULL, "invariant");
+ const Array<Method*>* const methods = this_klass->methods();
+ const int num_methods = methods->length();
// go thru each method and check if it overrides a final method
for (int index = 0; index < num_methods; index++) {
- Method* m = methods->at(index);
+ const Method* const m = methods->at(index);
// skip private, static, and <init> methods
if ((!m->is_private() && !m->is_static()) &&
(m->name() != vmSymbols::object_initializer_name())) {
- Symbol* name = m->name();
- Symbol* signature = m->signature();
- Klass* k = this_klass->super();
- Method* super_m = NULL;
+ const Symbol* const name = m->name();
+ const Symbol* const signature = m->signature();
+ const Klass* k = this_klass->super();
+ const Method* super_m = NULL;
while (k != NULL) {
// skip supers that don't have final methods.
if (k->has_final_method()) {
@@ -4743,7 +4408,7 @@
if (super_m->is_final() && !super_m->is_static() &&
// matching method in super is final, and not static
- (Reflection::verify_field_access(this_klass(),
+ (Reflection::verify_field_access(this_klass,
super_m->method_holder(),
super_m->method_holder(),
super_m->access_flags(), false))
@@ -4775,13 +4440,14 @@
// assumes that this_klass is an interface
-void ClassFileParser::check_illegal_static_method(instanceKlassHandle this_klass, TRAPS) {
+static void check_illegal_static_method(const InstanceKlass* this_klass, TRAPS) {
+ assert(this_klass != NULL, "invariant");
assert(this_klass->is_interface(), "not an interface");
- Array<Method*>* methods = this_klass->methods();
- int num_methods = methods->length();
+ const Array<Method*>* methods = this_klass->methods();
+ const int num_methods = methods->length();
for (int index = 0; index < num_methods; index++) {
- Method* m = methods->at(index);
+ const Method* const m = methods->at(index);
// if m is static and not the init method, throw a verify error
if ((m->is_static()) && (m->name() != vmSymbols::class_initializer_name())) {
ResourceMark rm(THREAD);
@@ -4799,7 +4465,7 @@
// utility methods for format checking
-void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) {
+void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const {
if (!_need_verify) { return; }
const bool is_interface = (flags & JVM_ACC_INTERFACE) != 0;
@@ -4825,7 +4491,7 @@
}
}
-bool ClassFileParser::has_illegal_visibility(jint flags) {
+static bool has_illegal_visibility(jint flags) {
const bool is_public = (flags & JVM_ACC_PUBLIC) != 0;
const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0;
const bool is_private = (flags & JVM_ACC_PRIVATE) != 0;
@@ -4835,16 +4501,17 @@
(is_protected && is_private));
}
-bool ClassFileParser::is_supported_version(u2 major, u2 minor) {
- u2 max_version = JAVA_MAX_SUPPORTED_VERSION;
+static bool is_supported_version(u2 major, u2 minor){
+ const u2 max_version = JAVA_MAX_SUPPORTED_VERSION;
return (major >= JAVA_MIN_SUPPORTED_VERSION) &&
(major <= max_version) &&
((major != max_version) ||
(minor <= JAVA_MAX_SUPPORTED_MINOR_VERSION));
}
-void ClassFileParser::verify_legal_field_modifiers(
- jint flags, bool is_interface, TRAPS) {
+void ClassFileParser::verify_legal_field_modifiers(jint flags,
+ bool is_interface,
+ TRAPS) const {
if (!_need_verify) { return; }
const bool is_public = (flags & JVM_ACC_PUBLIC) != 0;
@@ -4882,8 +4549,10 @@
}
}
-void ClassFileParser::verify_legal_method_modifiers(
- jint flags, bool is_interface, Symbol* name, TRAPS) {
+void ClassFileParser::verify_legal_method_modifiers(jint flags,
+ bool is_interface,
+ const Symbol* name,
+ TRAPS) const {
if (!_need_verify) { return; }
const bool is_public = (flags & JVM_ACC_PUBLIC) != 0;
@@ -4962,10 +4631,12 @@
}
}
-void ClassFileParser::verify_legal_utf8(const unsigned char* buffer, int length, TRAPS) {
+void ClassFileParser::verify_legal_utf8(const unsigned char* buffer,
+ int length,
+ TRAPS) const {
assert(_need_verify, "only called when _need_verify is true");
int i = 0;
- int count = length >> 2;
+ const int count = length >> 2;
for (int k=0; k<count; k++) {
unsigned char b0 = buffer[i];
unsigned char b1 = buffer[i+1];
@@ -4974,10 +4645,10 @@
// For an unsigned char v,
// (v | v - 1) is < 128 (highest bit 0) for 0 < v < 128;
// (v | v - 1) is >= 128 (highest bit 1) for v == 0 or v >= 128.
- unsigned char res = b0 | b0 - 1 |
- b1 | b1 - 1 |
- b2 | b2 - 1 |
- b3 | b3 - 1;
+ const unsigned char res = b0 | b0 - 1 |
+ b1 | b1 - 1 |
+ b2 | b2 - 1 |
+ b3 | b3 - 1;
if (res >= 128) break;
i += 4;
}
@@ -5025,8 +4696,193 @@
} // end of for
}
+// Unqualified names may not contain the characters '.', ';', '[', or '/'.
+// Method names also may not contain the characters '<' or '>', unless <init>
+// or <clinit>. Note that method names may not be <init> or <clinit> in this
+// method. Because these names have been checked as special cases before
+// calling this method in verify_legal_method_name.
+static bool verify_unqualified_name(const char* name,
+ unsigned int length,
+ int type) {
+ for (const char* p = name; p != name + length;) {
+ jchar ch = *p;
+ if (ch < 128) {
+ p++;
+ if (ch == '.' || ch == ';' || ch == '[') {
+ return false; // do not permit '.', ';', or '['
+ }
+ if (type != LegalClass && ch == '/') {
+ return false; // do not permit '/' unless it's class name
+ }
+ if (type == LegalMethod && (ch == '<' || ch == '>')) {
+ return false; // do not permit '<' or '>' in method names
+ }
+ }
+ else {
+ char* tmp_p = UTF8::next(p, &ch);
+ p = tmp_p;
+ }
+ }
+ return true;
+}
+
+// Take pointer to a string. Skip over the longest part of the string that could
+// be taken as a fieldname. Allow '/' if slash_ok is true.
+// Return a pointer to just past the fieldname.
+// Return NULL if no fieldname at all was found, or in the case of slash_ok
+// being true, we saw consecutive slashes (meaning we were looking for a
+// qualified path but found something that was badly-formed).
+static const char* skip_over_field_name(const char* name,
+ bool slash_ok,
+ unsigned int length) {
+ const char* p;
+ jboolean last_is_slash = false;
+ jboolean not_first_ch = false;
+
+ for (p = name; p != name + length; not_first_ch = true) {
+ const char* old_p = p;
+ jchar ch = *p;
+ if (ch < 128) {
+ p++;
+ // quick check for ascii
+ if ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch == '_' || ch == '$') ||
+ (not_first_ch && ch >= '0' && ch <= '9')) {
+ last_is_slash = false;
+ continue;
+ }
+ if (slash_ok && ch == '/') {
+ if (last_is_slash) {
+ return NULL; // Don't permit consecutive slashes
+ }
+ last_is_slash = true;
+ continue;
+ }
+ }
+ else {
+ jint unicode_ch;
+ char* tmp_p = UTF8::next_character(p, &unicode_ch);
+ p = tmp_p;
+ last_is_slash = false;
+ // Check if ch is Java identifier start or is Java identifier part
+ // 4672820: call java.lang.Character methods directly without generating separate tables.
+ EXCEPTION_MARK;
+
+ // return value
+ JavaValue result(T_BOOLEAN);
+ // Set up the arguments to isJavaIdentifierStart and isJavaIdentifierPart
+ JavaCallArguments args;
+ args.push_int(unicode_ch);
+
+ // public static boolean isJavaIdentifierStart(char ch);
+ JavaCalls::call_static(&result,
+ SystemDictionary::Character_klass(),
+ vmSymbols::isJavaIdentifierStart_name(),
+ vmSymbols::int_bool_signature(),
+ &args,
+ THREAD);
+
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ return 0;
+ }
+ if (result.get_jboolean()) {
+ continue;
+ }
+
+ if (not_first_ch) {
+ // public static boolean isJavaIdentifierPart(char ch);
+ JavaCalls::call_static(&result,
+ SystemDictionary::Character_klass(),
+ vmSymbols::isJavaIdentifierPart_name(),
+ vmSymbols::int_bool_signature(),
+ &args,
+ THREAD);
+
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ return 0;
+ }
+
+ if (result.get_jboolean()) {
+ continue;
+ }
+ }
+ }
+ return (not_first_ch) ? old_p : NULL;
+ }
+ return (not_first_ch) ? p : NULL;
+}
+
+// Take pointer to a string. Skip over the longest part of the string that could
+// be taken as a field signature. Allow "void" if void_ok.
+// Return a pointer to just past the signature.
+// Return NULL if no legal signature is found.
+const char* ClassFileParser::skip_over_field_signature(const char* signature,
+ bool void_ok,
+ unsigned int length,
+ TRAPS) const {
+ unsigned int array_dim = 0;
+ while (length > 0) {
+ switch (signature[0]) {
+ case JVM_SIGNATURE_VOID: if (!void_ok) { return NULL; }
+ case JVM_SIGNATURE_BOOLEAN:
+ case JVM_SIGNATURE_BYTE:
+ case JVM_SIGNATURE_CHAR:
+ case JVM_SIGNATURE_SHORT:
+ case JVM_SIGNATURE_INT:
+ case JVM_SIGNATURE_FLOAT:
+ case JVM_SIGNATURE_LONG:
+ case JVM_SIGNATURE_DOUBLE:
+ return signature + 1;
+ case JVM_SIGNATURE_CLASS: {
+ if (_major_version < JAVA_1_5_VERSION) {
+ // Skip over the class name if one is there
+ const char* const p = skip_over_field_name(signature + 1, true, --length);
+
+ // The next character better be a semicolon
+ if (p && (p - signature) > 1 && p[0] == ';') {
+ return p + 1;
+ }
+ }
+ else {
+ // 4900761: For class version > 48, any unicode is allowed in class name.
+ length--;
+ signature++;
+ while (length > 0 && signature[0] != ';') {
+ if (signature[0] == '.') {
+ classfile_parse_error("Class name contains illegal character '.' in descriptor in class file %s", CHECK_0);
+ }
+ length--;
+ signature++;
+ }
+ if (signature[0] == ';') { return signature + 1; }
+ }
+
+ return NULL;
+ }
+ case JVM_SIGNATURE_ARRAY:
+ array_dim++;
+ if (array_dim > 255) {
+ // 4277370: array descriptor is valid only if it represents 255 or fewer dimensions.
+ classfile_parse_error("Array type descriptor has more than 255 dimensions in class file %s", CHECK_0);
+ }
+ // The rest of what's there better be a legal signature
+ signature++;
+ length--;
+ void_ok = false;
+ break;
+
+ default:
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
// Checks if name is a legal class name.
-void ClassFileParser::verify_legal_class_name(Symbol* name, TRAPS) {
+void ClassFileParser::verify_legal_class_name(const Symbol* name, TRAPS) const {
if (!_need_verify || _relax_verify) { return; }
char buf[fixed_buffer_size];
@@ -5035,7 +4891,7 @@
bool legal = false;
if (length > 0) {
- char* p;
+ const char* p;
if (bytes[0] == JVM_SIGNATURE_ARRAY) {
p = skip_over_field_signature(bytes, false, length, CHECK);
legal = (p != NULL) && ((p - bytes) == (int)length);
@@ -5054,6 +4910,7 @@
}
if (!legal) {
ResourceMark rm(THREAD);
+ assert(_class_name != NULL, "invariant");
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -5065,7 +4922,7 @@
}
// Checks if name is a legal field name.
-void ClassFileParser::verify_legal_field_name(Symbol* name, TRAPS) {
+void ClassFileParser::verify_legal_field_name(const Symbol* name, TRAPS) const {
if (!_need_verify || _relax_verify) { return; }
char buf[fixed_buffer_size];
@@ -5076,7 +4933,7 @@
if (length > 0) {
if (_major_version < JAVA_1_5_VERSION) {
if (bytes[0] != '<') {
- char* p = skip_over_field_name(bytes, false, length);
+ const char* p = skip_over_field_name(bytes, false, length);
legal = (p != NULL) && ((p - bytes) == (int)length);
}
} else {
@@ -5087,6 +4944,7 @@
if (!legal) {
ResourceMark rm(THREAD);
+ assert(_class_name != NULL, "invariant");
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -5098,7 +4956,7 @@
}
// Checks if name is a legal method name.
-void ClassFileParser::verify_legal_method_name(Symbol* name, TRAPS) {
+void ClassFileParser::verify_legal_method_name(const Symbol* name, TRAPS) const {
if (!_need_verify || _relax_verify) { return; }
assert(name != NULL, "method name is null");
@@ -5113,7 +4971,7 @@
legal = true;
}
} else if (_major_version < JAVA_1_5_VERSION) {
- char* p;
+ const char* p;
p = skip_over_field_name(bytes, false, length);
legal = (p != NULL) && ((p - bytes) == (int)length);
} else {
@@ -5124,6 +4982,7 @@
if (!legal) {
ResourceMark rm(THREAD);
+ assert(_class_name != NULL, "invariant");
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -5136,13 +4995,15 @@
// Checks if signature is a legal field signature.
-void ClassFileParser::verify_legal_field_signature(Symbol* name, Symbol* signature, TRAPS) {
+void ClassFileParser::verify_legal_field_signature(const Symbol* name,
+ const Symbol* signature,
+ TRAPS) const {
if (!_need_verify) { return; }
char buf[fixed_buffer_size];
- char* bytes = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
- unsigned int length = signature->utf8_length();
- char* p = skip_over_field_signature(bytes, false, length, CHECK);
+ const char* const bytes = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
+ const unsigned int length = signature->utf8_length();
+ const char* const p = skip_over_field_signature(bytes, false, length, CHECK);
if (p == NULL || (p - bytes) != (int)length) {
throwIllegalSignature("Field", name, signature, CHECK);
@@ -5151,7 +5012,9 @@
// Checks if signature is a legal method signature.
// Returns number of parameters
-int ClassFileParser::verify_legal_method_signature(Symbol* name, Symbol* signature, TRAPS) {
+int ClassFileParser::verify_legal_method_signature(const Symbol* name,
+ const Symbol* signature,
+ TRAPS) const {
if (!_need_verify) {
// make sure caller's args_size will be less than 0 even for non-static
// method so it will be recomputed in compute_size_of_parameters().
@@ -5168,9 +5031,9 @@
unsigned int args_size = 0;
char buf[fixed_buffer_size];
- char* p = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
+ const char* p = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
unsigned int length = signature->utf8_length();
- char* nextp;
+ const char* nextp;
// The first character must be a '('
if ((length > 0) && (*p++ == JVM_SIGNATURE_FUNC)) {
@@ -5208,188 +5071,823 @@
return 0;
}
-
-// Unqualified names may not contain the characters '.', ';', '[', or '/'.
-// Method names also may not contain the characters '<' or '>', unless <init>
-// or <clinit>. Note that method names may not be <init> or <clinit> in this
-// method. Because these names have been checked as special cases before
-// calling this method in verify_legal_method_name.
-bool ClassFileParser::verify_unqualified_name(
- char* name, unsigned int length, int type) {
- jchar ch;
-
- for (char* p = name; p != name + length; ) {
- ch = *p;
- if (ch < 128) {
- p++;
- if (ch == '.' || ch == ';' || ch == '[' ) {
- return false; // do not permit '.', ';', or '['
+int ClassFileParser::static_field_size() const {
+ assert(_field_info != NULL, "invariant");
+ return _field_info->static_field_size;
+}
+
+int ClassFileParser::total_oop_map_count() const {
+ assert(_field_info != NULL, "invariant");
+ return _field_info->total_oop_map_count;
+}
+
+jint ClassFileParser::layout_size() const {
+ assert(_field_info != NULL, "invariant");
+ return _field_info->instance_size;
+}
+
+static void check_methods_for_intrinsics(const InstanceKlass* ik,
+ const Array<Method*>* methods) {
+ assert(ik != NULL, "invariant");
+ assert(methods != NULL, "invariant");
+
+ // Set up Method*::intrinsic_id as soon as we know the names of methods.
+ // (We used to do this lazily, but now we query it in Rewriter,
+ // which is eagerly done for every method, so we might as well do it now,
+ // when everything is fresh in memory.)
+ const vmSymbols::SID klass_id = Method::klass_id_for_intrinsics(ik);
+
+ if (klass_id != vmSymbols::NO_SID) {
+ for (int j = 0; j < methods->length(); ++j) {
+ Method* method = methods->at(j);
+ method->init_intrinsic_id();
+
+ if (CheckIntrinsics) {
+ // Check if an intrinsic is defined for method 'method',
+ // but the method is not annotated with @HotSpotIntrinsicCandidate.
+ if (method->intrinsic_id() != vmIntrinsics::_none &&
+ !method->intrinsic_candidate()) {
+ tty->print("Compiler intrinsic is defined for method [%s], "
+ "but the method is not annotated with @HotSpotIntrinsicCandidate.%s",
+ method->name_and_sig_as_C_string(),
+ NOT_DEBUG(" Method will not be inlined.") DEBUG_ONLY(" Exiting.")
+ );
+ tty->cr();
+ DEBUG_ONLY(vm_exit(1));
+ }
+ // Check is the method 'method' is annotated with @HotSpotIntrinsicCandidate,
+ // but there is no intrinsic available for it.
+ if (method->intrinsic_candidate() &&
+ method->intrinsic_id() == vmIntrinsics::_none) {
+ tty->print("Method [%s] is annotated with @HotSpotIntrinsicCandidate, "
+ "but no compiler intrinsic is defined for the method.%s",
+ method->name_and_sig_as_C_string(),
+ NOT_DEBUG("") DEBUG_ONLY(" Exiting.")
+ );
+ tty->cr();
+ DEBUG_ONLY(vm_exit(1));
+ }
}
- if (type != LegalClass && ch == '/') {
- return false; // do not permit '/' unless it's class name
- }
- if (type == LegalMethod && (ch == '<' || ch == '>')) {
- return false; // do not permit '<' or '>' in method names
- }
- } else {
- char* tmp_p = UTF8::next(p, &ch);
- p = tmp_p;
+ } // end for
+
+#ifdef ASSERT
+ if (CheckIntrinsics) {
+ // Check for orphan methods in the current class. A method m
+ // of a class C is orphan if an intrinsic is defined for method m,
+ // but class C does not declare m.
+ // The check is potentially expensive, therefore it is available
+ // only in debug builds.
+
+ for (int id = vmIntrinsics::FIRST_ID; id < (int)vmIntrinsics::ID_LIMIT; ++id) {
+ if (vmIntrinsics::_compiledLambdaForm == id) {
+ // The _compiledLamdbdaForm intrinsic is a special marker for bytecode
+ // generated for the JVM from a LambdaForm and therefore no method
+ // is defined for it.
+ continue;
+ }
+
+ if (vmIntrinsics::class_for(vmIntrinsics::ID_from(id)) == klass_id) {
+ // Check if the current class contains a method with the same
+ // name, flags, signature.
+ bool match = false;
+ for (int j = 0; j < methods->length(); ++j) {
+ const Method* method = methods->at(j);
+ if (method->intrinsic_id() == id) {
+ match = true;
+ break;
+ }
+ }
+
+ if (!match) {
+ char buf[1000];
+ tty->print("Compiler intrinsic is defined for method [%s], "
+ "but the method is not available in class [%s].%s",
+ vmIntrinsics::short_name_as_C_string(vmIntrinsics::ID_from(id),
+ buf, sizeof(buf)),
+ ik->name()->as_C_string(),
+ NOT_DEBUG("") DEBUG_ONLY(" Exiting.")
+ );
+ tty->cr();
+ DEBUG_ONLY(vm_exit(1));
+ }
+ }
+ } // end for
+ } // CheckIntrinsics
+#endif // ASSERT
+ }
+}
+
+InstanceKlass* ClassFileParser::create_instance_klass(TRAPS) {
+ if (_klass != NULL) {
+ return _klass;
+ }
+
+ InstanceKlass* const ik =
+ InstanceKlass::allocate_instance_klass(*this, CHECK_NULL);
+
+ fill_instance_klass(ik, CHECK_NULL);
+
+ assert(_klass == ik, "invariant");
+
+ return ik;
+}
+
+void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) {
+ assert(ik != NULL, "invariant");
+
+ set_klass_to_deallocate(ik);
+
+ assert(_field_info != NULL, "invariant");
+ assert(ik->static_field_size() == _field_info->static_field_size, "sanity");
+ assert(ik->nonstatic_oop_map_count() == _field_info->total_oop_map_count,
+ "sanity");
+
+ assert(ik->is_instance_klass(), "sanity");
+ assert(ik->size_helper() == _field_info->instance_size, "sanity");
+
+ // Fill in information already parsed
+ ik->set_should_verify_class(_need_verify);
+
+ // Not yet: supers are done below to support the new subtype-checking fields
+ ik->set_class_loader_data(_loader_data);
+ ik->set_nonstatic_field_size(_field_info->nonstatic_field_size);
+ ik->set_has_nonstatic_fields(_field_info->has_nonstatic_fields);
+ assert(_fac != NULL, "invariant");
+ ik->set_static_oop_field_count(_fac->count[STATIC_OOP]);
+
+ // this transfers ownership of a lot of arrays from
+ // the parser onto the InstanceKlass*
+ apply_parsed_class_metadata(ik, _java_fields_count, CHECK);
+
+ // note that is not safe to use the fields in the parser from this point on
+ assert(NULL == _cp, "invariant");
+ assert(NULL == _fields, "invariant");
+ assert(NULL == _methods, "invariant");
+ assert(NULL == _inner_classes, "invariant");
+ assert(NULL == _local_interfaces, "invariant");
+ assert(NULL == _transitive_interfaces, "invariant");
+ assert(NULL == _combined_annotations, "invariant");
+
+ if (_has_final_method) {
+ ik->set_has_final_method();
+ }
+
+ ik->copy_method_ordering(_method_ordering, CHECK);
+ // The InstanceKlass::_methods_jmethod_ids cache
+ // is managed on the assumption that the initial cache
+ // size is equal to the number of methods in the class. If
+ // that changes, then InstanceKlass::idnum_can_increment()
+ // has to be changed accordingly.
+ ik->set_initial_method_idnum(ik->methods()->length());
+
+ ik->set_name(_class_name);
+
+ if (is_anonymous()) {
+ // I am well known to myself
+ ik->constants()->klass_at_put(_this_class_index, ik); // eagerly resolve
+ }
+
+ ik->set_minor_version(_minor_version);
+ ik->set_major_version(_major_version);
+ ik->set_has_default_methods(_has_default_methods);
+ ik->set_declares_default_methods(_declares_default_methods);
+
+ if (_host_klass != NULL) {
+ assert (ik->is_anonymous(), "should be the same");
+ ik->set_host_klass(_host_klass);
+ }
+
+ const Array<Method*>* const methods = ik->methods();
+ assert(methods != NULL, "invariant");
+ const int methods_len = methods->length();
+
+ check_methods_for_intrinsics(ik, methods);
+
+ // Fill in field values obtained by parse_classfile_attributes
+ if (_parsed_annotations->has_any_annotations()) {
+ _parsed_annotations->apply_to(ik);
+ }
+
+ apply_parsed_class_attributes(ik);
+
+ // Miranda methods
+ if ((_num_miranda_methods > 0) ||
+ // if this class introduced new miranda methods or
+ (_super_klass != NULL && _super_klass->has_miranda_methods())
+ // super class exists and this class inherited miranda methods
+ ) {
+ ik->set_has_miranda_methods(); // then set a flag
+ }
+
+ // Fill in information needed to compute superclasses.
+ ik->initialize_supers(const_cast<InstanceKlass*>(_super_klass), CHECK);
+
+ // Initialize itable offset tables
+ klassItable::setup_itable_offset_table(ik);
+
+ // Compute transitive closure of interfaces this class implements
+ // Do final class setup
+ fill_oop_maps(ik,
+ _field_info->nonstatic_oop_map_count,
+ _field_info->nonstatic_oop_offsets,
+ _field_info->nonstatic_oop_counts);
+
+ // Fill in has_finalizer, has_vanilla_constructor, and layout_helper
+ set_precomputed_flags(ik);
+
+ // check if this class can access its super class
+ check_super_class_access(ik, CHECK);
+
+ // check if this class can access its superinterfaces
+ check_super_interface_access(ik, CHECK);
+
+ // check if this class overrides any final method
+ check_final_method_override(ik, CHECK);
+
+ // check that if this class is an interface then it doesn't have static methods
+ if (ik->is_interface()) {
+ /* An interface in a JAVA 8 classfile can be static */
+ if (_major_version < JAVA_8_VERSION) {
+ check_illegal_static_method(ik, CHECK);
}
}
- return true;
-}
-
-
-// Take pointer to a string. Skip over the longest part of the string that could
-// be taken as a fieldname. Allow '/' if slash_ok is true.
-// Return a pointer to just past the fieldname.
-// Return NULL if no fieldname at all was found, or in the case of slash_ok
-// being true, we saw consecutive slashes (meaning we were looking for a
-// qualified path but found something that was badly-formed).
-char* ClassFileParser::skip_over_field_name(char* name, bool slash_ok, unsigned int length) {
- char* p;
- jchar ch;
- jboolean last_is_slash = false;
- jboolean not_first_ch = false;
-
- for (p = name; p != name + length; not_first_ch = true) {
- char* old_p = p;
- ch = *p;
- if (ch < 128) {
- p++;
- // quick check for ascii
- if ((ch >= 'a' && ch <= 'z') ||
- (ch >= 'A' && ch <= 'Z') ||
- (ch == '_' || ch == '$') ||
- (not_first_ch && ch >= '0' && ch <= '9')) {
- last_is_slash = false;
- continue;
- }
- if (slash_ok && ch == '/') {
- if (last_is_slash) {
- return NULL; // Don't permit consecutive slashes
+
+ // Allocate mirror and initialize static fields
+ // The create_mirror() call will also call compute_modifiers()
+ java_lang_Class::create_mirror(ik,
+ _loader_data->class_loader(),
+ _protection_domain,
+ CHECK);
+
+ assert(_all_mirandas != NULL, "invariant");
+
+ // Generate any default methods - default methods are interface methods
+ // that have a default implementation. This is new with Lambda project.
+ if (_has_default_methods ) {
+ DefaultMethods::generate_default_methods(ik,
+ _all_mirandas,
+ CHECK);
+ }
+
+ // Update the loader_data graph.
+ record_defined_class_dependencies(ik, CHECK);
+
+ ClassLoadingService::notify_class_loaded(ik, false /* not shared class */);
+
+ if (!is_internal()) {
+ if (TraceClassLoading) {
+ ResourceMark rm;
+ // print in a single call to reduce interleaving of output
+ if (_stream->source() != NULL) {
+ tty->print("[Loaded %s from %s]\n",
+ ik->external_name(),
+ _stream->source());
+ } else if (_loader_data->class_loader() == NULL) {
+ const Klass* const caller =
+ THREAD->is_Java_thread()
+ ? ((JavaThread*)THREAD)->security_get_caller_class(1)
+ : NULL;
+ // caller can be NULL, for example, during a JVMTI VM_Init hook
+ if (caller != NULL) {
+ tty->print("[Loaded %s by instance of %s]\n",
+ ik->external_name(),
+ caller->external_name());
+ } else {
+ tty->print("[Loaded %s]\n", ik->external_name());
}
- last_is_slash = true;
- continue;
+ } else {
+ tty->print("[Loaded %s from %s]\n", ik->external_name(),
+ _loader_data->class_loader()->klass()->external_name());
}
- } else {
- jint unicode_ch;
- char* tmp_p = UTF8::next_character(p, &unicode_ch);
- p = tmp_p;
- last_is_slash = false;
- // Check if ch is Java identifier start or is Java identifier part
- // 4672820: call java.lang.Character methods directly without generating separate tables.
- EXCEPTION_MARK;
- instanceKlassHandle klass (THREAD, SystemDictionary::Character_klass());
-
- // return value
- JavaValue result(T_BOOLEAN);
- // Set up the arguments to isJavaIdentifierStart and isJavaIdentifierPart
- JavaCallArguments args;
- args.push_int(unicode_ch);
-
- // public static boolean isJavaIdentifierStart(char ch);
- JavaCalls::call_static(&result,
- klass,
- vmSymbols::isJavaIdentifierStart_name(),
- vmSymbols::int_bool_signature(),
- &args,
- THREAD);
-
- if (HAS_PENDING_EXCEPTION) {
- CLEAR_PENDING_EXCEPTION;
- return 0;
+ }
+
+ if (TraceClassResolution) {
+ ResourceMark rm;
+ // print out the superclass.
+ const char * from = ik->external_name();
+ if (ik->java_super() != NULL) {
+ tty->print("RESOLVE %s %s (super)\n",
+ from,
+ ik->java_super()->external_name());
}
- if (result.get_jboolean()) {
- continue;
- }
-
- if (not_first_ch) {
- // public static boolean isJavaIdentifierPart(char ch);
- JavaCalls::call_static(&result,
- klass,
- vmSymbols::isJavaIdentifierPart_name(),
- vmSymbols::int_bool_signature(),
- &args,
- THREAD);
-
- if (HAS_PENDING_EXCEPTION) {
- CLEAR_PENDING_EXCEPTION;
- return 0;
- }
-
- if (result.get_jboolean()) {
- continue;
+ // print out each of the interface classes referred to by this class.
+ const Array<Klass*>* const local_interfaces = ik->local_interfaces();
+ if (local_interfaces != NULL) {
+ const int length = local_interfaces->length();
+ for (int i = 0; i < length; i++) {
+ const Klass* const k = local_interfaces->at(i);
+ const char * to = k->external_name();
+ tty->print("RESOLVE %s %s (interface)\n", from, to);
}
}
}
- return (not_first_ch) ? old_p : NULL;
}
- return (not_first_ch) ? p : NULL;
+
+ TRACE_INIT_ID(ik);
+
+ // If we reach here, all is well.
+ // Now remove the InstanceKlass* from the _klass_to_deallocate field
+ // in order for it to not be destroyed in the ClassFileParser destructor.
+ set_klass_to_deallocate(NULL);
+
+ // it's official
+ set_klass(ik);
+
+ debug_only(ik->verify();)
+}
+
+ClassFileParser::ClassFileParser(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ TempNewSymbol* parsed_name,
+ const Klass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ Publicity pub_level,
+ TRAPS) :
+ _stream(stream),
+ _requested_name(name),
+ _loader_data(loader_data),
+ _host_klass(host_klass),
+ _cp_patches(cp_patches),
+ _parsed_name(parsed_name),
+ _super_klass(),
+ _cp(NULL),
+ _fields(NULL),
+ _methods(NULL),
+ _inner_classes(NULL),
+ _local_interfaces(NULL),
+ _transitive_interfaces(NULL),
+ _combined_annotations(NULL),
+ _annotations(NULL),
+ _type_annotations(NULL),
+ _fields_annotations(NULL),
+ _fields_type_annotations(NULL),
+ _klass(NULL),
+ _klass_to_deallocate(NULL),
+ _parsed_annotations(NULL),
+ _fac(NULL),
+ _field_info(NULL),
+ _method_ordering(NULL),
+ _all_mirandas(NULL),
+ _vtable_size(0),
+ _itable_size(0),
+ _num_miranda_methods(0),
+ _rt(REF_NONE),
+ _protection_domain(protection_domain),
+ _access_flags(),
+ _pub_level(pub_level),
+ _synthetic_flag(false),
+ _sde_length(false),
+ _sde_buffer(NULL),
+ _sourcefile_index(0),
+ _generic_signature_index(0),
+ _major_version(0),
+ _minor_version(0),
+ _this_class_index(0),
+ _super_class_index(0),
+ _itfs_len(0),
+ _java_fields_count(0),
+ _need_verify(false),
+ _relax_verify(false),
+ _has_default_methods(false),
+ _declares_default_methods(false),
+ _has_final_method(false),
+ _has_finalizer(false),
+ _has_empty_finalizer(false),
+ _has_vanilla_constructor(false),
+ _max_bootstrap_specifier_index(-1) {
+
+ _class_name = name != NULL ? name : vmSymbols::unknown_class_name();
+
+ assert(THREAD->is_Java_thread(), "invariant");
+ assert(_loader_data != NULL, "invariant");
+ assert(stream != NULL, "invariant");
+ assert(_stream != NULL, "invariant");
+ assert(_stream->buffer() == _stream->current(), "invariant");
+ assert(_class_name != NULL, "invariant");
+ assert(0 == _access_flags.as_int(), "invariant");
+
+ // Figure out whether we can skip format checking (matching classic VM behavior)
+ if (DumpSharedSpaces) {
+ // verify == true means it's a 'remote' class (i.e., non-boot class)
+ // Verification decision is based on BytecodeVerificationRemote flag
+ // for those classes.
+ _need_verify = (stream->need_verify()) ? BytecodeVerificationRemote :
+ BytecodeVerificationLocal;
+ }
+ else {
+ _need_verify = Verifier::should_verify_for(_loader_data->class_loader(),
+ stream->need_verify());
+ }
+
+ // synch back verification state to stream
+ stream->set_verify(_need_verify);
+
+ // Check if verification needs to be relaxed for this class file
+ // Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376)
+ _relax_verify = Verifier::relax_verify_for(_loader_data->class_loader());
+
+ parse_stream(stream, CHECK);
+
+ post_process_parsed_stream(stream, _cp, CHECK);
+}
+
+void ClassFileParser::clear_class_metadata() {
+ // metadata created before the instance klass is created. Must be
+ // deallocated if classfile parsing returns an error.
+ _cp = NULL;
+ _fields = NULL;
+ _methods = NULL;
+ _inner_classes = NULL;
+ _local_interfaces = NULL;
+ _transitive_interfaces = NULL;
+ _combined_annotations = NULL;
+ _annotations = _type_annotations = NULL;
+ _fields_annotations = _fields_type_annotations = NULL;
+}
+
+// Destructor to clean up
+ClassFileParser::~ClassFileParser() {
+ if (_cp != NULL) {
+ MetadataFactory::free_metadata(_loader_data, _cp);
+ }
+ if (_fields != NULL) {
+ MetadataFactory::free_array<u2>(_loader_data, _fields);
+ }
+
+ if (_methods != NULL) {
+ // Free methods
+ InstanceKlass::deallocate_methods(_loader_data, _methods);
+ }
+
+ // beware of the Universe::empty_blah_array!!
+ if (_inner_classes != NULL && _inner_classes != Universe::the_empty_short_array()) {
+ MetadataFactory::free_array<u2>(_loader_data, _inner_classes);
+ }
+
+ // Free interfaces
+ InstanceKlass::deallocate_interfaces(_loader_data, _super_klass,
+ _local_interfaces, _transitive_interfaces);
+
+ if (_combined_annotations != NULL) {
+ // After all annotations arrays have been created, they are installed into the
+ // Annotations object that will be assigned to the InstanceKlass being created.
+
+ // Deallocate the Annotations object and the installed annotations arrays.
+ _combined_annotations->deallocate_contents(_loader_data);
+
+ // If the _combined_annotations pointer is non-NULL,
+ // then the other annotations fields should have been cleared.
+ assert(_annotations == NULL, "Should have been cleared");
+ assert(_type_annotations == NULL, "Should have been cleared");
+ assert(_fields_annotations == NULL, "Should have been cleared");
+ assert(_fields_type_annotations == NULL, "Should have been cleared");
+ } else {
+ // If the annotations arrays were not installed into the Annotations object,
+ // then they have to be deallocated explicitly.
+ MetadataFactory::free_array<u1>(_loader_data, _annotations);
+ MetadataFactory::free_array<u1>(_loader_data, _type_annotations);
+ Annotations::free_contents(_loader_data, _fields_annotations);
+ Annotations::free_contents(_loader_data, _fields_type_annotations);
+ }
+
+ clear_class_metadata();
+
+ // deallocate the klass if already created. Don't directly deallocate, but add
+ // to the deallocate list so that the klass is removed from the CLD::_klasses list
+ // at a safepoint.
+ if (_klass_to_deallocate != NULL) {
+ _loader_data->add_to_deallocate_list(_klass_to_deallocate);
+ }
}
-
-// Take pointer to a string. Skip over the longest part of the string that could
-// be taken as a field signature. Allow "void" if void_ok.
-// Return a pointer to just past the signature.
-// Return NULL if no legal signature is found.
-char* ClassFileParser::skip_over_field_signature(char* signature,
- bool void_ok,
- unsigned int length,
+void ClassFileParser::parse_stream(const ClassFileStream* const stream,
+ TRAPS) {
+
+ assert(stream != NULL, "invariant");
+ assert(_class_name != NULL, "invariant");
+
+ // BEGIN STREAM PARSING
+ stream->guarantee_more(8, CHECK); // magic, major, minor
+ // Magic value
+ const u4 magic = stream->get_u4_fast();
+ guarantee_property(magic == JAVA_CLASSFILE_MAGIC,
+ "Incompatible magic value %u in class file %s",
+ magic, CHECK);
+
+ // Version numbers
+ _minor_version = stream->get_u2_fast();
+ _major_version = stream->get_u2_fast();
+
+ if (DumpSharedSpaces && _major_version < JAVA_1_5_VERSION) {
+ ResourceMark rm;
+ warning("Pre JDK 1.5 class not supported by CDS: %u.%u %s",
+ _major_version, _minor_version, _class_name->as_C_string());
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_UnsupportedClassVersionError(),
+ "Unsupported major.minor version for dump time %u.%u",
+ _major_version,
+ _minor_version);
+ }
+
+ // Check version numbers - we check this even with verifier off
+ if (!is_supported_version(_major_version, _minor_version)) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_UnsupportedClassVersionError(),
+ "%s has been compiled by a more recent version of the Java Runtime (class file version %u.%u), "
+ "this version of the Java Runtime only recognizes class file versions up to %u.%u",
+ _class_name->as_C_string(),
+ _major_version,
+ _minor_version,
+ JAVA_MAX_SUPPORTED_VERSION,
+ JAVA_MAX_SUPPORTED_MINOR_VERSION);
+ return;
+ }
+
+ stream->guarantee_more(3, CHECK); // length, first cp tag
+ const u2 cp_size = stream->get_u2_fast();
+
+ guarantee_property(
+ cp_size >= 1, "Illegal constant pool size %u in class file %s",
+ cp_size, CHECK);
+
+ _cp = ConstantPool::allocate(_loader_data,
+ cp_size,
+ CHECK);
+
+ ConstantPool* const cp = _cp;
+
+ parse_constant_pool(stream, cp, cp_size, CHECK);
+
+ assert(cp_size == (const u2)cp->length(), "invariant");
+
+ // ACCESS FLAGS
+ stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len
+
+ // Access flags
+ jint flags = stream->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
+
+ if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
+ // Set abstract bit for old class files for backward compatibility
+ flags |= JVM_ACC_ABSTRACT;
+ }
+
+ _access_flags.set_flags(flags);
+
+ verify_legal_class_modifiers((jint)_access_flags.as_int(), CHECK);
+
+ // This class and superclass
+ _this_class_index = stream->get_u2_fast();
+ check_property(
+ valid_cp_range(_this_class_index, cp_size) &&
+ cp->tag_at(_this_class_index).is_unresolved_klass(),
+ "Invalid this class index %u in constant pool in class file %s",
+ _this_class_index, CHECK);
+
+ Symbol* const class_name_in_cp = cp->klass_name_at(_this_class_index);
+ assert(class_name_in_cp != NULL, "class_name can't be null");
+
+ if (_parsed_name != NULL) {
+ // It's important to set parsed_name *before* resolving the super class.
+ // (it's used for cleanup by the caller if parsing fails)
+ *_parsed_name = class_name_in_cp;
+ // parsed_name is returned and can be used if there's an error, so add to
+ // its reference count. Caller will decrement the refcount.
+ (*_parsed_name)->increment_refcount();
+ }
+
+ // Update _class_name which could be null previously
+ // to reflect the name in the constant pool
+ _class_name = class_name_in_cp;
+
+ // Don't need to check whether this class name is legal or not.
+ // It has been checked when constant pool is parsed.
+ // However, make sure it is not an array type.
+ if (_need_verify) {
+ guarantee_property(_class_name->byte_at(0) != JVM_SIGNATURE_ARRAY,
+ "Bad class name in class file %s",
+ CHECK);
+ }
+
+ // Checks if name in class file matches requested name
+ if (_requested_name != NULL && _requested_name != _class_name) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_NoClassDefFoundError(),
+ "%s (wrong name: %s)",
+ _class_name->as_C_string(),
+ _requested_name != NULL ? _requested_name->as_C_string() : "NoName"
+ );
+ return;
+ }
+
+ if (!is_internal()) {
+ if (TraceClassLoadingPreorder) {
+ tty->print("[Loading %s",
+ _class_name->as_klass_external_name());
+
+ if (stream->source() != NULL) {
+ tty->print(" from %s", stream->source());
+ }
+ tty->print_cr("]");
+ }
+#if INCLUDE_CDS
+ if (DumpLoadedClassList != NULL && stream->source() != NULL && classlist_file->is_open()) {
+ // Only dump the classes that can be stored into CDS archive
+ if (SystemDictionaryShared::is_sharing_possible(_loader_data)) {
+ ResourceMark rm(THREAD);
+ classlist_file->print_cr("%s", _class_name->as_C_string());
+ classlist_file->flush();
+ }
+ }
+#endif
+ }
+
+ // SUPERKLASS
+ _super_class_index = stream->get_u2_fast();
+ _super_klass = parse_super_class(cp,
+ _super_class_index,
+ _need_verify,
+ CHECK);
+
+ // Interfaces
+ _itfs_len = stream->get_u2_fast();
+ parse_interfaces(stream,
+ _itfs_len,
+ cp,
+ &_has_default_methods,
+ CHECK);
+
+ assert(_local_interfaces != NULL, "invariant");
+
+ // Fields (offsets are filled in later)
+ _fac = new FieldAllocationCount();
+ parse_fields(stream,
+ _access_flags.is_interface(),
+ _fac,
+ cp,
+ cp_size,
+ &_java_fields_count,
+ CHECK);
+
+ assert(_fields != NULL, "invariant");
+
+ // Methods
+ AccessFlags promoted_flags;
+ parse_methods(stream,
+ _access_flags.is_interface(),
+ &promoted_flags,
+ &_has_final_method,
+ &_declares_default_methods,
+ CHECK);
+
+ assert(_methods != NULL, "invariant");
+
+ // promote flags from parse_methods() to the klass' flags
+ _access_flags.add_promoted_flags(promoted_flags.as_int());
+
+ if (_declares_default_methods) {
+ _has_default_methods = true;
+ }
+
+ // Additional attributes/annotations
+ _parsed_annotations = new ClassAnnotationCollector();
+ parse_classfile_attributes(stream, cp, _parsed_annotations, CHECK);
+
+ assert(_inner_classes != NULL, "invariant");
+
+ // Finalize the Annotations metadata object,
+ // now that all annotation arrays have been created.
+ create_combined_annotations(CHECK);
+
+ // Make sure this is the end of class file stream
+ guarantee_property(stream->at_eos(),
+ "Extra bytes at the end of class file %s",
+ CHECK);
+
+ // all bytes in stream read and parsed
+}
+
+void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const stream,
+ ConstantPool* cp,
TRAPS) {
- unsigned int array_dim = 0;
- while (length > 0) {
- switch (signature[0]) {
- case JVM_SIGNATURE_VOID: if (!void_ok) { return NULL; }
- case JVM_SIGNATURE_BOOLEAN:
- case JVM_SIGNATURE_BYTE:
- case JVM_SIGNATURE_CHAR:
- case JVM_SIGNATURE_SHORT:
- case JVM_SIGNATURE_INT:
- case JVM_SIGNATURE_FLOAT:
- case JVM_SIGNATURE_LONG:
- case JVM_SIGNATURE_DOUBLE:
- return signature + 1;
- case JVM_SIGNATURE_CLASS: {
- if (_major_version < JAVA_1_5_VERSION) {
- // Skip over the class name if one is there
- char* p = skip_over_field_name(signature + 1, true, --length);
-
- // The next character better be a semicolon
- if (p && (p - signature) > 1 && p[0] == ';') {
- return p + 1;
- }
- } else {
- // 4900761: For class version > 48, any unicode is allowed in class name.
- length--;
- signature++;
- while (length > 0 && signature[0] != ';') {
- if (signature[0] == '.') {
- classfile_parse_error("Class name contains illegal character '.' in descriptor in class file %s", CHECK_0);
- }
- length--;
- signature++;
- }
- if (signature[0] == ';') { return signature + 1; }
- }
-
- return NULL;
+ assert(stream != NULL, "invariant");
+ assert(stream->at_eos(), "invariant");
+ assert(cp != NULL, "invariant");
+ assert(_loader_data != NULL, "invariant");
+
+ // We check super class after class file is parsed and format is checked
+ if (_super_class_index > 0 && NULL ==_super_klass) {
+ Symbol* const super_class_name = cp->klass_name_at(_super_class_index);
+ if (_access_flags.is_interface()) {
+ // Before attempting to resolve the superclass, check for class format
+ // errors not checked yet.
+ guarantee_property(super_class_name == vmSymbols::java_lang_Object(),
+ "Interfaces must have java.lang.Object as superclass in class file %s",
+ CHECK);
}
- case JVM_SIGNATURE_ARRAY:
- array_dim++;
- if (array_dim > 255) {
- // 4277370: array descriptor is valid only if it represents 255 or fewer dimensions.
- classfile_parse_error("Array type descriptor has more than 255 dimensions in class file %s", CHECK_0);
- }
- // The rest of what's there better be a legal signature
- signature++;
- length--;
- void_ok = false;
- break;
-
- default:
- return NULL;
+ _super_klass = (const InstanceKlass*)
+ SystemDictionary::resolve_super_or_fail(_class_name,
+ super_class_name,
+ _loader_data->class_loader(),
+ _protection_domain,
+ true,
+ CHECK);
+ }
+
+ if (_super_klass != NULL) {
+ if (_super_klass->has_default_methods()) {
+ _has_default_methods = true;
+ }
+
+ if (_super_klass->is_interface()) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_IncompatibleClassChangeError(),
+ "class %s has interface %s as super class",
+ _class_name->as_klass_external_name(),
+ _super_klass->external_name()
+ );
+ return;
+ }
+ // Make sure super class is not final
+ if (_super_klass->is_final()) {
+ THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class");
}
}
- return NULL;
+
+ // Compute the transitive list of all unique interfaces implemented by this class
+ _transitive_interfaces =
+ compute_transitive_interfaces(_super_klass,
+ _local_interfaces,
+ _loader_data,
+ CHECK);
+
+ assert(_transitive_interfaces != NULL, "invariant");
+
+ // sort methods
+ _method_ordering = sort_methods(_methods);
+
+ _all_mirandas = new GrowableArray<Method*>(20);
+
+ klassVtable::compute_vtable_size_and_num_mirandas(&_vtable_size,
+ &_num_miranda_methods,
+ _all_mirandas,
+ _super_klass,
+ _methods,
+ _access_flags,
+ _loader_data->class_loader(),
+ _class_name,
+ _local_interfaces,
+ CHECK);
+
+ // Size of Java itable (in words)
+ _itable_size = _access_flags.is_interface() ? 0 :
+ klassItable::compute_itable_size(_transitive_interfaces);
+
+ assert(_fac != NULL, "invariant");
+ assert(_parsed_annotations != NULL, "invariant");
+
+ _field_info = new FieldLayoutInfo();
+ layout_fields(cp, _fac, _parsed_annotations, _field_info, CHECK);
+
+ // Compute reference typ
+ _rt = (NULL ==_super_klass) ? REF_NONE : _super_klass->reference_type();
+
}
+
+void ClassFileParser::set_klass(InstanceKlass* klass) {
+
+#ifdef ASSERT
+ if (klass != NULL) {
+ assert(NULL == _klass, "leaking?");
+ }
+#endif
+
+ _klass = klass;
+}
+
+void ClassFileParser::set_klass_to_deallocate(InstanceKlass* klass) {
+
+#ifdef ASSERT
+ if (klass != NULL) {
+ assert(NULL == _klass_to_deallocate, "leaking?");
+ }
+#endif
+
+ _klass_to_deallocate = klass;
+}
+
+// Caller responsible for ResourceMark
+// clone stream with rewound position
+const ClassFileStream* ClassFileParser::clone_stream() const {
+ assert(_stream != NULL, "invariant");
+
+ return _stream->clone();
+}
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -25,33 +25,123 @@
#ifndef SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
#define SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
-#include "classfile/classFileStream.hpp"
-#include "classfile/symbolTable.hpp"
-#include "oops/annotations.hpp"
+#include "memory/referenceType.hpp"
+#include "runtime/handles.inline.hpp"
#include "oops/constantPool.hpp"
#include "oops/typeArrayOop.hpp"
#include "utilities/accessFlags.hpp"
+class Annotations;
+template <typename T>
+class Array;
+class ClassFileStream;
+class ClassLoaderData;
class CompressedLineNumberWriteStream;
-class FieldAllocationCount;
+class ConstMethod;
class FieldInfo;
-class FieldLayoutInfo;
-
+template <typename T>
+class GrowableArray;
+class InstanceKlass;
+class intArray;
+class Symbol;
+class TempNewSymbol;
// Parser for for .class files
//
// The bytes describing the class file structure is read from a Stream object
class ClassFileParser VALUE_OBJ_CLASS_SPEC {
+
+ class ClassAnnotationCollector;
+ class FieldAllocationCount;
+ class FieldAnnotationCollector;
+ class FieldLayoutInfo;
+
+ public:
+ // The ClassFileParser has an associated "publicity" level
+ // It is used to control which subsystems (if any)
+ // will observe the parsing (logging, events, tracing).
+ // Default level is "BROADCAST", which is equivalent to
+ // a "public" parsing attempt.
+ //
+ // "INTERNAL" level should be entirely private to the
+ // caller - this allows for internal reuse of ClassFileParser
+ //
+ enum Publicity {
+ INTERNAL,
+ BROADCAST,
+ NOF_PUBLICITY_LEVELS
+ };
+
private:
+ const ClassFileStream* _stream; // Actual input stream
+ const Symbol* _requested_name;
+ Symbol* _class_name;
+ mutable ClassLoaderData* _loader_data;
+ const Klass* _host_klass;
+ GrowableArray<Handle>* _cp_patches; // overrides for CP entries
+ TempNewSymbol* _parsed_name;
+
+ // Metadata created before the instance klass is created. Must be deallocated
+ // if not transferred to the InstanceKlass upon successful class loading
+ // in which case these pointers have been set to NULL.
+ const InstanceKlass* _super_klass;
+ ConstantPool* _cp;
+ Array<u2>* _fields;
+ Array<Method*>* _methods;
+ Array<u2>* _inner_classes;
+ Array<Klass*>* _local_interfaces;
+ Array<Klass*>* _transitive_interfaces;
+ Annotations* _combined_annotations;
+ AnnotationArray* _annotations;
+ AnnotationArray* _type_annotations;
+ Array<AnnotationArray*>* _fields_annotations;
+ Array<AnnotationArray*>* _fields_type_annotations;
+ InstanceKlass* _klass; // InstanceKlass* once created.
+ InstanceKlass* _klass_to_deallocate; // an InstanceKlass* to be destroyed
+
+ ClassAnnotationCollector* _parsed_annotations;
+ FieldAllocationCount* _fac;
+ FieldLayoutInfo* _field_info;
+ const intArray* _method_ordering;
+ GrowableArray<Method*>* _all_mirandas;
+
+ enum { fixed_buffer_size = 128 };
+ u_char _linenumbertable_buffer[fixed_buffer_size];
+
+ // Size of Java vtable (in words)
+ int _vtable_size;
+ int _itable_size;
+
+ int _num_miranda_methods;
+
+ ReferenceType _rt;
+ Handle _protection_domain;
+ AccessFlags _access_flags;
+
+ // for tracing and notifications
+ Publicity _pub_level;
+
+ // class attributes parsed before the instance klass is created:
+ bool _synthetic_flag;
+ int _sde_length;
+ const char* _sde_buffer;
+ u2 _sourcefile_index;
+ u2 _generic_signature_index;
+
+ u2 _major_version;
+ u2 _minor_version;
+ u2 _this_class_index;
+ u2 _super_class_index;
+ u2 _itfs_len;
+ u2 _java_fields_count;
+
bool _need_verify;
bool _relax_verify;
- u2 _major_version;
- u2 _minor_version;
- Symbol* _class_name;
- ClassLoaderData* _loader_data;
- KlassHandle _host_klass;
- GrowableArray<Handle>* _cp_patches; // overrides for CP entries
+
+ bool _has_default_methods;
+ bool _declares_default_methods;
+ bool _has_final_method;
// precomputed flags
bool _has_finalizer;
@@ -59,270 +149,164 @@
bool _has_vanilla_constructor;
int _max_bootstrap_specifier_index; // detects BSS values
- // class attributes parsed before the instance klass is created:
- bool _synthetic_flag;
- int _sde_length;
- char* _sde_buffer;
- u2 _sourcefile_index;
- u2 _generic_signature_index;
+ void parse_stream(const ClassFileStream* const stream, TRAPS);
- // Metadata created before the instance klass is created. Must be deallocated
- // if not transferred to the InstanceKlass upon successful class loading
- // in which case these pointers have been set to NULL.
- instanceKlassHandle _super_klass;
- ConstantPool* _cp;
- Array<u2>* _fields;
- Array<Method*>* _methods;
- Array<u2>* _inner_classes;
- Array<Klass*>* _local_interfaces;
- Array<Klass*>* _transitive_interfaces;
- Annotations* _combined_annotations;
- AnnotationArray* _annotations;
- AnnotationArray* _type_annotations;
- Array<AnnotationArray*>* _fields_annotations;
- Array<AnnotationArray*>* _fields_type_annotations;
- InstanceKlass* _klass; // InstanceKlass once created.
+ void post_process_parsed_stream(const ClassFileStream* const stream,
+ ConstantPool* cp,
+ TRAPS);
+
+ void fill_instance_klass(InstanceKlass* ik, TRAPS);
+ void set_klass(InstanceKlass* instance);
void set_class_synthetic_flag(bool x) { _synthetic_flag = x; }
void set_class_sourcefile_index(u2 x) { _sourcefile_index = x; }
void set_class_generic_signature_index(u2 x) { _generic_signature_index = x; }
- void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; }
+ void set_class_sde_buffer(const char* x, int len) { _sde_buffer = x; _sde_length = len; }
void create_combined_annotations(TRAPS);
-
- void init_parsed_class_attributes(ClassLoaderData* loader_data) {
- _loader_data = loader_data;
- _synthetic_flag = false;
- _sourcefile_index = 0;
- _generic_signature_index = 0;
- _sde_buffer = NULL;
- _sde_length = 0;
- // initialize the other flags too:
- _has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false;
- _max_bootstrap_specifier_index = -1;
- clear_class_metadata();
- _klass = NULL;
- }
- void apply_parsed_class_attributes(instanceKlassHandle k); // update k
- void apply_parsed_class_metadata(instanceKlassHandle k, int fields_count, TRAPS);
- void clear_class_metadata() {
- // metadata created before the instance klass is created. Must be
- // deallocated if classfile parsing returns an error.
- _cp = NULL;
- _fields = NULL;
- _methods = NULL;
- _inner_classes = NULL;
- _local_interfaces = NULL;
- _transitive_interfaces = NULL;
- _combined_annotations = NULL;
- _annotations = _type_annotations = NULL;
- _fields_annotations = _fields_type_annotations = NULL;
- }
-
- class AnnotationCollector {
- public:
- enum Location { _in_field, _in_method, _in_class };
- enum ID {
- _unknown = 0,
- _method_CallerSensitive,
- _method_ForceInline,
- _method_DontInline,
- _method_InjectedProfile,
- _method_LambdaForm_Compiled,
- _method_LambdaForm_Hidden,
- _method_HotSpotIntrinsicCandidate,
- _jdk_internal_vm_annotation_Contended,
- _field_Stable,
- _annotation_LIMIT
- };
- const Location _location;
- int _annotations_present;
- u2 _contended_group;
-
- AnnotationCollector(Location location)
- : _location(location), _annotations_present(0)
- {
- assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
- }
- // If this annotation name has an ID, report it (or _none).
- ID annotation_index(ClassLoaderData* loader_data, Symbol* name);
- // Set the annotation name:
- void set_annotation(ID id) {
- assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
- _annotations_present |= nth_bit((int)id);
- }
-
- void remove_annotation(ID id) {
- assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
- _annotations_present &= ~nth_bit((int)id);
- }
-
- // Report if the annotation is present.
- bool has_any_annotations() const { return _annotations_present != 0; }
- bool has_annotation(ID id) const { return (nth_bit((int)id) & _annotations_present) != 0; }
-
- void set_contended_group(u2 group) { _contended_group = group; }
- u2 contended_group() const { return _contended_group; }
-
- bool is_contended() const { return has_annotation(_jdk_internal_vm_annotation_Contended); }
-
- void set_stable(bool stable) { set_annotation(_field_Stable); }
- bool is_stable() const { return has_annotation(_field_Stable); }
- };
-
- // This class also doubles as a holder for metadata cleanup.
- class FieldAnnotationCollector: public AnnotationCollector {
- ClassLoaderData* _loader_data;
- AnnotationArray* _field_annotations;
- AnnotationArray* _field_type_annotations;
- public:
- FieldAnnotationCollector(ClassLoaderData* loader_data) :
- AnnotationCollector(_in_field),
- _loader_data(loader_data),
- _field_annotations(NULL),
- _field_type_annotations(NULL) {}
- void apply_to(FieldInfo* f);
- ~FieldAnnotationCollector();
- AnnotationArray* field_annotations() { return _field_annotations; }
- AnnotationArray* field_type_annotations() { return _field_type_annotations; }
-
- void set_field_annotations(AnnotationArray* a) { _field_annotations = a; }
- void set_field_type_annotations(AnnotationArray* a) { _field_type_annotations = a; }
- };
-
- class MethodAnnotationCollector: public AnnotationCollector {
- public:
- MethodAnnotationCollector() : AnnotationCollector(_in_method) { }
- void apply_to(methodHandle m);
- };
- class ClassAnnotationCollector: public AnnotationCollector {
- public:
- ClassAnnotationCollector() : AnnotationCollector(_in_class) { }
- void apply_to(instanceKlassHandle k);
- };
-
- enum { fixed_buffer_size = 128 };
- u_char linenumbertable_buffer[fixed_buffer_size];
-
- ClassFileStream* _stream; // Actual input stream
-
- enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names
-
- // Accessors
- ClassFileStream* stream() { return _stream; }
- void set_stream(ClassFileStream* st) { _stream = st; }
+ void apply_parsed_class_attributes(InstanceKlass* k); // update k
+ void apply_parsed_class_metadata(InstanceKlass* k, int fields_count, TRAPS);
+ void clear_class_metadata();
// Constant pool parsing
- void parse_constant_pool_entries(int length, TRAPS);
+ void parse_constant_pool_entries(const ClassFileStream* const stream,
+ ConstantPool* cp,
+ const int length,
+ TRAPS);
- constantPoolHandle parse_constant_pool(TRAPS);
+ void parse_constant_pool(const ClassFileStream* const cfs,
+ ConstantPool* const cp,
+ const int length,
+ TRAPS);
// Interface parsing
- Array<Klass*>* parse_interfaces(int length,
- Handle protection_domain,
- Symbol* class_name,
- bool* has_default_methods,
- TRAPS);
- void record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS);
+ void parse_interfaces(const ClassFileStream* const stream,
+ const int itfs_len,
+ ConstantPool* const cp,
+ bool* has_default_methods,
+ TRAPS);
- instanceKlassHandle parse_super_class(int super_class_index, TRAPS);
+ const InstanceKlass* parse_super_class(ConstantPool* const cp,
+ const int super_class_index,
+ const bool need_verify,
+ TRAPS);
+
// Field parsing
- void parse_field_attributes(u2 attributes_count,
- bool is_static, u2 signature_index,
- u2* constantvalue_index_addr,
- bool* is_synthetic_addr,
- u2* generic_signature_index_addr,
+ void parse_field_attributes(const ClassFileStream* const cfs,
+ u2 attributes_count,
+ bool is_static,
+ u2 signature_index,
+ u2* const constantvalue_index_addr,
+ bool* const is_synthetic_addr,
+ u2* const generic_signature_index_addr,
FieldAnnotationCollector* parsed_annotations,
TRAPS);
- Array<u2>* parse_fields(Symbol* class_name,
- bool is_interface,
- FieldAllocationCount *fac,
- u2* java_fields_count_ptr, TRAPS);
- void print_field_layout(Symbol* name,
- Array<u2>* fields,
- const constantPoolHandle& cp,
- int instance_size,
- int instance_fields_start,
- int instance_fields_end,
- int static_fields_end);
+ void parse_fields(const ClassFileStream* const cfs,
+ bool is_interface,
+ FieldAllocationCount* const fac,
+ ConstantPool* cp,
+ const int cp_size,
+ u2* const java_fields_count_ptr,
+ TRAPS);
// Method parsing
- methodHandle parse_method(bool is_interface,
- AccessFlags* promoted_flags,
- TRAPS);
- Array<Method*>* parse_methods(bool is_interface,
- AccessFlags* promoted_flags,
- bool* has_final_method,
- bool* declares_default_methods,
- TRAPS);
- intArray* sort_methods(Array<Method*>* methods);
+ Method* parse_method(const ClassFileStream* const cfs,
+ bool is_interface,
+ const ConstantPool* cp,
+ AccessFlags* const promoted_flags,
+ TRAPS);
+
+ void parse_methods(const ClassFileStream* const cfs,
+ bool is_interface,
+ AccessFlags* const promoted_flags,
+ bool* const has_final_method,
+ bool* const declares_default_methods,
+ TRAPS);
+
+ const u2* parse_exception_table(const ClassFileStream* const stream,
+ u4 code_length,
+ u4 exception_table_length,
+ TRAPS);
- u2* parse_exception_table(u4 code_length, u4 exception_table_length,
- TRAPS);
- void parse_linenumber_table(
- u4 code_attribute_length, u4 code_length,
- CompressedLineNumberWriteStream** write_stream, TRAPS);
- u2* parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length,
- u2* localvariable_table_length,
- bool isLVTT, TRAPS);
- u2* parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length,
- TRAPS);
- void parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index,
- u1* u1_array, u2* u2_array, TRAPS);
- u1* parse_stackmap_table(u4 code_attribute_length, TRAPS);
+ void parse_linenumber_table(u4 code_attribute_length,
+ u4 code_length,
+ CompressedLineNumberWriteStream**const write_stream,
+ TRAPS);
+
+ const u2* parse_localvariable_table(const ClassFileStream* const cfs,
+ u4 code_length,
+ u2 max_locals,
+ u4 code_attribute_length,
+ u2* const localvariable_table_length,
+ bool isLVTT,
+ TRAPS);
+
+ const u2* parse_checked_exceptions(const ClassFileStream* const cfs,
+ u2* const checked_exceptions_length,
+ u4 method_attribute_length,
+ TRAPS);
+
+ void parse_type_array(u2 array_length,
+ u4 code_length,
+ u4* const u1_index,
+ u4* const u2_index,
+ u1* const u1_array,
+ u2* const u2_array,
+ TRAPS);
// Classfile attribute parsing
- u2 parse_generic_signature_attribute(TRAPS);
- void parse_classfile_sourcefile_attribute(TRAPS);
- void parse_classfile_source_debug_extension_attribute(int length, TRAPS);
- u2 parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start,
+ u2 parse_generic_signature_attribute(const ClassFileStream* const cfs, TRAPS);
+ void parse_classfile_sourcefile_attribute(const ClassFileStream* const cfs, TRAPS);
+ void parse_classfile_source_debug_extension_attribute(const ClassFileStream* const cfs,
+ int length,
+ TRAPS);
+
+ u2 parse_classfile_inner_classes_attribute(const ClassFileStream* const cfs,
+ const u1* const inner_classes_attribute_start,
bool parsed_enclosingmethod_attribute,
u2 enclosing_method_class_index,
u2 enclosing_method_method_index,
TRAPS);
- void parse_classfile_attributes(ClassAnnotationCollector* parsed_annotations,
+
+ void parse_classfile_attributes(const ClassFileStream* const cfs,
+ ConstantPool* cp,
+ ClassAnnotationCollector* parsed_annotations,
TRAPS);
+
void parse_classfile_synthetic_attribute(TRAPS);
- void parse_classfile_signature_attribute(TRAPS);
- void parse_classfile_bootstrap_methods_attribute(u4 attribute_length, TRAPS);
+ void parse_classfile_signature_attribute(const ClassFileStream* const cfs, TRAPS);
+ void parse_classfile_bootstrap_methods_attribute(const ClassFileStream* const cfs,
+ ConstantPool* cp,
+ u4 attribute_length,
+ TRAPS);
// Annotations handling
- AnnotationArray* assemble_annotations(u1* runtime_visible_annotations,
+ AnnotationArray* assemble_annotations(const u1* const runtime_visible_annotations,
int runtime_visible_annotations_length,
- u1* runtime_invisible_annotations,
- int runtime_invisible_annotations_length, TRAPS);
- int skip_annotation(u1* buffer, int limit, int index);
- int skip_annotation_value(u1* buffer, int limit, int index);
- void parse_annotations(u1* buffer, int limit,
- /* Results (currently, only one result is supported): */
- AnnotationCollector* result);
+ const u1* const runtime_invisible_annotations,
+ int runtime_invisible_annotations_length,
+ TRAPS);
- // Final setup
- unsigned int compute_oop_map_count(instanceKlassHandle super,
- unsigned int nonstatic_oop_count,
- int first_nonstatic_oop_offset);
- void fill_oop_maps(instanceKlassHandle k,
- unsigned int nonstatic_oop_map_count,
- int* nonstatic_oop_offsets,
- unsigned int* nonstatic_oop_counts);
- void set_precomputed_flags(instanceKlassHandle k);
- Array<Klass*>* compute_transitive_interfaces(instanceKlassHandle super,
- Array<Klass*>* local_ifs, TRAPS);
+ void set_precomputed_flags(InstanceKlass* k);
// Format checker methods
- void classfile_parse_error(const char* msg, TRAPS);
- void classfile_parse_error(const char* msg, int index, TRAPS);
- void classfile_parse_error(const char* msg, const char *name, TRAPS);
- void classfile_parse_error(const char* msg, int index, const char *name, TRAPS);
- inline void guarantee_property(bool b, const char* msg, TRAPS) {
+ void classfile_parse_error(const char* msg, TRAPS) const;
+ void classfile_parse_error(const char* msg, int index, TRAPS) const;
+ void classfile_parse_error(const char* msg, const char *name, TRAPS) const;
+ void classfile_parse_error(const char* msg,
+ int index,
+ const char *name,
+ TRAPS) const;
+
+ inline void guarantee_property(bool b, const char* msg, TRAPS) const {
if (!b) { classfile_parse_error(msg, CHECK); }
}
- void report_assert_property_failure(const char* msg, TRAPS) PRODUCT_RETURN;
- void report_assert_property_failure(const char* msg, int index, TRAPS) PRODUCT_RETURN;
+ void report_assert_property_failure(const char* msg, TRAPS) const PRODUCT_RETURN;
+ void report_assert_property_failure(const char* msg, int index, TRAPS) const PRODUCT_RETURN;
- inline void assert_property(bool b, const char* msg, TRAPS) {
+ inline void assert_property(bool b, const char* msg, TRAPS) const {
#ifdef ASSERT
if (!b) {
report_assert_property_failure(msg, THREAD);
@@ -330,7 +314,7 @@
#endif
}
- inline void assert_property(bool b, const char* msg, int index, TRAPS) {
+ inline void assert_property(bool b, const char* msg, int index, TRAPS) const {
#ifdef ASSERT
if (!b) {
report_assert_property_failure(msg, index, THREAD);
@@ -338,7 +322,10 @@
#endif
}
- inline void check_property(bool property, const char* msg, int index, TRAPS) {
+ inline void check_property(bool property,
+ const char* msg,
+ int index,
+ TRAPS) const {
if (_need_verify) {
guarantee_property(property, msg, index, CHECK);
} else {
@@ -346,7 +333,7 @@
}
}
- inline void check_property(bool property, const char* msg, TRAPS) {
+ inline void check_property(bool property, const char* msg, TRAPS) const {
if (_need_verify) {
guarantee_property(property, msg, CHECK);
} else {
@@ -354,136 +341,177 @@
}
}
- inline void guarantee_property(bool b, const char* msg, int index, TRAPS) {
+ inline void guarantee_property(bool b,
+ const char* msg,
+ int index,
+ TRAPS) const {
if (!b) { classfile_parse_error(msg, index, CHECK); }
}
- inline void guarantee_property(bool b, const char* msg, const char *name, TRAPS) {
+
+ inline void guarantee_property(bool b,
+ const char* msg,
+ const char *name,
+ TRAPS) const {
if (!b) { classfile_parse_error(msg, name, CHECK); }
}
- inline void guarantee_property(bool b, const char* msg, int index, const char *name, TRAPS) {
+
+ inline void guarantee_property(bool b,
+ const char* msg,
+ int index,
+ const char *name,
+ TRAPS) const {
if (!b) { classfile_parse_error(msg, index, name, CHECK); }
}
- void throwIllegalSignature(
- const char* type, Symbol* name, Symbol* sig, TRAPS);
+ void throwIllegalSignature(const char* type,
+ const Symbol* name,
+ const Symbol* sig,
+ TRAPS) const;
- bool is_supported_version(u2 major, u2 minor);
- bool has_illegal_visibility(jint flags);
+ void verify_constantvalue(const ConstantPool* const cp,
+ int constantvalue_index,
+ int signature_index,
+ TRAPS) const;
+
+ void verify_legal_utf8(const unsigned char* buffer, int length, TRAPS) const;
+ void verify_legal_class_name(const Symbol* name, TRAPS) const;
+ void verify_legal_field_name(const Symbol* name, TRAPS) const;
+ void verify_legal_method_name(const Symbol* name, TRAPS) const;
- void verify_constantvalue(int constantvalue_index, int signature_index, TRAPS);
- void verify_legal_utf8(const unsigned char* buffer, int length, TRAPS);
- void verify_legal_class_name(Symbol* name, TRAPS);
- void verify_legal_field_name(Symbol* name, TRAPS);
- void verify_legal_method_name(Symbol* name, TRAPS);
- void verify_legal_field_signature(Symbol* fieldname, Symbol* signature, TRAPS);
- int verify_legal_method_signature(Symbol* methodname, Symbol* signature, TRAPS);
- void verify_legal_class_modifiers(jint flags, TRAPS);
- void verify_legal_field_modifiers(jint flags, bool is_interface, TRAPS);
- void verify_legal_method_modifiers(jint flags, bool is_interface, Symbol* name, TRAPS);
- bool verify_unqualified_name(char* name, unsigned int length, int type);
- char* skip_over_field_name(char* name, bool slash_ok, unsigned int length);
- char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS);
+ void verify_legal_field_signature(const Symbol* fieldname,
+ const Symbol* signature,
+ TRAPS) const;
+ int verify_legal_method_signature(const Symbol* methodname,
+ const Symbol* signature,
+ TRAPS) const;
- bool is_anonymous() {
- return _host_klass.not_null();
- }
- bool has_cp_patch_at(int index) {
+ void verify_legal_class_modifiers(jint flags, TRAPS) const;
+ void verify_legal_field_modifiers(jint flags, bool is_interface, TRAPS) const;
+ void verify_legal_method_modifiers(jint flags,
+ bool is_interface,
+ const Symbol* name,
+ TRAPS) const;
+
+ const char* skip_over_field_signature(const char* signature,
+ bool void_ok,
+ unsigned int length,
+ TRAPS) const;
+
+ bool has_cp_patch_at(int index) const {
assert(index >= 0, "oob");
return (_cp_patches != NULL
&& index < _cp_patches->length()
&& _cp_patches->adr_at(index)->not_null());
}
- Handle cp_patch_at(int index) {
+
+ Handle cp_patch_at(int index) const {
assert(has_cp_patch_at(index), "oob");
return _cp_patches->at(index);
}
+
Handle clear_cp_patch_at(int index) {
Handle patch = cp_patch_at(index);
_cp_patches->at_put(index, Handle());
assert(!has_cp_patch_at(index), "");
return patch;
}
- void patch_constant_pool(const constantPoolHandle& cp, int index, Handle patch, TRAPS);
+
+ void patch_constant_pool(ConstantPool* cp,
+ int index,
+ Handle patch,
+ TRAPS);
// Wrapper for constantTag.is_klass_[or_]reference.
// In older versions of the VM, Klass*s cannot sneak into early phases of
// constant pool construction, but in later versions they can.
// %%% Let's phase out the old is_klass_reference.
- bool valid_klass_reference_at(int index) {
- return _cp->is_within_bounds(index) && _cp->tag_at(index).is_klass_or_reference();
+ bool valid_klass_reference_at(int index) const {
+ return _cp->is_within_bounds(index) &&
+ _cp->tag_at(index).is_klass_or_reference();
}
// Checks that the cpool index is in range and is a utf8
- bool valid_symbol_at(int cpool_index) {
- return (_cp->is_within_bounds(cpool_index) &&
- _cp->tag_at(cpool_index).is_utf8());
+ bool valid_symbol_at(int cpool_index) const {
+ return _cp->is_within_bounds(cpool_index) &&
+ _cp->tag_at(cpool_index).is_utf8();
}
- void copy_localvariable_table(ConstMethod* cm, int lvt_cnt,
- u2* localvariable_table_length,
- u2** localvariable_table_start,
+ void copy_localvariable_table(const ConstMethod* cm,
+ int lvt_cnt,
+ u2* const localvariable_table_length,
+ const u2**const localvariable_table_start,
int lvtt_cnt,
- u2* localvariable_type_table_length,
- u2** localvariable_type_table_start,
+ u2* const localvariable_type_table_length,
+ const u2** const localvariable_type_table_start,
TRAPS);
void copy_method_annotations(ConstMethod* cm,
- u1* runtime_visible_annotations,
+ const u1* runtime_visible_annotations,
int runtime_visible_annotations_length,
- u1* runtime_invisible_annotations,
+ const u1* runtime_invisible_annotations,
int runtime_invisible_annotations_length,
- u1* runtime_visible_parameter_annotations,
+ const u1* runtime_visible_parameter_annotations,
int runtime_visible_parameter_annotations_length,
- u1* runtime_invisible_parameter_annotations,
+ const u1* runtime_invisible_parameter_annotations,
int runtime_invisible_parameter_annotations_length,
- u1* runtime_visible_type_annotations,
+ const u1* runtime_visible_type_annotations,
int runtime_visible_type_annotations_length,
- u1* runtime_invisible_type_annotations,
+ const u1* runtime_invisible_type_annotations,
int runtime_invisible_type_annotations_length,
- u1* annotation_default,
+ const u1* annotation_default,
int annotation_default_length,
TRAPS);
// lays out fields in class and returns the total oopmap count
- void layout_fields(Handle class_loader, FieldAllocationCount* fac,
- ClassAnnotationCollector* parsed_annotations,
- FieldLayoutInfo* info, TRAPS);
+ void layout_fields(ConstantPool* cp,
+ const FieldAllocationCount* fac,
+ const ClassAnnotationCollector* parsed_annotations,
+ FieldLayoutInfo* info,
+ TRAPS);
public:
- // Constructor
- ClassFileParser(ClassFileStream* st) { set_stream(st); }
+ ClassFileParser(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ TempNewSymbol* parsed_name,
+ const Klass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ Publicity pub_level,
+ TRAPS);
+
~ClassFileParser();
- // Parse .class file and return new Klass*. The Klass* is not hooked up
- // to the system dictionary or any other structures, so a .class file can
- // be loaded several times if desired.
- // The system dictionary hookup is done by the caller.
- //
- // "parsed_name" is updated by this method, and is the name found
- // while parsing the stream.
- instanceKlassHandle parseClassFile(Symbol* name,
- ClassLoaderData* loader_data,
- Handle protection_domain,
- TempNewSymbol& parsed_name,
- bool verify,
- TRAPS) {
- KlassHandle no_host_klass;
- return parseClassFile(name, loader_data, protection_domain, no_host_klass, NULL, parsed_name, verify, THREAD);
- }
- instanceKlassHandle parseClassFile(Symbol* name,
- ClassLoaderData* loader_data,
- Handle protection_domain,
- KlassHandle host_klass,
- GrowableArray<Handle>* cp_patches,
- TempNewSymbol& parsed_name,
- bool verify,
- TRAPS);
+ InstanceKlass* create_instance_klass(TRAPS);
+
+ const ClassFileStream* clone_stream() const;
+
+ void set_klass_to_deallocate(InstanceKlass* klass);
+
+ int static_field_size() const;
+ int total_oop_map_count() const;
+ jint layout_size() const;
+
+ int vtable_size() const { return _vtable_size; }
+ int itable_size() const { return _itable_size; }
- // Verifier checks
- static void check_super_class_access(instanceKlassHandle this_klass, TRAPS);
- static void check_super_interface_access(instanceKlassHandle this_klass, TRAPS);
- static void check_final_method_override(instanceKlassHandle this_klass, TRAPS);
- static void check_illegal_static_method(instanceKlassHandle this_klass, TRAPS);
+ u2 this_class_index() const { return _this_class_index; }
+ u2 super_class_index() const { return _super_class_index; }
+
+ bool is_anonymous() const { return _host_klass != NULL; }
+ bool is_interface() const { return _access_flags.is_interface(); }
+
+ const Klass* host_klass() const { return _host_klass; }
+ const GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
+ ClassLoaderData* loader_data() const { return _loader_data; }
+ const Symbol* class_name() const { return _class_name; }
+ const Klass* super_klass() const { return _super_klass; }
+
+ ReferenceType reference_type() const { return _rt; }
+ AccessFlags access_flags() const { return _access_flags; }
+
+ bool is_internal() const { return INTERNAL == _pub_level; }
+
};
#endif // SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
--- a/hotspot/src/share/vm/classfile/classFileStream.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/classFileStream.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -26,19 +26,51 @@
#include "classfile/classFileStream.hpp"
#include "classfile/vmSymbols.hpp"
-void ClassFileStream::truncated_file_error(TRAPS) {
+const bool ClassFileStream::verify = true;
+const bool ClassFileStream::no_verification = false;
+
+void ClassFileStream::truncated_file_error(TRAPS) const {
THROW_MSG(vmSymbols::java_lang_ClassFormatError(), "Truncated class file");
}
-ClassFileStream::ClassFileStream(u1* buffer, int length, const char* source) {
- _buffer_start = buffer;
- _buffer_end = buffer + length;
- _current = buffer;
- _source = source;
- _need_verify = false;
+ClassFileStream::ClassFileStream(const u1* buffer,
+ int length,
+ const char* source,
+ bool verify_stream) :
+ _buffer_start(buffer),
+ _buffer_end(buffer + length),
+ _current(buffer),
+ _source(source),
+ _need_verify(verify_stream) {}
+
+const u1* ClassFileStream::clone_buffer() const {
+ u1* const new_buffer_start = NEW_RESOURCE_ARRAY(u1, length());
+ memcpy(new_buffer_start, _buffer_start, length());
+ return new_buffer_start;
}
-u1 ClassFileStream::get_u1(TRAPS) {
+const char* const ClassFileStream::clone_source() const {
+ const char* const src = source();
+ char* source_copy = NULL;
+ if (src != NULL) {
+ size_t source_len = strlen(src);
+ source_copy = NEW_RESOURCE_ARRAY(char, source_len + 1);
+ strncpy(source_copy, src, source_len + 1);
+ }
+ return source_copy;
+}
+
+// Caller responsible for ResourceMark
+// clone stream with a rewound position
+const ClassFileStream* ClassFileStream::clone() const {
+ const u1* const new_buffer_start = clone_buffer();
+ return new ClassFileStream(new_buffer_start,
+ length(),
+ clone_source(),
+ need_verify());
+}
+
+u1 ClassFileStream::get_u1(TRAPS) const {
if (_need_verify) {
guarantee_more(1, CHECK_0);
} else {
@@ -47,54 +79,54 @@
return *_current++;
}
-u2 ClassFileStream::get_u2(TRAPS) {
+u2 ClassFileStream::get_u2(TRAPS) const {
if (_need_verify) {
guarantee_more(2, CHECK_0);
} else {
assert(2 <= _buffer_end - _current, "buffer overflow");
}
- u1* tmp = _current;
+ const u1* tmp = _current;
_current += 2;
- return Bytes::get_Java_u2(tmp);
+ return Bytes::get_Java_u2((address)tmp);
}
-u4 ClassFileStream::get_u4(TRAPS) {
+u4 ClassFileStream::get_u4(TRAPS) const {
if (_need_verify) {
guarantee_more(4, CHECK_0);
} else {
assert(4 <= _buffer_end - _current, "buffer overflow");
}
- u1* tmp = _current;
+ const u1* tmp = _current;
_current += 4;
- return Bytes::get_Java_u4(tmp);
+ return Bytes::get_Java_u4((address)tmp);
}
-u8 ClassFileStream::get_u8(TRAPS) {
+u8 ClassFileStream::get_u8(TRAPS) const {
if (_need_verify) {
guarantee_more(8, CHECK_0);
} else {
assert(8 <= _buffer_end - _current, "buffer overflow");
}
- u1* tmp = _current;
+ const u1* tmp = _current;
_current += 8;
- return Bytes::get_Java_u8(tmp);
+ return Bytes::get_Java_u8((address)tmp);
}
-void ClassFileStream::skip_u1(int length, TRAPS) {
+void ClassFileStream::skip_u1(int length, TRAPS) const {
if (_need_verify) {
guarantee_more(length, CHECK);
}
_current += length;
}
-void ClassFileStream::skip_u2(int length, TRAPS) {
+void ClassFileStream::skip_u2(int length, TRAPS) const {
if (_need_verify) {
guarantee_more(length * 2, CHECK);
}
_current += length * 2;
}
-void ClassFileStream::skip_u4(int length, TRAPS) {
+void ClassFileStream::skip_u4(int length, TRAPS) const {
if (_need_verify) {
guarantee_more(length * 4, CHECK);
}
--- a/hotspot/src/share/vm/classfile/classFileStream.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/classFileStream.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -34,65 +34,88 @@
// The caller is responsible for deallocating the buffer and for using
// ResourceMarks appropriately when constructing streams.
+class ClassPathEntry;
+
class ClassFileStream: public ResourceObj {
private:
- u1* _buffer_start; // Buffer bottom
- u1* _buffer_end; // Buffer top (one past last element)
- u1* _current; // Current buffer position
- const char* _source; // Source of stream (directory name, ZIP/JAR archive name)
- bool _need_verify; // True if verification is on for the class file
+ const u1* const _buffer_start; // Buffer bottom
+ const u1* const _buffer_end; // Buffer top (one past last element)
+ mutable const u1* _current; // Current buffer position
+ const char* const _source; // Source of stream (directory name, ZIP/JAR archive name)
+ bool _need_verify; // True if verification is on for the class file
+
+ void truncated_file_error(TRAPS) const ;
- void truncated_file_error(TRAPS);
+ protected:
+ const u1* clone_buffer() const;
+ const char* const clone_source() const;
+
public:
- // Constructor
- ClassFileStream(u1* buffer, int length, const char* source);
+ static const bool no_verification;
+ static const bool verify;
+
+ ClassFileStream(const u1* buffer,
+ int length,
+ const char* source,
+ bool verify_stream = verify); // to be verified by default
+
+ virtual const ClassFileStream* clone() const;
// Buffer access
- u1* buffer() const { return _buffer_start; }
- int length() const { return _buffer_end - _buffer_start; }
- u1* current() const { return _current; }
- void set_current(u1* pos) { _current = pos; }
- const char* source() const { return _source; }
- void set_verify(bool flag) { _need_verify = flag; }
+ const u1* buffer() const { return _buffer_start; }
+ int length() const { return _buffer_end - _buffer_start; }
+ const u1* current() const { return _current; }
+ void set_current(const u1* pos) const {
+ assert(pos >= _buffer_start && pos <= _buffer_end, "invariant");
+ _current = pos;
+ }
- void check_truncated_file(bool b, TRAPS) {
+ // for relative positioning
+ juint current_offset() const {
+ return (juint)(_current - _buffer_start);
+ }
+ const char* source() const { return _source; }
+ bool need_verify() const { return _need_verify; }
+ void set_verify(bool flag) { _need_verify = flag; }
+
+ void check_truncated_file(bool b, TRAPS) const {
if (b) {
truncated_file_error(THREAD);
}
}
- void guarantee_more(int size, TRAPS) {
+ void guarantee_more(int size, TRAPS) const {
size_t remaining = (size_t)(_buffer_end - _current);
unsigned int usize = (unsigned int)size;
check_truncated_file(usize > remaining, CHECK);
}
// Read u1 from stream
- u1 get_u1(TRAPS);
- u1 get_u1_fast() {
+ u1 get_u1(TRAPS) const;
+ u1 get_u1_fast() const {
return *_current++;
}
// Read u2 from stream
- u2 get_u2(TRAPS);
- u2 get_u2_fast() {
- u2 res = Bytes::get_Java_u2(_current);
+ u2 get_u2(TRAPS) const;
+ u2 get_u2_fast() const {
+ u2 res = Bytes::get_Java_u2((address)_current);
_current += 2;
return res;
}
// Read u4 from stream
- u4 get_u4(TRAPS);
- u4 get_u4_fast() {
- u4 res = Bytes::get_Java_u4(_current);
+ u4 get_u4(TRAPS) const;
+ u4 get_u4_fast() const {
+ u4 res = Bytes::get_Java_u4((address)_current);
_current += 4;
return res;
}
// Read u8 from stream
- u8 get_u8(TRAPS);
- u8 get_u8_fast() {
- u8 res = Bytes::get_Java_u8(_current);
+ u8 get_u8(TRAPS) const;
+ u8 get_u8_fast() const {
+ u8 res = Bytes::get_Java_u8((address)_current);
_current += 8;
return res;
}
@@ -100,32 +123,32 @@
// Get direct pointer into stream at current position.
// Returns NULL if length elements are not remaining. The caller is
// responsible for calling skip below if buffer contents is used.
- u1* get_u1_buffer() {
+ const u1* get_u1_buffer() const {
return _current;
}
- u2* get_u2_buffer() {
- return (u2*) _current;
+ const u2* get_u2_buffer() const {
+ return (const u2*) _current;
}
// Skip length u1 or u2 elements from stream
- void skip_u1(int length, TRAPS);
- void skip_u1_fast(int length) {
+ void skip_u1(int length, TRAPS) const;
+ void skip_u1_fast(int length) const {
_current += length;
}
- void skip_u2(int length, TRAPS);
- void skip_u2_fast(int length) {
+ void skip_u2(int length, TRAPS) const;
+ void skip_u2_fast(int length) const {
_current += 2 * length;
}
- void skip_u4(int length, TRAPS);
- void skip_u4_fast(int length) {
+ void skip_u4(int length, TRAPS) const;
+ void skip_u4_fast(int length) const {
_current += 4 * length;
}
// Tells whether eos is reached
- bool at_eos() const { return _current == _buffer_end; }
+ bool at_eos() const { return _current == _buffer_end; }
};
#endif // SHARE_VM_CLASSFILE_CLASSFILESTREAM_HPP
--- a/hotspot/src/share/vm/classfile/classLoader.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -23,13 +23,13 @@
*/
#include "precompiled.hpp"
-#include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderExt.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/jimage.hpp"
+#include "classfile/klassFactory.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "compiler/compileBroker.hpp"
@@ -170,17 +170,13 @@
}
-ClassPathEntry::ClassPathEntry() {
- set_next(NULL);
-}
-
-
ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() {
char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass);
strcpy(copy, dir);
_dir = copy;
}
+
ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
// construct full path name
char path[JVM_MAXPATHLEN];
@@ -211,14 +207,17 @@
if (UsePerfData) {
ClassLoader::perf_sys_classfile_bytes_read()->inc(num_read);
}
- return new ClassFileStream(buffer, st.st_size, _dir); // Resource allocated
+ // Resource allocated
+ return new ClassFileStream(buffer,
+ st.st_size,
+ _dir,
+ ClassFileStream::verify);
}
}
}
return NULL;
}
-
ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassPathEntry() {
_zip = zip;
char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass);
@@ -269,14 +268,18 @@
ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) {
jint filesize;
- u1* buffer = open_entry(name, &filesize, false, CHECK_NULL);
+ const u1* buffer = open_entry(name, &filesize, false, CHECK_NULL);
if (buffer == NULL) {
return NULL;
}
if (UsePerfData) {
ClassLoader::perf_sys_classfile_bytes_read()->inc(filesize);
}
- return new ClassFileStream(buffer, filesize, _zip_name); // Resource allocated
+ // Resource allocated
+ return new ClassFileStream(buffer,
+ filesize,
+ _zip_name,
+ ClassFileStream::verify);
}
// invoke function for each entry in the zip file
@@ -366,7 +369,11 @@
}
char* data = NEW_RESOURCE_ARRAY(char, size);
(*JImageGetResource)(_jimage, location, data, size);
- return new ClassFileStream((u1*)data, (int)size, _name); // Resource allocated
+ // Resource allocated
+ return new ClassFileStream((u1*)data,
+ (int)size,
+ _name,
+ ClassFileStream::verify);
}
return NULL;
@@ -996,74 +1003,94 @@
return result();
}
+// caller needs ResourceMark
+const char* ClassLoader::file_name_for_class_name(const char* class_name,
+ int class_name_len) {
+ assert(class_name != NULL, "invariant");
+ assert((int)strlen(class_name) == class_name_len, "invariant");
-instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
- ResourceMark rm(THREAD);
- const char* class_name = h_name->as_C_string();
+ static const char class_suffix[] = ".class";
+
+ char* const file_name = NEW_RESOURCE_ARRAY(char,
+ class_name_len +
+ sizeof(class_suffix)); // includes term NULL
+
+ strncpy(file_name, class_name, class_name_len);
+ strncpy(&file_name[class_name_len], class_suffix, sizeof(class_suffix));
+
+ return file_name;
+}
+
+instanceKlassHandle ClassLoader::load_class(Symbol* name, TRAPS) {
+
+ assert(name != NULL, "invariant");
+ assert(THREAD->is_Java_thread(), "must be a JavaThread");
+
+ ResourceMark rm;
+ HandleMark hm;
+
+ const char* const class_name = name->as_C_string();
+
EventMark m("loading class %s", class_name);
ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);
- stringStream st;
- // st.print() uses too much stack space while handling a StackOverflowError
- // st.print("%s.class", h_name->as_utf8());
- st.print_raw(h_name->as_utf8());
- st.print_raw(".class");
- const char* file_name = st.as_string();
+ const char* const file_name = file_name_for_class_name(class_name,
+ name->utf8_length());
+ assert(file_name != NULL, "invariant");
+
ClassLoaderExt::Context context(class_name, file_name, THREAD);
- // Lookup stream for parsing .class file
+ // Lookup stream
ClassFileStream* stream = NULL;
int classpath_index = 0;
- ClassPathEntry* e = NULL;
- instanceKlassHandle h;
+ ClassPathEntry* e = _first_entry;
{
PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),
- ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(),
- PerfClassTraceTime::CLASS_LOAD);
- e = _first_entry;
- while (e != NULL) {
+ ((JavaThread*)THREAD)->get_thread_stat()->perf_timers_addr(),
+ PerfClassTraceTime::CLASS_LOAD);
+
+ for (; e != NULL; e = e->next(), ++classpath_index) {
stream = e->open_stream(file_name, CHECK_NULL);
+ if (NULL == stream) {
+ continue;
+ }
if (!context.check(stream, classpath_index)) {
- return h; // NULL
+ return NULL;
}
- if (stream != NULL) {
- break;
- }
- e = e->next();
- ++classpath_index;
+ break;
}
}
- if (stream != NULL) {
- // class file found, parse it
- ClassFileParser parser(stream);
- ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
- Handle protection_domain;
- TempNewSymbol parsed_name = NULL;
- instanceKlassHandle result = parser.parseClassFile(h_name,
- loader_data,
- protection_domain,
- parsed_name,
- context.should_verify(classpath_index),
- THREAD);
- if (HAS_PENDING_EXCEPTION) {
- ResourceMark rm;
- if (DumpSharedSpaces) {
- tty->print_cr("Preload Error: Failed to load %s", class_name);
- }
- return h;
- }
- h = context.record_result(classpath_index, e, result, THREAD);
- } else {
+ if (NULL == stream) {
if (DumpSharedSpaces) {
tty->print_cr("Preload Warning: Cannot find %s", class_name);
}
+ return NULL;
}
- return h;
+ stream->set_verify(context.should_verify(classpath_index));
+
+ ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
+ Handle protection_domain;
+
+ instanceKlassHandle result = KlassFactory::create_from_stream(stream,
+ name,
+ loader_data,
+ protection_domain,
+ NULL, // host_klass
+ NULL, // cp_patches
+ NULL, // parsed_name
+ THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ if (DumpSharedSpaces) {
+ tty->print_cr("Preload Error: Failed to load %s", class_name);
+ }
+ return NULL;
+ }
+
+ return context.record_result(classpath_index, e, result, THREAD);
}
-
void ClassLoader::create_package_info_table(HashtableBucket<mtClass> *t, int length,
int number_of_entries) {
assert(_package_hash_table == NULL, "One package info table allowed.");
--- a/hotspot/src/share/vm/classfile/classLoader.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/classLoader.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -25,8 +25,9 @@
#ifndef SHARE_VM_CLASSFILE_CLASSLOADER_HPP
#define SHARE_VM_CLASSFILE_CLASSLOADER_HPP
-#include "classfile/classFileParser.hpp"
+#include "runtime/orderAccess.hpp"
#include "runtime/perfData.hpp"
+#include "utilities/exceptions.hpp"
#include "utilities/macros.hpp"
// The VM class loader.
@@ -35,41 +36,39 @@
// Name of boot module image
#define BOOT_IMAGE_NAME "bootmodules.jimage"
-// Class path entry (directory or zip file)
-
class JImageFile;
+class ClassFileStream;
-class ClassPathEntry: public CHeapObj<mtClass> {
- private:
+class ClassPathEntry : public CHeapObj<mtClass> {
+private:
ClassPathEntry* _next;
- public:
+public:
// Next entry in class path
- ClassPathEntry* next() { return _next; }
+ ClassPathEntry* next() const { return _next; }
void set_next(ClassPathEntry* next) {
// may have unlocked readers, so write atomically.
OrderAccess::release_store_ptr(&_next, next);
}
- virtual bool is_jar_file() = 0;
- virtual const char* name() = 0;
- virtual JImageFile* jimage() = 0;
+ virtual bool is_jar_file() const = 0;
+ virtual const char* name() const = 0;
+ virtual JImageFile* jimage() const = 0;
// Constructor
- ClassPathEntry();
+ ClassPathEntry() : _next(NULL) {}
// Attempt to locate file_name through this class path entry.
// Returns a class file parsing stream if successfull.
virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0;
// Debugging
NOT_PRODUCT(virtual void compile_the_world(Handle loader, TRAPS) = 0;)
- NOT_PRODUCT(virtual bool is_jrt() = 0;)
+ NOT_PRODUCT(virtual bool is_jrt() = 0;)
};
-
class ClassPathDirEntry: public ClassPathEntry {
private:
const char* _dir; // Name of directory
public:
- bool is_jar_file() { return false; }
- const char* name() { return _dir; }
- JImageFile* jimage() { return NULL; }
+ bool is_jar_file() const { return false; }
+ const char* name() const { return _dir; }
+ JImageFile* jimage() const { return NULL; }
ClassPathDirEntry(const char* dir);
ClassFileStream* open_stream(const char* name, TRAPS);
// Debugging
@@ -97,9 +96,9 @@
jzfile* _zip; // The zip archive
const char* _zip_name; // Name of zip archive
public:
- bool is_jar_file() { return true; }
- const char* name() { return _zip_name; }
- JImageFile* jimage() { return NULL; }
+ bool is_jar_file() const { return true; }
+ const char* name() const { return _zip_name; }
+ JImageFile* jimage() const { return NULL; }
ClassPathZipEntry(jzfile* zip, const char* zip_name);
~ClassPathZipEntry();
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
@@ -117,10 +116,10 @@
JImageFile* _jimage;
const char* _name;
public:
- bool is_jar_file() { return false; }
- bool is_open() { return _jimage != NULL; }
- const char* name() { return _name == NULL ? "" : _name; }
- JImageFile* jimage() { return _jimage; }
+ bool is_jar_file() const { return false; }
+ bool is_open() const { return _jimage != NULL; }
+ const char* name() const { return _name == NULL ? "" : _name; }
+ JImageFile* jimage() const { return _jimage; }
ClassPathImageEntry(JImageFile* jimage, const char* name);
~ClassPathImageEntry();
static void name_to_package(const char* name, char* buffer, int length);
@@ -212,6 +211,10 @@
// Canonicalizes path names, so strcmp will work properly. This is mainly
// to avoid confusing the zip library
static bool get_canonical_path(const char* orig, char* out, int len);
+
+ static const char* file_name_for_class_name(const char* class_name,
+ int class_name_len);
+
public:
static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg);
static int crc32(int crc, const char* buf, int len);
@@ -282,7 +285,7 @@
}
// Load individual .class file
- static instanceKlassHandle load_classfile(Symbol* h_name, TRAPS);
+ static instanceKlassHandle load_class(Symbol* class_name, TRAPS);
// If the specified package has been loaded by the system, then returns
// the name of the directory or ZIP file that the package was loaded from.
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -166,7 +166,9 @@
}
}
-void ClassLoaderData::record_dependency(Klass* k, TRAPS) {
+void ClassLoaderData::record_dependency(const Klass* k, TRAPS) {
+ assert(k != NULL, "invariant");
+
ClassLoaderData * const from_cld = this;
ClassLoaderData * const to_cld = k->class_loader_data();
@@ -273,16 +275,18 @@
}
}
-void ClassLoaderData::add_class(Klass* k) {
- MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
- Klass* old_value = _klasses;
- k->set_next_link(old_value);
- // Make sure linked class is stable, since the class list is walked without a lock
- OrderAccess::storestore();
- // link the new item into the list
- _klasses = k;
+void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) {
+ {
+ MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
+ Klass* old_value = _klasses;
+ k->set_next_link(old_value);
+ // Make sure linked class is stable, since the class list is walked without a lock
+ OrderAccess::storestore();
+ // link the new item into the list
+ _klasses = k;
+ }
- if (TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
+ if (publicize && TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
ResourceMark rm;
tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
PTR_FORMAT " loader: " PTR_FORMAT " %s",
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -275,7 +275,7 @@
// Used to make sure that this CLD is not unloaded.
void set_keep_alive(bool value) { _keep_alive = value; }
- unsigned int identity_hash() {
+ unsigned int identity_hash() const {
return _class_loader == NULL ? 0 : _class_loader->identity_hash();
}
@@ -294,10 +294,10 @@
const char* loader_name();
jobject add_handle(Handle h);
- void add_class(Klass* k);
+ void add_class(Klass* k, bool publicize = true);
void remove_class(Klass* k);
bool contains_klass(Klass* k);
- void record_dependency(Klass* to, TRAPS);
+ void record_dependency(const Klass* to, TRAPS);
void init_dependencies(TRAPS);
void add_to_deallocate_list(Metadata* m);
@@ -312,7 +312,7 @@
Metaspace* rw_metaspace();
void initialize_shared_metaspaces();
- int shared_class_loader_id() {
+ int shared_class_loader_id() const {
return _shared_class_loader_id;
}
void set_shared_class_loader_id(int id) {
--- a/hotspot/src/share/vm/classfile/classLoaderExt.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -41,7 +41,7 @@
_file_name = file_name;
}
- bool check(ClassFileStream* stream, const int classpath_index) {
+ bool check(const ClassFileStream* stream, const int classpath_index) {
return true;
}
@@ -50,7 +50,8 @@
}
instanceKlassHandle record_result(const int classpath_index,
- ClassPathEntry* e, instanceKlassHandle result, TRAPS) {
+ const ClassPathEntry* e,
+ instanceKlassHandle result, TRAPS) {
if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) {
if (DumpSharedSpaces) {
result->set_shared_classpath_index(classpath_index);
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/compactHashtable.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "memory/metaspaceShared.hpp"
#include "prims/jvm.h"
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -27,8 +27,6 @@
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
-#include "memory/allocation.inline.hpp"
-#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "services/diagnosticCommand.hpp"
#include "utilities/hashtable.hpp"
@@ -117,13 +115,8 @@
return _required_bytes;
}
- void add(unsigned int hash, Symbol* symbol) {
- add(hash, new Entry(hash, symbol));
- }
-
- void add(unsigned int hash, oop string) {
- add(hash, new Entry(hash, string));
- }
+ inline void add(unsigned int hash, Symbol* symbol);
+ inline void add(unsigned int hash, oop string);
private:
void add(unsigned int hash, Entry* entry);
@@ -219,27 +212,10 @@
juint* _buckets;
inline Symbol* lookup_entry(CompactHashtable<Symbol*, char>* const t,
- juint* addr, const char* name, int len) {
- Symbol* sym = (Symbol*)((void*)(_base_address + *addr));
- if (sym->equals(name, len)) {
- assert(sym->refcount() == -1, "must be shared");
- return sym;
- }
-
- return NULL;
- }
+ juint* addr, const char* name, int len);
inline oop lookup_entry(CompactHashtable<oop, char>* const t,
- juint* addr, const char* name, int len) {
- narrowOop obj = (narrowOop)(*addr);
- oop string = oopDesc::decode_heap_oop(obj);
- if (java_lang_String::equals(string, (jchar*)name, len)) {
- return string;
- }
-
- return NULL;
- }
-
+ juint* addr, const char* name, int len);
public:
CompactHashtable() {
_entry_count = 0;
@@ -257,41 +233,7 @@
}
// Lookup an entry from the compact table
- inline T lookup(const N* name, unsigned int hash, int len) {
- if (_entry_count > 0) {
- assert(!DumpSharedSpaces, "run-time only");
- int index = hash % _bucket_count;
- juint bucket_info = _buckets[index];
- juint bucket_offset = BUCKET_OFFSET(bucket_info);
- int bucket_type = BUCKET_TYPE(bucket_info);
- juint* bucket = _buckets + bucket_offset;
- juint* bucket_end = _buckets;
-
- if (bucket_type == COMPACT_BUCKET_TYPE) {
- // the compact bucket has one entry with entry offset only
- T res = lookup_entry(this, &bucket[0], name, len);
- if (res != NULL) {
- return res;
- }
- } else {
- // This is a regular bucket, which has more than one
- // entries. Each entry is a pair of entry (hash, offset).
- // Seek until the end of the bucket.
- bucket_end += BUCKET_OFFSET(_buckets[index + 1]);
- while (bucket < bucket_end) {
- unsigned int h = (unsigned int)(bucket[0]);
- if (h == hash) {
- T res = lookup_entry(this, &bucket[1], name, len);
- if (res != NULL) {
- return res;
- }
- }
- bucket += 2;
- }
- }
- }
- return NULL;
- }
+ inline T lookup(const N* name, unsigned int hash, int len);
// iterate over symbols
void symbols_do(SymbolClosure *cl);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/compactHashtable.inline.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,102 @@
+/*
+ * 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_CLASSFILE_COMPACTHASHTABLE_INLINE_HPP
+#define SHARE_VM_CLASSFILE_COMPACTHASHTABLE_INLINE_HPP
+
+#include "classfile/compactHashtable.hpp"
+#include "memory/allocation.inline.hpp"
+#include "oops/oop.inline.hpp"
+
+template <class T, class N>
+inline Symbol* CompactHashtable<T, N>::lookup_entry(CompactHashtable<Symbol*, char>* const t,
+ juint* addr, const char* name, int len) {
+ Symbol* sym = (Symbol*)((void*)(_base_address + *addr));
+ if (sym->equals(name, len)) {
+ assert(sym->refcount() == -1, "must be shared");
+ return sym;
+ }
+
+ return NULL;
+}
+
+template <class T, class N>
+inline oop CompactHashtable<T, N>::lookup_entry(CompactHashtable<oop, char>* const t,
+ juint* addr, const char* name, int len) {
+ narrowOop obj = (narrowOop)(*addr);
+ oop string = oopDesc::decode_heap_oop(obj);
+ if (java_lang_String::equals(string, (jchar*)name, len)) {
+ return string;
+ }
+
+ return NULL;
+}
+
+template <class T, class N>
+inline T CompactHashtable<T,N>::lookup(const N* name, unsigned int hash, int len) {
+ if (_entry_count > 0) {
+ assert(!DumpSharedSpaces, "run-time only");
+ int index = hash % _bucket_count;
+ juint bucket_info = _buckets[index];
+ juint bucket_offset = BUCKET_OFFSET(bucket_info);
+ int bucket_type = BUCKET_TYPE(bucket_info);
+ juint* bucket = _buckets + bucket_offset;
+ juint* bucket_end = _buckets;
+
+ if (bucket_type == COMPACT_BUCKET_TYPE) {
+ // the compact bucket has one entry with entry offset only
+ T res = lookup_entry(this, &bucket[0], name, len);
+ if (res != NULL) {
+ return res;
+ }
+ } else {
+ // This is a regular bucket, which has more than one
+ // entries. Each entry is a pair of entry (hash, offset).
+ // Seek until the end of the bucket.
+ bucket_end += BUCKET_OFFSET(_buckets[index + 1]);
+ while (bucket < bucket_end) {
+ unsigned int h = (unsigned int)(bucket[0]);
+ if (h == hash) {
+ T res = lookup_entry(this, &bucket[1], name, len);
+ if (res != NULL) {
+ return res;
+ }
+ }
+ bucket += 2;
+ }
+ }
+ }
+ return NULL;
+}
+
+inline void CompactHashtableWriter::add(unsigned int hash, Symbol* symbol) {
+ add(hash, new Entry(hash, symbol));
+}
+
+inline void CompactHashtableWriter::add(unsigned int hash, oop string) {
+ add(hash, new Entry(hash, string));
+}
+
+
+#endif // SHARE_VM_CLASSFILE_COMPACTHASHTABLE_INLINE_HPP
--- a/hotspot/src/share/vm/classfile/defaultMethods.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -30,6 +30,7 @@
#include "memory/allocation.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/resourceArea.hpp"
+#include "runtime/handles.inline.hpp"
#include "runtime/signature.hpp"
#include "runtime/thread.hpp"
#include "oops/instanceKlass.hpp"
@@ -606,7 +607,7 @@
}
static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots(
- InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS) {
+ InstanceKlass* klass, const GrowableArray<Method*>* mirandas, TRAPS) {
assert(klass != NULL, "Must be valid class");
@@ -777,7 +778,8 @@
// candidate). These methods are then added to the class's method list.
// The JVM does not create bridges nor handle generic signatures here.
void DefaultMethods::generate_default_methods(
- InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS) {
+ InstanceKlass* klass, const GrowableArray<Method*>* mirandas, TRAPS) {
+ assert(klass != NULL, "invariant");
// This resource mark is the bound for all memory allocation that takes
// place during default method processing. After this goes out of scope,
@@ -787,6 +789,7 @@
ResourceMark rm(THREAD);
// Keep entire hierarchy alive for the duration of the computation
+ constantPoolHandle cp(THREAD, klass->constants());
KeepAliveRegistrar keepAlive(THREAD);
KeepAliveVisitor loadKeepAlive(&keepAlive);
loadKeepAlive.run(klass);
--- a/hotspot/src/share/vm/classfile/defaultMethods.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/defaultMethods.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -43,6 +43,6 @@
// default method. Overpass methods are added to the methods lists for
// the class.
static void generate_default_methods(
- InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS);
+ InstanceKlass* klass, const GrowableArray<Method*>* mirandas, TRAPS);
};
#endif // SHARE_VM_CLASSFILE_DEFAULTMETHODS_HPP
--- a/hotspot/src/share/vm/classfile/dictionary.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/dictionary.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -54,7 +54,7 @@
Symbol* name, ClassLoaderData* loader_data);
protected:
- DictionaryEntry* bucket(int i) {
+ DictionaryEntry* bucket(int i) const {
return (DictionaryEntry*)Hashtable<Klass*, mtClass>::bucket(i);
}
@@ -323,7 +323,7 @@
}
}
- bool equals(Symbol* class_name, ClassLoaderData* loader_data) const {
+ bool equals(const Symbol* class_name, ClassLoaderData* loader_data) const {
Klass* klass = (Klass*)literal();
return (klass->name() == class_name && _loader_data == loader_data);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/klassFactory.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,140 @@
+/*
+* 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 "classfile/classFileParser.hpp"
+#include "classfile/classFileStream.hpp"
+#include "classfile/classLoaderData.hpp"
+#include "classfile/klassFactory.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/jvmtiEnvBase.hpp"
+
+static ClassFileStream* prologue(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ JvmtiCachedClassFileData** cached_class_file,
+ TRAPS) {
+
+ assert(stream != NULL, "invariant");
+
+ if (JvmtiExport::should_post_class_file_load_hook()) {
+ assert(THREAD->is_Java_thread(), "must be a JavaThread");
+ const JavaThread* jt = (JavaThread*)THREAD;
+
+ Handle class_loader(THREAD, loader_data->class_loader());
+
+ // Get the cached class file bytes (if any) from the class that
+ // is being redefined or retransformed. We use jvmti_thread_state()
+ // instead of JvmtiThreadState::state_for(jt) so we don't allocate
+ // a JvmtiThreadState any earlier than necessary. This will help
+ // avoid the bug described by 7126851.
+
+ JvmtiThreadState* state = jt->jvmti_thread_state();
+
+ if (state != NULL) {
+ KlassHandle* h_class_being_redefined =
+ state->get_class_being_redefined();
+
+ if (h_class_being_redefined != NULL) {
+ instanceKlassHandle ikh_class_being_redefined =
+ instanceKlassHandle(THREAD, (*h_class_being_redefined)());
+
+ *cached_class_file = ikh_class_being_redefined->get_cached_class_file();
+ }
+ }
+
+ unsigned char* ptr = const_cast<unsigned char*>(stream->buffer());
+ unsigned char* end_ptr = ptr + stream->length();
+
+ JvmtiExport::post_class_file_load_hook(name,
+ class_loader,
+ protection_domain,
+ &ptr,
+ &end_ptr,
+ cached_class_file);
+
+ if (ptr != stream->buffer()) {
+ // JVMTI agent has modified class file data.
+ // Set new class file stream using JVMTI agent modified class file data.
+ stream = new ClassFileStream(ptr,
+ end_ptr - ptr,
+ stream->source(),
+ stream->need_verify());
+ }
+ }
+
+ return stream;
+}
+
+
+instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ const Klass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ TempNewSymbol* parsed_name,
+ TRAPS) {
+
+ assert(stream != NULL, "invariant");
+ assert(loader_data != NULL, "invariant");
+ assert(THREAD->is_Java_thread(), "must be a JavaThread");
+
+ ResourceMark rm;
+ HandleMark hm;
+
+ JvmtiCachedClassFileData* cached_class_file = NULL;
+
+ stream = prologue(stream,
+ name,
+ loader_data,
+ protection_domain,
+ &cached_class_file,
+ CHECK_NULL);
+
+ ClassFileParser parser(stream,
+ name,
+ loader_data,
+ protection_domain,
+ parsed_name,
+ host_klass,
+ cp_patches,
+ ClassFileParser::BROADCAST, // publicity level
+ CHECK_NULL);
+
+ instanceKlassHandle result = parser.create_instance_klass(CHECK_NULL);
+ assert(result == parser.create_instance_klass(THREAD), "invariant");
+
+ if (result.is_null()) {
+ return NULL;
+ }
+
+ if (cached_class_file != NULL) {
+ // JVMTI: we have an InstanceKlass now, tell it about the cached bytes
+ result->set_cached_class_file(cached_class_file);
+ }
+
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/klassFactory.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -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_CLASSFILE_KLASSFACTORY_HPP
+#define SHARE_VM_CLASSFILE_KLASSFACTORY_HPP
+
+#include "memory/allocation.inline.hpp"
+#include "runtime/handles.hpp"
+
+class ClassFileStream;
+class ClassLoaderData;
+template <typename>
+class GrowableArray;
+class Klass;
+class Symbol;
+class TempNewSymbol;
+
+/*
+ * KlassFactory is an interface to implementations of the following mapping/function:
+ *
+ * Summary: create a VM internal runtime representation ("Klass")
+ from a bytestream (classfile).
+ *
+ * Input: a named bytestream in the Java class file format (see JVMS, chapter 4).
+ * Output: a VM runtime representation of a Java class
+ *
+ * Pre-conditions:
+ * a non-NULL ClassFileStream* // the classfile bytestream
+ * a non-NULL Symbol* // the name of the class
+ * a non-NULL ClassLoaderData* // the metaspace allocator
+ * (no pending exceptions)
+ *
+ * Returns:
+ * if the returned value is non-NULL, that value is an indirection (pointer/handle)
+ * to a Klass. The caller will not have a pending exception.
+ *
+ * On broken invariants and/or runtime errors the returned value will be
+ * NULL (or a NULL handle) and the caller *might* now have a pending exception.
+ *
+ */
+
+class KlassFactory : AllStatic {
+
+ // approved clients
+ friend class ClassLoader;
+ friend class ClassLoaderExt;
+ friend class SystemDictionary;
+
+ private:
+ static instanceKlassHandle create_from_stream(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ const Klass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ TempNewSymbol* parsed_name,
+ TRAPS);
+};
+
+#endif // SHARE_VM_CLASSFILE_KLASSFACTORY_HPP
--- a/hotspot/src/share/vm/classfile/stringTable.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
-#include "classfile/compactHashtable.hpp"
+#include "classfile/compactHashtable.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
-#include "classfile/compactHashtable.hpp"
+#include "classfile/compactHashtable.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -23,9 +23,14 @@
*/
#include "precompiled.hpp"
+#include "classfile/classFileParser.hpp"
+#include "classfile/classFileStream.hpp"
+#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
+#include "classfile/classLoaderExt.hpp"
#include "classfile/dictionary.hpp"
#include "classfile/javaClasses.inline.hpp"
+#include "classfile/klassFactory.hpp"
#include "classfile/loaderConstraints.hpp"
#include "classfile/placeholders.hpp"
#include "classfile/resolutionErrors.hpp"
@@ -616,6 +621,25 @@
return (nh);
}
+// utility function for class load event
+static void post_class_load_event(const Ticks& start_time,
+ instanceKlassHandle k,
+ Handle initiating_loader) {
+#if INCLUDE_TRACE
+ EventClassLoad event(UNTIMED);
+ if (event.should_commit()) {
+ event.set_starttime(start_time);
+ event.set_loadedClass(k());
+ oop defining_class_loader = k->class_loader();
+ event.set_definingClassLoader(defining_class_loader != NULL ?
+ defining_class_loader->klass() : (Klass*)NULL);
+ oop class_loader = initiating_loader.is_null() ? (oop)NULL : initiating_loader();
+ event.set_initiatingClassLoader(class_loader != NULL ?
+ class_loader->klass() : (Klass*)NULL);
+ event.commit();
+ }
+#endif // INCLUDE_TRACE
+}
Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
Handle class_loader,
@@ -984,42 +1008,42 @@
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
- KlassHandle host_klass,
+ const Klass* host_klass,
GrowableArray<Handle>* cp_patches,
TRAPS) {
- TempNewSymbol parsed_name = NULL;
Ticks class_load_start_time = Ticks::now();
ClassLoaderData* loader_data;
- if (host_klass.not_null()) {
+ if (host_klass != NULL) {
// Create a new CLD for anonymous class, that uses the same class loader
// as the host_klass
guarantee(host_klass->class_loader() == class_loader(), "should be the same");
guarantee(!DumpSharedSpaces, "must not create anonymous classes when dumping");
loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL);
- loader_data->record_dependency(host_klass(), CHECK_NULL);
+ loader_data->record_dependency(host_klass, CHECK_NULL);
} else {
loader_data = ClassLoaderData::class_loader_data(class_loader());
}
- // Parse the stream. Note that we do this even though this klass might
+ assert(st != NULL, "invariant");
+ assert(st->need_verify(), "invariant");
+
+ // Parse stream and create a klass.
+ // Note that we do this even though this klass might
// already be present in the SystemDictionary, otherwise we would not
// throw potential ClassFormatErrors.
- //
- // Note: "name" is updated.
- instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
- loader_data,
- protection_domain,
- host_klass,
- cp_patches,
- parsed_name,
- true,
- THREAD);
+ instanceKlassHandle k = KlassFactory::create_from_stream(st,
+ class_name,
+ loader_data,
+ protection_domain,
+ host_klass,
+ cp_patches,
+ NULL, // parsed_name
+ THREAD);
-
- if (host_klass.not_null() && k.not_null()) {
+ if (host_klass != NULL && k.not_null()) {
// If it's anonymous, initialize it now, since nobody else will.
{
@@ -1050,7 +1074,7 @@
post_class_load_event(class_load_start_time, k, class_loader);
}
- assert(host_klass.not_null() || cp_patches == NULL,
+ assert(host_klass != NULL || NULL == cp_patches,
"cp_patches only found with host_klass");
return k();
@@ -1065,7 +1089,6 @@
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
- bool verify,
TRAPS) {
// Classloaders that support parallelism, e.g. bootstrap classloader,
@@ -1082,22 +1105,23 @@
check_loader_lock_contention(lockObject, THREAD);
ObjectLocker ol(lockObject, THREAD, DoObjectLock);
- TempNewSymbol parsed_name = NULL;
+ assert(st != NULL, "invariant");
- // Parse the stream. Note that we do this even though this klass might
+ // Parse the stream and create a klass.
+ // Note that we do this even though this klass might
// already be present in the SystemDictionary, otherwise we would not
// throw potential ClassFormatErrors.
//
- // Note: "name" is updated.
+ // Note: "parsed_name" is updated.
+ TempNewSymbol parsed_name = NULL;
- instanceKlassHandle k;
+ instanceKlassHandle k;
#if INCLUDE_CDS
k = SystemDictionaryShared::lookup_from_stream(class_name,
class_loader,
protection_domain,
st,
- verify,
CHECK_NULL);
#endif
@@ -1107,12 +1131,14 @@
if (st->buffer() == NULL) {
return NULL;
}
- k = ClassFileParser(st).parseClassFile(class_name,
- loader_data,
- protection_domain,
- parsed_name,
- verify,
- THREAD);
+ k = KlassFactory::create_from_stream(st,
+ class_name,
+ loader_data,
+ protection_domain,
+ NULL, // host_klass
+ NULL, // cp_patches
+ &parsed_name,
+ THREAD);
}
const char* pkg = "java/";
@@ -1319,7 +1345,7 @@
if (k.is_null()) {
// Use VM class loader
PerfTraceTime vmtimer(ClassLoader::perf_sys_classload_time());
- k = ClassLoader::load_classfile(class_name, CHECK_(nh));
+ k = ClassLoader::load_class(class_name, CHECK_(nh));
}
// find_or_define_instance_class may return a different InstanceKlass
@@ -2704,23 +2730,14 @@
constraints()->verify(dictionary(), placeholders());
}
-// utility function for class load event
-void SystemDictionary::post_class_load_event(const Ticks& start_time,
- instanceKlassHandle k,
- Handle initiating_loader) {
-#if INCLUDE_TRACE
- EventClassLoad event(UNTIMED);
- if (event.should_commit()) {
- event.set_starttime(start_time);
- event.set_loadedClass(k());
- oop defining_class_loader = k->class_loader();
- event.set_definingClassLoader(defining_class_loader != NULL ?
- defining_class_loader->klass() : (Klass*)NULL);
- oop class_loader = initiating_loader.is_null() ? (oop)NULL : initiating_loader();
- event.set_initiatingClassLoader(class_loader != NULL ?
- class_loader->klass() : (Klass*)NULL);
- event.commit();
- }
-#endif // INCLUDE_TRACE
+// caller needs ResourceMark
+const char* SystemDictionary::loader_name(const oop loader) {
+ return ((loader) == NULL ? "<bootloader>" :
+ InstanceKlass::cast((loader)->klass())->name()->as_C_string());
}
+// caller needs ResourceMark
+const char* SystemDictionary::loader_name(const ClassLoaderData* loader_data) {
+ return (loader_data->class_loader() == NULL ? "<bootloader>" :
+ InstanceKlass::cast((loader_data->class_loader())->klass())->name()->as_C_string());
+}
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -25,17 +25,15 @@
#ifndef SHARE_VM_CLASSFILE_SYSTEMDICTIONARY_HPP
#define SHARE_VM_CLASSFILE_SYSTEMDICTIONARY_HPP
-#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary_ext.hpp"
+#include "jvmci/systemDictionary_jvmci.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/symbol.hpp"
#include "runtime/java.hpp"
#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:
//
@@ -73,13 +71,13 @@
// of placeholders must hold the SystemDictionary_lock.
//
+class ClassFileStream;
class Dictionary;
class PlaceholderTable;
class LoaderConstraintTable;
template <MEMFLAGS F> class HashtableBucket;
class ResolutionErrorTable;
class SymbolPropertyTable;
-class Ticks;
// Certain classes are preloaded, such as java.lang.Object and java.lang.String.
// They are all "well-known", in the sense that no class loader is allowed
@@ -272,34 +270,41 @@
// parse_interfaces, resolve_instance_class_or_null, load_shared_class
// "child_name" is the class whose super class or interface is being resolved.
static Klass* resolve_super_or_fail(Symbol* child_name,
- Symbol* class_name,
- Handle class_loader,
- Handle protection_domain,
- bool is_superclass,
- TRAPS);
+ Symbol* class_name,
+ Handle class_loader,
+ Handle protection_domain,
+ bool is_superclass,
+ TRAPS);
// Parse new stream. This won't update the system dictionary or
// class hierarchy, simply parse the stream. Used by JVMTI RedefineClasses.
static Klass* parse_stream(Symbol* class_name,
- Handle class_loader,
- Handle protection_domain,
- ClassFileStream* st,
- TRAPS) {
- KlassHandle nullHandle;
- return parse_stream(class_name, class_loader, protection_domain, st, nullHandle, NULL, THREAD);
+ Handle class_loader,
+ Handle protection_domain,
+ ClassFileStream* st,
+ TRAPS) {
+ return parse_stream(class_name,
+ class_loader,
+ protection_domain,
+ st,
+ NULL, // host klass
+ NULL, // cp_patches
+ THREAD);
}
static Klass* parse_stream(Symbol* class_name,
- Handle class_loader,
- Handle protection_domain,
- ClassFileStream* st,
- KlassHandle host_klass,
- GrowableArray<Handle>* cp_patches,
- TRAPS);
+ Handle class_loader,
+ Handle protection_domain,
+ ClassFileStream* st,
+ const Klass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ TRAPS);
// Resolve from stream (called by jni_DefineClass and JVM_DefineClass)
- static Klass* resolve_from_stream(Symbol* class_name, Handle class_loader,
- Handle protection_domain,
- ClassFileStream* st, bool verify, TRAPS);
+ static Klass* resolve_from_stream(Symbol* class_name,
+ Handle class_loader,
+ Handle protection_domain,
+ ClassFileStream* st,
+ TRAPS);
// Lookup an already loaded class. If not found NULL is returned.
static Klass* find(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS);
@@ -546,14 +551,8 @@
TRAPS);
// Utility for printing loader "name" as part of tracing constraints
- static const char* loader_name(oop loader) {
- return ((loader) == NULL ? "<bootloader>" :
- InstanceKlass::cast((loader)->klass())->name()->as_C_string() );
- }
- static const char* loader_name(ClassLoaderData* loader_data) {
- return (loader_data->class_loader() == NULL ? "<bootloader>" :
- InstanceKlass::cast((loader_data->class_loader())->klass())->name()->as_C_string() );
- }
+ static const char* loader_name(const oop loader);
+ static const char* loader_name(const ClassLoaderData* loader_data);
// Record the error when the first attempt to resolve a reference from a constant
// pool entry to a class fails.
@@ -663,9 +662,6 @@
// Setup link to hierarchy
static void add_to_hierarchy(instanceKlassHandle k, TRAPS);
- // event based tracing
- static void post_class_load_event(const Ticks& start_time, instanceKlassHandle k,
- Handle initiating_loader);
// We pass in the hashtable index so we can calculate it outside of
// the SystemDictionary_lock.
--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -63,8 +63,7 @@
static InstanceKlass* lookup_from_stream(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
- ClassFileStream* st,
- bool verify,
+ const ClassFileStream* st,
TRAPS) {
return NULL;
}
--- a/hotspot/src/share/vm/classfile/verifier.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -48,6 +48,7 @@
#include "runtime/thread.hpp"
#include "services/threadService.hpp"
#include "utilities/bytes.hpp"
+#include "logging/log.hpp"
#define NOFAILOVER_MAJOR_VERSION 51
#define NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION 51
@@ -111,6 +112,18 @@
}
}
+// Prints the end-verification message to the appropriate output.
+void Verifier::log_end_verification(outputStream* st, const char* klassName, Symbol* exception_name, TRAPS) {
+ if (HAS_PENDING_EXCEPTION) {
+ st->print("Verification for %s has", klassName);
+ st->print_cr(" exception pending %s ",
+ PENDING_EXCEPTION->klass()->external_name());
+ } else if (exception_name != NULL) {
+ st->print_cr("Verification for %s failed", klassName);
+ }
+ st->print_cr("End class verification for: %s", klassName);
+}
+
bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool should_verify_class, TRAPS) {
HandleMark hm;
ResourceMark rm(THREAD);
@@ -155,9 +168,7 @@
bool can_failover = FailOverToOldVerifier &&
klass->major_version() < NOFAILOVER_MAJOR_VERSION;
- if (TraceClassInitialization) {
- tty->print_cr("Start class verification for: %s", klassName);
- }
+ log_info(classinit)("Start class verification for: %s", klassName);
if (klass->major_version() >= STACKMAP_ATTRIBUTE_MAJOR_VERSION) {
ClassVerifier split_verifier(klass, THREAD);
split_verifier.verify_class(THREAD);
@@ -165,10 +176,10 @@
if (can_failover && !HAS_PENDING_EXCEPTION &&
(exception_name == vmSymbols::java_lang_VerifyError() ||
exception_name == vmSymbols::java_lang_ClassFormatError())) {
- if (TraceClassInitialization || VerboseVerification) {
- tty->print_cr(
- "Fail over class verification to old verifier for: %s", klassName);
+ if (VerboseVerification) {
+ tty->print_cr("Fail over class verification to old verifier for: %s", klassName);
}
+ log_info(classinit)("Fail over class verification to old verifier for: %s", klassName);
exception_name = inference_verify(
klass, message_buffer, message_buffer_len, THREAD);
}
@@ -180,15 +191,11 @@
klass, message_buffer, message_buffer_len, THREAD);
}
- if (TraceClassInitialization || VerboseVerification) {
- if (HAS_PENDING_EXCEPTION) {
- tty->print("Verification for %s has", klassName);
- tty->print_cr(" exception pending %s ",
- PENDING_EXCEPTION->klass()->external_name());
- } else if (exception_name != NULL) {
- tty->print_cr("Verification for %s failed", klassName);
- }
- tty->print_cr("End class verification for: %s", klassName);
+ if (log_is_enabled(Info, classinit)){
+ log_end_verification(LogHandle(classinit)::info_stream(), klassName, exception_name, THREAD);
+ }
+ if (VerboseVerification){
+ log_end_verification(tty, klassName, exception_name, THREAD);
}
if (HAS_PENDING_EXCEPTION) {
@@ -598,10 +605,13 @@
verify_method(methodHandle(THREAD, m), CHECK_VERIFY(this));
}
- if (VerboseVerification || TraceClassInitialization) {
- if (was_recursively_verified())
+ if (was_recursively_verified()){
+ if (VerboseVerification){
tty->print_cr("Recursive verification detected for: %s",
- _klass->external_name());
+ _klass->external_name());
+ }
+ log_info(classinit)("Recursive verification detected for: %s",
+ _klass->external_name());
}
}
--- a/hotspot/src/share/vm/classfile/verifier.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/verifier.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -50,6 +50,7 @@
* Otherwise, no exception is thrown and the return indicates the
* error.
*/
+ static void log_end_verification(outputStream* st, const char* klassName, Symbol* exception_name, TRAPS);
static bool verify(instanceKlassHandle klass, Mode mode, bool should_verify_class, TRAPS);
// Return false if the class is loaded by the bootstrap loader,
--- a/hotspot/src/share/vm/classfile/vmSymbols.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -34,7 +34,7 @@
Symbol* vmSymbols::_type_signatures[T_VOID+1] = { NULL /*, NULL...*/ };
-inline int compare_symbol(Symbol* a, Symbol* b) {
+inline int compare_symbol(const Symbol* a, const Symbol* b) {
if (a == b) return 0;
// follow the natural address order:
return (address)a > (address)b ? +1 : -1;
@@ -43,8 +43,8 @@
static vmSymbols::SID vm_symbol_index[vmSymbols::SID_LIMIT];
extern "C" {
static int compare_vmsymbol_sid(const void* void_a, const void* void_b) {
- Symbol* a = vmSymbols::symbol_at(*((vmSymbols::SID*) void_a));
- Symbol* b = vmSymbols::symbol_at(*((vmSymbols::SID*) void_b));
+ const Symbol* a = vmSymbols::symbol_at(*((vmSymbols::SID*) void_a));
+ const Symbol* b = vmSymbols::symbol_at(*((vmSymbols::SID*) void_b));
return compare_symbol(a, b);
}
}
@@ -188,7 +188,7 @@
}
-BasicType vmSymbols::signature_type(Symbol* s) {
+BasicType vmSymbols::signature_type(const Symbol* s) {
assert(s != NULL, "checking");
for (int i = T_BOOLEAN; i < T_VOID+1; i++) {
if (s == _type_signatures[i]) {
@@ -206,7 +206,7 @@
// (Typical counts are calls=7000 and probes=17000.)
#endif
-vmSymbols::SID vmSymbols::find_sid(Symbol* symbol) {
+vmSymbols::SID vmSymbols::find_sid(const Symbol* symbol) {
// Handle the majority of misses by a bounds check.
// Then, use a binary search over the index.
// Expected trip count is less than log2_SID_LIMIT, about eight.
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -1367,7 +1367,7 @@
return _type_signatures[t];
}
// inverse of type_signature; returns T_OBJECT if s is not recognized
- static BasicType signature_type(Symbol* s);
+ static BasicType signature_type(const Symbol* s);
static Symbol* symbol_at(SID id) {
assert(id >= FIRST_SID && id < SID_LIMIT, "oob");
@@ -1376,7 +1376,7 @@
}
// Returns symbol's SID if one is assigned, else NO_SID.
- static SID find_sid(Symbol* symbol);
+ static SID find_sid(const Symbol* symbol);
static SID find_sid(const char* symbol_name);
#ifndef PRODUCT
--- a/hotspot/src/share/vm/code/nmethod.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -2609,7 +2609,7 @@
int cont_offset = ImplicitExceptionTable(this).at( exception_offset );
#ifdef ASSERT
if (cont_offset == 0) {
- Thread* thread = ThreadLocalStorage::get_thread_slow();
+ Thread* thread = Thread::current();
ResetNoHandleMark rnm; // Might be called from LEAF/QUICK ENTRY
HandleMark hm(thread);
ResourceMark rm(thread);
--- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2014, 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
@@ -30,7 +30,6 @@
#include "ci/ciUtilities.hpp"
#include "compiler/methodMatcher.hpp"
#include "compiler/compilerOracle.hpp"
-#include "oops/oop.inline.hpp"
#include "utilities/exceptions.hpp"
// Directives flag name, type, default value, compile command name
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/cms/cmsCollectorPolicy.hpp"
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -144,9 +144,6 @@
_cmst = NULL;
Terminator_lock->notify();
}
-
- // Thread destructor usually does this..
- ThreadLocalStorage::set_thread(NULL);
}
#ifndef PRODUCT
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "gc/g1/bufferingOopClosure.hpp"
@@ -112,18 +113,37 @@
class RedirtyLoggedCardTableEntryClosure : public CardTableEntryClosure {
private:
- size_t _num_processed;
+ size_t _num_dirtied;
+ G1CollectedHeap* _g1h;
+ G1SATBCardTableLoggingModRefBS* _g1_bs;
+
+ HeapRegion* region_for_card(jbyte* card_ptr) const {
+ return _g1h->heap_region_containing(_g1_bs->addr_for(card_ptr));
+ }
+
+ bool will_become_free(HeapRegion* hr) const {
+ // A region will be freed by free_collection_set if the region is in the
+ // collection set and has not had an evacuation failure.
+ return _g1h->is_in_cset(hr) && !hr->evacuation_failed();
+ }
public:
- RedirtyLoggedCardTableEntryClosure() : CardTableEntryClosure(), _num_processed(0) { }
+ RedirtyLoggedCardTableEntryClosure(G1CollectedHeap* g1h) : CardTableEntryClosure(),
+ _num_dirtied(0), _g1h(g1h), _g1_bs(g1h->g1_barrier_set()) { }
bool do_card_ptr(jbyte* card_ptr, uint worker_i) {
- *card_ptr = CardTableModRefBS::dirty_card_val();
- _num_processed++;
+ HeapRegion* hr = region_for_card(card_ptr);
+
+ // Should only dirty cards in regions that won't be freed.
+ if (!will_become_free(hr)) {
+ *card_ptr = CardTableModRefBS::dirty_card_val();
+ _num_dirtied++;
+ }
+
return true;
}
- size_t num_processed() const { return _num_processed; }
+ size_t num_dirtied() const { return _num_dirtied; }
};
@@ -2268,15 +2288,21 @@
return blk.result();
}
+bool G1CollectedHeap::is_user_requested_concurrent_full_gc(GCCause::Cause cause) {
+ switch (cause) {
+ case GCCause::_java_lang_system_gc: return ExplicitGCInvokesConcurrent;
+ case GCCause::_dcmd_gc_run: return ExplicitGCInvokesConcurrent;
+ case GCCause::_update_allocation_context_stats_inc: return true;
+ case GCCause::_wb_conc_mark: return true;
+ default : return false;
+ }
+}
+
bool G1CollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) {
switch (cause) {
case GCCause::_gc_locker: return GCLockerInvokesConcurrent;
- case GCCause::_java_lang_system_gc: return ExplicitGCInvokesConcurrent;
- case GCCause::_dcmd_gc_run: return ExplicitGCInvokesConcurrent;
case GCCause::_g1_humongous_allocation: return true;
- case GCCause::_update_allocation_context_stats_inc: return true;
- case GCCause::_wb_conc_mark: return true;
- default: return false;
+ default: return is_user_requested_concurrent_full_gc(cause);
}
}
@@ -3240,11 +3266,11 @@
// Print the per-region information.
st->cr();
- st->print_cr("Heap Regions: (E=young(eden), S=young(survivor), O=old, "
+ st->print_cr("Heap Regions: E=young(eden), S=young(survivor), O=old, "
"HS=humongous(starts), HC=humongous(continues), "
"CS=collection set, F=free, A=archive, TS=gc time stamp, "
- "PTAMS=previous top-at-mark-start, "
- "NTAMS=next top-at-mark-start)");
+ "AC=allocation context, "
+ "TAMS=top-at-mark-start (previous, next)");
PrintRegionClosure blk(st);
heap_region_iterate(&blk);
}
@@ -4619,24 +4645,26 @@
class G1RedirtyLoggedCardsTask : public AbstractGangTask {
private:
DirtyCardQueueSet* _queue;
+ G1CollectedHeap* _g1h;
public:
- G1RedirtyLoggedCardsTask(DirtyCardQueueSet* queue) : AbstractGangTask("Redirty Cards"), _queue(queue) { }
+ G1RedirtyLoggedCardsTask(DirtyCardQueueSet* queue, G1CollectedHeap* g1h) : AbstractGangTask("Redirty Cards"),
+ _queue(queue), _g1h(g1h) { }
virtual void work(uint worker_id) {
- G1GCPhaseTimes* phase_times = G1CollectedHeap::heap()->g1_policy()->phase_times();
+ G1GCPhaseTimes* phase_times = _g1h->g1_policy()->phase_times();
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::RedirtyCards, worker_id);
- RedirtyLoggedCardTableEntryClosure cl;
+ RedirtyLoggedCardTableEntryClosure cl(_g1h);
_queue->par_apply_closure_to_all_completed_buffers(&cl);
- phase_times->record_thread_work_item(G1GCPhaseTimes::RedirtyCards, worker_id, cl.num_processed());
+ phase_times->record_thread_work_item(G1GCPhaseTimes::RedirtyCards, worker_id, cl.num_dirtied());
}
};
void G1CollectedHeap::redirty_logged_cards() {
double redirty_logged_cards_start = os::elapsedTime();
- G1RedirtyLoggedCardsTask redirty_task(&dirty_card_queue_set());
+ G1RedirtyLoggedCardsTask redirty_task(&dirty_card_queue_set(), this);
dirty_card_queue_set().reset_for_par_iteration();
workers()->run_task(&redirty_task);
@@ -5471,36 +5499,36 @@
return true;
}
if (cset_state.is_in_cset()) {
- gclog_or_tty->print_cr("\n## inconsistent cset state %d for humongous region %u", cset_state.value(), i);
+ gclog_or_tty->print_cr("\n## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i);
_failures = true;
return true;
}
if (hr->is_continues_humongous() && cset_state.is_humongous()) {
- gclog_or_tty->print_cr("\n## inconsistent cset state %d for continues humongous region %u", cset_state.value(), i);
+ gclog_or_tty->print_cr("\n## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i);
_failures = true;
return true;
}
} else {
if (cset_state.is_humongous()) {
- gclog_or_tty->print_cr("\n## inconsistent cset state %d for non-humongous region %u", cset_state.value(), i);
+ gclog_or_tty->print_cr("\n## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i);
_failures = true;
return true;
}
if (hr->in_collection_set() != cset_state.is_in_cset()) {
- gclog_or_tty->print_cr("\n## in CSet %d / cset state %d inconsistency for region %u",
+ gclog_or_tty->print_cr("\n## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
hr->in_collection_set(), cset_state.value(), i);
_failures = true;
return true;
}
if (cset_state.is_in_cset()) {
if (hr->is_young() != (cset_state.is_young())) {
- gclog_or_tty->print_cr("\n## is_young %d / cset state %d inconsistency for region %u",
+ gclog_or_tty->print_cr("\n## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
hr->is_young(), cset_state.value(), i);
_failures = true;
return true;
}
if (hr->is_old() != (cset_state.is_old())) {
- gclog_or_tty->print_cr("\n## is_old %d / cset state %d inconsistency for region %u",
+ gclog_or_tty->print_cr("\n## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
hr->is_old(), cset_state.value(), i);
_failures = true;
return true;
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -245,9 +245,11 @@
// instead of doing a STW GC. Currently, a concurrent cycle is
// explicitly started if:
// (a) cause == _gc_locker and +GCLockerInvokesConcurrent, or
- // (b) cause == _java_lang_system_gc and +ExplicitGCInvokesConcurrent.
- // (c) cause == _dcmd_gc_run and +ExplicitGCInvokesConcurrent.
- // (d) cause == _g1_humongous_allocation
+ // (b) cause == _g1_humongous_allocation
+ // (c) cause == _java_lang_system_gc and +ExplicitGCInvokesConcurrent.
+ // (d) cause == _dcmd_gc_run and +ExplicitGCInvokesConcurrent.
+ // (e) cause == _update_allocation_context_stats_inc
+ // (f) cause == _wb_conc_mark
bool should_do_concurrent_full_gc(GCCause::Cause cause);
// indicates whether we are in young or mixed GC mode
@@ -579,6 +581,8 @@
_in_cset_fast_test.clear();
}
+ bool is_user_requested_concurrent_full_gc(GCCause::Cause cause);
+
// This is called at the start of either a concurrent cycle or a Full
// GC to update the number of old marking cycles started.
void increment_old_marking_cycles_started();
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -191,6 +191,7 @@
_recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime());
_prev_collection_pause_end_ms = os::elapsedTime() * 1000.0;
+ clear_ratio_check_data();
_phase_times = new G1GCPhaseTimes(_parallel_gc_threads);
@@ -291,7 +292,7 @@
// for the first time during initialization.
_reserve_regions = 0;
- _collectionSetChooser = new CollectionSetChooser();
+ _cset_chooser = new CollectionSetChooser();
}
G1CollectorPolicy::~G1CollectorPolicy() {
@@ -854,7 +855,7 @@
_survivor_surv_rate_group->reset();
update_young_list_max_and_target_length();
update_rs_lengths_prediction();
- _collectionSetChooser->clear();
+ cset_chooser()->clear();
_bytes_allocated_in_old_since_last_gc = 0;
@@ -1082,6 +1083,14 @@
_recent_avg_pause_time_ratio = 1.0;
}
}
+
+ // Compute the ratio of just this last pause time to the entire time range stored
+ // in the vectors. Comparing this pause to the entire range, rather than only the
+ // most recent interval, has the effect of smoothing over a possible transient 'burst'
+ // of more frequent pauses that don't really reflect a change in heap occupancy.
+ // This reduces the likelihood of a needless heap expansion being triggered.
+ _last_pause_time_ratio =
+ (pause_time_ms * _recent_prev_end_times_for_all_gcs_sec->num()) / interval_ms;
}
bool new_in_marking_window = collector_state()->in_marking_window();
@@ -1237,7 +1246,7 @@
phase_times()->sum_thread_work_items(G1GCPhaseTimes::UpdateRS),
update_rs_time_goal_ms);
- _collectionSetChooser->verify();
+ cset_chooser()->verify();
}
G1IHOPControl* G1CollectorPolicy::create_ihop_control() const {
@@ -1599,41 +1608,124 @@
_prev_collection_pause_end_ms = end_time_sec * 1000.0;
}
-size_t G1CollectorPolicy::expansion_amount() const {
+void G1CollectorPolicy::clear_ratio_check_data() {
+ _ratio_over_threshold_count = 0;
+ _ratio_over_threshold_sum = 0.0;
+ _pauses_since_start = 0;
+}
+
+size_t G1CollectorPolicy::expansion_amount() {
double recent_gc_overhead = recent_avg_pause_time_ratio() * 100.0;
+ double last_gc_overhead = _last_pause_time_ratio * 100.0;
double threshold = _gc_overhead_perc;
- if (recent_gc_overhead > threshold) {
- // We will double the existing space, or take
- // G1ExpandByPercentOfAvailable % of the available expansion
- // space, whichever is smaller, bounded below by a minimum
- // expansion (unless that's all that's left.)
- const size_t min_expand_bytes = 1*M;
+ size_t expand_bytes = 0;
+
+ // If the heap is at less than half its maximum size, scale the threshold down,
+ // to a limit of 1. Thus the smaller the heap is, the more likely it is to expand,
+ // though the scaling code will likely keep the increase small.
+ if (_g1->capacity() <= _g1->max_capacity() / 2) {
+ threshold *= (double)_g1->capacity() / (double)(_g1->max_capacity() / 2);
+ threshold = MAX2(threshold, 1.0);
+ }
+
+ // If the last GC time ratio is over the threshold, increment the count of
+ // times it has been exceeded, and add this ratio to the sum of exceeded
+ // ratios.
+ if (last_gc_overhead > threshold) {
+ _ratio_over_threshold_count++;
+ _ratio_over_threshold_sum += last_gc_overhead;
+ }
+
+ // Check if we've had enough GC time ratio checks that were over the
+ // threshold to trigger an expansion. We'll also expand if we've
+ // reached the end of the history buffer and the average of all entries
+ // is still over the threshold. This indicates a smaller number of GCs were
+ // long enough to make the average exceed the threshold.
+ bool filled_history_buffer = _pauses_since_start == NumPrevPausesForHeuristics;
+ if ((_ratio_over_threshold_count == MinOverThresholdForGrowth) ||
+ (filled_history_buffer && (recent_gc_overhead > threshold))) {
+ size_t min_expand_bytes = HeapRegion::GrainBytes;
size_t reserved_bytes = _g1->max_capacity();
size_t committed_bytes = _g1->capacity();
size_t uncommitted_bytes = reserved_bytes - committed_bytes;
- size_t expand_bytes;
size_t expand_bytes_via_pct =
uncommitted_bytes * G1ExpandByPercentOfAvailable / 100;
- expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes);
- expand_bytes = MAX2(expand_bytes, min_expand_bytes);
- expand_bytes = MIN2(expand_bytes, uncommitted_bytes);
+ double scale_factor = 1.0;
+
+ // If the current size is less than 1/4 of the Initial heap size, expand
+ // by half of the delta between the current and Initial sizes. IE, grow
+ // back quickly.
+ //
+ // Otherwise, take the current size, or G1ExpandByPercentOfAvailable % of
+ // the available expansion space, whichever is smaller, as the base
+ // expansion size. Then possibly scale this size according to how much the
+ // threshold has (on average) been exceeded by. If the delta is small
+ // (less than the StartScaleDownAt value), scale the size down linearly, but
+ // not by less than MinScaleDownFactor. If the delta is large (greater than
+ // the StartScaleUpAt value), scale up, but adding no more than MaxScaleUpFactor
+ // times the base size. The scaling will be linear in the range from
+ // StartScaleUpAt to (StartScaleUpAt + ScaleUpRange). In other words,
+ // ScaleUpRange sets the rate of scaling up.
+ if (committed_bytes < InitialHeapSize / 4) {
+ expand_bytes = (InitialHeapSize - committed_bytes) / 2;
+ } else {
+ double const MinScaleDownFactor = 0.2;
+ double const MaxScaleUpFactor = 2;
+ double const StartScaleDownAt = _gc_overhead_perc;
+ double const StartScaleUpAt = _gc_overhead_perc * 1.5;
+ double const ScaleUpRange = _gc_overhead_perc * 2.0;
+
+ double ratio_delta;
+ if (filled_history_buffer) {
+ ratio_delta = recent_gc_overhead - threshold;
+ } else {
+ ratio_delta = (_ratio_over_threshold_sum/_ratio_over_threshold_count) - threshold;
+ }
+
+ expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes);
+ if (ratio_delta < StartScaleDownAt) {
+ scale_factor = ratio_delta / StartScaleDownAt;
+ scale_factor = MAX2(scale_factor, MinScaleDownFactor);
+ } else if (ratio_delta > StartScaleUpAt) {
+ scale_factor = 1 + ((ratio_delta - StartScaleUpAt) / ScaleUpRange);
+ scale_factor = MIN2(scale_factor, MaxScaleUpFactor);
+ }
+ }
ergo_verbose5(ErgoHeapSizing,
"attempt heap expansion",
ergo_format_reason("recent GC overhead higher than "
"threshold after GC")
ergo_format_perc("recent GC overhead")
- ergo_format_perc("threshold")
+ ergo_format_perc("current threshold")
ergo_format_byte("uncommitted")
- ergo_format_byte_perc("calculated expansion amount"),
+ ergo_format_byte_perc("base expansion amount and scale"),
recent_gc_overhead, threshold,
uncommitted_bytes,
- expand_bytes_via_pct, (double) G1ExpandByPercentOfAvailable);
-
- return expand_bytes;
+ expand_bytes, scale_factor * 100);
+
+ expand_bytes = static_cast<size_t>(expand_bytes * scale_factor);
+
+ // Ensure the expansion size is at least the minimum growth amount
+ // and at most the remaining uncommitted byte size.
+ expand_bytes = MAX2(expand_bytes, min_expand_bytes);
+ expand_bytes = MIN2(expand_bytes, uncommitted_bytes);
+
+ clear_ratio_check_data();
} else {
- return 0;
+ // An expansion was not triggered. If we've started counting, increment
+ // the number of checks we've made in the current window. If we've
+ // reached the end of the window without resizing, clear the counters to
+ // start again the next time we see a ratio above the threshold.
+ if (_ratio_over_threshold_count > 0) {
+ _pauses_since_start++;
+ if (_pauses_since_start > NumPrevPausesForHeuristics) {
+ clear_ratio_check_data();
+ }
+ }
}
+
+ return expand_bytes;
}
void G1CollectorPolicy::print_tracing_info() const {
@@ -1710,6 +1802,11 @@
}
}
+void G1CollectorPolicy::initiate_conc_mark() {
+ collector_state()->set_during_initial_mark_pause(true);
+ collector_state()->set_initiate_conc_mark_if_possible(false);
+}
+
void G1CollectorPolicy::decide_on_conc_mark_initiation() {
// We are about to decide on whether this pause will be an
// initial-mark pause.
@@ -1726,17 +1823,22 @@
// concurrent marking cycle. So we might initiate one.
if (!about_to_start_mixed_phase() && collector_state()->gcs_are_young()) {
- // Initiate a new initial mark only if there is no marking or reclamation going
- // on.
-
- collector_state()->set_during_initial_mark_pause(true);
- // And we can now clear initiate_conc_mark_if_possible() as
- // we've already acted on it.
- collector_state()->set_initiate_conc_mark_if_possible(false);
-
+ // Initiate a new initial mark if there is no marking or reclamation going on.
+ initiate_conc_mark();
ergo_verbose0(ErgoConcCycles,
- "initiate concurrent cycle",
- ergo_format_reason("concurrent cycle initiation requested"));
+ "initiate concurrent cycle",
+ ergo_format_reason("concurrent cycle initiation requested"));
+ } else if (_g1->is_user_requested_concurrent_full_gc(_g1->gc_cause())) {
+ // Initiate a user requested initial mark. An initial mark must be young only
+ // GC, so the collector state must be updated to reflect this.
+ collector_state()->set_gcs_are_young(true);
+ collector_state()->set_last_young_gc(false);
+
+ abort_time_to_mixed_tracking();
+ initiate_conc_mark();
+ ergo_verbose0(ErgoConcCycles,
+ "initiate concurrent cycle",
+ ergo_format_reason("user requested concurrent cycle"));
} else {
// The concurrent marking thread is still finishing up the
// previous cycle. If we start one right now the two cycles
@@ -1807,18 +1909,18 @@
}
void G1CollectorPolicy::record_concurrent_mark_cleanup_end() {
- _collectionSetChooser->clear();
+ cset_chooser()->clear();
WorkGang* workers = _g1->workers();
uint n_workers = workers->active_workers();
uint n_regions = _g1->num_regions();
uint chunk_size = calculate_parallel_work_chunk_size(n_workers, n_regions);
- _collectionSetChooser->prepare_for_par_region_addition(n_workers, n_regions, chunk_size);
- ParKnownGarbageTask par_known_garbage_task(_collectionSetChooser, chunk_size, n_workers);
+ cset_chooser()->prepare_for_par_region_addition(n_workers, n_regions, chunk_size);
+ ParKnownGarbageTask par_known_garbage_task(cset_chooser(), chunk_size, n_workers);
workers->run_task(&par_known_garbage_task);
- _collectionSetChooser->sort_regions();
+ cset_chooser()->sort_regions();
double end_sec = os::elapsedTime();
double elapsed_time_ms = (end_sec - _mark_cleanup_start_sec) * 1000.0;
@@ -2097,8 +2199,7 @@
bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str,
const char* false_action_str) const {
- CollectionSetChooser* cset_chooser = _collectionSetChooser;
- if (cset_chooser->is_empty()) {
+ if (cset_chooser()->is_empty()) {
ergo_verbose0(ErgoMixedGCs,
false_action_str,
ergo_format_reason("candidate old regions not available"));
@@ -2106,7 +2207,7 @@
}
// Is the amount of uncollected reclaimable space above G1HeapWastePercent?
- size_t reclaimable_bytes = cset_chooser->remaining_reclaimable_bytes();
+ size_t reclaimable_bytes = cset_chooser()->remaining_reclaimable_bytes();
double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes);
double threshold = (double) G1HeapWastePercent;
if (reclaimable_perc <= threshold) {
@@ -2116,7 +2217,7 @@
ergo_format_region("candidate old regions")
ergo_format_byte_perc("reclaimable")
ergo_format_perc("threshold"),
- cset_chooser->remaining_regions(),
+ cset_chooser()->remaining_regions(),
reclaimable_bytes,
reclaimable_perc, threshold);
return false;
@@ -2128,7 +2229,7 @@
ergo_format_region("candidate old regions")
ergo_format_byte_perc("reclaimable")
ergo_format_perc("threshold"),
- cset_chooser->remaining_regions(),
+ cset_chooser()->remaining_regions(),
reclaimable_bytes,
reclaimable_perc, threshold);
return true;
@@ -2145,7 +2246,7 @@
// to the CSet chooser in the first place, not how many remain, so
// that the result is the same during all mixed GCs that follow a cycle.
- const size_t region_num = (size_t) _collectionSetChooser->length();
+ const size_t region_num = (size_t) cset_chooser()->length();
const size_t gc_num = (size_t) MAX2(G1MixedGCCountTarget, (uintx) 1);
size_t result = region_num / gc_num;
// emulate ceiling
@@ -2254,15 +2355,14 @@
if (!collector_state()->gcs_are_young()) {
- CollectionSetChooser* cset_chooser = _collectionSetChooser;
- cset_chooser->verify();
+ cset_chooser()->verify();
const uint min_old_cset_length = calc_min_old_cset_length();
const uint max_old_cset_length = calc_max_old_cset_length();
uint expensive_region_num = 0;
bool check_time_remaining = adaptive_young_list_length();
- HeapRegion* hr = cset_chooser->peek();
+ HeapRegion* hr = cset_chooser()->peek();
while (hr != NULL) {
if (old_cset_region_length() >= max_old_cset_length) {
// Added maximum number of old regions to the CSet.
@@ -2278,7 +2378,7 @@
// Stop adding regions if the remaining reclaimable space is
// not above G1HeapWastePercent.
- size_t reclaimable_bytes = cset_chooser->remaining_reclaimable_bytes();
+ size_t reclaimable_bytes = cset_chooser()->remaining_reclaimable_bytes();
double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes);
double threshold = (double) G1HeapWastePercent;
if (reclaimable_perc <= threshold) {
@@ -2340,11 +2440,11 @@
// We will add this region to the CSet.
time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0);
predicted_old_time_ms += predicted_time_ms;
- cset_chooser->pop(); // already have region via peek()
+ cset_chooser()->pop(); // already have region via peek()
_g1->old_set_remove(hr);
add_old_region_to_cset(hr);
- hr = cset_chooser->peek();
+ hr = cset_chooser()->peek();
}
if (hr == NULL) {
ergo_verbose0(ErgoCSetConstruction,
@@ -2369,7 +2469,7 @@
time_remaining_ms);
}
- cset_chooser->verify();
+ cset_chooser()->verify();
}
stop_incremental_cset_building();
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -191,7 +191,7 @@
void initialize_alignments();
void initialize_flags();
- CollectionSetChooser* _collectionSetChooser;
+ CollectionSetChooser* _cset_chooser;
double _full_collection_start_sec;
@@ -201,6 +201,11 @@
TruncatedSeq* _concurrent_mark_remark_times_ms;
TruncatedSeq* _concurrent_mark_cleanup_times_ms;
+ // Ratio check data for determining if heap growth is necessary.
+ uint _ratio_over_threshold_count;
+ double _ratio_over_threshold_sum;
+ uint _pauses_since_start;
+
TraceYoungGenTimeData _trace_young_gen_time_data;
TraceOldGenTimeData _trace_old_gen_time_data;
@@ -224,7 +229,11 @@
enum PredictionConstants {
TruncatedSeqLength = 10,
- NumPrevPausesForHeuristics = 10
+ NumPrevPausesForHeuristics = 10,
+ // MinOverThresholdForGrowth must be less than NumPrevPausesForHeuristics,
+ // representing the minimum number of pause time ratios that exceed
+ // GCTimeRatio before a heap expansion will be triggered.
+ MinOverThresholdForGrowth = 4
};
TruncatedSeq* _alloc_rate_ms_seq;
@@ -405,6 +414,10 @@
double non_young_other_time_ms() const;
double constant_other_time_ms(double pause_time_ms) const;
+ CollectionSetChooser* cset_chooser() const {
+ return _cset_chooser;
+ }
+
private:
// Statistics kept per GC stoppage, pause or full.
TruncatedSeq* _recent_prev_end_times_for_all_gcs_sec;
@@ -479,8 +492,10 @@
G1GCPhaseTimes* _phase_times;
- // The ratio of gc time to elapsed time, computed over recent pauses.
+ // The ratio of gc time to elapsed time, computed over recent pauses,
+ // and the ratio for just the last pause.
double _recent_avg_pause_time_ratio;
+ double _last_pause_time_ratio;
double recent_avg_pause_time_ratio() const {
return _recent_avg_pause_time_ratio;
@@ -725,6 +740,11 @@
// (should not be called directly).
void add_region_to_incremental_cset_common(HeapRegion* hr);
+ // Set the state to start a concurrent marking cycle and clear
+ // _initiate_conc_mark_if_possible because it has now been
+ // acted on.
+ void initiate_conc_mark();
+
public:
// Add hr to the LHS of the incremental collection set.
void add_region_to_incremental_cset_lhs(HeapRegion* hr);
@@ -752,7 +772,10 @@
// 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() const;
+ virtual size_t expansion_amount();
+
+ // Clear ratio tracking data used by expansion_amount().
+ void clear_ratio_check_data();
// Print tracing information.
void print_tracing_info() const;
--- a/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -47,8 +47,9 @@
virtual void do_oop( oop* p) { do_oop_work(p); }
template <class T> void do_oop_work(T* p) {
assert(_from->is_in_reserved(p), "paranoia");
- if (!_from->is_in_reserved(oopDesc::load_decode_heap_oop(p)) &&
- !_from->is_survivor()) {
+ assert(!_from->is_survivor(), "Unexpected evac failure in survivor region");
+
+ if (!_from->is_in_reserved(oopDesc::load_decode_heap_oop(p))) {
size_t card_index = _ct_bs->index_for(p);
if (_ct_bs->mark_card_deferred(card_index)) {
_dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index));
--- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -141,6 +141,7 @@
assert(active_gc_threads <= _max_gc_threads, "The number of active threads must be <= the max number of threads");
_active_gc_threads = active_gc_threads;
_cur_expand_heap_time_ms = 0.0;
+ _external_accounted_time_ms = 0.0;
for (int i = 0; i < GCParPhasesSentinel; i++) {
_gc_par_phases[i]->reset();
@@ -185,9 +186,12 @@
}
double G1GCPhaseTimes::accounted_time_ms() {
+ // First subtract any externally accounted time
+ double misc_time_ms = _external_accounted_time_ms;
+
// Subtract the root region scanning wait time. It's initialized to
// zero at the start of the pause.
- double misc_time_ms = _root_region_scan_wait_time_ms;
+ misc_time_ms += _root_region_scan_wait_time_ms;
misc_time_ms += _cur_collection_par_time_ms;
--- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -99,6 +99,8 @@
double _cur_collection_start_sec;
double _root_region_scan_wait_time_ms;
+ double _external_accounted_time_ms;
+
double _recorded_young_cset_choice_time_ms;
double _recorded_non_young_cset_choice_time_ms;
@@ -244,6 +246,10 @@
_cur_verify_after_time_ms = time_ms;
}
+ void inc_external_accounted_time_ms(double time_ms) {
+ _external_accounted_time_ms += time_ms;
+ }
+
double accounted_time_ms();
double cur_collection_start_sec() {
--- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -123,7 +123,7 @@
// Resets the hot card cache and discards the entries.
void reset_hot_cache() {
assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint");
- assert(Thread::current_noinline()->is_VM_thread(), "Current thread should be the VMthread");
+ assert(Thread::current()->is_VM_thread(), "Current thread should be the VMthread");
if (default_use_cache()) {
reset_hot_cache_internal();
}
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -91,7 +91,7 @@
if (state.is_humongous()) {
_g1->set_humongous_is_live(obj);
}
- _par_scan_state->update_rs(_from, p);
+ _par_scan_state->update_rs(_from, p, obj);
}
}
}
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -98,10 +98,10 @@
template <class T> void push_on_queue(T* ref);
- template <class T> void update_rs(HeapRegion* from, T* p) {
+ template <class T> void update_rs(HeapRegion* from, T* p, oop o) {
// 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()) {
+ if (!HeapRegion::is_in_same_region(p, o) && !from->is_young()) {
size_t card_index = ctbs()->index_for(p);
// If the card hasn't been added to the buffer, do it.
if (ctbs()->mark_card_deferred(card_index)) {
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -40,14 +40,13 @@
// processed multiple times. So redo this check.
const InCSetState in_cset_state = _g1h->in_cset_state(obj);
if (in_cset_state.is_in_cset()) {
- oop forwardee;
markOop m = obj->mark();
if (m->is_marked()) {
- forwardee = (oop) m->decode_pointer();
+ obj = (oop) m->decode_pointer();
} else {
- forwardee = copy_to_survivor_space(in_cset_state, obj, m);
+ obj = copy_to_survivor_space(in_cset_state, obj, m);
}
- oopDesc::encode_store_heap_oop(p, forwardee);
+ oopDesc::encode_store_heap_oop(p, obj);
} else if (in_cset_state.is_humongous()) {
_g1h->set_humongous_is_live(obj);
} else {
@@ -56,7 +55,7 @@
}
assert(obj != NULL, "Must be");
- update_rs(from, p);
+ update_rs(from, p, obj);
}
template <class T> inline void G1ParScanThreadState::push_on_queue(T* ref) {
--- a/hotspot/src/share/vm/gc/g1/g1Predictions.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1Predictions.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -25,7 +25,6 @@
#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.
--- a/hotspot/src/share/vm/gc/g1/g1RootClosures.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1RootClosures.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -23,7 +23,38 @@
*/
#include "precompiled.hpp"
-#include "gc/g1/g1RootClosures.inline.hpp"
+#include "gc/g1/g1OopClosures.inline.hpp"
+#include "gc/g1/g1RootClosures.hpp"
+#include "gc/g1/g1SharedClosures.hpp"
+
+// Closures used for standard G1 evacuation.
+class G1EvacuationClosures : public G1EvacuationRootClosures {
+ G1SharedClosures<G1MarkNone> _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,
--- a/hotspot/src/share/vm/gc/g1/g1RootClosures.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*
- * 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 "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"
-
-// Simple holder object for a complete set of closures used by the G1 evacuation code.
-template <G1Mark Mark>
-class G1SharedClosures VALUE_OBJ_CLASS_SPEC {
-public:
- G1ParCopyClosure<G1BarrierNone, Mark> _oops;
- G1ParCopyClosure<G1BarrierKlass, Mark> _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<G1MarkNone> _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; }
-};
--- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -85,11 +85,6 @@
return false;
}
- if (val == g1_young_gen) {
- // the card is for a young gen region. We don't need to keep track of all pointers into young
- return false;
- }
-
// Cached bit can be installed either on a clean card or on a claimed card.
jbyte new_val = val;
if (val == clean_card_val()) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1SharedClosures.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -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 "gc/g1/bufferingOopClosure.hpp"
+#include "gc/g1/g1CodeBlobClosure.hpp"
+#include "gc/g1/g1OopClosures.hpp"
+#include "memory/iterator.hpp"
+
+class G1CollectedHeap;
+class G1ParScanThreadState;
+
+// Simple holder object for a complete set of closures used by the G1 evacuation code.
+template <G1Mark Mark>
+class G1SharedClosures VALUE_OBJ_CLASS_SPEC {
+public:
+ G1ParCopyClosure<G1BarrierNone, Mark> _oops;
+ G1ParCopyClosure<G1BarrierKlass, Mark> _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) {}
+};
--- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -33,9 +33,11 @@
#define G1_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, manageable, product_rw, range, constraint) \
\
- product(bool, G1UseAdaptiveIHOP, false, \
- "Adaptively adjust InitiatingHeapOccupancyPercent from the " \
- "initial value.") \
+ product(bool, G1UseAdaptiveIHOP, true, \
+ "Adaptively adjust the initiating heap occupancy from the " \
+ "initial value of InitiatingHeapOccupancyPercent. The policy " \
+ "attempts to start marking in time based on application " \
+ "behavior.") \
\
experimental(size_t, G1AdaptiveIHOPNumInitialSamples, 3, \
"How many completed time periods from initial mark to first " \
@@ -155,6 +157,7 @@
"Each time the rset update queue increases by this amount " \
"activate the next refinement thread if available. " \
"Will be selected ergonomically by default.") \
+ range(0, max_jint) \
\
product(intx, G1RSetUpdatingPauseTimePercent, 10, \
"A target percentage of time that is allowed to be spend on " \
@@ -298,6 +301,7 @@
\
product(uintx, G1MixedGCCountTarget, 8, \
"The target number of mixed GCs after a marking cycle.") \
+ range(0, max_uintx) \
\
experimental(bool, G1EagerReclaimHumongousObjects, true, \
"Try to reclaim dead large objects at every young GC.") \
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -592,17 +592,20 @@
void HeapRegion::print() const { print_on(gclog_or_tty); }
void HeapRegion::print_on(outputStream* st) const {
- st->print("AC%4u", allocation_context());
-
- st->print(" %2s", get_short_type_str());
- if (in_collection_set())
- st->print(" CS");
- else
- st->print(" ");
- st->print(" TS %5d", _gc_time_stamp);
- st->print(" PTAMS " PTR_FORMAT " NTAMS " PTR_FORMAT,
- p2i(prev_top_at_mark_start()), p2i(next_top_at_mark_start()));
- G1OffsetTableContigSpace::print_on(st);
+ st->print("|%4u", this->_hrm_index);
+ st->print("|" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT,
+ p2i(bottom()), p2i(top()), p2i(end()));
+ st->print("|%3d%%", (int) ((double) used() * 100 / capacity()));
+ st->print("|%2s", get_short_type_str());
+ if (in_collection_set()) {
+ st->print("|CS");
+ } else {
+ st->print("| ");
+ }
+ st->print("|TS%3u", _gc_time_stamp);
+ st->print("|AC%3u", allocation_context());
+ st->print_cr("|TAMS " PTR_FORMAT ", " PTR_FORMAT "|",
+ p2i(prev_top_at_mark_start()), p2i(next_top_at_mark_start()));
}
class VerifyLiveClosure: public OopClosure {
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -351,6 +351,15 @@
~((1 << (size_t) LogOfHRGrainBytes) - 1);
}
+
+ // Returns whether a field is in the same region as the obj it points to.
+ template <typename T>
+ static bool is_in_same_region(T* p, oop obj) {
+ assert(p != NULL, "p can't be NULL");
+ assert(obj != NULL, "obj can't be NULL");
+ return (((uintptr_t) p ^ cast_from_oop<uintptr_t>(obj)) >> LogOfHRGrainBytes) == 0;
+ }
+
static size_t max_region_size();
static size_t min_region_size_in_words();
--- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1020,24 +1020,6 @@
}
#ifndef PRODUCT
-void PerRegionTable::test_fl_mem_size() {
- PerRegionTable* dummy = alloc(NULL);
-
- size_t min_prt_size = sizeof(void*) + dummy->bm()->size_in_words() * HeapWordSize;
- assert(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
- _free_list = NULL;
- delete dummy;
-}
-
-void HeapRegionRemSet::test_prt() {
- PerRegionTable::test_fl_mem_size();
-}
-
void HeapRegionRemSet::test() {
os::sleep(Thread::current(), (jlong)5000, false);
G1CollectedHeap* g1h = G1CollectedHeap::heap();
--- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -392,7 +392,6 @@
// Run unit tests.
#ifndef PRODUCT
- static void test_prt();
static void test();
#endif
};
--- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,4 +1,3 @@
-
/*
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -96,7 +95,6 @@
void GCTaskThread::run() {
// Set up the thread for stack overflow support
this->record_stack_base_and_size();
- this->initialize_thread_local_storage();
this->initialize_named_thread();
// Bind yourself to your processor.
if (processor_id() != GCTaskManager::sentinel_worker()) {
--- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/parallel/parallelScavengeHeap.hpp"
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/parallel/gcTaskManager.hpp"
--- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
--- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -51,7 +51,6 @@
void ConcurrentGCThread::initialize_in_thread() {
this->record_stack_base_and_size();
- this->initialize_thread_local_storage();
this->initialize_named_thread();
this->set_active_handles(JNIHandleBlock::allocate_block());
// From this time Thread::current() should be working.
@@ -74,9 +73,6 @@
_has_terminated = true;
Terminator_lock->notify();
}
-
- // Thread destructor usually does this..
- ThreadLocalStorage::set_thread(NULL);
}
static void _sltLoop(JavaThread* thread, TRAPS) {
--- a/hotspot/src/share/vm/gc/shared/workgroup.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -275,7 +275,6 @@
}
void AbstractGangWorker::initialize() {
- this->initialize_thread_local_storage();
this->record_stack_base_and_size();
this->initialize_named_thread();
assert(_gang != NULL, "No gang to run in");
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/defaultMethods.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "compiler/compileBroker.hpp"
--- a/hotspot/src/share/vm/logging/logConfiguration.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/logging/logConfiguration.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -39,6 +39,7 @@
LogOutput** LogConfiguration::_outputs = NULL;
size_t LogConfiguration::_n_outputs = 0;
+bool LogConfiguration::_post_initialized = false;
void LogConfiguration::post_initialize() {
assert(LogConfiguration_lock != NULL, "Lock must be initialized before post-initialization");
@@ -51,6 +52,8 @@
MutexLocker ml(LogConfiguration_lock);
describe(log.trace_stream());
}
+
+ _post_initialized = true;
}
void LogConfiguration::initialize(jlong vm_start_time) {
@@ -422,3 +425,12 @@
"\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");
}
+
+void LogConfiguration::rotate_all_outputs() {
+ for (size_t idx = 0; idx < _n_outputs; idx++) {
+ if (_outputs[idx]->is_rotatable()) {
+ _outputs[idx]->rotate(true);
+ }
+ }
+}
+
--- a/hotspot/src/share/vm/logging/logConfiguration.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/logging/logConfiguration.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -40,6 +40,7 @@
private:
static LogOutput** _outputs;
static size_t _n_outputs;
+ static bool _post_initialized;
// Create a new output. Returns NULL if failed.
static LogOutput* new_output(char* name, const char* options = NULL);
@@ -94,6 +95,13 @@
// Prints usage help for command line log configuration.
static void print_command_line_help(FILE* out);
+
+ static bool is_post_initialized() {
+ return _post_initialized;
+ }
+
+ // Rotates all LogOutput
+ static void rotate_all_outputs();
};
#endif // SHARE_VM_LOGGING_LOGCONFIGURATION_HPP
--- a/hotspot/src/share/vm/logging/logDecorations.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/logging/logDecorations.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -96,7 +96,7 @@
char * LogDecorations::create_tid_decoration(char* pos) {
int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer),
- INTX_FORMAT, Thread::current()->osthread()->thread_id());
+ INTX_FORMAT, os::current_thread_id());
ASSERT_AND_RETURN(written, pos)
}
--- a/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -35,13 +35,15 @@
_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) {
+ _list("list", "Lists current log configuration.", "BOOLEAN", false),
+ _rotate("rotate", "Rotates all logs.", "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);
+ _dcmdparser.add_dcmd_option(&_rotate);
}
int LogDiagnosticCommand::num_arguments() {
@@ -86,6 +88,11 @@
any_command = true;
}
+ if (_rotate.has_value()) {
+ LogConfiguration::rotate_all_outputs();
+ any_command = true;
+ }
+
if (!any_command) {
// If no argument was provided, print usage
print_help(LogDiagnosticCommand::name());
--- a/hotspot/src/share/vm/logging/logDiagnosticCommand.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -43,6 +43,7 @@
DCmdArgument<char *> _decorators;
DCmdArgument<bool> _disable;
DCmdArgument<bool> _list;
+ DCmdArgument<bool> _rotate;
public:
LogDiagnosticCommand(outputStream* output, bool heap_allocated);
@@ -55,7 +56,7 @@
}
static const char* description() {
- return "Lists, enables, disables or changes a log output configuration.";
+ return "Lists current log configuration, enables/disables/configures a log output, or rotates all logs.";
}
// Used by SecurityManager. This DCMD requires ManagementPermission = control.
--- a/hotspot/src/share/vm/logging/logFileOutput.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/logging/logFileOutput.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -155,12 +155,7 @@
int written = LogFileStreamOutput::write(decorations, msg);
_current_size += written;
- if (should_rotate()) {
- MutexLockerEx ml(&_rotation_lock, true /* no safepoint check */);
- if (should_rotate()) {
- rotate();
- }
- }
+ rotate(false);
return written;
}
@@ -182,7 +177,14 @@
}
}
-void LogFileOutput::rotate() {
+void LogFileOutput::rotate(bool force) {
+
+ if (!should_rotate(force)) {
+ return;
+ }
+
+ MutexLockerEx ml(&_rotation_lock, true /* no safepoint check */);
+
// Archive the current log file
archive();
--- a/hotspot/src/share/vm/logging/logFileOutput.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/logging/logFileOutput.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -58,13 +58,13 @@
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;
+ bool should_rotate(bool force) {
+ return is_rotatable() &&
+ (force || (_rotate_size > 0 && _current_size >= _rotate_size));
}
public:
@@ -73,6 +73,12 @@
virtual bool initialize(const char* options);
virtual int write(const LogDecorations& decorations, const char* msg);
+ virtual bool is_rotatable() {
+ return LogConfiguration::is_post_initialized() && (_file_count > 0);
+ }
+
+ virtual void rotate(bool force);
+
virtual const char* name() const {
return _name;
}
--- a/hotspot/src/share/vm/logging/logOutput.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/logging/logOutput.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -75,6 +75,14 @@
virtual const char* name() const = 0;
virtual bool initialize(const char* options) = 0;
virtual int write(const LogDecorations &decorations, const char* msg) = 0;
+
+ virtual bool is_rotatable() {
+ return false;
+ }
+
+ virtual void rotate(bool force) {
+ // Do nothing by default.
+ }
};
#endif // SHARE_VM_LOGGING_LOGOUTPUT_HPP
--- a/hotspot/src/share/vm/logging/logTag.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/logging/logTag.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -31,13 +31,14 @@
// (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(classinit) \
LOG_TAG(defaultmethods) \
LOG_TAG(gc) \
LOG_TAG(logging) \
LOG_TAG(safepoint) \
LOG_TAG(vmoperation)
-#define PREFIX_LOG_TAG(T) (LogTag::T)
+#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.
@@ -46,7 +47,7 @@
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))
+#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.
@@ -62,7 +63,7 @@
enum type {
__NO_TAG,
-#define LOG_TAG(name) name,
+#define LOG_TAG(name) _##name,
LOG_TAG_LIST
#undef LOG_TAG
Count
--- a/hotspot/src/share/vm/memory/allocation.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/memory/allocation.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -790,7 +790,7 @@
ReallocMark::ReallocMark() {
#ifdef ASSERT
- Thread *thread = ThreadLocalStorage::get_thread_slow();
+ Thread *thread = Thread::current();
_nesting = thread->resource_area()->nesting();
#endif
}
--- a/hotspot/src/share/vm/memory/filemap.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/memory/filemap.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/classLoader.hpp"
+#include "classfile/compactHashtable.inline.hpp"
#include "classfile/sharedClassUtil.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
--- a/hotspot/src/share/vm/memory/resourceArea.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/memory/resourceArea.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -121,7 +121,7 @@
debug_only(_area->_nesting++;)
assert( _area->_nesting > 0, "must stack allocate RMs" );
#ifdef ASSERT
- Thread* thread = ThreadLocalStorage::thread();
+ Thread* thread = Thread::current_or_null();
if (thread != NULL) {
_thread = thread;
_previous_resource_mark = thread->current_resource_mark();
--- a/hotspot/src/share/vm/oops/arrayKlass.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/arrayKlass.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -71,7 +71,9 @@
return super()->find_field(name, sig, fd);
}
-Method* ArrayKlass::uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const {
+Method* ArrayKlass::uncached_lookup_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode) const {
// There are no methods in an array klass but the super class (Object) has some
assert(super(), "super klass must be present");
// Always ignore overpass methods in superclasses, although technically the
@@ -80,19 +82,18 @@
return super()->uncached_lookup_method(name, signature, Klass::skip_overpass);
}
-ArrayKlass::ArrayKlass(Symbol* name) {
- set_name(name);
-
- set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass());
- set_layout_helper(Klass::_lh_neutral_value);
- set_dimension(1);
- set_higher_dimension(NULL);
- set_lower_dimension(NULL);
+ArrayKlass::ArrayKlass(Symbol* name) :
+ _dimension(1),
+ _higher_dimension(NULL),
+ _lower_dimension(NULL),
// Arrays don't add any new methods, so their vtable is the same size as
// the vtable of klass Object.
- int vtable_size = Universe::base_vtable_size();
- set_vtable_length(vtable_size);
- set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5)
+ _vtable_len(Universe::base_vtable_size()) {
+ set_name(name);
+ set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass());
+ set_layout_helper(Klass::_lh_neutral_value);
+ set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5)
+ TRACE_INIT_ID(this);
}
--- a/hotspot/src/share/vm/oops/arrayKlass.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/arrayKlass.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -82,12 +82,17 @@
Klass* find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const;
// Lookup operations
- Method* uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const;
+ Method* uncached_lookup_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode) const;
- // Casting from Klass*
static ArrayKlass* cast(Klass* k) {
+ return const_cast<ArrayKlass*>(cast(const_cast<const Klass*>(k)));
+ }
+
+ static const ArrayKlass* cast(const Klass* k) {
assert(k->is_array_klass(), "cast to ArrayKlass");
- return static_cast<ArrayKlass*>(k);
+ return static_cast<const ArrayKlass*>(k);
}
GrowableArray<Klass*>* compute_secondary_supers(int num_extra_slots);
--- a/hotspot/src/share/vm/oops/constantPool.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/constantPool.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -60,25 +60,33 @@
return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags);
}
-ConstantPool::ConstantPool(Array<u1>* tags) {
- set_length(tags->length());
- set_tags(NULL);
- set_cache(NULL);
- set_reference_map(NULL);
- set_resolved_references(NULL);
- set_operands(NULL);
- set_pool_holder(NULL);
- set_flags(0);
+#ifdef ASSERT
- // only set to non-zero if constant pool is merged by RedefineClasses
- set_version(0);
+// MetaspaceObj allocation invariant is calloc equivalent memory
+// simple verification of this here (JVM_CONSTANT_Invalid == 0 )
+static bool tag_array_is_zero_initialized(Array<u1>* tags) {
+ assert(tags != NULL, "invariant");
+ const int length = tags->length();
+ for (int index = 0; index < length; ++index) {
+ if (JVM_CONSTANT_Invalid != tags->at(index)) {
+ return false;
+ }
+ }
+ return true;
+}
- // initialize tag array
- int length = tags->length();
- for (int index = 0; index < length; index++) {
- tags->at_put(index, JVM_CONSTANT_Invalid);
- }
- set_tags(tags);
+#endif
+
+ConstantPool::ConstantPool(Array<u1>* tags) :
+ _tags(tags),
+ _length(tags->length()) {
+
+ assert(_tags != NULL, "invariant");
+ assert(tags->length() == _length, "invariant");
+ assert(tag_array_is_zero_initialized(tags), "invariant");
+ assert(0 == _flags, "invariant");
+ assert(0 == version(), "invariant");
+ assert(NULL == _pool_holder, "invariant");
}
void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) {
@@ -466,7 +474,7 @@
}
-Symbol* ConstantPool::klass_name_at(int which) {
+Symbol* ConstantPool::klass_name_at(int which) const {
assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(),
"Corrupted constant pool");
// A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
@@ -497,7 +505,7 @@
return unresolved_string_at(which)->as_C_string();
}
-BasicType ConstantPool::basic_type_for_signature_at(int which) {
+BasicType ConstantPool::basic_type_for_signature_at(int which) const {
return FieldType::basic_type(symbol_at(which));
}
--- a/hotspot/src/share/vm/oops/constantPool.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/constantPool.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -116,7 +116,7 @@
private:
intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); }
- CPSlot slot_at(int which) {
+ CPSlot slot_at(int which) const {
assert(is_within_bounds(which), "index out of bounds");
// Uses volatile because the klass slot changes without a lock.
volatile intptr_t adr = (intptr_t)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which));
@@ -349,7 +349,7 @@
return klass_at_impl(h_this, which, false, THREAD);
}
- Symbol* klass_name_at(int which); // Returns the name, w/o resolving.
+ Symbol* klass_name_at(int which) const; // Returns the name, w/o resolving.
Klass* resolved_klass_at(int which) const { // Used by Compiler
guarantee(tag_at(which).is_klass(), "Corrupted constant pool");
@@ -384,7 +384,7 @@
return *((jdouble*)&tmp);
}
- Symbol* symbol_at(int which) {
+ Symbol* symbol_at(int which) const {
assert(tag_at(which).is_utf8(), "Corrupted constant pool");
return *symbol_at_addr(which);
}
@@ -668,7 +668,7 @@
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)
- BasicType basic_type_for_signature_at(int which);
+ BasicType basic_type_for_signature_at(int which) const;
// Resolve string constants (to prevent allocation during compilation)
void resolve_string_constants(TRAPS) {
--- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -29,6 +29,8 @@
#include "oops/instanceKlass.hpp"
#include "utilities/macros.hpp"
+class ClassFileParser;
+
// An InstanceClassLoaderKlass is a specialization of the InstanceKlass. It does
// not add any field. It is added to walk the dependencies for the class loader
// key that this class loader points to. This is how the loader_data graph is
@@ -38,11 +40,8 @@
class InstanceClassLoaderKlass: public InstanceKlass {
friend class VMStructs;
friend class 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,
- InstanceKlass::_misc_kind_class_loader, rt, access_flags, is_anonymous) {}
+ private:
+ InstanceClassLoaderKlass(const ClassFileParser& parser) : InstanceKlass(parser, InstanceKlass::_misc_kind_class_loader) {}
public:
InstanceClassLoaderKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/classFileParser.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verifier.hpp"
@@ -63,6 +64,7 @@
#include "services/threadService.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/macros.hpp"
+#include "logging/log.hpp"
#ifdef COMPILER1
#include "c1/c1_Compiler.hpp"
#endif
@@ -113,47 +115,57 @@
volatile int InstanceKlass::_total_instanceKlass_count = 0;
-InstanceKlass* InstanceKlass::allocate_instance_klass(
- ClassLoaderData* loader_data,
- int vtable_len,
- int itable_len,
- int static_field_size,
- int nonstatic_oop_map_size,
- ReferenceType rt,
- AccessFlags access_flags,
- Symbol* name,
- Klass* super_klass,
- bool is_anonymous,
- TRAPS) {
-
- int size = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size,
- access_flags.is_interface(), is_anonymous);
+static inline bool is_class_loader(const Symbol* class_name,
+ const ClassFileParser& parser) {
+ assert(class_name != NULL, "invariant");
+
+ if (class_name == vmSymbols::java_lang_ClassLoader()) {
+ return true;
+ }
+
+ if (SystemDictionary::ClassLoader_klass_loaded()) {
+ const Klass* const super_klass = parser.super_klass();
+ if (super_klass != NULL) {
+ if (super_klass->is_subtype_of(SystemDictionary::ClassLoader_klass())) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) {
+ const int size = InstanceKlass::size(parser.vtable_size(),
+ parser.itable_size(),
+ nonstatic_oop_map_size(parser.total_oop_map_count()),
+ parser.is_interface(),
+ parser.is_anonymous());
+
+ const Symbol* const class_name = parser.class_name();
+ assert(class_name != NULL, "invariant");
+ ClassLoaderData* loader_data = parser.loader_data();
+ assert(loader_data != NULL, "invariant");
+
+ InstanceKlass* ik;
// Allocation
- InstanceKlass* ik;
- if (rt == REF_NONE) {
- if (name == vmSymbols::java_lang_Class()) {
- ik = new (loader_data, size, THREAD) InstanceMirrorKlass(
- vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt,
- access_flags, is_anonymous);
- } else if (name == vmSymbols::java_lang_ClassLoader() ||
- (SystemDictionary::ClassLoader_klass_loaded() &&
- super_klass != NULL &&
- super_klass->is_subtype_of(SystemDictionary::ClassLoader_klass()))) {
- ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(
- vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt,
- access_flags, is_anonymous);
- } else {
- // normal class
- ik = new (loader_data, size, THREAD) InstanceKlass(
- vtable_len, itable_len, static_field_size, nonstatic_oop_map_size,
- InstanceKlass::_misc_kind_other, rt, access_flags, is_anonymous);
+ if (REF_NONE == parser.reference_type()) {
+ if (class_name == vmSymbols::java_lang_Class()) {
+ // mirror
+ ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser);
+ }
+ else if (is_class_loader(class_name, parser)) {
+ // class loader
+ ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser);
}
- } else {
- // reference klass
- ik = new (loader_data, size, THREAD) InstanceRefKlass(
- vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt,
- access_flags, is_anonymous);
+ else {
+ // normal
+ ik = new (loader_data, size, THREAD) InstanceKlass(parser, InstanceKlass::_misc_kind_other);
+ }
+ }
+ else {
+ // reference
+ ik = new (loader_data, size, THREAD) InstanceRefKlass(parser);
}
// Check for pending exception before adding to the loader data and incrementing
@@ -162,17 +174,21 @@
return NULL;
}
+ assert(ik != NULL, "invariant");
+
+ const bool publicize = !parser.is_internal();
+
// Add all classes to our internal class loader list here,
// including classes in the bootstrap (NULL) class loader.
- loader_data->add_class(ik);
-
+ loader_data->add_class(ik, publicize);
Atomic::inc(&_total_instanceKlass_count);
+
return ik;
}
// copy method ordering from resource area to Metaspace
-void InstanceKlass::copy_method_ordering(intArray* m, TRAPS) {
+void InstanceKlass::copy_method_ordering(const intArray* m, TRAPS) {
if (m != NULL) {
// allocate a new array and copy contents (memcpy?)
_method_ordering = MetadataFactory::new_array<int>(class_loader_data(), m->length(), CHECK);
@@ -192,79 +208,23 @@
return vtable_indices;
}
-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) {
- No_Safepoint_Verifier no_safepoint; // until k becomes parsable
-
- int iksize = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size,
- access_flags.is_interface(), is_anonymous);
- set_vtable_length(vtable_len);
- set_itable_length(itable_len);
- set_static_field_size(static_field_size);
- set_nonstatic_oop_map_size(nonstatic_oop_map_size);
- set_access_flags(access_flags);
- _misc_flags = 0; // initialize to zero
- set_kind(kind);
- set_is_anonymous(is_anonymous);
- assert(size() == iksize, "wrong size for object");
-
- set_array_klasses(NULL);
- set_methods(NULL);
- set_method_ordering(NULL);
- set_default_methods(NULL);
- set_default_vtable_indices(NULL);
- set_local_interfaces(NULL);
- set_transitive_interfaces(NULL);
- init_implementor();
- set_fields(NULL, 0);
- set_constants(NULL);
- set_class_loader_data(NULL);
- set_source_file_name_index(0);
- set_source_debug_extension(NULL, 0);
- set_array_name(NULL);
- set_inner_classes(NULL);
- set_static_oop_field_count(0);
- set_nonstatic_field_size(0);
- set_is_marked_dependent(false);
- _dep_context = DependencyContext::EMPTY;
- set_init_state(InstanceKlass::allocated);
- set_init_thread(NULL);
- set_reference_type(rt);
- set_oop_map_cache(NULL);
- set_jni_ids(NULL);
- set_osr_nmethods_head(NULL);
- set_breakpoints(NULL);
- init_previous_versions();
- set_generic_signature_index(0);
- release_set_methods_jmethod_ids(NULL);
- set_annotations(NULL);
- set_jvmti_cached_class_field_map(NULL);
- set_initial_method_idnum(0);
- set_jvmti_cached_class_field_map(NULL);
- set_cached_class_file(NULL);
- set_initial_method_idnum(0);
- set_minor_version(0);
- set_major_version(0);
- NOT_PRODUCT(_verify_count = 0;)
-
- // initialize the non-header words to zero
- intptr_t* p = (intptr_t*)this;
- for (int index = InstanceKlass::header_size(); index < iksize; index++) {
- p[index] = NULL_WORD;
- }
-
- // Set temporary value until parseClassFile updates it with the real instance
- // size.
- set_layout_helper(Klass::instance_layout_helper(0, true));
+InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind) :
+ _static_field_size(parser.static_field_size()),
+ _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
+ _vtable_len(parser.vtable_size()),
+ _itable_len(parser.itable_size()),
+ _reference_type(parser.reference_type()) {
+ set_kind(kind);
+ set_access_flags(parser.access_flags());
+ set_is_anonymous(parser.is_anonymous());
+ set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
+ false));
+
+ assert(NULL == _methods, "underlying memory not zeroed?");
+ assert(is_instance_klass(), "is layout incorrect?");
+ assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
}
-
void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
Array<Method*>* methods) {
if (methods != NULL && methods != Universe::the_empty_method_array() &&
@@ -282,7 +242,7 @@
}
void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data,
- Klass* super_klass,
+ const Klass* super_klass,
Array<Klass*>* local_interfaces,
Array<Klass*>* transitive_interfaces) {
// Only deallocate transitive interfaces if not empty, same as super class
@@ -491,9 +451,9 @@
this_k->set_init_state (fully_initialized);
this_k->fence_and_clear_init_lock();
// trace
- if (TraceClassInitialization) {
+ if (log_is_enabled(Info, classinit)) {
ResourceMark rm(THREAD);
- tty->print_cr("[Initialized %s without side effects]", this_k->external_name());
+ log_info(classinit)("[Initialized %s without side effects]", this_k->external_name());
}
}
}
@@ -1129,10 +1089,12 @@
methodHandle h_method(THREAD, this_k->class_initializer());
assert(!this_k->is_initialized(), "we cannot initialize twice");
- 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)" : "", p2i(this_k()));
+ if (log_is_enabled(Info, classinit)) {
+ ResourceMark rm;
+ outputStream* log = LogHandle(classinit)::info_stream();
+ log->print("%d Initializing ", call_class_initializer_impl_counter++);
+ this_k->name()->print_value_on(log);
+ log->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", p2i(this_k()));
}
if (h_method() != NULL) {
JavaCallArguments args; // No arguments
@@ -1346,10 +1308,12 @@
}
#ifdef ASSERT
-static int linear_search(Array<Method*>* methods, Symbol* name, Symbol* signature) {
- int len = methods->length();
+static int linear_search(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature) {
+ const int len = methods->length();
for (int index = 0; index < len; index++) {
- Method* m = methods->at(index);
+ const Method* const m = methods->at(index);
assert(m->is_method(), "must be method");
if (m->signature() == signature && m->name() == name) {
return index;
@@ -1359,7 +1323,7 @@
}
#endif
-static int binary_search(Array<Method*>* methods, Symbol* name) {
+static int binary_search(const Array<Method*>* methods, const Symbol* name) {
int len = methods->length();
// methods are sorted, so do binary search
int l = 0;
@@ -1381,31 +1345,44 @@
}
// find_method looks up the name/signature in the local methods array
-Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const {
+Method* InstanceKlass::find_method(const Symbol* name,
+ const Symbol* signature) const {
return find_method_impl(name, signature, find_overpass, find_static, find_private);
}
-Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature,
+Method* InstanceKlass::find_method_impl(const Symbol* name,
+ const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode) const {
- return InstanceKlass::find_method_impl(methods(), name, signature, overpass_mode, static_mode, private_mode);
+ return InstanceKlass::find_method_impl(methods(),
+ name,
+ signature,
+ overpass_mode,
+ static_mode,
+ private_mode);
}
// find_instance_method looks up the name/signature in the local methods array
// and skips over static methods
-Method* InstanceKlass::find_instance_method(
- Array<Method*>* methods, Symbol* name, Symbol* signature) {
- Method* meth = InstanceKlass::find_method_impl(methods, name, signature,
- find_overpass, skip_static, find_private);
- assert(((meth == NULL) || !meth->is_static()), "find_instance_method should have skipped statics");
+Method* InstanceKlass::find_instance_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature) {
+ Method* const meth = InstanceKlass::find_method_impl(methods,
+ name,
+ signature,
+ find_overpass,
+ skip_static,
+ find_private);
+ assert(((meth == NULL) || !meth->is_static()),
+ "find_instance_method should have skipped statics");
return meth;
}
// find_instance_method looks up the name/signature in the local methods array
// and skips over static methods
-Method* InstanceKlass::find_instance_method(Symbol* name, Symbol* signature) {
- return InstanceKlass::find_instance_method(methods(), name, signature);
+Method* InstanceKlass::find_instance_method(const Symbol* name, const Symbol* signature) const {
+ return InstanceKlass::find_instance_method(methods(), name, signature);
}
// Find looks up the name/signature in the local methods array
@@ -1413,11 +1390,17 @@
// This returns the first one found
// note that the local methods array can have up to one overpass, one static
// and one instance (private or not) with the same name/signature
-Method* InstanceKlass::find_local_method(Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode,
- StaticLookupMode static_mode,
- PrivateLookupMode private_mode) const {
- return InstanceKlass::find_method_impl(methods(), name, signature, overpass_mode, static_mode, private_mode);
+Method* InstanceKlass::find_local_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode) const {
+ return InstanceKlass::find_method_impl(methods(),
+ name,
+ signature,
+ overpass_mode,
+ static_mode,
+ private_mode);
}
// Find looks up the name/signature in the local methods array
@@ -1425,34 +1408,51 @@
// This returns the first one found
// note that the local methods array can have up to one overpass, one static
// and one instance (private or not) with the same name/signature
-Method* InstanceKlass::find_local_method(Array<Method*>* methods,
- Symbol* name, Symbol* signature,
+Method* InstanceKlass::find_local_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode) {
+ return InstanceKlass::find_method_impl(methods,
+ name,
+ signature,
+ overpass_mode,
+ static_mode,
+ private_mode);
+}
+
+Method* InstanceKlass::find_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature) {
+ return InstanceKlass::find_method_impl(methods,
+ name,
+ signature,
+ find_overpass,
+ find_static,
+ find_private);
+}
+
+Method* InstanceKlass::find_method_impl(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode) {
- return InstanceKlass::find_method_impl(methods, name, signature, overpass_mode, static_mode, private_mode);
-}
-
-
-// find_method looks up the name/signature in the local methods array
-Method* InstanceKlass::find_method(
- Array<Method*>* methods, Symbol* name, Symbol* signature) {
- return InstanceKlass::find_method_impl(methods, name, signature, find_overpass, find_static, find_private);
-}
-
-Method* InstanceKlass::find_method_impl(
- Array<Method*>* methods, Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode, StaticLookupMode static_mode,
- PrivateLookupMode private_mode) {
int hit = find_method_index(methods, name, signature, overpass_mode, static_mode, private_mode);
return hit >= 0 ? methods->at(hit): NULL;
}
-bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static, bool skipping_private) {
- return ((m->signature() == signature) &&
- (!skipping_overpass || !m->is_overpass()) &&
- (!skipping_static || !m->is_static()) &&
- (!skipping_private || !m->is_private()));
+// true if method matches signature and conforms to skipping_X conditions.
+static bool method_matches(const Method* m,
+ const Symbol* signature,
+ bool skipping_overpass,
+ bool skipping_static,
+ bool skipping_private) {
+ return ((m->signature() == signature) &&
+ (!skipping_overpass || !m->is_overpass()) &&
+ (!skipping_static || !m->is_static()) &&
+ (!skipping_private || !m->is_private()));
}
// Used directly for default_methods to find the index into the
@@ -1467,50 +1467,65 @@
// To correctly catch a given method, the search criteria may need
// to explicitly skip the other two. For local instance methods, it
// is often necessary to skip private methods
-int InstanceKlass::find_method_index(
- Array<Method*>* methods, Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode, StaticLookupMode static_mode,
- PrivateLookupMode private_mode) {
- bool skipping_overpass = (overpass_mode == skip_overpass);
- bool skipping_static = (static_mode == skip_static);
- bool skipping_private = (private_mode == skip_private);
- int hit = binary_search(methods, name);
+int InstanceKlass::find_method_index(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode) {
+ const bool skipping_overpass = (overpass_mode == skip_overpass);
+ const bool skipping_static = (static_mode == skip_static);
+ const bool skipping_private = (private_mode == skip_private);
+ const int hit = binary_search(methods, name);
if (hit != -1) {
- Method* m = methods->at(hit);
+ const Method* const m = methods->at(hit);
// Do linear search to find matching signature. First, quick check
// for common case, ignoring overpasses if requested.
- if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return hit;
+ if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) {
+ return hit;
+ }
// search downwards through overloaded methods
int i;
for (i = hit - 1; i >= 0; --i) {
- Method* m = methods->at(i);
+ const Method* const m = methods->at(i);
assert(m->is_method(), "must be method");
- if (m->name() != name) break;
- if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return i;
+ if (m->name() != name) {
+ break;
+ }
+ if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) {
+ return i;
+ }
}
// search upwards
for (i = hit + 1; i < methods->length(); ++i) {
- Method* m = methods->at(i);
+ const Method* const m = methods->at(i);
assert(m->is_method(), "must be method");
- if (m->name() != name) break;
- if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return i;
+ if (m->name() != name) {
+ break;
+ }
+ if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) {
+ return i;
+ }
}
// not found
#ifdef ASSERT
- int index = (skipping_overpass || skipping_static || skipping_private) ? -1 : linear_search(methods, name, signature);
- assert(index == -1, "binary search should have found entry %d", index);
+ const int index = (skipping_overpass || skipping_static || skipping_private) ? -1 :
+ linear_search(methods, name, signature);
+ assert(-1 == index, "binary search should have found entry %d", index);
#endif
}
return -1;
}
-int InstanceKlass::find_method_by_name(Symbol* name, int* end) {
+
+int InstanceKlass::find_method_by_name(const Symbol* name, int* end) const {
return find_method_by_name(methods(), name, end);
}
-int InstanceKlass::find_method_by_name(
- Array<Method*>* methods, Symbol* name, int* end_ptr) {
+int InstanceKlass::find_method_by_name(const Array<Method*>* methods,
+ const Symbol* name,
+ int* end_ptr) {
assert(end_ptr != NULL, "just checking");
int start = binary_search(methods, name);
int end = start + 1;
@@ -1525,11 +1540,17 @@
// uncached_lookup_method searches both the local class methods array and all
// superclasses methods arrays, skipping any overpass methods in superclasses.
-Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const {
+Method* InstanceKlass::uncached_lookup_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode) const {
OverpassLookupMode overpass_local_mode = overpass_mode;
- Klass* klass = const_cast<InstanceKlass*>(this);
+ const Klass* klass = this;
while (klass != NULL) {
- Method* method = InstanceKlass::cast(klass)->find_method_impl(name, signature, overpass_local_mode, find_static, find_private);
+ Method* const method = InstanceKlass::cast(klass)->find_method_impl(name,
+ signature,
+ overpass_local_mode,
+ find_static,
+ find_private);
if (method != NULL) {
return method;
}
@@ -1542,8 +1563,8 @@
#ifdef ASSERT
// search through class hierarchy and return true if this class or
// one of the superclasses was redefined
-bool InstanceKlass::has_redefined_this_or_super() {
- Klass* klass = this;
+bool InstanceKlass::has_redefined_this_or_super() const {
+ const Klass* klass = this;
while (klass != NULL) {
if (InstanceKlass::cast(klass)->has_been_redefined()) {
return true;
@@ -1612,19 +1633,18 @@
return probe;
}
-u2 InstanceKlass::enclosing_method_data(int offset) {
- Array<jushort>* inner_class_list = inner_classes();
+u2 InstanceKlass::enclosing_method_data(int offset) const {
+ const Array<jushort>* const inner_class_list = inner_classes();
if (inner_class_list == NULL) {
return 0;
}
- int length = inner_class_list->length();
+ const int length = inner_class_list->length();
if (length % inner_class_next_offset == 0) {
return 0;
- } else {
- int index = length - enclosing_method_attribute_size;
- assert(offset < enclosing_method_attribute_size, "invalid offset");
- return inner_class_list->at(index + offset);
}
+ const int index = length - enclosing_method_attribute_size;
+ assert(offset < enclosing_method_attribute_size, "invalid offset");
+ return inner_class_list->at(index + offset);
}
void InstanceKlass::set_enclosing_method_indices(u2 class_index,
@@ -2100,7 +2120,7 @@
Atomic::dec(&_total_instanceKlass_count);
}
-void InstanceKlass::set_source_debug_extension(char* array, int length) {
+void InstanceKlass::set_source_debug_extension(const char* array, int length) {
if (array == NULL) {
_source_debug_extension = NULL;
} else {
@@ -2161,26 +2181,42 @@
}
// different verisons of is_same_class_package
-bool InstanceKlass::is_same_class_package(Klass* class2) {
+bool InstanceKlass::is_same_class_package(const Klass* class2) const {
+ const Klass* const class1 = (const Klass* const)this;
+ oop classloader1 = InstanceKlass::cast(class1)->class_loader();
+ const Symbol* const classname1 = class1->name();
+
if (class2->is_objArray_klass()) {
class2 = ObjArrayKlass::cast(class2)->bottom_klass();
}
- oop classloader2 = class2->class_loader();
- Symbol* classname2 = class2->name();
-
- return InstanceKlass::is_same_class_package(class_loader(), name(),
+ oop classloader2;
+ if (class2->is_instance_klass()) {
+ classloader2 = InstanceKlass::cast(class2)->class_loader();
+ } else {
+ assert(class2->is_typeArray_klass(), "should be type array");
+ classloader2 = NULL;
+ }
+ const Symbol* classname2 = class2->name();
+
+ return InstanceKlass::is_same_class_package(classloader1, classname1,
classloader2, classname2);
}
-bool InstanceKlass::is_same_class_package(oop classloader2, Symbol* classname2) {
- return InstanceKlass::is_same_class_package(class_loader(), name(),
- classloader2, classname2);
+bool InstanceKlass::is_same_class_package(oop other_class_loader,
+ const Symbol* other_class_name) const {
+ oop this_class_loader = class_loader();
+ const Symbol* const this_class_name = name();
+
+ return InstanceKlass::is_same_class_package(this_class_loader,
+ this_class_name,
+ other_class_loader,
+ other_class_name);
}
// return true if two classes are in the same package, classloader
// and classname information is enough to determine a class's package
-bool InstanceKlass::is_same_class_package(oop class_loader1, Symbol* class_name1,
- oop class_loader2, Symbol* class_name2) {
+bool InstanceKlass::is_same_class_package(oop class_loader1, const Symbol* class_name1,
+ oop class_loader2, const Symbol* class_name2) {
if (class_loader1 != class_loader2) {
return false;
} else if (class_name1 == class_name2) {
@@ -2259,11 +2295,11 @@
*/
// tell if two classes have the same enclosing class (at package level)
-bool InstanceKlass::is_same_package_member_impl(instanceKlassHandle class1,
- Klass* class2_oop, TRAPS) {
- if (class2_oop == class1()) return true;
- if (!class2_oop->is_instance_klass()) return false;
- instanceKlassHandle class2(THREAD, class2_oop);
+bool InstanceKlass::is_same_package_member_impl(const InstanceKlass* class1,
+ const Klass* class2,
+ TRAPS) {
+ if (class2 == class1) return true;
+ if (!class2->is_instance_klass()) return false;
// must be in same package before we try anything else
if (!class1->is_same_class_package(class2->class_loader(), class2->name()))
@@ -2271,30 +2307,30 @@
// As long as there is an outer1.getEnclosingClass,
// shift the search outward.
- instanceKlassHandle outer1 = class1;
+ const InstanceKlass* outer1 = class1;
for (;;) {
// As we walk along, look for equalities between outer1 and class2.
// Eventually, the walks will terminate as outer1 stops
// at the top-level class around the original class.
bool ignore_inner_is_member;
- Klass* next = outer1->compute_enclosing_class(&ignore_inner_is_member,
- CHECK_false);
+ const Klass* next = outer1->compute_enclosing_class(&ignore_inner_is_member,
+ CHECK_false);
if (next == NULL) break;
- if (next == class2()) return true;
- outer1 = instanceKlassHandle(THREAD, next);
+ if (next == class2) return true;
+ outer1 = InstanceKlass::cast(next);
}
// Now do the same for class2.
- instanceKlassHandle outer2 = class2;
+ const InstanceKlass* outer2 = InstanceKlass::cast(class2);
for (;;) {
bool ignore_inner_is_member;
Klass* next = outer2->compute_enclosing_class(&ignore_inner_is_member,
CHECK_false);
if (next == NULL) break;
// Might as well check the new outer against all available values.
- if (next == class1()) return true;
- if (next == outer1()) return true;
- outer2 = instanceKlassHandle(THREAD, next);
+ if (next == class1) return true;
+ if (next == outer1) return true;
+ outer2 = InstanceKlass::cast(next);
}
// If by this point we have not found an equality between the
@@ -2322,36 +2358,38 @@
return false;
}
-Klass* InstanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, bool* inner_is_member, TRAPS) {
- instanceKlassHandle outer_klass;
+InstanceKlass* InstanceKlass::compute_enclosing_class_impl(const InstanceKlass* k,
+ bool* inner_is_member,
+ TRAPS) {
+ InstanceKlass* outer_klass = NULL;
*inner_is_member = false;
int ooff = 0, noff = 0;
if (find_inner_classes_attr(k, &ooff, &noff, THREAD)) {
constantPoolHandle i_cp(THREAD, k->constants());
if (ooff != 0) {
Klass* ok = i_cp->klass_at(ooff, CHECK_NULL);
- outer_klass = instanceKlassHandle(THREAD, ok);
+ outer_klass = InstanceKlass::cast(ok);
*inner_is_member = true;
}
- if (outer_klass.is_null()) {
+ if (NULL == outer_klass) {
// It may be anonymous; try for that.
int encl_method_class_idx = k->enclosing_method_class_index();
if (encl_method_class_idx != 0) {
Klass* ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL);
- outer_klass = instanceKlassHandle(THREAD, ok);
+ outer_klass = InstanceKlass::cast(ok);
*inner_is_member = false;
}
}
}
// If no inner class attribute found for this class.
- if (outer_klass.is_null()) return NULL;
+ if (NULL == outer_klass) return NULL;
// Throws an exception if outer klass has not declared k as an inner klass
// We need evidence that each klass knows about the other, or else
// the system could allow a spoof of an inner class to gain access rights.
Reflection::check_for_inner_class(outer_klass, k, *inner_is_member, CHECK_NULL);
- return outer_klass();
+ return outer_klass;
}
jint InstanceKlass::compute_modifier_flags(TRAPS) const {
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -54,6 +54,7 @@
// forward declaration for class -- see below for definition
class BreakpointInfo;
+class ClassFileParser;
class DepChange;
class DependencyContext;
class fieldDescriptor;
@@ -112,29 +113,9 @@
friend class CompileReplay;
protected:
- // Constructor
- 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);
+ InstanceKlass(const ClassFileParser& parser, unsigned kind);
+
public:
- static InstanceKlass* allocate_instance_klass(
- ClassLoaderData* loader_data,
- int vtable_len,
- int itable_len,
- int static_field_size,
- int nonstatic_oop_map_size,
- ReferenceType rt,
- AccessFlags access_flags,
- Symbol* name,
- Klass* super_klass,
- bool is_anonymous,
- TRAPS);
-
InstanceKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
// See "The Java Virtual Machine Specification" section 2.16.2-5 for a detailed description
@@ -152,6 +133,7 @@
private:
static volatile int _total_instanceKlass_count;
+ static InstanceKlass* allocate_instance_klass(const ClassFileParser& parser, TRAPS);
protected:
// Annotations for this class
@@ -176,7 +158,7 @@
// the source debug extension for this klass, NULL if not specified.
// Specified as UTF-8 string without terminating zero byte in the classfile,
// it is stored in the instanceklass as a NULL-terminated UTF-8 string
- char* _source_debug_extension;
+ const char* _source_debug_extension;
// Array name derived from this class which needs unreferencing
// if this class is unloaded.
Symbol* _array_name;
@@ -350,7 +332,7 @@
// method ordering
Array<int>* method_ordering() const { return _method_ordering; }
void set_method_ordering(Array<int>* m) { _method_ordering = m; }
- void copy_method_ordering(intArray* m, TRAPS);
+ void copy_method_ordering(const intArray* m, TRAPS);
// default_methods
Array<Method*>* default_methods() const { return _default_methods; }
@@ -416,29 +398,32 @@
bool is_override(const methodHandle& super_method, Handle targetclassloader, Symbol* targetclassname, TRAPS);
// package
- bool is_same_class_package(Klass* class2);
- bool is_same_class_package(oop classloader2, Symbol* classname2);
- static bool is_same_class_package(oop class_loader1, Symbol* class_name1, oop class_loader2, Symbol* class_name2);
+ bool is_same_class_package(const Klass* class2) const;
+ bool is_same_class_package(oop classloader2, const Symbol* classname2) const;
+ static bool is_same_class_package(oop class_loader1,
+ const Symbol* class_name1,
+ oop class_loader2,
+ const Symbol* class_name2);
// find an enclosing class
- Klass* compute_enclosing_class(bool* inner_is_member, TRAPS) {
- instanceKlassHandle self(THREAD, this);
- return compute_enclosing_class_impl(self, inner_is_member, THREAD);
+ InstanceKlass* compute_enclosing_class(bool* inner_is_member, TRAPS) const {
+ return compute_enclosing_class_impl(this, inner_is_member, THREAD);
}
- static Klass* compute_enclosing_class_impl(instanceKlassHandle self,
- bool* inner_is_member, TRAPS);
+ static InstanceKlass* compute_enclosing_class_impl(const InstanceKlass* self,
+ bool* inner_is_member,
+ TRAPS);
// Find InnerClasses attribute for k and return outer_class_info_index & inner_name_index.
static bool find_inner_classes_attr(instanceKlassHandle k,
int* ooff, int* noff, TRAPS);
// tell if two classes have the same enclosing class (at package level)
- bool is_same_package_member(Klass* class2, TRAPS) {
- instanceKlassHandle self(THREAD, this);
- return is_same_package_member_impl(self, class2, THREAD);
+ bool is_same_package_member(const Klass* class2, TRAPS) const {
+ return is_same_package_member_impl(this, class2, THREAD);
}
- static bool is_same_package_member_impl(instanceKlassHandle self,
- Klass* class2, TRAPS);
+ static bool is_same_package_member_impl(const InstanceKlass* self,
+ const Klass* class2,
+ TRAPS);
// initialization state
bool is_loaded() const { return _init_state >= loaded; }
@@ -507,38 +492,44 @@
bool find_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const;
// find a local method (returns NULL if not found)
- Method* find_method(Symbol* name, Symbol* signature) const;
- static Method* find_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
+ Method* find_method(const Symbol* name, const Symbol* signature) const;
+ static Method* find_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature);
// find a local method, but skip static methods
- Method* find_instance_method(Symbol* name, Symbol* signature);
- static Method* find_instance_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
+ Method* find_instance_method(const Symbol* name, const Symbol* signature) const;
+ static Method* find_instance_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature);
// find a local method (returns NULL if not found)
- Method* find_local_method(Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode,
- StaticLookupMode static_mode,
- PrivateLookupMode private_mode) const;
+ Method* find_local_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode) const;
// find a local method from given methods array (returns NULL if not found)
- static Method* find_local_method(Array<Method*>* methods,
- Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode,
- StaticLookupMode static_mode,
- PrivateLookupMode private_mode);
-
- // true if method matches signature and conforms to skipping_X conditions.
- static bool method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static, bool skipping_private);
+ static Method* find_local_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode);
// find a local method index in methods or default_methods (returns -1 if not found)
- static int find_method_index(Array<Method*>* methods,
- Symbol* name, Symbol* signature,
+ static int find_method_index(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode);
// lookup operation (returns NULL if not found)
- Method* uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const;
+ Method* uncached_lookup_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode) const;
// lookup a method in all the interfaces that this class implements
// (returns NULL if not found)
@@ -552,8 +543,9 @@
// found the index to the first method is returned, and 'end' is filled in
// with the index of first non-name-matching method. If no method is found
// -1 is returned.
- int find_method_by_name(Symbol* name, int* end);
- static int find_method_by_name(Array<Method*>* methods, Symbol* name, int* end);
+ int find_method_by_name(const Symbol* name, int* end) const;
+ static int find_method_by_name(const Array<Method*>* methods,
+ const Symbol* name, int* end);
// constant pool
ConstantPool* constants() const { return _constants; }
@@ -575,9 +567,9 @@
return *hk;
}
}
- void set_host_klass(Klass* host) {
+ void set_host_klass(const Klass* host) {
assert(is_anonymous(), "not anonymous");
- Klass** addr = (Klass**)adr_host_klass();
+ const Klass** addr = (const Klass**)adr_host_klass();
assert(addr != NULL, "no reversed space");
if (addr != NULL) {
*addr = host;
@@ -630,8 +622,8 @@
void set_major_version(u2 major_version) { _major_version = major_version; }
// source debug extension
- char* source_debug_extension() const { return _source_debug_extension; }
- void set_source_debug_extension(char* array, int length);
+ const char* source_debug_extension() const { return _source_debug_extension; }
+ void set_source_debug_extension(const char* array, int length);
// symbol unloading support (refcount already added)
Symbol* array_name() { return _array_name; }
@@ -764,8 +756,8 @@
_generic_signature_index = sig_index;
}
- u2 enclosing_method_data(int offset);
- u2 enclosing_method_class_index() {
+ u2 enclosing_method_data(int offset) const;
+ u2 enclosing_method_class_index() const {
return enclosing_method_data(enclosing_method_class_index_offset);
}
u2 enclosing_method_method_index() {
@@ -859,7 +851,7 @@
#ifdef ASSERT
// check whether this class or one of its superclasses was redefined
- bool has_redefined_this_or_super();
+ bool has_redefined_this_or_super() const;
#endif
// Access to the implementor of an interface.
@@ -919,11 +911,14 @@
void array_klasses_do(void f(Klass* k, TRAPS), TRAPS);
bool super_types_do(SuperTypeClosure* blk);
- // Casting from Klass*
static InstanceKlass* cast(Klass* k) {
+ return const_cast<InstanceKlass*>(cast(const_cast<const Klass*>(k)));
+ }
+
+ static const InstanceKlass* cast(const Klass* k) {
assert(k != NULL, "k should not be null");
assert(k->is_instance_klass(), "cast to InstanceKlass");
- return static_cast<InstanceKlass*>(k);
+ return static_cast<const InstanceKlass*>(k);
}
InstanceKlass* java_super() const {
@@ -1032,7 +1027,7 @@
static void deallocate_methods(ClassLoaderData* loader_data,
Array<Method*>* methods);
void static deallocate_interfaces(ClassLoaderData* loader_data,
- Klass* super_klass,
+ const Klass* super_klass,
Array<Klass*>* local_interfaces,
Array<Klass*>* transitive_interfaces);
@@ -1203,12 +1198,15 @@
Klass* array_klass_impl(bool or_null, TRAPS);
// find a local method (returns NULL if not found)
- Method* find_method_impl(Symbol* name, Symbol* signature,
+ Method* find_method_impl(const Symbol* name,
+ const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode) const;
- static Method* find_method_impl(Array<Method*>* methods,
- Symbol* name, Symbol* signature,
+
+ static Method* find_method_impl(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode);
--- a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -31,6 +31,8 @@
#include "runtime/handles.hpp"
#include "utilities/macros.hpp"
+class ClassFileParser;
+
// An InstanceMirrorKlass is a specialized InstanceKlass for
// java.lang.Class instances. These instances are special because
// they contain the static fields of the class in addition to the
@@ -46,10 +48,7 @@
private:
static int _offset_of_static_fields;
- // 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,
- InstanceKlass::_misc_kind_mirror, rt, access_flags, is_anonymous) {}
+ InstanceMirrorKlass(const ClassFileParser& parser) : InstanceKlass(parser, InstanceKlass::_misc_kind_mirror) {}
public:
InstanceMirrorKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
--- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -29,6 +29,8 @@
#include "oops/instanceKlass.hpp"
#include "utilities/macros.hpp"
+class ClassFileParser;
+
// An InstanceRefKlass is a specialized InstanceKlass for Java
// classes that are subclasses of java/lang/ref/Reference.
//
@@ -48,11 +50,8 @@
class InstanceRefKlass: public InstanceKlass {
friend class 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,
- InstanceKlass::_misc_kind_reference, rt, access_flags, is_anonymous) {}
+ private:
+ InstanceRefKlass(const ClassFileParser& parser) : InstanceKlass(parser, InstanceKlass::_misc_kind_reference) {}
public:
InstanceRefKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
--- a/hotspot/src/share/vm/oops/klass.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/klass.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -136,7 +136,7 @@
return NULL;
}
-Method* Klass::uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const {
+Method* Klass::uncached_lookup_method(const Symbol* name, const Symbol* signature, OverpassLookupMode overpass_mode) const {
#ifdef ASSERT
tty->print_cr("Error: uncached_lookup_method called on a klass oop."
" Likely error: reflection method does not correctly"
@@ -151,45 +151,18 @@
MetaspaceObj::ClassType, THREAD);
}
-Klass::Klass() {
- Klass* k = this;
-
- // Preinitialize supertype information.
- // A later call to initialize_supers() may update these settings:
- set_super(NULL);
- for (juint i = 0; i < Klass::primary_super_limit(); i++) {
- _primary_supers[i] = NULL;
- }
- set_secondary_supers(NULL);
- set_secondary_super_cache(NULL);
- _primary_supers[0] = k;
- set_super_check_offset(in_bytes(primary_supers_offset()));
-
- // The constructor is used from init_self_patching_vtbl_list,
- // which doesn't zero out the memory before calling the constructor.
- // Need to set the field explicitly to not hit an assert that the field
- // should be NULL before setting it.
- _java_mirror = NULL;
+// "Normal" instantiation is preceeded by a MetaspaceObj allocation
+// which zeros out memory - calloc equivalent.
+// The constructor is also used from init_self_patching_vtbl_list,
+// which doesn't zero out the memory before calling the constructor.
+// Need to set the _java_mirror field explicitly to not hit an assert that the field
+// should be NULL before setting it.
+Klass::Klass() : _prototype_header(markOopDesc::prototype()),
+ _shared_class_path_index(-1),
+ _java_mirror(NULL) {
- set_modifier_flags(0);
- set_layout_helper(Klass::_lh_neutral_value);
- set_name(NULL);
- AccessFlags af;
- af.set_flags(0);
- set_access_flags(af);
- set_subklass(NULL);
- set_next_sibling(NULL);
- set_next_link(NULL);
- TRACE_INIT_ID(this);
-
- set_prototype_header(markOopDesc::prototype());
- set_biased_lock_revocation_count(0);
- set_last_biased_lock_bulk_revocation_time(0);
-
- // The klass doesn't have any references at this point.
- clear_modified_oops();
- clear_accumulated_modified_oops();
- _shared_class_path_index = -1;
+ _primary_supers[0] = this;
+ set_super_check_offset(in_bytes(primary_supers_offset()));
}
jint Klass::array_layout_helper(BasicType etype) {
--- a/hotspot/src/share/vm/oops/klass.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/klass.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -410,9 +410,9 @@
// lookup operation for MethodLookupCache
friend class MethodLookupCache;
virtual Klass* find_field(Symbol* name, Symbol* signature, fieldDescriptor* fd) const;
- virtual Method* uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const;
+ virtual Method* uncached_lookup_method(const Symbol* name, const Symbol* signature, OverpassLookupMode overpass_mode) const;
public:
- Method* lookup_method(Symbol* name, Symbol* signature) const {
+ Method* lookup_method(const Symbol* name, const Symbol* signature) const {
return uncached_lookup_method(name, signature, find_overpass);
}
--- a/hotspot/src/share/vm/oops/klassVtable.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -54,7 +54,7 @@
// treated as any other public method in C for method over-ride purposes.
void klassVtable::compute_vtable_size_and_num_mirandas(
int* vtable_length_ret, int* num_new_mirandas,
- GrowableArray<Method*>* all_mirandas, Klass* super,
+ GrowableArray<Method*>* all_mirandas, const Klass* super,
Array<Method*>* methods, AccessFlags class_flags,
Handle classloader, Symbol* classname, Array<Klass*>* local_interfaces,
TRAPS) {
@@ -548,7 +548,7 @@
// However, the vtable entries are filled in at link time, and therefore
// the superclass' vtable may not yet have been filled in.
bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
- Klass* super,
+ const Klass* super,
Handle classloader,
Symbol* classname,
AccessFlags class_flags,
@@ -605,7 +605,7 @@
ResourceMark rm;
Symbol* name = target_method()->name();
Symbol* signature = target_method()->signature();
- Klass* k = super;
+ const Klass* k = super;
Method* super_method = NULL;
InstanceKlass *holder = NULL;
Method* recheck_method = NULL;
@@ -640,7 +640,7 @@
// miranda method in the super, whose entry it should re-use.
// Actually, to handle cases that javac would not generate, we need
// this check for all access permissions.
- InstanceKlass *sk = InstanceKlass::cast(super);
+ const InstanceKlass *sk = InstanceKlass::cast(super);
if (sk->has_miranda_methods()) {
if (sk->lookup_method_in_all_interfaces(name, signature, Klass::find_defaults) != NULL) {
return false; // found a matching miranda; we do not need a new entry
@@ -734,7 +734,7 @@
// Part of the Miranda Rights in the US mean that if you do not have
// an attorney one will be appointed for you.
bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods,
- Array<Method*>* default_methods, Klass* super) {
+ Array<Method*>* default_methods, const Klass* super) {
if (m->is_static() || m->is_private() || m->is_overpass()) {
return false;
}
@@ -760,7 +760,7 @@
// Overpasses may or may not exist for supers for pass 1,
// they should have been created for pass 2 and later.
- for (Klass* cursuper = super; cursuper != NULL; cursuper = cursuper->super())
+ for (const Klass* cursuper = super; cursuper != NULL; cursuper = cursuper->super())
{
if (InstanceKlass::cast(cursuper)->find_local_method(name, signature,
Klass::find_overpass, Klass::skip_static, Klass::skip_private) != NULL) {
@@ -782,7 +782,7 @@
void klassVtable::add_new_mirandas_to_lists(
GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas,
Array<Method*>* current_interface_methods, Array<Method*>* class_methods,
- Array<Method*>* default_methods, Klass* super) {
+ Array<Method*>* default_methods, const Klass* super) {
// iterate thru the current interface's method to see if it a miranda
int num_methods = current_interface_methods->length();
@@ -802,7 +802,7 @@
if (!is_duplicate) { // we don't want duplicate miranda entries in the vtable
if (is_miranda(im, class_methods, default_methods, super)) { // is it a miranda at all?
- InstanceKlass *sk = InstanceKlass::cast(super);
+ const InstanceKlass *sk = InstanceKlass::cast(super);
// check if it is a duplicate of a super's miranda
if (sk->lookup_method_in_all_interfaces(im->name(), im->signature(), Klass::find_defaults) == NULL) {
new_mirandas->append(im);
@@ -817,7 +817,8 @@
void klassVtable::get_mirandas(GrowableArray<Method*>* new_mirandas,
GrowableArray<Method*>* all_mirandas,
- Klass* super, Array<Method*>* class_methods,
+ const Klass* super,
+ Array<Method*>* class_methods,
Array<Method*>* default_methods,
Array<Klass*>* local_interfaces) {
assert((new_mirandas->length() == 0) , "current mirandas must be 0");
--- a/hotspot/src/share/vm/oops/klassVtable.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/klassVtable.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -84,11 +84,16 @@
bool is_initialized();
// computes vtable length (in words) and the number of miranda methods
- static void compute_vtable_size_and_num_mirandas(
- int* vtable_length, int* num_new_mirandas,
- GrowableArray<Method*>* all_mirandas, Klass* super,
- Array<Method*>* methods, AccessFlags class_flags, Handle classloader,
- Symbol* classname, Array<Klass*>* local_interfaces, TRAPS);
+ static void compute_vtable_size_and_num_mirandas(int* vtable_length,
+ int* num_new_mirandas,
+ GrowableArray<Method*>* all_mirandas,
+ const Klass* super,
+ Array<Method*>* methods,
+ AccessFlags class_flags,
+ Handle classloader,
+ Symbol* classname,
+ Array<Klass*>* local_interfaces,
+ TRAPS);
#if INCLUDE_JVMTI
// RedefineClasses() API support:
@@ -116,7 +121,12 @@
int initialize_from_super(KlassHandle super);
int index_of(Method* m, int len) const; // same as index_of, but search only up to len
void put_method_at(Method* m, int index);
- static bool needs_new_vtable_entry(methodHandle m, Klass* super, Handle classloader, Symbol* classname, AccessFlags access_flags, TRAPS);
+ static bool needs_new_vtable_entry(methodHandle m,
+ const Klass* super,
+ Handle classloader,
+ Symbol* classname,
+ AccessFlags access_flags,
+ TRAPS);
bool update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len, int default_index, bool checkconstraints, TRAPS);
InstanceKlass* find_transitive_override(InstanceKlass* initialsuper, methodHandle target_method, int vtable_index,
@@ -126,17 +136,18 @@
bool is_miranda_entry_at(int i);
int fill_in_mirandas(int initialized);
static bool is_miranda(Method* m, Array<Method*>* class_methods,
- Array<Method*>* default_methods, Klass* super);
+ Array<Method*>* default_methods, const Klass* super);
static void add_new_mirandas_to_lists(
GrowableArray<Method*>* new_mirandas,
GrowableArray<Method*>* all_mirandas,
Array<Method*>* current_interface_methods,
Array<Method*>* class_methods,
Array<Method*>* default_methods,
- Klass* super);
+ const Klass* super);
static void get_mirandas(
GrowableArray<Method*>* new_mirandas,
- GrowableArray<Method*>* all_mirandas, Klass* super,
+ GrowableArray<Method*>* all_mirandas,
+ const Klass* super,
Array<Method*>* class_methods,
Array<Method*>* default_methods,
Array<Klass*>* local_interfaces);
--- a/hotspot/src/share/vm/oops/method.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/method.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1320,12 +1320,12 @@
return newm;
}
-vmSymbols::SID Method::klass_id_for_intrinsics(Klass* holder) {
+vmSymbols::SID Method::klass_id_for_intrinsics(const Klass* holder) {
// if loader is not the default loader (i.e., != NULL), we can't know the intrinsics
// because we are not loading from core libraries
// exception: the AES intrinsics come from lib/ext/sunjce_provider.jar
// which does not use the class default class loader so we check for its loader here
- InstanceKlass* ik = InstanceKlass::cast(holder);
+ const InstanceKlass* ik = InstanceKlass::cast(holder);
if ((ik->class_loader() != NULL) && !SystemDictionary::is_ext_class_loader(ik->class_loader())) {
return vmSymbols::NO_SID; // regardless of name, no intrinsics here
}
--- a/hotspot/src/share/vm/oops/method.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/method.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -84,7 +84,7 @@
_running_emcp = 1 << 6,
_intrinsic_candidate = 1 << 7
};
- u1 _flags;
+ mutable u1 _flags;
#ifndef PRODUCT
int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging)
@@ -784,12 +784,12 @@
// Helper routines for intrinsic_id() and vmIntrinsics::method().
void init_intrinsic_id(); // updates from _none if a match
- static vmSymbols::SID klass_id_for_intrinsics(Klass* holder);
+ static vmSymbols::SID klass_id_for_intrinsics(const Klass* holder);
- bool jfr_towrite() {
+ bool jfr_towrite() const {
return (_flags & _jfr_towrite) != 0;
}
- void set_jfr_towrite(bool x) {
+ void set_jfr_towrite(bool x) const {
_flags = x ? (_flags | _jfr_towrite) : (_flags & ~_jfr_towrite);
}
--- a/hotspot/src/share/vm/oops/objArrayKlass.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -89,10 +89,14 @@
virtual Klass* array_klass_impl(bool or_null, TRAPS);
public:
- // Casting from Klass*
+
static ObjArrayKlass* cast(Klass* k) {
+ return const_cast<ObjArrayKlass*>(cast(const_cast<const Klass*>(k)));
+ }
+
+ static const ObjArrayKlass* cast(const Klass* k) {
assert(k->is_objArray_klass(), "cast to ObjArrayKlass");
- return static_cast<ObjArrayKlass*>(k);
+ return static_cast<const ObjArrayKlass*>(k);
}
// Sizing
--- a/hotspot/src/share/vm/oops/oopsHierarchy.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/oopsHierarchy.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -35,7 +35,7 @@
assert (CheckUnhandledOops, "should only call when CheckUnhandledOops");
if (!Universe::is_fully_initialized()) return;
// This gets expensive, which is why checking unhandled oops is on a switch.
- Thread* t = ThreadLocalStorage::thread();
+ Thread* t = Thread::current_or_null();
if (t != NULL && t->is_Java_thread()) {
frame fr = os::current_frame();
// This points to the oop creator, I guess current frame points to caller
@@ -48,7 +48,7 @@
assert (CheckUnhandledOops, "should only call when CheckUnhandledOops");
if (!Universe::is_fully_initialized()) return;
// This gets expensive, which is why checking unhandled oops is on a switch.
- Thread* t = ThreadLocalStorage::thread();
+ Thread* t = Thread::current_or_null();
if (t != NULL && t->is_Java_thread()) {
t->unhandled_oops()->unregister_unhandled_oop(this);
}
--- a/hotspot/src/share/vm/oops/symbol.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/symbol.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -148,8 +148,8 @@
int size() { return size(utf8_length()); }
// Returns the largest size symbol we can safely hold.
- static int max_length() { return max_symbol_length; }
- unsigned identity_hash() {
+ static int max_length() { return max_symbol_length; }
+ unsigned identity_hash() const {
unsigned addr_bits = (unsigned)((uintptr_t)this >> (LogMinObjAlignmentInBytes + 3));
return ((unsigned)_identity_hash & 0xffff) |
((addr_bits ^ (_length << 8) ^ (( _body[0] << 8) | _body[1])) << 16);
@@ -197,7 +197,7 @@
// Three-way compare for sorting; returns -1/0/1 if receiver is </==/> than arg
// note that the ordering is not alfabetical
- inline int fast_compare(Symbol* other) const;
+ inline int fast_compare(const Symbol* other) const;
// Returns receiver converted to null-terminated UTF-8 string; string is
// allocated in resource area, or in the char buffer provided by caller.
@@ -246,7 +246,7 @@
// what order it defines, as long as it is a total, time-invariant order
// Since Symbol*s are in C_HEAP, their relative order in memory never changes,
// so use address comparison for speed
-int Symbol::fast_compare(Symbol* other) const {
+int Symbol::fast_compare(const Symbol* other) const {
return (((uintptr_t)this < (uintptr_t)other) ? -1
: ((uintptr_t)this == (uintptr_t) other) ? 0 : 1);
}
--- a/hotspot/src/share/vm/oops/typeArrayKlass.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/oops/typeArrayKlass.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -120,10 +120,13 @@
virtual Klass* array_klass_impl(bool or_null, TRAPS);
public:
- // Casting from Klass*
static TypeArrayKlass* cast(Klass* k) {
+ return const_cast<TypeArrayKlass*>(cast(const_cast<const Klass*>(k)));
+ }
+
+ static const TypeArrayKlass* cast(const Klass* k) {
assert(k->is_typeArray_klass(), "cast to TypeArrayKlass");
- return static_cast<TypeArrayKlass*>(k);
+ return static_cast<const TypeArrayKlass*>(k);
}
// Naming
--- a/hotspot/src/share/vm/precompiled/precompiled.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/precompiled/precompiled.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -203,7 +203,6 @@
# include "runtime/stubRoutines.hpp"
# include "runtime/synchronizer.hpp"
# include "runtime/thread.hpp"
-# include "runtime/threadLocalStorage.hpp"
# include "runtime/timer.hpp"
# include "runtime/unhandledOops.hpp"
# include "runtime/vframe.hpp"
--- a/hotspot/src/share/vm/prims/jni.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/jni.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -26,6 +26,7 @@
#include "precompiled.hpp"
#include "ci/ciReplay.hpp"
#include "classfile/altHashing.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
@@ -326,7 +327,7 @@
class_name = SymbolTable::new_symbol(name, CHECK_NULL);
}
ResourceMark rm(THREAD);
- ClassFileStream st((u1*) buf, bufLen, NULL);
+ ClassFileStream st((u1*)buf, bufLen, NULL, ClassFileStream::verify);
Handle class_loader (THREAD, JNIHandles::resolve(loaderRef));
if (UsePerfData && !class_loader.is_null()) {
@@ -338,9 +339,11 @@
ClassLoader::sync_JNIDefineClassLockFreeCounter()->inc();
}
}
- Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader,
- Handle(), &st, true,
- CHECK_NULL);
+ Klass* k = SystemDictionary::resolve_from_stream(class_name,
+ class_loader,
+ Handle(),
+ &st,
+ CHECK_NULL);
if (TraceClassResolution && k != NULL) {
trace_class_resolution(k);
@@ -3933,7 +3936,6 @@
#if INCLUDE_ALL_GCS
run_unit_test(TestOldFreeSpaceCalculation_test());
run_unit_test(TestG1BiasedArray_test());
- run_unit_test(HeapRegionRemSet::test_prt());
run_unit_test(TestBufferingOopClosure_test());
run_unit_test(TestCodeCacheRemSet_test());
if (UseG1GC) {
@@ -4175,7 +4177,7 @@
}
*/
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null();
if (t != NULL) {
// If the thread has been attached this operation is a no-op
*(JNIEnv**)penv = ((JavaThread*) t)->jni_environment();
@@ -4190,10 +4192,8 @@
// initializing the Java level thread object. Hence, the correct state must
// be set in order for the Safepoint code to deal with it correctly.
thread->set_thread_state(_thread_in_vm);
- // Must do this before initialize_thread_local_storage
thread->record_stack_base_and_size();
-
- thread->initialize_thread_local_storage();
+ thread->initialize_thread_current();
if (!os::create_attached_thread(thread)) {
delete thread;
@@ -4300,8 +4300,8 @@
JNIWrapper("DetachCurrentThread");
- // If the thread has been deattacted the operations is a no-op
- if (ThreadLocalStorage::thread() == NULL) {
+ // If the thread has already been detached the operation is a no-op
+ if (Thread::current_or_null() == NULL) {
HOTSPOT_JNI_DETACHCURRENTTHREAD_RETURN(JNI_OK);
return JNI_OK;
}
@@ -4358,7 +4358,7 @@
#define JVMPI_VERSION_1_2 ((jint)0x10000003)
#endif // !JVMPI_VERSION_1
- Thread* thread = ThreadLocalStorage::thread();
+ Thread* thread = Thread::current_or_null();
if (thread != NULL && thread->is_Java_thread()) {
if (Threads::is_supported_jni_version_including_1_1(version)) {
*(JNIEnv**)penv = ((JavaThread*) thread)->jni_environment();
--- a/hotspot/src/share/vm/prims/jniCheck.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/jniCheck.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -87,9 +87,9 @@
#define JNI_ENTRY_CHECKED(result_type, header) \
extern "C" { \
result_type JNICALL header { \
- JavaThread* thr = (JavaThread*)ThreadLocalStorage::get_thread_slow();\
+ JavaThread* thr = (JavaThread*) Thread::current_or_null(); \
if (thr == NULL || !thr->is_Java_thread()) { \
- tty->print_cr("%s", fatal_using_jnienv_in_nonjava); \
+ tty->print_cr("%s", fatal_using_jnienv_in_nonjava); \
os::abort(true); \
} \
JNIEnv* xenv = thr->jni_environment(); \
--- a/hotspot/src/share/vm/prims/jvm.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/jvm.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/javaAssertions.hpp"
#include "classfile/javaClasses.inline.hpp"
@@ -965,7 +966,7 @@
}
ResourceMark rm(THREAD);
- ClassFileStream st((u1*) buf, len, (char *)source);
+ ClassFileStream st((u1*)buf, len, source, ClassFileStream::verify);
Handle class_loader (THREAD, JNIHandles::resolve(loader));
if (UsePerfData) {
is_lock_held_by_thread(class_loader,
@@ -973,9 +974,11 @@
THREAD);
}
Handle protection_domain (THREAD, JNIHandles::resolve(pd));
- Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader,
- protection_domain, &st,
- true, CHECK_NULL);
+ Klass* k = SystemDictionary::resolve_from_stream(class_name,
+ class_loader,
+ protection_domain,
+ &st,
+ CHECK_NULL);
if (TraceClassResolution && k != NULL) {
trace_class_resolution(k);
@@ -3719,3 +3722,7 @@
info->is_attachable = AttachListener::is_attach_supported();
}
JVM_END
+
+JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name))
+ return os::get_signal_number(name);
+JVM_END
--- a/hotspot/src/share/vm/prims/jvmtiEnter.xsl Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiEnter.xsl Wed Jul 05 21:09:54 2017 +0200
@@ -494,7 +494,7 @@
}</xsl:text>
<xsl:text>
- Thread* this_thread = (Thread*)ThreadLocalStorage::thread(); </xsl:text>
+ Thread* this_thread = Thread::current_or_null(); </xsl:text>
<xsl:apply-templates select="." mode="transition"/>
</xsl:when>
@@ -528,7 +528,7 @@
</xsl:if>
<xsl:text> return JVMTI_ERROR_WRONG_PHASE;
}
- Thread* this_thread = (Thread*)ThreadLocalStorage::thread(); </xsl:text>
+ Thread* this_thread = Thread::current_or_null(); </xsl:text>
<xsl:apply-templates select="." mode="transition"/>
</xsl:if>
</xsl:otherwise>
@@ -558,7 +558,7 @@
<xsl:choose>
<xsl:when test="count(@callbacksafe)=0 or not(contains(@callbacksafe,'safe'))">
<xsl:text> if (Threads::number_of_threads() != 0) {
- Thread* this_thread = (Thread*)ThreadLocalStorage::thread();</xsl:text>
+ Thread* this_thread = Thread::current_or_null();</xsl:text>
</xsl:when>
<xsl:otherwise>
@@ -567,7 +567,7 @@
if (Threads::number_of_threads() == 0) {
transition = false;
} else {
- this_thread = (Thread*)ThreadLocalStorage::thread();
+ this_thread = Thread::current_or_null();
transition = ((this_thread != NULL) && !this_thread->is_VM_thread() && !this_thread->is_ConcurrentGC_thread());
}
if (transition) {</xsl:text>
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -2577,7 +2577,7 @@
if (!k->is_instance_klass()) {
return JVMTI_ERROR_ABSENT_INFORMATION;
}
- char* sde = InstanceKlass::cast(k)->source_debug_extension();
+ const char* sde = InstanceKlass::cast(k)->source_debug_extension();
NULL_CHECK(sde, JVMTI_ERROR_ABSENT_INFORMATION);
{
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -374,7 +374,7 @@
}
if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
- JavaThread* current_thread = (JavaThread*) ThreadLocalStorage::thread();
+ JavaThread* current_thread = JavaThread::current();
// transition code: native to VM
ThreadInVMfromNative __tiv(current_thread);
VM_ENTRY_BASE(jvmtiEnv*, JvmtiExport::get_jvmti_interface, current_thread)
@@ -1901,7 +1901,7 @@
// Collect all the vm internally allocated objects which are visible to java world
void JvmtiExport::record_vm_internal_object_allocation(oop obj) {
- Thread* thread = ThreadLocalStorage::thread();
+ Thread* thread = Thread::current_or_null();
if (thread != NULL && thread->is_Java_thread()) {
// Can not take safepoint here.
No_Safepoint_Verifier no_sfpt;
@@ -2436,7 +2436,7 @@
if (!JvmtiExport::should_post_vm_object_alloc()) {
return;
}
- Thread* thread = ThreadLocalStorage::thread();
+ Thread* thread = Thread::current_or_null();
if (thread != NULL && thread->is_Java_thread()) {
JavaThread* current_thread = (JavaThread*)thread;
JvmtiThreadState *state = current_thread->jvmti_thread_state();
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verifier.hpp"
@@ -977,8 +978,10 @@
the_class->external_name(), _class_load_kind,
os::available_memory() >> 10));
- ClassFileStream st((u1*) _class_defs[i].class_bytes,
- _class_defs[i].class_byte_count, (char *)"__VM_RedefineClasses__");
+ ClassFileStream st((u1*)_class_defs[i].class_bytes,
+ _class_defs[i].class_byte_count,
+ "__VM_RedefineClasses__",
+ ClassFileStream::verify);
// Parse the stream.
Handle the_class_loader(THREAD, the_class->class_loader());
--- a/hotspot/src/share/vm/prims/jvmtiUtil.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiUtil.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, 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
@@ -79,7 +79,7 @@
if (Threads::number_of_threads() == 0) {
return JvmtiUtil::single_threaded_resource_area();
}
- thread = ThreadLocalStorage::thread();
+ thread = Thread::current_or_null();
if (thread == NULL) {
return JvmtiUtil::single_threaded_resource_area();
}
--- a/hotspot/src/share/vm/prims/unsafe.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/prims/unsafe.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/vmSymbols.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/objArrayOop.inline.hpp"
@@ -997,7 +998,9 @@
cp_patches_h = objArrayHandle(THREAD, (objArrayOop)p);
}
- KlassHandle host_klass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(host_class)));
+ const Klass* host_klass = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(host_class));
+ assert(host_klass != NULL, "invariant");
+
const char* host_source = host_klass->external_name();
Handle host_loader(THREAD, host_klass->class_loader());
Handle host_domain(THREAD, host_klass->protection_domain());
@@ -1016,15 +1019,21 @@
}
}
- ClassFileStream st(class_bytes, class_bytes_length, (char*) host_source);
+ ClassFileStream st(class_bytes,
+ class_bytes_length,
+ host_source,
+ ClassFileStream::verify);
instanceKlassHandle anon_klass;
{
Symbol* no_class_name = NULL;
Klass* anonk = SystemDictionary::parse_stream(no_class_name,
- host_loader, host_domain,
- &st, host_klass, cp_patches,
- CHECK_NULL);
+ host_loader,
+ host_domain,
+ &st,
+ host_klass,
+ cp_patches,
+ CHECK_NULL);
if (anonk == NULL) return NULL;
anon_klass = instanceKlassHandle(THREAD, anonk);
}
--- a/hotspot/src/share/vm/runtime/arguments.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1949,12 +1949,9 @@
if (FLAG_IS_DEFAULT(GCTimeRatio) || GCTimeRatio == 0) {
// In G1, we want the default GC overhead goal to be higher than
- // say in PS. So we set it here to 10%. Otherwise the heap might
- // be expanded more aggressively than we would like it to. In
- // fact, even 10% seems to not be high enough in some cases
- // (especially small GC stress tests that the main thing they do
- // is allocation). We might consider increase it further.
- FLAG_SET_DEFAULT(GCTimeRatio, 9);
+ // it is for PS, or the heap might be expanded too aggressively.
+ // We set it here to ~8%.
+ FLAG_SET_DEFAULT(GCTimeRatio, 12);
}
if (PrintGCDetails && Verbose) {
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -223,7 +223,7 @@
#define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type
// the "name" argument must be a string literal
-#define INITIAL_CONSTRAINTS_SIZE 69
+#define INITIAL_CONSTRAINTS_SIZE 72
GrowableArray<CommandLineFlagConstraint*>* CommandLineFlagConstraintList::_constraints = NULL;
CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse;
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -31,6 +31,7 @@
#include "runtime/commandLineFlagRangeList.hpp"
#include "runtime/globals.hpp"
#include "runtime/globals_extension.hpp"
+#include "runtime/thread.inline.hpp"
#include "utilities/defaultStream.hpp"
#if INCLUDE_ALL_GCS
@@ -506,6 +507,19 @@
return Flag::SUCCESS;
}
+// To avoid an overflow by 'align_size_up(value, alignment)'.
+static Flag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) {
+ size_t aligned_max = ((max_uintx - alignment) & ~(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;
+}
+
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;
@@ -519,16 +533,7 @@
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;
+ return MaxSizeForAlignment(name, value, heap_alignment, verbose);
}
Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) {
@@ -544,6 +549,29 @@
return status;
}
+Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) {
+ // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value.
+ // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx.
+ if (UseCompressedOops && FLAG_IS_ERGO(MaxHeapSize) && (value > (max_uintx - MaxHeapSize))) {
+ CommandLineError::print(verbose,
+ "HeapBaseMinAddress (" SIZE_FORMAT ") or MaxHeapSize (" SIZE_FORMAT ") is too large. "
+ "Sum of them must be less than or equal to maximum of size_t (" SIZE_FORMAT ")\n",
+ value, MaxHeapSize, max_uintx);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+
+ return MaxSizeForHeapAlignment("HeapBaseMinAddress", value, verbose);
+}
+
+Flag::Error NUMAInterleaveGranularityConstraintFunc(size_t value, bool verbose) {
+ if (UseNUMA && UseNUMAInterleaving) {
+ size_t min_interleave_granularity = UseLargePages ? os::large_page_size() : os::vm_allocation_granularity();
+ return MaxSizeForAlignment("NUMAInterleaveGranularity", value, min_interleave_granularity, verbose);
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) {
#ifdef _LP64
#if INCLUDE_ALL_GCS
@@ -596,6 +624,24 @@
return Flag::SUCCESS;
}
+// We will protect overflow from ThreadLocalAllocBuffer::record_slow_allocation(),
+// so AfterMemoryInit type is enough to check.
+Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) {
+ if (UseTLAB) {
+ size_t refill_waste_limit = Thread::current()->tlab().refill_waste_limit();
+
+ // Compare with 'max_uintx' as ThreadLocalAllocBuffer::_refill_waste_limit is 'size_t'.
+ if (refill_waste_limit > (max_uintx - value)) {
+ CommandLineError::print(verbose,
+ "TLABWasteIncrement (" UINTX_FORMAT ") must be "
+ "less than or equal to ergonomic TLAB waste increment maximum size(" SIZE_FORMAT ")\n",
+ value, (max_uintx - refill_waste_limit));
+ 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()))) {
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -67,9 +67,12 @@
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 HeapBaseMinAddressConstraintFunc(size_t value, bool verbose);
+Flag::Error NUMAInterleaveGranularityConstraintFunc(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 TLABWasteIncrementConstraintFunc(uintx 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);
--- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -250,6 +250,9 @@
void emit_range_intx(const char* name, intx min, intx max) {
CommandLineFlagRangeList::add(new CommandLineFlagRange_intx(name, min, max));
}
+void emit_range_uint(const char* name, uint min, uint max) {
+ CommandLineFlagRangeList::add(new CommandLineFlagRange_uint(name, min, max));
+}
void emit_range_uintx(const char* name, uintx min, uintx max) {
CommandLineFlagRangeList::add(new CommandLineFlagRange_uintx(name, min, max));
}
@@ -279,7 +282,7 @@
// Generate func argument to pass into emit_range_xxx functions
#define EMIT_RANGE_CHECK(a, b) , a, b
-#define INITIAL_RANGES_SIZE 320
+#define INITIAL_RANGES_SIZE 379
GrowableArray<CommandLineFlagRange*>* CommandLineFlagRangeList::_ranges = NULL;
// Check the ranges of all flags that have them
--- a/hotspot/src/share/vm/runtime/deoptimization.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -571,6 +571,23 @@
thread->dec_in_deopt_handler();
}
+// Moved from cpu directories because none of the cpus has callee save values.
+// If a cpu implements callee save values, move this to deoptimization_<cpu>.cpp.
+void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) {
+
+ // This code is sort of the equivalent of C2IAdapter::setup_stack_frame back in
+ // the days we had adapter frames. When we deoptimize a situation where a
+ // compiled caller calls a compiled caller will have registers it expects
+ // to survive the call to the callee. If we deoptimize the callee the only
+ // way we can restore these registers is to have the oldest interpreter
+ // frame that we create restore these values. That is what this routine
+ // will accomplish.
+
+ // At the moment we have modified c2 to not have any callee save registers
+ // so this problem does not exist and this routine is just a place holder.
+
+ assert(f->is_interpreted_frame(), "must be interpreted");
+}
// Return BasicType of value being returned
JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_mode))
--- a/hotspot/src/share/vm/runtime/globals.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -25,7 +25,6 @@
#ifndef SHARE_VM_RUNTIME_GLOBALS_HPP
#define SHARE_VM_RUNTIME_GLOBALS_HPP
-#include <float.h>
#include "utilities/debug.hpp"
#include <float.h> // for DBL_MAX
@@ -625,9 +624,6 @@
notproduct(bool, CheckCompressedOops, true, \
"Generate checks in encoding/decoding code in debug VM") \
\
- product_pd(size_t, HeapBaseMinAddress, \
- "OS specific low limit for heap base address") \
- \
product(uintx, HeapSearchSteps, 3 PPC64_ONLY(+17), \
"Heap allocation steps through preferred address regions to find" \
" where it can allocate the heap. Number of steps to take per " \
@@ -692,6 +688,8 @@
\
product(size_t, NUMAInterleaveGranularity, 2*M, \
"Granularity to use for NUMA interleaving on Windows OS") \
+ range(os::vm_allocation_granularity(), max_uintx) \
+ constraint(NUMAInterleaveGranularityConstraintFunc,AfterErgo) \
\
product(bool, ForceNUMA, false, \
"Force NUMA optimizations on single-node/UMA systems") \
@@ -704,6 +702,7 @@
\
product(size_t, NUMASpaceResizeRate, 1*G, \
"Do not reallocate more than this amount per collection") \
+ range(0, max_uintx) \
\
product(bool, UseAdaptiveNUMAChunkSizing, true, \
"Enable adaptive chunk sizing for NUMA") \
@@ -713,6 +712,7 @@
\
product(uintx, NUMAPageScanRate, 256, \
"Maximum number of pages to include in the page scan procedure") \
+ range(0, max_uintx) \
\
product_pd(bool, NeedsDeoptSuspend, \
"True for register window machines (sparc/ia64)") \
@@ -733,9 +733,11 @@
\
product(size_t, LargePageSizeInBytes, 0, \
"Large page size (0 to let VM choose the page size)") \
+ range(0, max_uintx) \
\
product(size_t, LargePageHeapSizeThreshold, 128*M, \
"Use large pages if maximum heap is at least this big") \
+ range(0, max_uintx) \
\
product(bool, ForceTimeHighResolution, false, \
"Using high time resolution (for Win32 only)") \
@@ -1421,6 +1423,13 @@
range(500, max_intx) \
constraint(BiasedLockingDecayTimeFunc,AfterErgo) \
\
+ product(bool, ExitOnOutOfMemoryError, false, \
+ "JVM exits on the first occurrence of an out-of-memory error") \
+ \
+ product(bool, CrashOnOutOfMemoryError, false, \
+ "JVM aborts, producing an error log and core/mini dump, on the " \
+ "first occurrence of an out-of-memory error") \
+ \
/* tracing */ \
\
develop(bool, StressRewriter, false, \
@@ -1449,9 +1458,6 @@
develop(bool, TraceBytecodes, false, \
"Trace bytecode execution") \
\
- develop(bool, TraceClassInitialization, false, \
- "Trace class initialization") \
- \
product(bool, TraceExceptions, false, \
"Trace exceptions") \
\
@@ -1529,9 +1535,11 @@
product(uintx, HeapMaximumCompactionInterval, 20, \
"How often should we maximally compact the heap (not allowing " \
"any dead space)") \
+ range(0, max_uintx) \
\
product(uintx, HeapFirstMaximumCompactionCount, 3, \
"The collection count for the first maximum compaction") \
+ range(0, max_uintx) \
\
product(bool, UseMaximumCompactionOnSystemGC, true, \
"Use maximum compaction in the Parallel Old garbage collector " \
@@ -1613,6 +1621,7 @@
diagnostic(uintx, GCLockerRetryAllocationCount, 2, \
"Number of times to retry allocations when " \
"blocked by the GC locker") \
+ range(0, max_uintx) \
\
product(bool, UseCMSBestFit, true, \
"Use CMS best fit allocation strategy") \
@@ -1667,6 +1676,7 @@
\
product(uintx, ParGCDesiredObjsFromOverflowList, 20, \
"The desired number of objects to claim from the overflow list") \
+ range(0, max_uintx) \
\
diagnostic(uintx, ParGCStridesPerThread, 2, \
"The number of strides per worker thread that we divide up the " \
@@ -1720,6 +1730,7 @@
product(uintx, CMSOldPLABReactivityFactor, 2, \
"The gain in the feedback loop for on-the-fly PLAB resizing " \
"during a scavenge") \
+ range(1, max_uintx) \
\
product(bool, AlwaysPreTouch, false, \
"Force all freshly committed pages to be pre-touched") \
@@ -1748,6 +1759,7 @@
product(uintx, CMS_FLSPadding, 1, \
"The multiple of deviation from mean to use for buffering " \
"against volatility in free list demand") \
+ range(0, max_juint) \
\
product(uintx, FLSCoalescePolicy, 2, \
"CMS: aggressiveness level for coalescing, increasing " \
@@ -1796,10 +1808,12 @@
product(uintx, CMS_SweepPadding, 1, \
"The multiple of deviation from mean to use for buffering " \
"against volatility in inter-sweep duration") \
+ range(0, max_juint) \
\
product(uintx, CMS_SweepTimerThresholdMillis, 10, \
"Skip block flux-rate sampling for an epoch unless inter-sweep " \
"duration exceeds this threshold in milliseconds") \
+ range(0, max_uintx) \
\
product(bool, CMSClassUnloadingEnabled, true, \
"Whether class unloading enabled when using CMS GC") \
@@ -1807,6 +1821,7 @@
product(uintx, CMSClassUnloadingMaxInterval, 0, \
"When CMS class unloading is enabled, the maximum CMS cycle " \
"count for which classes may not be unloaded") \
+ range(0, max_uintx) \
\
product(uintx, CMSIndexedFreeListReplenish, 4, \
"Replenish an indexed free list with this number of chunks") \
@@ -1840,6 +1855,7 @@
\
product(uintx, CMSMaxAbortablePrecleanLoops, 0, \
"Maximum number of abortable preclean iterations, if > 0") \
+ range(0, max_uintx) \
\
product(intx, CMSMaxAbortablePrecleanTime, 5000, \
"Maximum time in abortable preclean (in milliseconds)") \
@@ -1847,6 +1863,7 @@
\
product(uintx, CMSAbortablePrecleanMinWorkPerIteration, 100, \
"Nominal minimum work per abortable preclean iteration") \
+ range(0, max_uintx) \
\
manageable(intx, CMSAbortablePrecleanWaitMillis, 100, \
"Time that we sleep between iterations when not given " \
@@ -1934,6 +1951,7 @@
\
product(size_t, CMSScheduleRemarkEdenSizeThreshold, 2*M, \
"If Eden size is below this, do not try to schedule remark") \
+ range(0, max_uintx) \
\
product(uintx, CMSScheduleRemarkEdenPenetration, 50, \
"The Eden occupancy percentage (0-100) at which " \
@@ -1963,6 +1981,7 @@
\
manageable(intx, CMSWaitDuration, 2000, \
"Time in milliseconds that CMS thread waits for young GC") \
+ range(min_jint, max_jint) \
\
develop(uintx, CMSCheckInterval, 1000, \
"Interval in milliseconds that CMS thread checks if it " \
@@ -2164,6 +2183,7 @@
product(size_t, ErgoHeapSizeLimit, 0, \
"Maximum ergonomically set heap size (in bytes); zero means use " \
"MaxRAM / MaxRAMFraction") \
+ range(0, max_uintx) \
\
product(uintx, MaxRAMFraction, 4, \
"Maximum fraction (1/n) of real memory used for maximum heap " \
@@ -2188,6 +2208,7 @@
\
product(uintx, AutoGCSelectPauseMillis, 5000, \
"Automatic GC selection pause threshold in milliseconds") \
+ range(0, max_uintx) \
\
product(bool, UseAdaptiveSizePolicy, true, \
"Use adaptive generation sizing policies") \
@@ -2220,12 +2241,14 @@
\
product(uintx, AdaptiveSizePolicyInitializingSteps, 20, \
"Number of steps where heuristics is used before data is used") \
+ range(0, max_uintx) \
\
develop(uintx, AdaptiveSizePolicyReadyThreshold, 5, \
"Number of collections before the adaptive sizing is started") \
\
product(uintx, AdaptiveSizePolicyOutputInterval, 0, \
"Collection interval for printing information; zero means never") \
+ range(0, max_uintx) \
\
product(bool, UseAdaptiveSizePolicyFootprintGoal, true, \
"Use adaptive minimum footprint as a goal") \
@@ -2240,12 +2263,15 @@
\
product(uintx, PausePadding, 1, \
"How much buffer to keep for pause time") \
+ range(0, max_juint) \
\
product(uintx, PromotedPadding, 3, \
"How much buffer to keep for promotion failure") \
+ range(0, max_juint) \
\
product(uintx, SurvivorPadding, 3, \
"How much buffer to keep for survivor overflow") \
+ range(0, max_juint) \
\
product(uintx, ThresholdTolerance, 10, \
"Allowed collection cost difference between generations") \
@@ -2254,6 +2280,7 @@
product(uintx, AdaptiveSizePolicyCollectionCostMargin, 50, \
"If collection costs are within margin, reduce both by full " \
"delta") \
+ range(0, 100) \
\
product(uintx, YoungGenerationSizeIncrement, 20, \
"Adaptive size percentage change in young generation") \
@@ -2292,9 +2319,11 @@
product(uintx, MaxGCMinorPauseMillis, max_uintx, \
"Adaptive size policy maximum GC minor pause time goal " \
"in millisecond") \
+ range(0, max_uintx) \
\
product(uintx, GCTimeRatio, 99, \
"Adaptive size policy application time to GC time ratio") \
+ range(0, max_juint) \
\
product(uintx, AdaptiveSizeDecrementScaleFactor, 4, \
"Adaptive size scale down factor for shrinking") \
@@ -2305,6 +2334,7 @@
\
product(uintx, AdaptiveSizeMajorGCDecayTimeScale, 10, \
"Time scale over which major costs decay") \
+ range(0, max_uintx) \
\
product(uintx, MinSurvivorRatio, 3, \
"Minimum ratio of young generation/survivor space size") \
@@ -2312,9 +2342,11 @@
\
product(uintx, InitialSurvivorRatio, 8, \
"Initial ratio of young generation/survivor space size") \
+ range(0, max_uintx) \
\
product(size_t, BaseFootPrintEstimate, 256*M, \
"Estimate of footprint other than Java Heap") \
+ range(0, max_uintx) \
\
product(bool, UseGCOverheadLimit, true, \
"Use policy to limit of proportion of time spent in GC " \
@@ -2339,12 +2371,15 @@
\
product(intx, PrefetchCopyIntervalInBytes, -1, \
"How far ahead to prefetch destination area (<= 0 means off)") \
+ range(-1, max_jint) \
\
product(intx, PrefetchScanIntervalInBytes, -1, \
"How far ahead to prefetch scan area (<= 0 means off)") \
+ range(-1, max_jint) \
\
product(intx, PrefetchFieldsAhead, -1, \
"How many fields ahead to prefetch in oop scan (<= 0 means off)") \
+ range(-1, max_jint) \
\
diagnostic(bool, VerifySilently, false, \
"Do not print the verification progress") \
@@ -2392,6 +2427,7 @@
\
diagnostic(uintx, CPUForCMSThread, 0, \
"When BindCMSThreadToCPU is true, the CPU to bind CMS thread to") \
+ range(0, max_juint) \
\
product(bool, BindGCTaskThreadsToCPUs, false, \
"Bind GCTaskThreads to CPUs if possible") \
@@ -2401,14 +2437,17 @@
\
product(uintx, ProcessDistributionStride, 4, \
"Stride through processors when distributing processes") \
+ range(0, max_juint) \
\
product(uintx, CMSCoordinatorYieldSleepCount, 10, \
"Number of times the coordinator GC thread will sleep while " \
"yielding before giving up and resuming GC") \
+ range(0, max_juint) \
\
product(uintx, CMSYieldSleepCount, 0, \
"Number of times a GC thread (minus the coordinator) " \
"will sleep while yielding before giving up and resuming GC") \
+ range(0, max_juint) \
\
/* gc tracing */ \
manageable(bool, PrintGC, false, \
@@ -2557,10 +2596,12 @@
product(uintx, NumberOfGCLogFiles, 0, \
"Number of gclog files in rotation " \
"(default: 0, no rotation)") \
+ range(0, max_uintx) \
\
product(size_t, GCLogFileSize, 8*K, \
"GC log file size, requires UseGCLogFileRotation. " \
"Set to 0 to only trigger rotation via jcmd") \
+ range(0, max_uintx) \
\
/* JVMTI heap profiling */ \
\
@@ -3328,6 +3369,7 @@
\
product(size_t, OldSize, ScaleForWordSize(4*M), \
"Initial tenured generation size (in bytes)") \
+ range(0, max_uintx) \
\
product(size_t, NewSize, ScaleForWordSize(1*M), \
"Initial new generation size (in bytes)") \
@@ -3336,10 +3378,16 @@
product(size_t, MaxNewSize, max_uintx, \
"Maximum new generation size (in bytes), max_uintx means set " \
"ergonomically") \
+ range(0, max_uintx) \
+ \
+ product_pd(size_t, HeapBaseMinAddress, \
+ "OS specific low limit for heap base address") \
+ constraint(HeapBaseMinAddressConstraintFunc,AfterErgo) \
\
product(size_t, PretenureSizeThreshold, 0, \
"Maximum size in bytes of objects allocated in DefNew " \
"generation; zero means no maximum") \
+ range(0, max_uintx) \
\
product(size_t, MinTLABSize, 2*K, \
"Minimum allowed TLAB size (in bytes)") \
@@ -3371,10 +3419,12 @@
\
product(uintx, TLABRefillWasteFraction, 64, \
"Maximum TLAB waste at a refill (internal fragmentation)") \
- range(1, max_uintx) \
+ range(1, max_juint) \
\
product(uintx, TLABWasteIncrement, 4, \
"Increment allowed waste at slow allocation") \
+ range(0, max_jint) \
+ constraint(TLABWasteIncrementConstraintFunc,AfterMemoryInit) \
\
product(uintx, SurvivorRatio, 8, \
"Ratio of eden/survivor space size") \
@@ -3388,6 +3438,7 @@
product_pd(size_t, NewSizeThreadIncrease, \
"Additional size added to desired new generation size per " \
"non-daemon thread (in bytes)") \
+ range(0, max_uintx) \
\
product_pd(size_t, MetaspaceSize, \
"Initial size of Metaspaces (in bytes)") \
@@ -3423,9 +3474,11 @@
\
product(size_t, MinHeapDeltaBytes, ScaleForWordSize(128*K), \
"The minimum change in heap space due to GC (in bytes)") \
+ range(0, max_uintx) \
\
product(size_t, MinMetaspaceExpansion, ScaleForWordSize(256*K), \
"The minimum expansion of Metaspace (in bytes)") \
+ range(0, max_uintx) \
\
product(uintx, MaxMetaspaceFreeRatio, 70, \
"The maximum percentage of Metaspace free after GC to avoid " \
@@ -3441,13 +3494,16 @@
\
product(size_t, MaxMetaspaceExpansion, ScaleForWordSize(4*M), \
"The maximum expansion of Metaspace without full GC (in bytes)") \
+ range(0, max_uintx) \
\
product(uintx, QueuedAllocationWarningCount, 0, \
"Number of times an allocation that queues behind a GC " \
"will retry before printing a warning") \
+ range(0, max_uintx) \
\
diagnostic(uintx, VerifyGCStartAt, 0, \
"GC invoke count where +VerifyBefore/AfterGC kicks in") \
+ range(0, max_uintx) \
\
diagnostic(intx, VerifyGCLevel, 0, \
"Generation level at which to start +VerifyBefore/AfterGC") \
@@ -3485,15 +3541,18 @@
\
product(intx, PrintCMSStatistics, 0, \
"Statistics for CMS") \
+ range(0, 2) \
\
product(bool, PrintCMSInitiationStatistics, false, \
"Statistics for initiating a CMS collection") \
\
product(intx, PrintFLSStatistics, 0, \
"Statistics for CMS' FreeListSpace") \
+ range(0, 2) \
\
product(intx, PrintFLSCensus, 0, \
"Census for CMS' FreeListSpace") \
+ range(0, 1) \
\
develop(uintx, GCExpandToAllocateDelayMillis, 0, \
"Delay between expansion and allocation (in milliseconds)") \
@@ -3520,6 +3579,7 @@
product(uintx, GCDrainStackTargetSize, 64, \
"Number of entries we will try to leave on the stack " \
"during parallel gc") \
+ range(0, max_juint) \
\
/* stack parameters */ \
product_pd(intx, StackYellowPages, \
--- a/hotspot/src/share/vm/runtime/init.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/init.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "code/codeCacheExtensions.hpp"
#include "code/icBuffer.hpp"
#include "gc/shared/collectedHeap.hpp"
--- a/hotspot/src/share/vm/runtime/interfaceSupport.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/interfaceSupport.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -32,7 +32,6 @@
#include "runtime/interfaceSupport.hpp"
#include "runtime/orderAccess.inline.hpp"
#include "runtime/os.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
#include "runtime/vframe.hpp"
#include "utilities/preserveException.hpp"
--- a/hotspot/src/share/vm/runtime/interfaceSupport.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/interfaceSupport.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -562,7 +562,7 @@
#define JVM_ENTRY_NO_ENV(result_type, header) \
extern "C" { \
result_type JNICALL header { \
- JavaThread* thread = (JavaThread*)ThreadLocalStorage::thread(); \
+ JavaThread* thread = JavaThread::current(); \
ThreadInVMfromNative __tiv(thread); \
debug_only(VMNativeEntryWrapper __vew;) \
VM_ENTRY_BASE(result_type, header, thread)
--- a/hotspot/src/share/vm/runtime/java.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/java.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -512,10 +512,10 @@
}
void vm_exit(int code) {
- Thread* thread = ThreadLocalStorage::is_initialized() ?
- ThreadLocalStorage::get_thread_slow() : NULL;
+ Thread* thread =
+ ThreadLocalStorage::is_initialized() ? Thread::current_or_null() : NULL;
if (thread == NULL) {
- // we have serious problems -- just exit
+ // very early initialization failure -- just exit
vm_direct_exit(code);
}
@@ -551,8 +551,7 @@
// Calling 'exit_globals()' will disable thread-local-storage and cause all
// kinds of assertions to trigger in debug mode.
if (is_init_completed()) {
- Thread* thread = ThreadLocalStorage::is_initialized() ?
- ThreadLocalStorage::get_thread_slow() : NULL;
+ Thread* thread = Thread::current_or_null();
if (thread != NULL && thread->is_Java_thread()) {
// We are leaving the VM, set state to native (in case any OS exit
// handlers call back to the VM)
@@ -606,7 +605,7 @@
// If there are exceptions on this thread it must be cleared
// first and here. Any future calls to EXCEPTION_MARK requires
// that no pending exceptions exist.
- Thread *THREAD = Thread::current();
+ Thread *THREAD = Thread::current(); // can't be NULL
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
}
--- a/hotspot/src/share/vm/runtime/mutex.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/mutex.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2014, 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
@@ -1035,10 +1035,10 @@
Exeunt:
assert(ILocked(), "invariant");
assert(_owner == NULL, "invariant");
- // This can potentially be called by non-java Threads. Thus, the ThreadLocalStorage
+ // This can potentially be called by non-java Threads. Thus, the Thread::current_or_null()
// might return NULL. Don't call set_owner since it will break on an NULL owner
// Consider installing a non-null "ANON" distinguished value instead of just NULL.
- _owner = ThreadLocalStorage::thread();
+ _owner = Thread::current_or_null();
return;
}
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -27,7 +27,6 @@
#include "runtime/os.inline.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/thread.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
#include "runtime/vmThread.hpp"
// Mutexes used in the VM (see comment in mutexLocker.hpp):
--- a/hotspot/src/share/vm/runtime/os.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -420,28 +420,6 @@
}
#endif
}
- static jboolean onLoaded = JNI_FALSE;
- if (onLoaded) {
- // We may have to wait to fire OnLoad until TLS is initialized.
- if (ThreadLocalStorage::is_initialized()) {
- // The JNI_OnLoad handling is normally done by method load in
- // java.lang.ClassLoader$NativeLibrary, but the VM loads the base library
- // explicitly so we have to check for JNI_OnLoad as well
- const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
- JNI_OnLoad_t JNI_OnLoad = CAST_TO_FN_PTR(
- JNI_OnLoad_t, dll_lookup(_native_java_library, onLoadSymbols[0]));
- if (JNI_OnLoad != NULL) {
- JavaThread* thread = JavaThread::current();
- ThreadToNativeFromVM ttn(thread);
- HandleMark hm(thread);
- jint ver = (*JNI_OnLoad)(&main_vm, NULL);
- onLoaded = JNI_TRUE;
- if (!Threads::is_supported_jni_version_including_1_1(ver)) {
- vm_exit_during_initialization("Unsupported JNI version");
- }
- }
- }
- }
return _native_java_library;
}
@@ -574,7 +552,7 @@
// exists and has crash protection.
WatcherThread *wt = WatcherThread::watcher_thread();
if (wt != NULL && wt->has_crash_protection()) {
- Thread* thread = ThreadLocalStorage::get_thread_slow();
+ Thread* thread = Thread::current_or_null();
if (thread == wt) {
assert(!wt->has_crash_protection(),
"Can't malloc with crash protection from WatcherThread");
--- a/hotspot/src/share/vm/runtime/os.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -642,6 +642,9 @@
// returns NULL if exception_code is not an OS exception/signal.
static const char* exception_name(int exception_code, char* buf, size_t buflen);
+ // Returns the signal number (e.g. 11) for a given signal name (SIGSEGV).
+ static int get_signal_number(const char* signal_name);
+
// Returns native Java library, loads if necessary
static void* native_java_library();
@@ -667,12 +670,6 @@
static jlong current_file_offset(int fd);
static jlong seek_to_file_offset(int fd, jlong offset);
- // Thread Local Storage
- static int allocate_thread_local_storage();
- static void thread_local_storage_at_put(int index, void* value);
- static void* thread_local_storage_at(int index);
- static void free_thread_local_storage(int index);
-
// Retrieve native stack frames.
// Parameter:
// stack: an array to storage stack pointers.
--- a/hotspot/src/share/vm/runtime/reflection.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/reflection.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -46,7 +46,7 @@
#include "runtime/signature.hpp"
#include "runtime/vframe.hpp"
-static void trace_class_resolution(Klass* to_class) {
+static void trace_class_resolution(const Klass* to_class) {
ResourceMark rm;
int line_number = -1;
const char * source_file = NULL;
@@ -300,23 +300,23 @@
}
}
-
-Klass* Reflection::basic_type_mirror_to_arrayklass(oop basic_type_mirror, TRAPS) {
+static Klass* basic_type_mirror_to_arrayklass(oop basic_type_mirror, TRAPS) {
assert(java_lang_Class::is_primitive(basic_type_mirror), "just checking");
BasicType type = java_lang_Class::primitive_type(basic_type_mirror);
if (type == T_VOID) {
THROW_0(vmSymbols::java_lang_IllegalArgumentException());
- } else {
+ }
+ else {
return Universe::typeArrayKlassObj(type);
}
}
-
-oop Reflection:: basic_type_arrayklass_to_mirror(Klass* basic_type_arrayklass, TRAPS) {
+#ifdef ASSERT
+static oop basic_type_arrayklass_to_mirror(Klass* basic_type_arrayklass, TRAPS) {
BasicType type = TypeArrayKlass::cast(basic_type_arrayklass)->element_type();
return Universe::java_mirror(type);
}
-
+#endif
arrayOop Reflection::reflect_new_array(oop element_mirror, jint length, TRAPS) {
if (element_mirror == NULL) {
@@ -410,8 +410,51 @@
return result;
}
+static bool under_host_klass(const InstanceKlass* ik, const Klass* host_klass) {
+ DEBUG_ONLY(int inf_loop_check = 1000 * 1000 * 1000);
+ for (;;) {
+ const Klass* hc = (const Klass*)ik->host_klass();
+ if (hc == NULL) return false;
+ if (hc == host_klass) return true;
+ ik = InstanceKlass::cast(hc);
-bool Reflection::verify_class_access(Klass* current_class, Klass* new_class, bool classloader_only) {
+ // There's no way to make a host class loop short of patching memory.
+ // Therefore there cannot be a loop here unless there's another bug.
+ // Still, let's check for it.
+ assert(--inf_loop_check > 0, "no host_klass loop");
+ }
+}
+
+static bool can_relax_access_check_for(const Klass* accessor,
+ const Klass* accessee,
+ bool classloader_only) {
+
+ const InstanceKlass* accessor_ik = InstanceKlass::cast(accessor);
+ const InstanceKlass* accessee_ik = InstanceKlass::cast(accessee);
+
+ // If either is on the other's host_klass chain, access is OK,
+ // because one is inside the other.
+ if (under_host_klass(accessor_ik, accessee) ||
+ under_host_klass(accessee_ik, accessor))
+ return true;
+
+ if ((RelaxAccessControlCheck &&
+ accessor_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION &&
+ accessee_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION) ||
+ (accessor_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION &&
+ accessee_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION)) {
+ return classloader_only &&
+ Verifier::relax_verify_for(accessor_ik->class_loader()) &&
+ accessor_ik->protection_domain() == accessee_ik->protection_domain() &&
+ accessor_ik->class_loader() == accessee_ik->class_loader();
+ }
+
+ return false;
+}
+
+bool Reflection::verify_class_access(const Klass* current_class,
+ const Klass* new_class,
+ bool classloader_only) {
// Verify that current_class can access new_class. If the classloader_only
// flag is set, we automatically allow any accesses in which current_class
// doesn't have a classloader.
@@ -430,49 +473,9 @@
return can_relax_access_check_for(current_class, new_class, classloader_only);
}
-static bool under_host_klass(InstanceKlass* ik, Klass* host_klass) {
- DEBUG_ONLY(int inf_loop_check = 1000 * 1000 * 1000);
- for (;;) {
- Klass* hc = (Klass*) ik->host_klass();
- if (hc == NULL) return false;
- if (hc == host_klass) return true;
- ik = InstanceKlass::cast(hc);
-
- // There's no way to make a host class loop short of patching memory.
- // Therefore there cannot be a loop here unless there's another bug.
- // Still, let's check for it.
- assert(--inf_loop_check > 0, "no host_klass loop");
- }
-}
-
-bool Reflection::can_relax_access_check_for(
- Klass* accessor, Klass* accessee, bool classloader_only) {
- InstanceKlass* accessor_ik = InstanceKlass::cast(accessor);
- InstanceKlass* accessee_ik = InstanceKlass::cast(accessee);
-
- // If either is on the other's host_klass chain, access is OK,
- // because one is inside the other.
- if (under_host_klass(accessor_ik, accessee) ||
- under_host_klass(accessee_ik, accessor))
- return true;
-
- if ((RelaxAccessControlCheck &&
- accessor_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION &&
- accessee_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION) ||
- (accessor_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION &&
- accessee_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION)) {
- return classloader_only &&
- Verifier::relax_verify_for(accessor_ik->class_loader()) &&
- accessor_ik->protection_domain() == accessee_ik->protection_domain() &&
- accessor_ik->class_loader() == accessee_ik->class_loader();
- } else {
- return false;
- }
-}
-
-bool Reflection::verify_field_access(Klass* current_class,
- Klass* resolved_class,
- Klass* field_class,
+bool Reflection::verify_field_access(const Klass* current_class,
+ const Klass* resolved_class,
+ const Klass* field_class,
AccessFlags access,
bool classloader_only,
bool protected_restriction) {
@@ -494,10 +497,10 @@
return true;
}
- Klass* host_class = current_class;
+ const Klass* host_class = current_class;
while (host_class->is_instance_klass() &&
InstanceKlass::cast(host_class)->is_anonymous()) {
- Klass* next_host_class = InstanceKlass::cast(host_class)->host_klass();
+ const Klass* next_host_class = InstanceKlass::cast(host_class)->host_klass();
if (next_host_class == NULL) break;
host_class = next_host_class;
}
@@ -535,16 +538,10 @@
current_class, field_class, classloader_only);
}
-
-bool Reflection::is_same_class_package(Klass* class1, Klass* class2) {
+bool Reflection::is_same_class_package(const Klass* class1, const Klass* class2) {
return InstanceKlass::cast(class1)->is_same_class_package(class2);
}
-bool Reflection::is_same_package_member(Klass* class1, Klass* class2, TRAPS) {
- return InstanceKlass::cast(class1)->is_same_package_member(class2, THREAD);
-}
-
-
// Checks that the 'outer' klass has declared 'inner' as being an inner klass. If not,
// throw an incompatible class change exception
// If inner_is_member, require the inner to be a member of the outer.
@@ -588,38 +585,43 @@
}
// Utility method converting a single SignatureStream element into java.lang.Class instance
+static oop get_mirror_from_signature(methodHandle method,
+ SignatureStream* ss,
+ TRAPS) {
-oop get_mirror_from_signature(methodHandle method, SignatureStream* ss, TRAPS) {
- switch (ss->type()) {
- default:
- assert(ss->type() != T_VOID || ss->at_return_type(), "T_VOID should only appear as return type");
- return java_lang_Class::primitive_mirror(ss->type());
- case T_OBJECT:
- case T_ARRAY:
- Symbol* name = ss->as_symbol(CHECK_NULL);
- oop loader = method->method_holder()->class_loader();
- oop protection_domain = method->method_holder()->protection_domain();
- Klass* k = SystemDictionary::resolve_or_fail(
- name,
- Handle(THREAD, loader),
- Handle(THREAD, protection_domain),
- true, CHECK_NULL);
- if (TraceClassResolution) {
- trace_class_resolution(k);
- }
- return k->java_mirror();
- };
+
+ if (T_OBJECT == ss->type() || T_ARRAY == ss->type()) {
+ Symbol* name = ss->as_symbol(CHECK_NULL);
+ oop loader = method->method_holder()->class_loader();
+ oop protection_domain = method->method_holder()->protection_domain();
+ const Klass* k = SystemDictionary::resolve_or_fail(name,
+ Handle(THREAD, loader),
+ Handle(THREAD, protection_domain),
+ true,
+ CHECK_NULL);
+ if (TraceClassResolution) {
+ trace_class_resolution(k);
+ }
+ return k->java_mirror();
+ }
+
+ assert(ss->type() != T_VOID || ss->at_return_type(),
+ "T_VOID should only appear as return type");
+
+ return java_lang_Class::primitive_mirror(ss->type());
}
-
-objArrayHandle Reflection::get_parameter_types(const methodHandle& method, int parameter_count, oop* return_type, TRAPS) {
+static objArrayHandle get_parameter_types(methodHandle method,
+ int parameter_count,
+ oop* return_type,
+ TRAPS) {
// Allocate array holding parameter types (java.lang.Class instances)
objArrayOop m = oopFactory::new_objArray(SystemDictionary::Class_klass(), parameter_count, CHECK_(objArrayHandle()));
- objArrayHandle mirrors (THREAD, m);
+ objArrayHandle mirrors(THREAD, m);
int index = 0;
// Collect parameter types
ResourceMark rm(THREAD);
- Symbol* signature = method->signature();
+ Symbol* signature = method->signature();
SignatureStream ss(signature);
while (!ss.at_return_type()) {
oop mirror = get_mirror_from_signature(method, &ss, CHECK_(objArrayHandle()));
@@ -635,22 +637,22 @@
return mirrors;
}
-objArrayHandle Reflection::get_exception_types(const methodHandle& method, TRAPS) {
+static objArrayHandle get_exception_types(methodHandle method, TRAPS) {
return method->resolved_checked_exceptions(THREAD);
}
-
-Handle Reflection::new_type(Symbol* signature, KlassHandle k, TRAPS) {
+static Handle new_type(Symbol* signature, KlassHandle k, TRAPS) {
// Basic types
BasicType type = vmSymbols::signature_type(signature);
if (type != T_OBJECT) {
return Handle(THREAD, Universe::java_mirror(type));
}
- Klass* result = SystemDictionary::resolve_or_fail(signature,
- Handle(THREAD, k->class_loader()),
- Handle(THREAD, k->protection_domain()),
- true, CHECK_(Handle()));
+ Klass* result =
+ SystemDictionary::resolve_or_fail(signature,
+ Handle(THREAD, k->class_loader()),
+ Handle(THREAD, k->protection_domain()),
+ true, CHECK_(Handle()));
if (TraceClassResolution) {
trace_class_resolution(result);
@@ -686,7 +688,7 @@
Handle name = Handle(THREAD, name_oop);
if (name == NULL) return NULL;
- int modifiers = method->access_flags().as_int() & JVM_RECOGNIZED_METHOD_MODIFIERS;
+ const int modifiers = method->access_flags().as_int() & JVM_RECOGNIZED_METHOD_MODIFIERS;
Handle mh = java_lang_reflect_Method::create(CHECK_NULL);
@@ -738,7 +740,7 @@
objArrayHandle exception_types = get_exception_types(method, CHECK_NULL);
if (exception_types.is_null()) return NULL;
- int modifiers = method->access_flags().as_int() & JVM_RECOGNIZED_METHOD_MODIFIERS;
+ const int modifiers = method->access_flags().as_int() & JVM_RECOGNIZED_METHOD_MODIFIERS;
Handle ch = java_lang_reflect_Constructor::create(CHECK_NULL);
@@ -822,8 +824,12 @@
}
-methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, const methodHandle& method,
- KlassHandle recv_klass, Handle receiver, TRAPS) {
+static methodHandle resolve_interface_call(instanceKlassHandle klass,
+ const methodHandle& method,
+ KlassHandle recv_klass,
+ Handle receiver,
+ TRAPS) {
+
assert(!method.is_null() , "method should not be null");
CallInfo info;
@@ -836,10 +842,48 @@
return info.selected_method();
}
+// Conversion
+static BasicType basic_type_mirror_to_basic_type(oop basic_type_mirror, TRAPS) {
+ assert(java_lang_Class::is_primitive(basic_type_mirror),
+ "just checking");
+ return java_lang_Class::primitive_type(basic_type_mirror);
+}
-oop Reflection::invoke(instanceKlassHandle klass, const methodHandle& reflected_method,
- Handle receiver, bool override, objArrayHandle ptypes,
- BasicType rtype, objArrayHandle args, bool is_method_invoke, TRAPS) {
+// Narrowing of basic types. Used to create correct jvalues for
+// boolean, byte, char and short return return values from interpreter
+// which are returned as ints. Throws IllegalArgumentException.
+static void narrow(jvalue* value, BasicType narrow_type, TRAPS) {
+ switch (narrow_type) {
+ case T_BOOLEAN:
+ value->z = (jboolean)value->i;
+ return;
+ case T_BYTE:
+ value->b = (jbyte)value->i;
+ return;
+ case T_CHAR:
+ value->c = (jchar)value->i;
+ return;
+ case T_SHORT:
+ value->s = (jshort)value->i;
+ return;
+ default:
+ break; // fail
+ }
+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
+}
+
+
+// Method call (shared by invoke_method and invoke_constructor)
+static oop invoke(instanceKlassHandle klass,
+ methodHandle reflected_method,
+ Handle receiver,
+ bool override,
+ objArrayHandle ptypes,
+ BasicType rtype,
+ objArrayHandle args,
+ bool is_method_invoke,
+ TRAPS) {
+
ResourceMark rm(THREAD);
methodHandle method; // actual method to invoke
@@ -876,18 +920,18 @@
// Linktime resolution & IllegalAccessCheck already done by Class.getMethod()
method = resolve_interface_call(klass, reflected_method, target_klass, receiver, THREAD);
if (HAS_PENDING_EXCEPTION) {
- // Method resolution threw an exception; wrap it in an InvocationTargetException
+ // Method resolution threw an exception; wrap it in an InvocationTargetException
oop resolution_exception = PENDING_EXCEPTION;
CLEAR_PENDING_EXCEPTION;
// JVMTI has already reported the pending exception
// JVMTI internal flag reset is needed in order to report InvocationTargetException
if (THREAD->is_Java_thread()) {
- JvmtiExport::clear_detected_exception((JavaThread*) THREAD);
+ JvmtiExport::clear_detected_exception((JavaThread*)THREAD);
}
JavaCallArguments args(Handle(THREAD, resolution_exception));
THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
- vmSymbols::throwable_void_signature(),
- &args);
+ vmSymbols::throwable_void_signature(),
+ &args);
}
} else {
// if the method can be overridden, we resolve using the vtable index.
@@ -906,10 +950,10 @@
// new default: 6531596
ResourceMark rm(THREAD);
Handle h_origexception = Exceptions::new_exception(THREAD,
- vmSymbols::java_lang_AbstractMethodError(),
- Method::name_and_sig_as_C_string(target_klass(),
- method->name(),
- method->signature()));
+ vmSymbols::java_lang_AbstractMethodError(),
+ Method::name_and_sig_as_C_string(target_klass(),
+ method->name(),
+ method->signature()));
JavaCallArguments args(h_origexception);
THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
vmSymbols::throwable_void_signature(),
@@ -926,15 +970,16 @@
ResourceMark rm(THREAD);
THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(),
Method::name_and_sig_as_C_string(klass(),
- reflected_method->name(),
- reflected_method->signature()));
+ reflected_method->name(),
+ reflected_method->signature()));
}
assert(ptypes->is_objArray(), "just checking");
int args_len = args.is_null() ? 0 : args->length();
// Check number of arguments
if (ptypes->length() != args_len) {
- THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "wrong number of arguments");
+ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+ "wrong number of arguments");
}
// Create object to contain parameters for the JavaCall
@@ -950,9 +995,9 @@
if (java_lang_Class::is_primitive(type_mirror)) {
jvalue value;
BasicType ptype = basic_type_mirror_to_basic_type(type_mirror, CHECK_NULL);
- BasicType atype = unbox_for_primitive(arg, &value, CHECK_NULL);
+ BasicType atype = Reflection::unbox_for_primitive(arg, &value, CHECK_NULL);
if (ptype != atype) {
- widen(&value, atype, ptype, CHECK_NULL);
+ Reflection::widen(&value, atype, ptype, CHECK_NULL);
}
switch (ptype) {
case T_BOOLEAN: java_args.push_int(value.z); break;
@@ -970,7 +1015,8 @@
if (arg != NULL) {
Klass* k = java_lang_Class::as_Klass(type_mirror);
if (!arg->is_a(k)) {
- THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
+ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+ "argument type mismatch");
}
}
Handle arg_handle(THREAD, arg); // Create handle for argument
@@ -978,7 +1024,8 @@
}
}
- assert(java_args.size_of_parameters() == method->size_of_parameters(), "just checking");
+ assert(java_args.size_of_parameters() == method->size_of_parameters(),
+ "just checking");
// All oops (including receiver) is passed in as Handles. An potential oop is returned as an
// oop (i.e., NOT as an handle)
@@ -992,7 +1039,7 @@
// JVMTI has already reported the pending exception
// JVMTI internal flag reset is needed in order to report InvocationTargetException
if (THREAD->is_Java_thread()) {
- JvmtiExport::clear_detected_exception((JavaThread*) THREAD);
+ JvmtiExport::clear_detected_exception((JavaThread*)THREAD);
}
JavaCallArguments args(Handle(THREAD, target_exception));
@@ -1001,39 +1048,12 @@
&args);
} else {
if (rtype == T_BOOLEAN || rtype == T_BYTE || rtype == T_CHAR || rtype == T_SHORT) {
- narrow((jvalue*) result.get_value_addr(), rtype, CHECK_NULL);
+ narrow((jvalue*)result.get_value_addr(), rtype, CHECK_NULL);
}
- return box((jvalue*) result.get_value_addr(), rtype, THREAD);
+ return Reflection::box((jvalue*)result.get_value_addr(), rtype, THREAD);
}
}
-
-void Reflection::narrow(jvalue* value, BasicType narrow_type, TRAPS) {
- switch (narrow_type) {
- case T_BOOLEAN:
- value->z = (jboolean) value->i;
- return;
- case T_BYTE:
- value->b = (jbyte) value->i;
- return;
- case T_CHAR:
- value->c = (jchar) value->i;
- return;
- case T_SHORT:
- value->s = (jshort) value->i;
- return;
- default:
- break; // fail
- }
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
-}
-
-
-BasicType Reflection::basic_type_mirror_to_basic_type(oop basic_type_mirror, TRAPS) {
- assert(java_lang_Class::is_primitive(basic_type_mirror), "just checking");
- return java_lang_Class::primitive_type(basic_type_mirror);
-}
-
// This would be nicer if, say, java.lang.reflect.Method was a subclass
// of java.lang.reflect.Constructor
--- a/hotspot/src/share/vm/runtime/reflection.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/reflection.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -43,16 +43,6 @@
class FieldStream;
class Reflection: public AllStatic {
- private:
- // Conversion
- static Klass* basic_type_mirror_to_arrayklass(oop basic_type_mirror, TRAPS);
- static oop basic_type_arrayklass_to_mirror(Klass* basic_type_arrayklass, TRAPS);
-
- static objArrayHandle get_parameter_types(const methodHandle& method, int parameter_count, oop* return_type, TRAPS);
- static objArrayHandle get_exception_types(const methodHandle& method, TRAPS);
- // Creating new java.lang.reflect.xxx wrappers
- static Handle new_type(Symbol* signature, KlassHandle k, TRAPS);
-
public:
// Constants defined by java reflection api classes
enum SomeConstants {
@@ -83,27 +73,27 @@
static arrayOop reflect_new_multi_array(oop element_mirror, typeArrayOop dimensions, TRAPS);
// Verification
- static bool verify_class_access(Klass* current_class, Klass* new_class, bool classloader_only);
+ static bool verify_class_access(const Klass* current_class,
+ const Klass* new_class,
+ bool classloader_only);
- static bool verify_field_access(Klass* current_class,
- Klass* resolved_class,
- Klass* field_class,
+ static bool verify_field_access(const Klass* current_class,
+ const Klass* resolved_class,
+ const Klass* field_class,
AccessFlags access,
bool classloader_only,
bool protected_restriction = false);
- static bool is_same_class_package(Klass* class1, Klass* class2);
- static bool is_same_package_member(Klass* class1, Klass* class2, TRAPS);
-
- static bool can_relax_access_check_for(
- Klass* accessor, Klass* accesee, bool classloader_only);
+ static bool is_same_class_package(const Klass* class1, const Klass* class2);
// inner class reflection
// raise an ICCE unless the required relationship can be proven to hold
// If inner_is_member, require the inner to be a member of the outer.
// If !inner_is_member, require the inner to be anonymous (a non-member).
// Caller is responsible for figuring out in advance which case must be true.
- static void check_for_inner_class(instanceKlassHandle outer, instanceKlassHandle inner,
- bool inner_is_member, TRAPS);
+ static void check_for_inner_class(instanceKlassHandle outer,
+ instanceKlassHandle inner,
+ bool inner_is_member,
+ TRAPS);
//
// Support for reflection based on dynamic bytecode generation (JDK 1.4)
@@ -119,31 +109,11 @@
// MethodParameterElement
static oop new_parameter(Handle method, int index, Symbol* sym,
int flags, TRAPS);
-
-private:
- // method resolution for invoke
- static methodHandle resolve_interface_call(instanceKlassHandle klass, const methodHandle& method, KlassHandle recv_klass, Handle receiver, TRAPS);
- // Method call (shared by invoke_method and invoke_constructor)
- static oop invoke(instanceKlassHandle klass,
- const methodHandle& method,
- Handle receiver,
- bool override,
- objArrayHandle ptypes,
- BasicType rtype,
- objArrayHandle args,
- bool is_method_invoke, TRAPS);
-
- // Narrowing of basic types. Used to create correct jvalues for
- // boolean, byte, char and short return return values from interpreter
- // which are returned as ints. Throws IllegalArgumentException.
- static void narrow(jvalue* value, BasicType narrow_type, TRAPS);
-
- // Conversion
- static BasicType basic_type_mirror_to_basic_type(oop basic_type_mirror, TRAPS);
-
-public:
// Method invocation through java.lang.reflect.Method
- static oop invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS);
+ static oop invoke_method(oop method_mirror,
+ Handle receiver,
+ objArrayHandle args,
+ TRAPS);
// Method invocation through java.lang.reflect.Constructor
static oop invoke_constructor(oop method_mirror, objArrayHandle args, TRAPS);
--- a/hotspot/src/share/vm/runtime/safepoint.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/safepoint.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
--- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -30,7 +30,6 @@
#include "interpreter/linkResolver.hpp"
#include "memory/allocation.hpp"
#include "memory/resourceArea.hpp"
-#include "runtime/threadLocalStorage.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/macros.hpp"
--- a/hotspot/src/share/vm/runtime/thread.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -78,7 +78,6 @@
#include "runtime/task.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
-#include "runtime/threadLocalStorage.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vframeArray.hpp"
#include "runtime/vframe_hp.hpp"
@@ -142,6 +141,10 @@
#endif // ndef DTRACE_ENABLED
+#ifndef USE_LIBRARY_BASED_TLS_ONLY
+// Current thread is maintained as a thread-local variable
+THREAD_LOCAL_DECL Thread* Thread::_thr_current = NULL;
+#endif
// Class hierarchy
// - Thread
@@ -281,22 +284,22 @@
#endif // ASSERT
}
-// Non-inlined version to be used where thread.inline.hpp shouldn't be included.
-Thread* Thread::current_noinline() {
- return Thread::current();
+void Thread::initialize_thread_current() {
+#ifndef USE_LIBRARY_BASED_TLS_ONLY
+ assert(_thr_current == NULL, "Thread::current already initialized");
+ _thr_current = this;
+#endif
+ assert(ThreadLocalStorage::thread() == NULL, "ThreadLocalStorage::thread already initialized");
+ ThreadLocalStorage::set_thread(this);
+ assert(Thread::current() == ThreadLocalStorage::thread(), "TLS mismatch!");
}
-void Thread::initialize_thread_local_storage() {
- // Note: Make sure this method only calls
- // non-blocking operations. Otherwise, it might not work
- // with the thread-startup/safepoint interaction.
-
- // During Java thread startup, safepoint code should allow this
- // method to complete because it may need to allocate memory to
- // store information for the new thread.
-
- // initialize structure dependent on thread local storage
- ThreadLocalStorage::set_thread(this);
+void Thread::clear_thread_current() {
+ assert(Thread::current() == ThreadLocalStorage::thread(), "TLS mismatch!");
+#ifndef USE_LIBRARY_BASED_TLS_ONLY
+ _thr_current = NULL;
+#endif
+ ThreadLocalStorage::set_thread(NULL);
}
void Thread::record_stack_base_and_size() {
@@ -364,15 +367,12 @@
delete _SR_lock;
- // clear thread local storage if the Thread is deleting itself
+ // clear Thread::current if thread is deleting itself.
+ // Needed to ensure JNI correctly detects non-attached threads.
if (this == Thread::current()) {
- ThreadLocalStorage::set_thread(NULL);
- } else {
- // In the case where we're not the current thread, invalidate all the
- // caches in case some code tries to get the current thread or the
- // thread that was destroyed, and gets stale information.
- ThreadLocalStorage::invalidate_all();
+ clear_thread_current();
}
+
CHECK_UNHANDLED_OOPS_ONLY(if (CheckUnhandledOops) delete unhandled_oops();)
}
@@ -1273,7 +1273,6 @@
assert(this == watcher_thread(), "just checking");
this->record_stack_base_and_size();
- this->initialize_thread_local_storage();
this->set_native_thread_name(this->name());
this->set_active_handles(JNIHandleBlock::allocate_block());
while (true) {
@@ -1326,9 +1325,6 @@
_watcher_thread = NULL;
Terminator_lock->notify();
}
-
- // Thread destructor usually does this..
- ThreadLocalStorage::set_thread(NULL);
}
void WatcherThread::start() {
@@ -1663,9 +1659,6 @@
// Record real stack base and size.
this->record_stack_base_and_size();
- // Initialize thread local storage; set before calling MutexLocker
- this->initialize_thread_local_storage();
-
this->create_stack_guard_pages();
this->cache_global_variables();
@@ -1997,8 +1990,7 @@
JavaThread* JavaThread::active() {
- Thread* thread = ThreadLocalStorage::thread();
- assert(thread != NULL, "just checking");
+ Thread* thread = Thread::current();
if (thread->is_Java_thread()) {
return (JavaThread*) thread;
} else {
@@ -3407,7 +3399,7 @@
jint adjust_after_os_result = Arguments::adjust_after_os();
if (adjust_after_os_result != JNI_OK) return adjust_after_os_result;
- // initialize TLS
+ // Initialize library-based TLS
ThreadLocalStorage::init();
// Initialize output stream logging
@@ -3444,14 +3436,9 @@
// Attach the main thread to this os thread
JavaThread* main_thread = new JavaThread();
main_thread->set_thread_state(_thread_in_vm);
- // must do this before set_active_handles and initialize_thread_local_storage
- // Note: on solaris initialize_thread_local_storage() will (indirectly)
- // change the stack size recorded here to one based on the java thread
- // stacksize. This adjusted size is what is used to figure the placement
- // of the guard pages.
+ main_thread->initialize_thread_current();
+ // must do this before set_active_handles
main_thread->record_stack_base_and_size();
- main_thread->initialize_thread_local_storage();
-
main_thread->set_active_handles(JNIHandleBlock::allocate_block());
if (!main_thread->set_as_starting_thread()) {
--- a/hotspot/src/share/vm/runtime/thread.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/thread.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -102,6 +102,12 @@
class Thread: public ThreadShadow {
friend class VMStructs;
private:
+
+#ifndef USE_LIBRARY_BASED_TLS_ONLY
+ // Current thread is maintained as a thread-local variable
+ static THREAD_LOCAL_DECL Thread* _thr_current;
+#endif
+
// Exception handling
// (Note: _pending_exception and friends are in ThreadShadow)
//oop _pending_exception; // pending exception for current thread
@@ -260,14 +266,13 @@
friend class No_Alloc_Verifier;
friend class No_Safepoint_Verifier;
friend class Pause_No_Safepoint_Verifier;
- friend class ThreadLocalStorage;
friend class GC_locker;
ThreadLocalAllocBuffer _tlab; // Thread-local eden
jlong _allocated_bytes; // Cumulative number of bytes allocated on
// the Java heap
- TRACE_DATA _trace_data; // Thread-local data for tracing
+ mutable TRACE_DATA _trace_data; // Thread-local data for tracing
ThreadExt _ext;
@@ -307,9 +312,12 @@
Thread();
virtual ~Thread();
- // initializtion
- void initialize_thread_local_storage();
+ // Manage Thread::current()
+ void initialize_thread_current();
+ private:
+ void clear_thread_current(); // needed for detaching JNI threads
+ public:
// thread entry point
virtual void run();
@@ -337,10 +345,13 @@
virtual char* name() const { return (char*)"Unknown thread"; }
- // Returns the current thread
+ // Returns the current thread (ASSERTS if NULL)
static inline Thread* current();
- // ... without having to include thread.inline.hpp.
- static Thread* current_noinline();
+ // Returns the current thread, or NULL if not attached
+ static inline Thread* current_or_null();
+ // Returns the current thread, or NULL if not attached, and is
+ // safe for use from signal-handlers
+ static inline Thread* current_or_null_safe();
// Common thread operations
static void set_priority(Thread* thread, ThreadPriority priority);
@@ -649,25 +660,22 @@
};
// Inline implementation of Thread::current()
-// Thread::current is "hot" it's called > 128K times in the 1st 500 msecs of
-// startup.
-// ThreadLocalStorage::thread is warm -- it's called > 16K times in the same
-// period. This is inlined in thread_<os_family>.inline.hpp.
+inline Thread* Thread::current() {
+ Thread* current = current_or_null();
+ assert(current != NULL, "Thread::current() called on detached thread");
+ return current;
+}
-inline Thread* Thread::current() {
-#ifdef ASSERT
- // This function is very high traffic. Define PARANOID to enable expensive
- // asserts.
-#ifdef PARANOID
- // Signal handler should call ThreadLocalStorage::get_thread_slow()
- Thread* t = ThreadLocalStorage::get_thread_slow();
- assert(t != NULL && !t->is_inside_signal_handler(),
- "Don't use Thread::current() inside signal handler");
+inline Thread* Thread::current_or_null() {
+#ifndef USE_LIBRARY_BASED_TLS_ONLY
+ return _thr_current;
+#else
+ return ThreadLocalStorage::thread();
#endif
-#endif
- Thread* thread = ThreadLocalStorage::thread();
- assert(thread != NULL, "just checking");
- return thread;
+}
+
+inline Thread* Thread::current_or_null_safe() {
+ return ThreadLocalStorage::thread();
}
// Name support for threads. non-JavaThread subclasses with multiple
@@ -1842,8 +1850,8 @@
// Inline implementation of JavaThread::current
inline JavaThread* JavaThread::current() {
- Thread* thread = ThreadLocalStorage::thread();
- assert(thread != NULL && thread->is_Java_thread(), "just checking");
+ Thread* thread = Thread::current();
+ assert(thread->is_Java_thread(), "just checking");
return (JavaThread*)thread;
}
--- a/hotspot/src/share/vm/runtime/thread.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/thread.inline.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2014, 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
@@ -30,21 +30,6 @@
#include "runtime/atomic.inline.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/thread.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_solaris
-# include "thread_solaris.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_windows
-# include "thread_windows.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_aix
-# include "thread_aix.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_bsd
-# include "thread_bsd.inline.hpp"
-#endif
#undef SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
--- a/hotspot/src/share/vm/runtime/threadLocalStorage.cpp Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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/os.inline.hpp"
-#include "runtime/thread.inline.hpp"
-#include "runtime/threadLocalStorage.hpp"
-
-// Solaris no longer has this kind of ThreadLocalStorage implementation.
-// This will be removed from all platforms in the near future.
-
-#ifndef SOLARIS
-
-// static member initialization
-int ThreadLocalStorage::_thread_index = -1;
-
-Thread* ThreadLocalStorage::get_thread_slow() {
- return (Thread*) os::thread_local_storage_at(ThreadLocalStorage::thread_index());
-}
-
-void ThreadLocalStorage::set_thread(Thread* thread) {
- pd_set_thread(thread);
-
- // The following ensure that any optimization tricks we have tried
- // did not backfire on us:
- guarantee(get_thread() == thread, "must be the same thread, quickly");
- guarantee(get_thread_slow() == thread, "must be the same thread, slowly");
-}
-
-void ThreadLocalStorage::init() {
- assert(!is_initialized(),
- "More than one attempt to initialize threadLocalStorage");
- pd_init();
- set_thread_index(os::allocate_thread_local_storage());
- generate_code_for_get_thread();
-}
-
-bool ThreadLocalStorage::is_initialized() {
- return (thread_index() != -1);
-}
-
-#endif // SOLARIS
--- a/hotspot/src/share/vm/runtime/threadLocalStorage.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/threadLocalStorage.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -25,86 +25,26 @@
#ifndef SHARE_VM_RUNTIME_THREADLOCALSTORAGE_HPP
#define SHARE_VM_RUNTIME_THREADLOCALSTORAGE_HPP
-#include "gc/shared/gcUtil.hpp"
-#include "runtime/os.hpp"
#include "utilities/top.hpp"
-// Interface for thread local storage
+// forward-decl as we can't have an include cycle
+class Thread;
-// Fast variant of ThreadLocalStorage::get_thread_slow
-extern "C" Thread* get_thread();
-
-// Get raw thread id: e.g., %g7 on sparc, fs or gs on x86
-extern "C" uintptr_t _raw_thread_id();
+// Wrapper class for library-based (as opposed to compiler-based)
+// thread-local storage (TLS). All platforms require this for
+// signal-handler based TLS access (which while not strictly async-signal
+// safe in theory, is and has-been for a long time, in practice).
+// Platforms without compiler-based TLS (i.e. __thread storage-class modifier)
+// will use this implementation for all TLS access - see thread.hpp/cpp
class ThreadLocalStorage : AllStatic {
// Exported API
public:
- static void set_thread(Thread* thread);
- static Thread* get_thread_slow();
- static void invalidate_all() { pd_invalidate_all(); }
+ static Thread* thread(); // return current thread, if attached
+ static void set_thread(Thread* thread); // set current thread
static void init();
- static bool is_initialized();
-
- // Machine dependent stuff
-#ifdef TARGET_OS_ARCH_linux_x86
-# include "threadLS_linux_x86.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_linux_sparc
-# include "threadLS_linux_sparc.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_linux_zero
-# include "threadLS_linux_zero.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_solaris_x86
-# include "threadLS_solaris_x86.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_solaris_sparc
-# include "threadLS_solaris_sparc.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_windows_x86
-# include "threadLS_windows_x86.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_linux_arm
-# include "threadLS_linux_arm.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_linux_ppc
-# include "threadLS_linux_ppc.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_linux_aarch64
-# include "threadLS_linux_aarch64.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_aix_ppc
-# include "threadLS_aix_ppc.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_bsd_x86
-# include "threadLS_bsd_x86.hpp"
-#endif
-#ifdef TARGET_OS_ARCH_bsd_zero
-# include "threadLS_bsd_zero.hpp"
-#endif
-
-#ifndef SOLARIS
- public:
- // Accessor
- static inline int thread_index() { return _thread_index; }
- static inline void set_thread_index(int index) { _thread_index = index; }
-
- private:
- static int _thread_index;
-
- static void generate_code_for_get_thread();
-
- // Processor dependent parts of set_thread and initialization
- static void pd_set_thread(Thread* thread);
- static void pd_init();
-
-#endif // SOLARIS
-
- // Invalidate any thread cacheing or optimization schemes.
- static void pd_invalidate_all();
-
+ static bool is_initialized(); // can't use TLS prior to initialization
};
#endif // SHARE_VM_RUNTIME_THREADLOCALSTORAGE_HPP
--- a/hotspot/src/share/vm/runtime/vframe.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/vframe.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -232,14 +232,12 @@
// disable the extra printing below.
mark = NULL;
}
- } else if (frame_count != 0 && ObjectMonitor::Knob_Verbose) {
+ } else if (frame_count != 0) {
// This is not the first frame so we either own this monitor
// or we owned the monitor before and called wait(). Because
// wait() could have been called on any monitor in a lower
// numbered frame on the stack, we have to check all the
// monitors on the list for this frame.
- // Note: Only enable this new output line in verbose mode
- // since existing tests are not ready for it.
mark = monitor->owner()->mark();
if (mark->has_monitor() &&
( // we have marked ourself as pending on this monitor
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -320,7 +320,7 @@
nonstatic_field(InstanceKlass, _constants, ConstantPool*) \
nonstatic_field(InstanceKlass, _class_loader_data, ClassLoaderData*) \
nonstatic_field(InstanceKlass, _source_file_name_index, u2) \
- nonstatic_field(InstanceKlass, _source_debug_extension, char*) \
+ nonstatic_field(InstanceKlass, _source_debug_extension, const char*) \
nonstatic_field(InstanceKlass, _inner_classes, Array<jushort>*) \
nonstatic_field(InstanceKlass, _nonstatic_field_size, int) \
nonstatic_field(InstanceKlass, _static_field_size, int) \
--- a/hotspot/src/share/vm/runtime/vmThread.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/vmThread.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -240,7 +240,6 @@
void VMThread::run() {
assert(this == vm_thread(), "check");
- this->initialize_thread_local_storage();
this->initialize_named_thread();
this->record_stack_base_and_size();
// Notify_lock wait checks on active_handles() to rewait in
@@ -308,9 +307,6 @@
_terminate_lock->notify();
}
- // Thread destructor usually does this.
- ThreadLocalStorage::set_thread(NULL);
-
// Deletion must be done synchronously by the JNI DestroyJavaVM thread
// so that the VMThread deletion completes before the main thread frees
// up the CodeHeap.
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -378,7 +378,7 @@
int VM_Exit::set_vm_exited() {
CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::LastStep);
- Thread * thr_cur = ThreadLocalStorage::get_thread_slow();
+ Thread * thr_cur = Thread::current();
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint already");
@@ -400,7 +400,7 @@
// to wait for threads in _thread_in_native state to be quiescent.
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint already");
- Thread * thr_cur = ThreadLocalStorage::get_thread_slow();
+ Thread * thr_cur = Thread::current();
Monitor timer(Mutex::leaf, "VM_Exit timer", true,
Monitor::_safepoint_check_never);
@@ -477,7 +477,7 @@
void VM_Exit::wait_if_vm_exited() {
if (_vm_exited &&
- ThreadLocalStorage::get_thread_slow() != _shutdown_thread) {
+ Thread::current_or_null() != _shutdown_thread) {
// _vm_exited is set at safepoint, and the Threads_lock is never released
// we will block here until the process dies
Threads_lock->lock_without_safepoint_check();
--- a/hotspot/src/share/vm/utilities/accessFlags.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/accessFlags.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -100,6 +100,9 @@
jint _flags;
public:
+ AccessFlags() : _flags(0) {}
+ explicit AccessFlags(jint flags) : _flags(flags) {}
+
// Java access flags
bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; }
bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; }
--- a/hotspot/src/share/vm/utilities/debug.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/debug.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -215,7 +215,7 @@
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);
+ VMError::report_and_die(Thread::current_or_null(), file, line, error_msg, detail_fmt, detail_args);
va_end(detail_args);
}
@@ -224,7 +224,7 @@
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);
+ VMError::report_and_die(Thread::current_or_null(), file, line, "fatal error", detail_fmt, detail_args);
va_end(detail_args);
}
@@ -233,7 +233,7 @@
if (Debugging) return;
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);
+ VMError::report_and_die(Thread::current_or_null(), 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
@@ -305,6 +305,16 @@
if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
VMError::report_java_out_of_memory(message);
}
+
+ if (CrashOnOutOfMemoryError) {
+ tty->print_cr("Aborting due to java.lang.OutOfMemoryError: %s", message);
+ fatal("OutOfMemory encountered: %s", message);
+ }
+
+ if (ExitOnOutOfMemoryError) {
+ tty->print_cr("Terminating due to java.lang.OutOfMemoryError: %s", message);
+ os::exit(3);
+ }
}
}
@@ -536,7 +546,7 @@
#endif // !PRODUCT
extern "C" void ps() { // print stack
- if (Thread::current() == NULL) return;
+ if (Thread::current_or_null() == NULL) return;
Command c("ps");
@@ -615,7 +625,7 @@
#endif // !PRODUCT
extern "C" void pss() { // print all stacks
- if (Thread::current() == NULL) return;
+ if (Thread::current_or_null() == NULL) return;
Command c("pss");
Threads::print(true, PRODUCT_ONLY(false) NOT_PRODUCT(true));
}
@@ -772,7 +782,7 @@
extern "C" void pns(void* sp, void* fp, void* pc) { // print native stack
Command c("pns");
static char buf[O_BUFLEN];
- Thread* t = ThreadLocalStorage::get_thread_slow();
+ Thread* t = Thread::current_or_null();
// Call generic frame constructor (certain arguments may be ignored)
frame fr(sp, fp, pc);
print_native_stack(tty, fr, t, buf, sizeof(buf));
--- a/hotspot/src/share/vm/utilities/elfSymbolTable.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/elfSymbolTable.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -69,6 +69,26 @@
}
}
+bool ElfSymbolTable::compare(const Elf_Sym* sym, address addr, int* stringtableIndex, int* posIndex, int* offset, ElfFuncDescTable* funcDescTable) {
+ if (STT_FUNC == ELF_ST_TYPE(sym->st_info)) {
+ Elf_Word st_size = sym->st_size;
+ address sym_addr;
+ if (funcDescTable != NULL && funcDescTable->get_index() == sym->st_shndx) {
+ // We need to go another step trough the function descriptor table (currently PPC64 only)
+ sym_addr = funcDescTable->lookup(sym->st_value);
+ } else {
+ sym_addr = (address)sym->st_value;
+ }
+ if (sym_addr <= addr && (Elf_Word)(addr - sym_addr) < st_size) {
+ *offset = (int)(addr - sym_addr);
+ *posIndex = sym->st_name;
+ *stringtableIndex = m_shdr.sh_link;
+ return true;
+ }
+ }
+ return false;
+}
+
bool ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset, ElfFuncDescTable* funcDescTable) {
assert(stringtableIndex, "null string table index pointer");
assert(posIndex, "null string table offset pointer");
@@ -83,21 +103,8 @@
int count = m_shdr.sh_size / sym_size;
if (m_symbols != NULL) {
for (int index = 0; index < count; index ++) {
- if (STT_FUNC == ELF_ST_TYPE(m_symbols[index].st_info)) {
- Elf_Word st_size = m_symbols[index].st_size;
- address sym_addr;
- if (funcDescTable != NULL && funcDescTable->get_index() == m_symbols[index].st_shndx) {
- // We need to go another step trough the function descriptor table (currently PPC64 only)
- sym_addr = funcDescTable->lookup(m_symbols[index].st_value);
- } else {
- sym_addr = (address)m_symbols[index].st_value;
- }
- if (sym_addr <= addr && (Elf_Word)(addr - sym_addr) < st_size) {
- *offset = (int)(addr - sym_addr);
- *posIndex = m_symbols[index].st_name;
- *stringtableIndex = m_shdr.sh_link;
- return true;
- }
+ if (compare(&m_symbols[index], addr, stringtableIndex, posIndex, offset, funcDescTable)) {
+ return true;
}
}
} else {
@@ -111,21 +118,8 @@
Elf_Sym sym;
for (int index = 0; index < count; index ++) {
if (fread(&sym, sym_size, 1, m_file) == 1) {
- if (STT_FUNC == ELF_ST_TYPE(sym.st_info)) {
- Elf_Word st_size = sym.st_size;
- address sym_addr;
- if (funcDescTable != NULL && funcDescTable->get_index() == sym.st_shndx) {
- // We need to go another step trough the function descriptor table (currently PPC64 only)
- sym_addr = funcDescTable->lookup(sym.st_value);
- } else {
- sym_addr = (address)sym.st_value;
- }
- if (sym_addr <= addr && (Elf_Word)(addr - sym_addr) < st_size) {
- *offset = (int)(addr - sym_addr);
- *posIndex = sym.st_name;
- *stringtableIndex = m_shdr.sh_link;
- return true;
- }
+ if (compare(&sym, addr, stringtableIndex, posIndex, offset, funcDescTable)) {
+ return true;
}
} else {
m_status = NullDecoder::file_invalid;
@@ -134,7 +128,7 @@
}
fseek(m_file, cur_pos, SEEK_SET);
}
- return true;
+ return false;
}
#endif // !_WINDOWS && !__APPLE__
--- a/hotspot/src/share/vm/utilities/elfSymbolTable.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/elfSymbolTable.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -63,6 +63,8 @@
Elf_Shdr m_shdr;
NullDecoder::decoder_status m_status;
+
+ bool compare(const Elf_Sym* sym, address addr, int* stringtableIndex, int* posIndex, int* offset, ElfFuncDescTable* funcDescTable);
};
#endif // !_WINDOWS and !__APPLE__
--- a/hotspot/src/share/vm/utilities/events.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/events.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -29,7 +29,6 @@
#include "runtime/osThread.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
-#include "runtime/threadLocalStorage.hpp"
#include "runtime/timer.hpp"
#include "utilities/events.hpp"
--- a/hotspot/src/share/vm/utilities/events.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/events.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -248,8 +248,8 @@
template <class T>
inline void EventLogBase<T>::print_log_on(outputStream* out) {
- if (ThreadLocalStorage::get_thread_slow() == NULL) {
- // Not a regular Java thread so don't bother locking
+ if (Thread::current_or_null() == NULL) {
+ // Not yet attached? Don't try to use locking
print_log_impl(out);
} else {
MutexLockerEx ml(&_mutex, Mutex::_no_safepoint_check_flag);
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -949,7 +949,6 @@
// (in order to reduce interface dependencies & reduce
// number of unnecessary compilations after changes)
-class symbolTable;
class ClassFileStream;
class Event;
--- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -326,4 +326,8 @@
#define JLONG_FORMAT "%ld"
#endif // _LP64 && __APPLE__
+#ifndef USE_LIBRARY_BASED_TLS_ONLY
+#define THREAD_LOCAL_DECL __thread
+#endif
+
#endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_GCC_HPP
--- a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -273,4 +273,8 @@
#define offset_of(klass,field) offsetof(klass,field)
+#ifndef USE_LIBRARY_BASED_TLS_ONLY
+#define THREAD_LOCAL_DECL __thread
+#endif
+
#endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_SPARCWORKS_HPP
--- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -234,4 +234,8 @@
#define offset_of(klass,field) offsetof(klass,field)
+#ifndef USE_LIBRARY_BASED_TLS_ONLY
+#define THREAD_LOCAL_DECL __declspec( thread )
+#endif
+
#endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_VISCPP_HPP
--- a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -180,5 +180,8 @@
#define SIZE_64G ((uint64_t) UCONST64( 0x1000000000))
#define SIZE_1T ((uint64_t) UCONST64(0x10000000000))
+#ifndef USE_LIBRARY_BASED_TLS_ONLY
+#define THREAD_LOCAL_DECL __thread
+#endif
#endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_XLC_HPP
--- a/hotspot/src/share/vm/utilities/hashtable.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/hashtable.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -151,7 +151,7 @@
void copy_table(char** top, char* end);
// Bucket handling
- int hash_to_index(unsigned int full_hash) {
+ int hash_to_index(unsigned int full_hash) const {
int h = full_hash % _table_size;
assert(h >= 0 && h < _table_size, "Illegal hash value");
return h;
@@ -173,8 +173,8 @@
protected:
#ifdef ASSERT
- int _lookup_count;
- int _lookup_length;
+ mutable int _lookup_count;
+ mutable int _lookup_length;
void verify_lookup_length(double load);
#endif
@@ -184,7 +184,7 @@
int entry_size() const { return _entry_size; }
// The following method is MT-safe and may be used with caution.
- BasicHashtableEntry<F>* bucket(int i);
+ BasicHashtableEntry<F>* bucket(int i) const;
// The following method is not MT-safe and must be done under lock.
BasicHashtableEntry<F>** bucket_addr(int i) { return _buckets[i].entry_addr(); }
@@ -263,7 +263,7 @@
HashtableEntry<T, F>* new_entry(unsigned int hashValue, T obj);
// The following method is MT-safe and may be used with caution.
- HashtableEntry<T, F>* bucket(int i) {
+ HashtableEntry<T, F>* bucket(int i) const {
return (HashtableEntry<T, F>*)BasicHashtable<F>::bucket(i);
}
@@ -329,7 +329,7 @@
: Hashtable<T, F>(table_size, entry_size, t, number_of_entries) {}
public:
- unsigned int compute_hash(Symbol* name, ClassLoaderData* loader_data) {
+ unsigned int compute_hash(const Symbol* name, const ClassLoaderData* loader_data) const {
unsigned int name_hash = name->identity_hash();
// loader is null with CDS
assert(loader_data != NULL || UseSharedSpaces || DumpSharedSpaces,
--- a/hotspot/src/share/vm/utilities/hashtable.inline.hpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/hashtable.inline.hpp Wed Jul 05 21:09:54 2017 +0200
@@ -72,7 +72,7 @@
// The following method is MT-safe and may be used with caution.
-template <MEMFLAGS F> inline BasicHashtableEntry<F>* BasicHashtable<F>::bucket(int i) {
+template <MEMFLAGS F> inline BasicHashtableEntry<F>* BasicHashtable<F>::bucket(int i) const {
return _buckets[i].get_entry();
}
--- a/hotspot/src/share/vm/utilities/ostream.cpp Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/src/share/vm/utilities/ostream.cpp Wed Jul 05 21:09:54 2017 +0200
@@ -738,7 +738,7 @@
}
#ifdef ASSERT
- Thread *thread = Thread::current();
+ Thread *thread = Thread::current_or_null();
assert(thread == NULL ||
(thread->is_VM_thread() && SafepointSynchronize::is_at_safepoint()),
"Must be VMThread at safepoint");
@@ -1058,8 +1058,8 @@
// bootstrap problem
tty_lock == NULL ||
- // can't grab a lock or call Thread::current() if TLS isn't initialized
- ThreadLocalStorage::thread() == NULL ||
+ // can't grab a lock if current Thread isn't set
+ Thread::current_or_null() == NULL ||
// developer hook
!SerializeVMOutput ||
--- a/hotspot/test/TEST.ROOT Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/TEST.ROOT Wed Jul 05 21:09:54 2017 +0200
@@ -30,7 +30,7 @@
keys=cte_test jcmd nmt regression gc stress
groups=TEST.groups [closed/TEST.groups]
-requires.properties=sun.arch.data.model
+requires.properties=sun.arch.data.model java.version
# Tests using jtreg 4.1 b12 features
requiredVersion=4.1 b12
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/parallel/TestPrintGCDetailsVerbose.java Wed Jul 05 21:09:54 2017 +0200
@@ -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.
+ */
+
+/*
+ * @test TestPrintGCDetailsVerbose
+ * @bug 8016740
+ * @summary Tests that jvm with PrintGCDetails and Verbose flags do not crash when ParOldGC has no memory
+ * @key gc
+ * @requires java.version ~= ".*fastdebug"
+ * @requires vm.gc=="Parallel" | vm.gc=="null"
+ * @library /testlibrary
+ * @run main/othervm -Xmx50m -XX:+UseParallelOldGC -XX:+PrintGCDetails -XX:+Verbose TestPrintGCDetailsVerbose
+ */
+public class TestPrintGCDetailsVerbose {
+
+ public static void main(String[] args) {
+ for (int t = 0; t <= 10; t++) {
+ byte a[][] = new byte[100000][];
+ try {
+ for (int i = 0; i < a.length; i++) {
+ a[i] = new byte[100000];
+ }
+ } catch (OutOfMemoryError oome) {
+ a = null;
+ System.out.println("OOM!");
+ continue;
+ }
+ }
+ }
+}
+
--- a/hotspot/test/runtime/CommandLine/IgnoreUnrecognizedVMOptions.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/runtime/CommandLine/IgnoreUnrecognizedVMOptions.java Wed Jul 05 21:09:54 2017 +0200
@@ -163,9 +163,9 @@
-IgnoreUnrecognizedVMOptions ERR ERR
+IgnoreUnrecognizedVMOptions ERR ERR
*/
- runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockDiagnosticVMOptions", "-XX:PrintInlining", "-version");
- runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockExperimentalVMOptions", "-XX:AlwaysSafeConstructors", "-version");
- runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockDiagnosticVMOptions", "-XX:PrintInlining", "-version");
- runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockExperimentalVMOptions", "-XX:AlwaysSafeConstructors", "-version");
+ runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:PrintInlining", "-version");
+ runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:+UnlockExperimentalVMOptions", "-XX:AlwaysSafeConstructors", "-version");
+ runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:PrintInlining", "-version");
+ runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+UnlockExperimentalVMOptions", "-XX:AlwaysSafeConstructors", "-version");
}
}
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,7 +29,7 @@
* java.management
* jdk.attach
* jdk.management/sun.tools.attach
- * @run main/othervm/timeout=780 TestOptionsWithRanges
+ * @run main/othervm/timeout=900 TestOptionsWithRanges
*/
import java.util.ArrayList;
@@ -116,11 +116,26 @@
* Exclude below options as their maximum value would consume too much memory
* and would affect other tests that run in parallel.
*/
+ excludeTestMaxRange("ConcGCThreads");
excludeTestMaxRange("G1ConcRefinementThreads");
excludeTestMaxRange("G1RSetRegionEntries");
excludeTestMaxRange("G1RSetSparseRegionEntries");
excludeTestMaxRange("G1UpdateBufferSize");
excludeTestMaxRange("InitialBootClassLoaderMetaspaceSize");
+ excludeTestMaxRange("InitialHeapSize");
+ excludeTestMaxRange("MaxHeapSize");
+ excludeTestMaxRange("MaxRAM");
+ excludeTestMaxRange("NewSize");
+ excludeTestMaxRange("OldSize");
+ excludeTestMaxRange("ParallelGCThreads");
+
+ excludeTestMaxRange("VMThreadStackSize");
+
+ /*
+ * JDK-8145027
+ * Temporarily exclude as current range/constraint is not enough for some option combinations.
+ */
+ excludeTestRange("NUMAInterleaveGranularity");
/*
* Remove parameters controlling the code cache. As these
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java Wed Jul 05 21:09:54 2017 +0200
@@ -168,6 +168,10 @@
option.addPrepend("-Xshare:dump");
}
+ if (name.startsWith("NUMA")) {
+ option.addPrepend("-XX:+UseNUMA");
+ }
+
switch (name) {
case "MinHeapFreeRatio":
option.addPrepend("-XX:MaxHeapFreeRatio=100");
@@ -196,6 +200,19 @@
case "InitialTenuringThreshold":
option.addPrepend("-XX:MaxTenuringThreshold=" + option.getMax());
break;
+ case "NUMAInterleaveGranularity":
+ option.addPrepend("-XX:+UseNUMAInterleaving");
+ break;
+ case "CPUForCMSThread":
+ option.addPrepend("-XX:+BindCMSThreadToCPU");
+ break;
+ case "VerifyGCStartAt":
+ option.addPrepend("-XX:+VerifyBeforeGC");
+ option.addPrepend("-XX:+VerifyAfterGC");
+ break;
+ case "NewSizeThreadIncrease":
+ option.addPrepend("-XX:+UseSerialGC");
+ break;
default:
/* Do nothing */
break;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java Wed Jul 05 21:09:54 2017 +0200
@@ -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 TestCrashOnOutOfMemoryError
+ * @summary Test using -XX:+CrashOnOutOfMemoryError
+ * @library /testlibrary
+ * @build jdk.test.lib.*
+ * @run driver TestCrashOnOutOfMemoryError
+ * @bug 8138745
+ */
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+public class TestCrashOnOutOfMemoryError {
+
+ public static void main(String[] args) throws Exception {
+ if (args.length == 1) {
+ // This should guarantee to throw:
+ // java.lang.OutOfMemoryError: Requested array size exceeds VM limit
+ try {
+ Object[] oa = new Object[Integer.MAX_VALUE];
+ throw new Error("OOME not triggered");
+ } catch (OutOfMemoryError err) {
+ throw new Error("OOME didn't abort JVM!");
+ }
+ }
+ // else this is the main test
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+CrashOnOutOfMemoryError",
+ "-XX:-CreateCoredumpOnCrash", "-Xmx64m", TestCrashOnOutOfMemoryError.class.getName(),"throwOOME");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ int exitValue = output.getExitValue();
+ if (0 == exitValue) {
+ //expecting a non zero value
+ throw new Error("Expected to get non zero exit value");
+ }
+
+ /* Output should look something like this. The actual text will depend on the OS and its core dump processing.
+ Aborting due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit
+ # To suppress the following error report, specify this argument
+ # after -XX: or in .hotspotrc: SuppressErrorAt=/debug.cpp:303
+ #
+ # A fatal error has been detected by the Java Runtime Environment:
+ #
+ # Internal Error (/home/cheleswer/Desktop/jdk9/dev/hotspot/src/share/vm/utilities/debug.cpp:303), pid=6212, tid=6213
+ # fatal error: OutOfMemory encountered: Requested array size exceeds VM limit
+ #
+ # JRE version: OpenJDK Runtime Environment (9.0) (build 1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00)
+ # Java VM: OpenJDK 64-Bit Server VM (1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00, mixed mode, tiered, compressed oops, serial gc, linux-amd64)
+ # Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %P" (or dumping to
+ /home/cheleswer/Desktop/core.6212)
+ #
+ # An error report file with more information is saved as:
+ # /home/cheleswer/Desktop/hs_err_pid6212.log
+ #
+ # If you would like to submit a bug report, please visit:
+ # http://bugreport.java.com/bugreport/crash.jsp
+ #
+ Current thread is 6213
+ Dumping core ...
+ Aborted (core dumped)
+ */
+ output.shouldContain("Aborting due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit");
+ // extract hs-err file
+ String hs_err_file = output.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1);
+ if (hs_err_file == null) {
+ throw new Error("Did not find hs-err file in output.\n");
+ }
+
+ /*
+ * Check if hs_err files exist or not
+ */
+ File f = new File(hs_err_file);
+ if (!f.exists()) {
+ throw new Error("hs-err file missing at "+ f.getAbsolutePath() + ".\n");
+ }
+
+ /*
+ * Checking the completness of hs_err file. If last line of hs_err file is "END"
+ * then it proves that file is complete.
+ */
+ try (FileInputStream fis = new FileInputStream(f);
+ BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
+ String line = null;
+ String lastLine = null;
+ while ((line = br.readLine()) != null) {
+ lastLine = line;
+ }
+ if (!lastLine.equals("END.")) {
+ throw new Error("hs-err file incomplete (missing END marker.)");
+ } else {
+ System.out.println("End marker found.");
+ }
+ }
+ System.out.println("PASSED");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ErrorHandling/TestExitOnOutOfMemoryError.java Wed Jul 05 21:09:54 2017 +0200
@@ -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 TestExitOnOutOfMemoryError
+ * @summary Test using -XX:ExitOnOutOfMemoryError
+ * @library /testlibrary
+ * @build jdk.test.lib.*
+ * @run driver TestExitOnOutOfMemoryError
+ * @bug 8138745
+ */
+
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.OutputAnalyzer;
+
+public class TestExitOnOutOfMemoryError {
+
+ public static void main(String[] args) throws Exception {
+ if (args.length == 1) {
+ // This should guarantee to throw:
+ // java.lang.OutOfMemoryError: Requested array size exceeds VM limit
+ try {
+ Object[] oa = new Object[Integer.MAX_VALUE];
+ throw new Error("OOME not triggered");
+ } catch (OutOfMemoryError err) {
+ throw new Error("OOME didn't terminate JVM!");
+ }
+ }
+
+ // else this is the main test
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+ExitOnOutOfMemoryError",
+ "-Xmx64m", TestExitOnOutOfMemoryError.class.getName(), "throwOOME");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+ /*
+ * Actual output should look like this:
+ * Terminating due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit
+ */
+ output.shouldHaveExitValue(3);
+ output.stdoutShouldNotBeEmpty();
+ output.shouldContain("Terminating due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit");
+ System.out.println("PASSED");
+ }
+}
--- a/hotspot/test/runtime/Thread/Fibonacci.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/runtime/Thread/Fibonacci.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,7 +29,7 @@
* make this test inherently unstable on Windows with 32-bit VM data model.
* @requires !(os.family == "windows" & sun.arch.data.model == "32")
* @library /testlibrary
- * @run main Fibonacci 15
+ * @run main/othervm Fibonacci 15
*/
import jdk.test.lib.Asserts;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/BadMap50.jasm Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+/*
+ * This class should throw VerifyError because the StackMap for bytecode
+ * index 45 is incorrect. The stack maps for bytecode indexes 45 and 49 are
+ * incompatible because 45 doesn't supply enough locals to satisfy 49.
+ *
+ * The astore_2 bytecode at bytecode index 45 changes the type state,
+ * preventing the stackmap mismatch. But, if the incoming type state is used,
+ * as required by JVM Spec 8, then the verifier will detected the stackmap
+ * mismatch, and throw VerifyError.
+ */
+
+super public class BadMap50
+ version 50:0
+{
+
+
+public Method "<init>":"()V"
+ stack 1 locals 1
+{
+ aload_0;
+ invokespecial Method java/lang/Object."<init>":"()V";
+ return;
+}
+
+public static Method main:"([Ljava/lang/String;)V"
+ throws java/lang/Throwable
+ stack 0 locals 1
+{
+ return;
+}
+
+public static Method foo:"()V"
+ stack 3 locals 5
+{
+ iconst_0;
+ ifne L5;
+ nop;
+ try t7;
+ L5: stack_frame_type full;
+ aconst_null;
+ astore_0;
+ iconst_3;
+ istore_1;
+ try t0;
+ aconst_null;
+ astore_0;
+ endtry t0;
+ goto L19;
+ catch t0 java/io/IOException;
+ stack_frame_type full;
+ locals_map class java/lang/Object, int;
+ stack_map class java/io/IOException;
+ astore_2;
+ aconst_null;
+ astore_0;
+ iconst_2;
+ istore_1;
+ try t1;
+ L19: stack_frame_type full;
+ locals_map class java/lang/Object, int;
+ iconst_0;
+ istore_2;
+ endtry t1;
+ iload_1;
+ ifeq L37;
+ nop;
+ goto L37;
+ catch t1 #0;
+ catch t2 #0;
+ try t2;
+ stack_frame_type full;
+ locals_map class java/lang/Object, int;
+ stack_map class java/lang/Throwable;
+astore_3;
+iconst_2;
+istore_2;
+ endtry t2;
+ iload_1;
+ ifeq L35;
+ nop;
+ L35: stack_frame_type full;
+ locals_map class java/lang/Object, int, bogus, class java/lang/Throwable;
+aload_3;
+ athrow;
+ try t3, t4;
+ L37: stack_frame_type full;
+ locals_map class java/lang/Object, int, int;
+ iload_2;
+ ifeq L42;
+ nop;
+ endtry t3, t4;
+ L42: stack_frame_type full;
+ locals_map class java/lang/Object, int, int;
+ goto L54;
+ catch t3 java/lang/Exception;
+ try t5;
+ stack_frame_type full;
+ locals_map class java/lang/Object, int;
+ stack_map class java/lang/Exception;
+ // astore_2; // astore_2, at bci 45, that changes the type state.
+// pop;
+iconst_1;
+ istore_2; // astore_2, at bci 45, that changes the type state.
+ endtry t5;
+ goto L54;
+ catch t4 #0;
+ catch t5 #0;
+ catch t6 #0;
+ try t6;
+ stack_frame_type full;
+ locals_map class java/lang/Object, int, int;
+ stack_map class java/lang/Throwable;
+// astore 3;
+ istore_1;
+ endtry t6;
+// aload 3;
+// athrow;
+ L54: stack_frame_type full;
+ locals_map class java/lang/Object, int, int;
+ goto L57;
+ L57: stack_frame_type full;
+ locals_map class java/lang/Object, int, int;
+ nop;
+ endtry t7;
+ return;
+ catch t7 #0;
+ stack_frame_type full;
+ stack_map class java/lang/Throwable;
+ nop;
+ athrow;
+}
+
+} // end Class BadMap50
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/ClassInitializationTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -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.
+ */
+
+
+/*
+ * @test ClassInitializationTest
+ * @bug 8142976
+ * @library /testlibrary
+ * @compile BadMap50.jasm
+ * @run driver ClassInitializationTest
+ */
+
+import jdk.test.lib.*;
+
+public class ClassInitializationTest {
+
+ public static void main(String... args) throws Exception {
+
+ // (1)
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:classinit=info", "-Xverify:all", "-Xmx64m", "BadMap50");
+ OutputAnalyzer out = new OutputAnalyzer(pb.start());
+ out.shouldContain("Start class verification for:");
+ out.shouldContain("End class verification for:");
+ out.shouldContain("Initializing");
+ out.shouldContain("Verification for BadMap50 failed");
+ out.shouldContain("Fail over class verification to old verifier for: BadMap50");
+
+ // (2)
+ if (Platform.isDebugBuild()) {
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog:classinit=info", "-Xverify:all", "-XX:+EagerInitialization", "-Xmx64m", "-version");
+ out = new OutputAnalyzer(pb.start());
+ out.shouldContain("[Initialized").shouldContain("without side effects]");
+ out.shouldHaveExitValue(0);
+ }
+ // (3) Ensure that VerboseVerification still triggers appropriate messages.
+ pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", "-XX:+VerboseVerification", "-Xverify:all", "-Xmx64m", "BadMap50");
+ out = new OutputAnalyzer(pb.start());
+ out.shouldContain("End class verification for:");
+ out.shouldContain("Verification for BadMap50 failed");
+ out.shouldContain("Fail over class verification to old verifier for: BadMap50");
+ }
+}
--- a/hotspot/test/runtime/logging/DefaultMethodsTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/runtime/logging/DefaultMethodsTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -28,7 +28,7 @@
* @library /testlibrary
* @modules java.base/sun.misc
* java.management
- * @run main DefaultMethodsTest
+ * @run driver DefaultMethodsTest
*/
import jdk.test.lib.*;
--- a/hotspot/test/runtime/logging/SafepointTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/runtime/logging/SafepointTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -26,19 +26,18 @@
* @bug 8140348
* @summary safepoint=trace should have output from each log statement in the code
* @library /testlibrary
- * @compile SafepointTestMain.java
* @modules java.base/sun.misc
* java.management
- * @build SafepointTest
- * @run main SafepointTest
+ * @run driver SafepointTest
*/
import jdk.test.lib.*;
+import java.lang.ref.WeakReference;
public class SafepointTest {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:safepoint=trace", "SafepointTestMain");
+ "-Xlog:safepoint=trace", InnerClass.class.getName());
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("Safepoint synchronization initiated. (");
output.shouldContain("Entering safepoint region: ");
@@ -46,4 +45,25 @@
output.shouldContain("_at_poll_safepoint");
output.shouldHaveExitValue(0);
}
+
+ public static class InnerClass {
+ public static byte[] garbage;
+ public static volatile WeakReference<Object> weakref;
+
+ public static void createweakref() {
+ Object o = new Object();
+ weakref = new WeakReference<>(o);
+ }
+
+ public static void main(String[] args) throws Exception {
+ // Cause several safepoints to run GC to see safepoint messages
+ for (int i = 0; i < 2; i++) {
+ createweakref();
+ while(weakref.get() != null) {
+ garbage = new byte[8192];
+ System.gc();
+ }
+ }
+ }
+ }
}
--- a/hotspot/test/runtime/logging/SafepointTestMain.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * 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.lang.ref.WeakReference;
-
-public class SafepointTestMain {
- public static byte[] garbage;
- public static volatile WeakReference<Object> weakref;
-
- public static void createweakref() {
- Object o = new Object();
- weakref = new WeakReference<>(o);
- }
-
- public static void main(String[] args) throws Exception {
- // Cause several safepoints to run GC to see safepoint messages
- for (int i = 0; i < 2; i++) {
- createweakref();
- while(weakref.get() != null) {
- garbage = new byte[8192];
- System.gc();
- }
- }
- }
-}
--- a/hotspot/test/runtime/logging/VMOperationTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/runtime/logging/VMOperationTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -26,21 +26,41 @@
* @bug 8143157
* @summary vmoperation=debug should have logging output
* @library /testlibrary
- * @compile VMOperationTestMain.java
* @modules java.base/sun.misc
* java.management
- * @run main VMOperationTest
+ * @run driver VMOperationTest
*/
import jdk.test.lib.*;
+import java.lang.ref.WeakReference;
public class VMOperationTest {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:vmoperation=debug", "-Xmx64m", "-Xms64m", "VMOperationTestMain");
+ "-Xlog:vmoperation=debug", "-Xmx64m", "-Xms64m",
+ InternalClass.class.getName());
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("VM_Operation (");
output.shouldHaveExitValue(0);
}
+
+ public static class InternalClass {
+ public static byte[] garbage;
+ public static volatile WeakReference<Object> weakref;
+
+ public static void createweakref() {
+ Object o = new Object();
+ weakref = new WeakReference<>(o);
+ }
+
+ // Loop until a GC runs.
+ public static void main(String[] args) throws Exception {
+ createweakref();
+ while (weakref.get() != null) {
+ garbage = new byte[8192];
+ System.gc();
+ }
+ }
+ }
}
--- a/hotspot/test/runtime/logging/VMOperationTestMain.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * 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.lang.ref.WeakReference;
-
-public class VMOperationTestMain {
- public static byte[] garbage;
- public static volatile WeakReference<Object> weakref;
-
- public static void createweakref() {
- Object o = new Object();
- weakref = new WeakReference<>(o);
- }
-
- // Loop until a GC runs.
- public static void main(String[] args) throws Exception {
- createweakref();
- while (weakref.get() != null) {
- garbage = new byte[8192];
- System.gc();
- }
- }
-}
--- a/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -23,20 +23,22 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
-import jdk.test.lib.OutputAnalyzer;
-import jdk.test.lib.ProcessTools;
+import jdk.test.lib.process.ProcessTools;
/*
* @test
* @summary Test of diagnostic command GC.run_finalization
* @library /testlibrary
+ * @library /test/lib/share/classes
* @modules java.base/sun.misc
* java.compiler
* java.management
* jdk.jvmstat/sun.jvmstat.monitor
* @build jdk.test.lib.*
* @build jdk.test.lib.dcmd.*
+ * @build jdk.test.lib.process.*
* @build RunFinalizationTest FinalizationRunner
* @run main RunFinalizationTest
*/
@@ -50,8 +52,21 @@
javaArgs.add(TEST_APP_NAME);
ProcessBuilder testAppPb = ProcessTools.createJavaProcessBuilder(javaArgs.toArray(new String[javaArgs.size()]));
- OutputAnalyzer out = ProcessTools.executeProcess(testAppPb);
- out.stderrShouldNotMatch("^" + FinalizationRunner.FAILED + ".*")
- .stdoutShouldMatch("^" + FinalizationRunner.PASSED + ".*");
+ final AtomicBoolean failed = new AtomicBoolean();
+ final AtomicBoolean passed = new AtomicBoolean();
+
+ Process runner = ProcessTools.startProcess(
+ "FinalizationRunner",
+ testAppPb,
+ l -> {
+ failed.compareAndSet(false, l.contains(FinalizationRunner.FAILED));
+ passed.compareAndSet(false, l.contains(FinalizationRunner.PASSED));
+ }
+ );
+ runner.waitFor();
+
+ if (failed.get() || !passed.get()) {
+ throw new Error("RunFinalizationTest failed");
+ }
}
}
--- a/hotspot/test/testlibrary/jdk/test/lib/Asserts.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/testlibrary/jdk/test/lib/Asserts.java Wed Jul 05 21:09:54 2017 +0200
@@ -41,7 +41,10 @@
* multiple times, then the line number won't provide enough context to
* understand the failure.
* </pre>
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib}
*/
+@Deprecated
public class Asserts {
/**
--- a/hotspot/test/testlibrary/jdk/test/lib/JDKToolFinder.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/testlibrary/jdk/test/lib/JDKToolFinder.java Wed Jul 05 21:09:54 2017 +0200
@@ -27,6 +27,11 @@
import java.nio.file.Path;
import java.nio.file.Paths;
+/**
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib}
+ */
+@Deprecated
public final class JDKToolFinder {
private JDKToolFinder() {
--- a/hotspot/test/testlibrary/jdk/test/lib/JDKToolLauncher.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/testlibrary/jdk/test/lib/JDKToolLauncher.java Wed Jul 05 21:09:54 2017 +0200
@@ -46,7 +46,10 @@
* Process p = pb.start();
* }
* </pre>
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib}
*/
+@Deprecated
public class JDKToolLauncher {
private final String executable;
private final List<String> vmArgs = new ArrayList<String>();
--- a/hotspot/test/testlibrary/jdk/test/lib/OutputAnalyzer.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/testlibrary/jdk/test/lib/OutputAnalyzer.java Wed Jul 05 21:09:54 2017 +0200
@@ -41,7 +41,11 @@
*
* @param process Process to analyze
* @throws IOException If an I/O error occurs.
+ *
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib/process}
*/
+ @Deprecated
public OutputAnalyzer(Process process) throws IOException {
OutputBuffer output = ProcessTools.getOutput(process);
exitValue = process.exitValue();
--- a/hotspot/test/testlibrary/jdk/test/lib/OutputBuffer.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/testlibrary/jdk/test/lib/OutputBuffer.java Wed Jul 05 21:09:54 2017 +0200
@@ -23,6 +23,11 @@
package jdk.test.lib;
+/**
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib/process}
+ */
+@Deprecated
public class OutputBuffer {
private final String stdout;
private final String stderr;
--- a/hotspot/test/testlibrary/jdk/test/lib/Platform.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/testlibrary/jdk/test/lib/Platform.java Wed Jul 05 21:09:54 2017 +0200
@@ -25,6 +25,11 @@
import java.util.regex.Pattern;
+/**
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib}
+ */
+@Deprecated
public class Platform {
private static final String osName = System.getProperty("os.name");
private static final String dataModel = System.getProperty("sun.arch.data.model");
--- a/hotspot/test/testlibrary/jdk/test/lib/ProcessTools.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/testlibrary/jdk/test/lib/ProcessTools.java Wed Jul 05 21:09:54 2017 +0200
@@ -31,6 +31,11 @@
import java.util.Collections;
import java.util.List;
+/**
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib/process}
+ */
+@Deprecated
public final class ProcessTools {
private ProcessTools() {
--- a/hotspot/test/testlibrary/jdk/test/lib/StreamPumper.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/testlibrary/jdk/test/lib/StreamPumper.java Wed Jul 05 21:09:54 2017 +0200
@@ -27,6 +27,11 @@
import java.io.InputStream;
import java.io.IOException;
+/**
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib/process}
+ */
+@Deprecated
public final class StreamPumper implements Runnable {
private static final int BUF_SIZE = 256;
--- a/hotspot/test/testlibrary/jdk/test/lib/Utils.java Mon Dec 21 17:47:21 2015 +0100
+++ b/hotspot/test/testlibrary/jdk/test/lib/Utils.java Wed Jul 05 21:09:54 2017 +0200
@@ -55,7 +55,11 @@
/**
* Common library for various test helper functions.
+ *
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib}
*/
+@Deprecated
public final class Utils {
/**
--- a/jaxp/.hgtags Mon Dec 21 17:47:21 2015 +0100
+++ b/jaxp/.hgtags Wed Jul 05 21:09:54 2017 +0200
@@ -340,3 +340,4 @@
c8d0845877a811ab4350935892f826929359a3ff jdk-9+95
1f3182529f2c474e5506955ccb3820cfa5822265 jdk-9+96
9c107c050335d7ee63b2a8b38ca5d498f19713a2 jdk-9+97
+52b01339235f24c93b679bd6b8fb36a1072ad0ac jdk-9+98
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -357,7 +357,7 @@
* The length of the duration in milliseconds.
*/
protected DurationImpl(final long durationInMilliSeconds) {
-
+ boolean is0x8000000000000000L = false;
long l = durationInMilliSeconds;
if (l > 0) {
@@ -368,6 +368,7 @@
if (l == 0x8000000000000000L) {
// negating 0x8000000000000000L causes an overflow
l++;
+ is0x8000000000000000L = true;
}
l *= -1;
}
@@ -406,7 +407,8 @@
// seconds & milliseconds
int2long = (gregorianCalendar.get(Calendar.SECOND) * 1000)
- + gregorianCalendar.get(Calendar.MILLISECOND);
+ + gregorianCalendar.get(Calendar.MILLISECOND)
+ + (is0x8000000000000000L ? 1 : 0);
this.seconds = BigDecimal.valueOf(int2long, 3);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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 datatype;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.Duration;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/*
+ * @bug 8068839
+ * @summary Verifies that Duration's edge cases
+ */
+public class JDK8068839Test {
+
+ @Test
+ public void test() throws DatatypeConfigurationException {
+ DatatypeFactory df = DatatypeFactory.newInstance();
+ Duration durationx = df.newDuration(Long.MIN_VALUE);
+ Assert.assertEquals(durationx.toString(), "-P292277024Y7M16DT7H12M55.808S");
+ durationx = df.newDuration(Long.MAX_VALUE);
+ Assert.assertEquals(durationx.toString(), "P292277024Y7M16DT7H12M55.807S");
+ }
+
+}
--- a/jaxws/.hgtags Mon Dec 21 17:47:21 2015 +0100
+++ b/jaxws/.hgtags Wed Jul 05 21:09:54 2017 +0200
@@ -343,3 +343,4 @@
3e03ddaaac6585fa27e91596eb2a9a31e10bdcc9 jdk-9+95
b55cebc47555293cf9c2aefb3bf63c56e847ab19 jdk-9+96
7293db4716ee25b814e14f738b9acfb85700e3fa jdk-9+97
+67c84077edc3db6b24998b35970b37c01aae985e jdk-9+98
--- a/jdk/.hgtags Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/.hgtags Wed Jul 05 21:09:54 2017 +0200
@@ -340,3 +340,4 @@
8581faf0d474472e32f589bbc16db7eec912d83f jdk-9+95
c021b855f51e572e63982654b17742cb1f814fb4 jdk-9+96
fdd84b2265ddce7f50e084b7c8635189bba6f012 jdk-9+97
+f86ee68d1107dad41a27efc34306e0e56244a12e jdk-9+98
--- a/jdk/make/CompileDemos.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/CompileDemos.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -309,7 +309,7 @@
ifeq ($$($1_TOOLCHAIN), TOOLCHAIN_LINK_CXX)
# For C++, we also need some special treatment.
- $1_LDFLAGS := $(LDFLAGS_CXX_JDK)
+ $1_LDFLAGS := $$(LDFLAGS_CXX_JDK)
$1_LIBS := $(LIBCXX)
ifeq ($(OPENJDK_TARGET_CPU_ARCH), sparc)
@@ -324,9 +324,9 @@
OPTIMIZATION := LOW, \
CFLAGS := $$($1_CFLAGS_INCLUDE) $$(CFLAGS_JDKLIB) $$(CFLAGS_DEBUG_SYMBOLS), \
CXXFLAGS := $$($1_CXXFLAGS), \
- LDFLAGS := $(filter-out -incremental:no -opt:ref, $(LDFLAGS_JDKLIB)) \
+ LDFLAGS := $(filter-out -incremental:no -opt:ref, $$(LDFLAGS_JDKLIB)) \
$$($1_LDFLAGS), \
- LDFLAGS_macosx := $(call SET_EXECUTABLE_ORIGIN), \
+ LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN), \
LIBS := $$($1_LIBS), \
LIBS_solaris := -lc, \
VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
--- a/jdk/make/launcher/Launcher-java.base.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/launcher/Launcher-java.base.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -127,8 +127,7 @@
$(BUILD_JEXEC_INC), \
CFLAGS_linux := -fPIC, \
CFLAGS_solaris := -KPIC, \
- LDFLAGS := $(LDFLAGS_JDKEXE) \
- $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)$(SHARED_LIBRARY_SUFFIX)), \
+ LDFLAGS := $(LDFLAGS_JDKEXE), \
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/jexec_obj, \
OUTPUT_DIR := $(BUILD_JEXEC_DST_DIR), \
DEBUG_SYMBOLS := true, \
--- a/jdk/make/launcher/Launcher-jdk.pack200.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/launcher/Launcher-jdk.pack200.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -89,7 +89,6 @@
MAPFILE := $(UNPACK_MAPFILE),\
LDFLAGS := $(UNPACKEXE_ZIPOBJS) \
$(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \
- $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)unpack$(SHARED_LIBRARY_SUFFIX)) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := $(UNPACKEXE_LIBS) $(LIBCXX), \
LIBS_solaris := -lc, \
--- a/jdk/make/launcher/LauncherCommon.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/launcher/LauncherCommon.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -25,6 +25,12 @@
include NativeCompilation.gmk
+# SetupNativeCompilation now supports debug symbols on macosx for hotspot.
+# Disable it here for the jdk binaries until we decide to enable them.
+ifeq ($(OPENJDK_TARGET_OS), macosx)
+ ENABLE_DEBUG_SYMBOLS := false
+endif
+
# Prepare the find cache.
$(eval $(call FillCacheFind, $(JDK_TOPDIR)/src/java.base/share/native/launcher))
@@ -180,15 +186,12 @@
CFLAGS_linux := -fPIC, \
CFLAGS_solaris := -KPIC -DHAVE_GETHRTIME, \
CFLAGS_windows := $$($1_CFLAGS_windows), \
- LDFLAGS := $(LDFLAGS_JDKEXE) \
+ LDFLAGS := $$(LDFLAGS_JDKEXE) \
$$(ORIGIN_ARG) \
$$($1_LDFLAGS), \
LDFLAGS_linux := \
- $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)$(SHARED_LIBRARY_SUFFIX)) \
-L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \
- LDFLAGS_macosx := $(call SET_SHARED_LIBRARY_NAME,$1), \
LDFLAGS_solaris := $$($1_LDFLAGS_solaris) \
- $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)$(SHARED_LIBRARY_SUFFIX)) \
-L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \
MAPFILE := $$($1_MAPFILE), \
LIBS := $(JDKEXE_LIBS) $$($1_LIBS), \
--- a/jdk/make/lib/Awt2dLibraries.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/lib/Awt2dLibraries.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -683,7 +683,7 @@
WARNINGS_AS_ERRORS_gcc := false, \
WARNINGS_AS_ERRORS_solstudio := false, \
MAPFILE := $(BUILD_LIBFONTMANAGER_MAPFILE), \
- LDFLAGS := $(subst -Xlinker -z -Xlinker defs,,$(LDFLAGS_JDKLIB)) $(LDFLAGS_CXX_JDK) \
+ LDFLAGS := $(subst -Wl$(COMMA)-z$(COMMA)defs,,$(LDFLAGS_JDKLIB)) $(LDFLAGS_CXX_JDK) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \
LDFLAGS_macosx := -undefined dynamic_lookup, \
@@ -799,7 +799,7 @@
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \
- LDFLAGS_macosx := -Xlinker -rpath -Xlinker @loader_path, \
+ LDFLAGS_macosx := -Wl$(COMMA)-rpath$(COMMA)@loader_path, \
LIBS_unix := $(JAWT_LIBS) $(JDKLIB_LIBS), \
LIBS_solaris := $(X_LIBS) -lXrender, \
LIBS_macosx := -framework Cocoa, \
@@ -1034,7 +1034,7 @@
-I$(SUPPORT_OUTPUTDIR)/headers/java.desktop, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN) \
- -Xlinker -rpath -Xlinker @loader_path \
+ -Wl$(COMMA)-rpath$(COMMA)@loader_path \
-L$(INSTALL_LIBRARIES_HERE), \
LIBS := -lawt -losxapp -lawt_lwawt \
-framework Cocoa \
--- a/jdk/make/lib/Lib-java.instrument.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/lib/Lib-java.instrument.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -65,7 +65,7 @@
-L$(call FindLibDirForModule, java.base)/jli, \
LDFLAGS_solaris := $(call SET_SHARED_LIBRARY_ORIGIN,/jli) \
-L$(call FindLibDirForModule, java.base)/jli, \
- LDFLAGS_macosx := -Xlinker -all_load $(SUPPORT_OUTPUTDIR)/native/java.base/libjli_static.a, \
+ LDFLAGS_macosx := -Wl$(COMMA)-all_load, \
LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \
LDFLAGS_windows := -export:Agent_OnAttach, \
LIBS := $(JDKLIB_LIBS), \
@@ -74,7 +74,8 @@
LIBS_solaris := -ljli $(LIBDL), \
LIBS_aix := -liconv -ljli_static $(LIBDL), \
LIBS_macosx := -liconv -framework Cocoa -framework Security \
- -framework ApplicationServices, \
+ -framework ApplicationServices \
+ $(SUPPORT_OUTPUTDIR)/native/java.base/libjli_static.a, \
LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib \
$(SUPPORT_OUTPUTDIR)/native/java.base/jli_static.lib, \
VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
--- a/jdk/make/lib/LibCommon.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/lib/LibCommon.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -46,6 +46,12 @@
endif
endif
+# SetupNativeCompilation now supports debug symbols on macosx for hotspot.
+# Disable it here for the jdk libraries until we decide to enable them.
+ifeq ($(OPENJDK_TARGET_OS), macosx)
+ ENABLE_DEBUG_SYMBOLS := false
+endif
+
################################################################################
# Find the default set of src dirs for a native library.
# Param 1 - module name
--- a/jdk/make/mapfiles/libzip/mapfile-vers Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/mapfiles/libzip/mapfile-vers Wed Jul 05 21:09:54 2017 +0200
@@ -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
@@ -27,7 +27,6 @@
SUNWprivate_1.1 {
global:
- Java_java_util_jar_JarFile_getMetaInfEntryNames;
Java_java_util_zip_Adler32_update;
Java_java_util_zip_Adler32_updateBytes;
Java_java_util_zip_Adler32_updateByteBuffer;
@@ -48,25 +47,6 @@
Java_java_util_zip_Inflater_initIDs;
Java_java_util_zip_Inflater_reset;
Java_java_util_zip_Inflater_setDictionary;
- Java_java_util_zip_ZipFile_close;
- Java_java_util_zip_ZipFile_getCommentBytes;
- Java_java_util_zip_ZipFile_freeEntry;
- Java_java_util_zip_ZipFile_getEntry;
- Java_java_util_zip_ZipFile_getEntryBytes;
- Java_java_util_zip_ZipFile_getEntryCrc;
- Java_java_util_zip_ZipFile_getEntryCSize;
- Java_java_util_zip_ZipFile_getEntryFlag;
- Java_java_util_zip_ZipFile_getEntryMethod;
- Java_java_util_zip_ZipFile_getEntrySize;
- Java_java_util_zip_ZipFile_getEntryTime;
- Java_java_util_zip_ZipFile_getNextEntry;
- Java_java_util_zip_ZipFile_getZipMessage;
- Java_java_util_zip_ZipFile_getTotal;
- Java_java_util_zip_ZipFile_initIDs;
- Java_java_util_zip_ZipFile_open;
- Java_java_util_zip_ZipFile_read;
- Java_java_util_zip_ZipFile_startsWithLOC;
-
ZIP_Close;
ZIP_CRC32;
ZIP_FindEntry;
--- a/jdk/make/mapfiles/libzip/reorder-sparc Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/mapfiles/libzip/reorder-sparc Wed Jul 05 21:09:54 2017 +0200
@@ -16,30 +16,14 @@
text: .text%ZIP_Lock;
text: .text%ZIP_Unlock;
text: .text%ZIP_FreeEntry;
-text: .text%Java_java_util_zip_ZipFile_initIDs;
-text: .text%Java_java_util_zip_ZipFile_open;
-text: .text%Java_java_util_zip_ZipFile_getTotal;
-text: .text%Java_java_util_zip_ZipFile_startsWithLOC;
-text: .text%Java_java_util_zip_ZipFile_getEntry;
-text: .text%Java_java_util_zip_ZipFile_freeEntry;
-text: .text%Java_java_util_zip_ZipFile_getEntryTime;
-text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
-text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
-text: .text%Java_java_util_zip_ZipFile_getEntrySize;
-text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
-text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
-text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
text: .text%Java_java_util_zip_Inflater_initIDs;
text: .text%Java_java_util_zip_Inflater_init;
text: .text%inflateInit2_;
text: .text%zcalloc;
text: .text%Java_java_util_zip_Inflater_inflateBytes;
-text: .text%Java_java_util_zip_ZipFile_read;
text: .text%ZIP_Read;
text: .text%zcfree;
-text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
text: .text%Java_java_util_zip_Inflater_reset;
text: .text%Java_java_util_zip_Inflater_end;
text: .text%inflateEnd;
-text: .text%Java_java_util_zip_ZipFile_close;
text: .text%ZIP_Close;
--- a/jdk/make/mapfiles/libzip/reorder-sparcv9 Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/mapfiles/libzip/reorder-sparcv9 Wed Jul 05 21:09:54 2017 +0200
@@ -15,19 +15,6 @@
text: .text%ZIP_Lock;
text: .text%ZIP_Unlock;
text: .text%ZIP_FreeEntry;
-text: .text%Java_java_util_zip_ZipFile_initIDs;
-text: .text%Java_java_util_zip_ZipFile_open;
-text: .text%Java_java_util_zip_ZipFile_getTotal;
-text: .text%Java_java_util_zip_ZipFile_startsWithLOC;
-text: .text%Java_java_util_zip_ZipFile_getEntry;
-text: .text%Java_java_util_zip_ZipFile_freeEntry;
-text: .text%Java_java_util_zip_ZipFile_getEntryTime;
-text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
-text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
-text: .text%Java_java_util_zip_ZipFile_getEntrySize;
-text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
-text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
-text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
text: .text%Java_java_util_zip_Inflater_initIDs;
text: .text%Java_java_util_zip_Inflater_init;
text: .text%inflateInit2_;
@@ -35,7 +22,6 @@
text: .text%inflateReset;
text: .text%Java_java_util_zip_Inflater_inflateBytes;
text: .text%inflate;
-text: .text%Java_java_util_zip_ZipFile_read;
text: .text%ZIP_Read;
text: .text%zcfree;
text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
@@ -43,6 +29,5 @@
text: .text%InflateFully;
text: .text%inflateEnd;
text: .text%Java_java_util_zip_Inflater_reset;
-text: .text%Java_java_util_zip_ZipFile_close;
text: .text%ZIP_Close;
text: .text%Java_java_util_zip_Inflater_end;
--- a/jdk/make/mapfiles/libzip/reorder-x86 Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/make/mapfiles/libzip/reorder-x86 Wed Jul 05 21:09:54 2017 +0200
@@ -16,34 +16,16 @@
text: .text%ZIP_Lock;
text: .text%ZIP_Unlock;
text: .text%ZIP_FreeEntry;
-text: .text%Java_java_util_zip_ZipFile_initIDs;
-text: .text%Java_java_util_zip_ZipFile_open;
-text: .text%Java_java_util_zip_ZipFile_getTotal;
-text: .text%Java_java_util_zip_ZipFile_startsWithLOC;
-text: .text%Java_java_util_zip_ZipFile_getEntry;
-text: .text%Java_java_util_zip_ZipFile_freeEntry;
-text: .text%Java_java_util_zip_ZipFile_getEntryTime;
-text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
-text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
-text: .text%Java_java_util_zip_ZipFile_getEntrySize;
-text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
-text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
-text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
-text: .text%Java_java_util_zip_Inflater_initIDs;
-text: .text%Java_java_util_zip_Inflater_init;
text: .text%inflateInit2_;
text: .text%zcalloc;
text: .text%inflateReset;
text: .text%Java_java_util_zip_Inflater_inflateBytes;
text: .text%inflate;
-text: .text%Java_java_util_zip_ZipFile_read;
text: .text%ZIP_Read;
text: .text%zcfree;
-text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
text: .text%ZIP_ReadEntry;
text: .text%InflateFully;
text: .text%inflateEnd;
text: .text%Java_java_util_zip_Inflater_reset;
-text: .text%Java_java_util_zip_ZipFile_close;
text: .text%ZIP_Close;
text: .text%Java_java_util_zip_Inflater_end;
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/BlockCipherParamsCore.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/BlockCipherParamsCore.java Wed Jul 05 21:09:54 2017 +0200
@@ -27,7 +27,7 @@
import java.io.*;
import sun.security.util.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.spec.IvParameterSpec;
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GCMParameters.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GCMParameters.java Wed Jul 05 21:09:54 2017 +0200
@@ -30,7 +30,7 @@
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.spec.GCMParameterSpec;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.*;
/**
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBEParameters.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBEParameters.java Wed Jul 05 21:09:54 2017 +0200
@@ -31,7 +31,7 @@
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.spec.PBEParameterSpec;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.*;
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java Wed Jul 05 21:09:54 2017 +0200
@@ -33,7 +33,7 @@
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEParameterSpec;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.*;
/**
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/RC2Parameters.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/RC2Parameters.java Wed Jul 05 21:09:54 2017 +0200
@@ -30,7 +30,7 @@
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.spec.RC2ParameterSpec;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.*;
/**
--- a/jdk/src/java.base/share/classes/com/sun/security/ntlm/NTLM.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/security/ntlm/NTLM.java Wed Jul 05 21:09:54 2017 +0200
@@ -118,7 +118,7 @@
public void debug(byte[] bytes) {
if (DEBUG) {
try {
- new sun.misc.HexDumpEncoder().encodeBuffer(bytes, System.out);
+ new sun.security.util.HexDumpEncoder().encodeBuffer(bytes, System.out);
} catch (IOException ioe) {
// Impossible
}
--- a/jdk/src/java.base/share/classes/java/io/CharArrayReader.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/io/CharArrayReader.java Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2005, 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
@@ -225,9 +225,12 @@
* Closes the stream and releases any system resources associated with
* it. Once the stream has been closed, further read(), ready(),
* mark(), reset(), or skip() invocations will throw an IOException.
- * Closing a previously closed stream has no effect.
+ * Closing a previously closed stream has no effect. This method will block
+ * while there is another thread blocking on the reader.
*/
public void close() {
- buf = null;
+ synchronized (lock) {
+ buf = null;
+ }
}
}
--- a/jdk/src/java.base/share/classes/java/io/PushbackReader.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/io/PushbackReader.java Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, 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
@@ -241,13 +241,16 @@
* Closes the stream and releases any system resources associated with
* it. Once the stream has been closed, further read(),
* unread(), ready(), or skip() invocations will throw an IOException.
- * Closing a previously closed stream has no effect.
+ * Closing a previously closed stream has no effect. This method will block
+ * while there is another thread blocking on the reader.
*
* @exception IOException If an I/O error occurs
*/
public void close() throws IOException {
- super.close();
- buf = null;
+ synchronized (lock) {
+ super.close();
+ buf = null;
+ }
}
/**
--- a/jdk/src/java.base/share/classes/java/io/StringReader.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/io/StringReader.java Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, 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
@@ -194,9 +194,12 @@
* Closes the stream and releases any system resources associated with
* it. Once the stream has been closed, further read(),
* ready(), mark(), or reset() invocations will throw an IOException.
- * Closing a previously closed stream has no effect.
+ * Closing a previously closed stream has no effect. This method will block
+ * while there is another thread blocking on the reader.
*/
public void close() {
- str = null;
+ synchronized (lock) {
+ str = null;
+ }
}
}
--- a/jdk/src/java.base/share/classes/java/lang/InheritableThreadLocal.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/InheritableThreadLocal.java Wed Jul 05 21:09:54 2017 +0200
@@ -40,6 +40,11 @@
* maintained in the variable (e.g., User ID, Transaction ID) must be
* automatically transmitted to any child threads that are created.
*
+ * <p>Note: During the creation of a new {@link
+ * Thread#Thread(ThreadGroup,Runnable,String,long,boolean) thread}, it is
+ * possible to <i>opt out</i> of receiving initial values for inheritable
+ * thread-local variables.
+ *
* @author Josh Bloch and Doug Lea
* @see ThreadLocal
* @since 1.2
--- a/jdk/src/java.base/share/classes/java/lang/StackWalker.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/StackWalker.java Wed Jul 05 21:09:54 2017 +0200
@@ -304,8 +304,8 @@
}
/**
- * Returns a {@code StackWalker} instance with the given {@ocde options} specifying
- * the stack frame information it can access. If the given {@ocde options}
+ * Returns a {@code StackWalker} instance with the given {@code options} specifying
+ * the stack frame information it can access. If the given {@code options}
* is empty, this {@code StackWalker} is configured to skip all
* {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and no
* {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained.
--- a/jdk/src/java.base/share/classes/java/lang/StringUTF16.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/StringUTF16.java Wed Jul 05 21:09:54 2017 +0200
@@ -120,7 +120,8 @@
public static byte[] toBytes(char[] value, int off, int len) {
byte[] val = newBytesFor(len);
for (int i = 0; i < len; i++) {
- putChar(val, i, value[off++]);
+ putChar(val, i, value[off]);
+ off++;
}
return val;
}
@@ -145,11 +146,14 @@
@HotSpotIntrinsicCandidate
private static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) {
for (int i = 0; i < len; i++) {
- int c = src[srcOff++];
- if (c >>> 8 != 0) {
- return 0;
+ char c = src[srcOff];
+ if (c > 0xFF) {
+ len = 0;
+ break;
}
- dst[dstOff++] = (byte)c;
+ dst[dstOff] = (byte)c;
+ srcOff++;
+ dstOff++;
}
return len;
}
@@ -160,11 +164,14 @@
// We need a range check here because 'getChar' has no checks
checkBoundsOffCount(srcOff, len, src.length);
for (int i = 0; i < len; i++) {
- int c = getChar(src, srcOff++);
- if (c >>> 8 != 0) {
- return 0;
+ char c = getChar(src, srcOff);
+ if (c > 0xFF) {
+ len = 0;
+ break;
}
- dst[dstOff++] = (byte)c;
+ dst[dstOff] = (byte)c;
+ srcOff++;
+ dstOff++;
}
return len;
}
@@ -581,7 +588,7 @@
bits |= cp;
putChar(result, i, cp);
}
- if (bits >>> 8 != 0) {
+ if (bits > 0xFF) {
return new String(result, UTF16);
} else {
return newString(result, 0, len);
@@ -678,7 +685,7 @@
bits |= cp;
putChar(result, i, cp);
}
- if (bits >>> 8 != 0) {
+ if (bits > 0xFF) {
return new String(result, UTF16);
} else {
return newString(result, 0, len);
--- a/jdk/src/java.base/share/classes/java/lang/Thread.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/Thread.java Wed Jul 05 21:09:54 2017 +0200
@@ -344,11 +344,11 @@
/**
* Initializes a Thread with the current AccessControlContext.
- * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext)
+ * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext,boolean)
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
- init(g, target, name, stackSize, null);
+ init(g, target, name, stackSize, null, true);
}
/**
@@ -361,9 +361,12 @@
* zero to indicate that this parameter is to be ignored.
* @param acc the AccessControlContext to inherit, or
* AccessController.getContext() if null
+ * @param inheritThreadLocals if {@code true}, inherit initial values for
+ * inheritable thread-locals from the constructing thread
*/
private void init(ThreadGroup g, Runnable target, String name,
- long stackSize, AccessControlContext acc) {
+ long stackSize, AccessControlContext acc,
+ boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
@@ -414,7 +417,7 @@
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
- if (parent.inheritableThreadLocals != null)
+ if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
@@ -468,7 +471,7 @@
* This is not a public constructor.
*/
Thread(Runnable target, AccessControlContext acc) {
- init(null, target, "Thread-" + nextThreadNum(), 0, acc);
+ init(null, target, "Thread-" + nextThreadNum(), 0, acc, true);
}
/**
@@ -678,6 +681,62 @@
}
/**
+ * Allocates a new {@code Thread} object so that it has {@code target}
+ * as its run object, has the specified {@code name} as its name,
+ * belongs to the thread group referred to by {@code group}, has
+ * the specified {@code stackSize}, and inherits initial values for
+ * {@linkplain InheritableThreadLocal inheritable thread-local} variables
+ * if {@code inheritThreadLocals} is {@code true}.
+ *
+ * <p> This constructor is identical to {@link
+ * #Thread(ThreadGroup,Runnable,String,long)} with the added ability to
+ * suppress, or not, the inheriting of initial values for inheritable
+ * thread-local variables from the constructing thread. This allows for
+ * finer grain control over inheritable thread-locals. Care must be taken
+ * when passing a value of {@code false} for {@code inheritThreadLocals},
+ * as it may lead to unexpected behavior if the new thread executes code
+ * that expects a specific thread-local value to be inherited.
+ *
+ * <p> Specifying a value of {@code true} for the {@code inheritThreadLocals}
+ * parameter will cause this constructor to behave exactly like the
+ * {@code Thread(ThreadGroup, Runnable, String, long)} constructor.
+ *
+ * @param group
+ * the thread group. If {@code null} and there is a security
+ * manager, the group is determined by {@linkplain
+ * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
+ * If there is not a security manager or {@code
+ * SecurityManager.getThreadGroup()} returns {@code null}, the group
+ * is set to the current thread's thread group.
+ *
+ * @param target
+ * the object whose {@code run} method is invoked when this thread
+ * is started. If {@code null}, this thread's run method is invoked.
+ *
+ * @param name
+ * the name of the new thread
+ *
+ * @param stackSize
+ * the desired stack size for the new thread, or zero to indicate
+ * that this parameter is to be ignored
+ *
+ * @param inheritThreadLocals
+ * if {@code true}, inherit initial values for inheritable
+ * thread-locals from the constructing thread, otherwise no initial
+ * values are inherited
+ *
+ * @throws SecurityException
+ * if the current thread cannot create a thread in the specified
+ * thread group
+ *
+ * @since 9
+ */
+ public Thread(ThreadGroup group, Runnable target, String name,
+ long stackSize, boolean inheritThreadLocals) {
+ init(group, target, name, stackSize, null, inheritThreadLocals);
+ }
+
+ /**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>
--- a/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java Wed Jul 05 21:09:54 2017 +0200
@@ -83,7 +83,6 @@
*/
abstract
public class CallSite {
- static { MethodHandleImpl.initStatics(); }
// The actual payload of this call site:
/*package-private*/
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java Wed Jul 05 21:09:54 2017 +0200
@@ -1073,11 +1073,6 @@
}
}
-// static {
-// System.out.println("Hello world! My methods are:");
-// System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null));
-// }
-
static {
// Allow privileged classes outside of java.lang
jdk.internal.misc.SharedSecrets.setJavaLangInvokeAccess(new jdk.internal.misc.JavaLangInvokeAccess() {
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java Wed Jul 05 21:09:54 2017 +0200
@@ -420,7 +420,6 @@
* @author John Rose, JSR 292 EG
*/
public abstract class MethodHandle {
- static { MethodHandleImpl.initStatics(); }
/**
* Internal marker interface which distinguishes (to the Java compiler)
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -32,7 +32,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
-import java.util.stream.Collectors;
import sun.invoke.empty.Empty;
import sun.invoke.util.ValueConversions;
@@ -65,11 +64,6 @@
/// Factory methods to create method handles:
- static void initStatics() {
- // Trigger selected static initializations.
- MemberName.Factory.INSTANCE.getClass();
- }
-
static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
if (arrayClass == Object[].class)
return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER);
@@ -700,33 +694,43 @@
MethodHandle makeBlockInliningWrapper(MethodHandle target) {
LambdaForm lform;
if (DONT_INLINE_THRESHOLD > 0) {
- lform = PRODUCE_BLOCK_INLINING_FORM.apply(target);
+ lform = Makers.PRODUCE_BLOCK_INLINING_FORM.apply(target);
} else {
- lform = PRODUCE_REINVOKER_FORM.apply(target);
+ lform = Makers.PRODUCE_REINVOKER_FORM.apply(target);
}
return new CountingWrapper(target, lform,
- PRODUCE_BLOCK_INLINING_FORM, PRODUCE_REINVOKER_FORM,
+ Makers.PRODUCE_BLOCK_INLINING_FORM, Makers.PRODUCE_REINVOKER_FORM,
DONT_INLINE_THRESHOLD);
}
- /** Constructs reinvoker lambda form which block inlining during JIT-compilation for a particular method handle */
- private static final Function<MethodHandle, LambdaForm> PRODUCE_BLOCK_INLINING_FORM = new Function<MethodHandle, LambdaForm>() {
- @Override
- public LambdaForm apply(MethodHandle target) {
- return DelegatingMethodHandle.makeReinvokerForm(target,
- MethodTypeForm.LF_DELEGATE_BLOCK_INLINING, CountingWrapper.class, "reinvoker.dontInline", false,
- DelegatingMethodHandle.NF_getTarget, CountingWrapper.NF_maybeStopCounting);
- }
- };
+ private final static class Makers {
+ /** Constructs reinvoker lambda form which block inlining during JIT-compilation for a particular method handle */
+ static final Function<MethodHandle, LambdaForm> PRODUCE_BLOCK_INLINING_FORM = new Function<MethodHandle, LambdaForm>() {
+ @Override
+ public LambdaForm apply(MethodHandle target) {
+ return DelegatingMethodHandle.makeReinvokerForm(target,
+ MethodTypeForm.LF_DELEGATE_BLOCK_INLINING, CountingWrapper.class, "reinvoker.dontInline", false,
+ DelegatingMethodHandle.NF_getTarget, CountingWrapper.NF_maybeStopCounting);
+ }
+ };
- /** Constructs simple reinvoker lambda form for a particular method handle */
- private static final Function<MethodHandle, LambdaForm> PRODUCE_REINVOKER_FORM = new Function<MethodHandle, LambdaForm>() {
- @Override
- public LambdaForm apply(MethodHandle target) {
- return DelegatingMethodHandle.makeReinvokerForm(target,
- MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, DelegatingMethodHandle.NF_getTarget);
- }
- };
+ /** Constructs simple reinvoker lambda form for a particular method handle */
+ static final Function<MethodHandle, LambdaForm> PRODUCE_REINVOKER_FORM = new Function<MethodHandle, LambdaForm>() {
+ @Override
+ public LambdaForm apply(MethodHandle target) {
+ return DelegatingMethodHandle.makeReinvokerForm(target,
+ MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, DelegatingMethodHandle.NF_getTarget);
+ }
+ };
+
+ /** Maker of type-polymorphic varargs */
+ static final ClassValue<MethodHandle[]> TYPED_COLLECTORS = new ClassValue<MethodHandle[]>() {
+ @Override
+ protected MethodHandle[] computeValue(Class<?> type) {
+ return new MethodHandle[MAX_JVM_ARITY + 1];
+ }
+ };
+ }
/**
* Counting method handle. It has 2 states: counting and non-counting.
@@ -1527,15 +1531,6 @@
return MethodHandles.collectArguments(rightFill, 0, midFill);
}
- // Type-polymorphic version of varargs maker.
- private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
- = new ClassValue<MethodHandle[]>() {
- @Override
- protected MethodHandle[] computeValue(Class<?> type) {
- return new MethodHandle[256];
- }
- };
-
static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM
/** Return a method handle that takes the indicated number of
@@ -1557,7 +1552,7 @@
if (elemType == Object.class)
return varargsArray(nargs);
// other cases: primitive arrays, subtypes of Object[]
- MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
+ MethodHandle cache[] = Makers.TYPED_COLLECTORS.get(elemType);
MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
if (mh != null) return mh;
if (nargs == 0) {
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java Wed Jul 05 21:09:54 2017 +0200
@@ -87,9 +87,6 @@
private static native void registerNatives();
static {
registerNatives();
-
- // The JVM calls MethodHandleNatives.<clinit>. Cascade the <clinit> calls as needed:
- MethodHandleImpl.initStatics();
}
/**
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Jul 05 21:09:54 2017 +0200
@@ -61,7 +61,7 @@
private MethodHandles() { } // do not instantiate
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
- static { MethodHandleImpl.initStatics(); }
+
// See IMPL_LOOKUP below.
//// Method handle creation from ordinary methods.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/ref/Cleaner.java Wed Jul 05 21:09:54 2017 +0200
@@ -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. 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 java.lang.ref;
+
+import java.util.Objects;
+import java.util.concurrent.ThreadFactory;
+
+import jdk.internal.misc.CleanerImpl;
+
+/**
+ * {@code Cleaner} manages a set of object references and corresponding cleaning actions.
+ * <p>
+ * Cleaning actions are {@link #register(Object object, Runnable action) registered}
+ * to run after the cleaner is notified that the object has become
+ * phantom reachable.
+ * The cleaner uses {@link PhantomReference} and {@link ReferenceQueue} to be
+ * notified when the <a href="package-summary.html#reachability">reachability</a>
+ * changes.
+ * <p>
+ * Each cleaner operates independently, managing the pending cleaning actions
+ * and handling threading and termination when the cleaner is no longer in use.
+ * Registering an object reference and corresponding cleaning action returns
+ * a {@link Cleanable Cleanable}. The most efficient use is to explicitly invoke
+ * the {@link Cleanable#clean clean} method when the object is closed or
+ * no longer needed.
+ * The cleaning action is a {@link Runnable} to be invoked at most once when
+ * the object has become phantom reachable unless it has already been explicitly cleaned.
+ * Note that the cleaning action must not refer to the object being registered.
+ * If so, the object will not become phantom reachable and the cleaning action
+ * will not be invoked automatically.
+ * <p>
+ * The execution of the cleaning action is performed
+ * by a thread associated with the cleaner.
+ * All exceptions thrown by the cleaning action are ignored.
+ * The cleaner and other cleaning actions are not affected by
+ * exceptions in a cleaning action.
+ * The thread runs until all registered cleaning actions have
+ * completed and the cleaner itself is reclaimed by the garbage collector.
+ * <p>
+ * The behavior of cleaners during {@link System#exit(int) System.exit}
+ * is implementation specific. No guarantees are made relating
+ * to whether cleaning actions are invoked or not.
+ * <p>
+ * Unless otherwise noted, passing a {@code null} argument to a constructor or
+ * method in this class will cause a
+ * {@link java.lang.NullPointerException NullPointerException} to be thrown.
+ *
+ * @apiNote
+ * The cleaning action is invoked only after the associated object becomes
+ * phantom reachable, so it is important that the object implementing the
+ * cleaning action does not hold references to the object.
+ * In this example, a static class encapsulates the cleaning state and action.
+ * An "inner" class, anonymous or not, must not be used because it implicitly
+ * contains a reference to the outer instance, preventing it from becoming
+ * phantom reachable.
+ * The choice of a new cleaner or sharing an existing cleaner is determined
+ * by the use case.
+ * <p>
+ * If the CleaningExample is used in a try-finally block then the
+ * {@code close} method calls the cleaning action.
+ * If the {@code close} method is not called, the cleaning action is called
+ * by the Cleaner when the CleaningExample instance has become phantom reachable.
+ * <pre>{@code
+ * public class CleaningExample implements AutoCloseable {
+ * // A cleaner, preferably one shared within a library
+ * private static final Cleaner cleaner = <cleaner>;
+ *
+ * static class State implements Runnable {
+ *
+ * State(...) {
+ * // initialize State needed for cleaning action
+ * }
+ *
+ * public void run() {
+ * // cleanup action accessing State, executed at most once
+ * }
+ * }
+ *
+ * private final State;
+ * private final Cleaner.Cleanable cleanable
+ *
+ * public CleaningExample() {
+ * this.state = new State(...);
+ * this.cleanable = cleaner.register(this, state);
+ * }
+ *
+ * public void close() {
+ * cleanable.clean();
+ * }
+ * }
+ * }</pre>
+ * The cleaning action could be a lambda but all too easily will capture
+ * the object reference, by referring to fields of the object being cleaned,
+ * preventing the object from becoming phantom reachable.
+ * Using a static nested class, as above, will avoid accidentally retaining the
+ * object reference.
+ * <p>
+ * <a name="compatible-cleaners"></a>
+ * Cleaning actions should be prepared to be invoked concurrently with
+ * other cleaning actions.
+ * Typically the cleaning actions should be very quick to execute
+ * and not block. If the cleaning action blocks, it may delay processing
+ * other cleaning actions registered to the same cleaner.
+ * All cleaning actions registered to a cleaner should be mutually compatible.
+ * @since 9
+ */
+public final class Cleaner {
+
+ /**
+ * The Cleaner implementation.
+ */
+ final CleanerImpl impl;
+
+ static {
+ CleanerImpl.setCleanerImplAccess((Cleaner c) -> c.impl);
+ }
+
+ /**
+ * Construct a Cleaner implementation and start it.
+ */
+ private Cleaner() {
+ impl = new CleanerImpl();
+ }
+
+ /**
+ * Returns a new {@code Cleaner}.
+ * <p>
+ * The cleaner creates a {@link Thread#setDaemon(boolean) daemon thread}
+ * to process the phantom reachable objects and to invoke cleaning actions.
+ * The {@linkplain java.lang.Thread#getContextClassLoader context class loader}
+ * of the thread is set to the
+ * {@link ClassLoader#getSystemClassLoader() system class loader}.
+ * The thread has no permissions, enforced only if a
+ * {@link java.lang.System#setSecurityManager(SecurityManager) SecurityManager is set}.
+ * <p>
+ * The cleaner terminates when it is phantom reachable and all of the
+ * registered cleaning actions are complete.
+ *
+ * @return a new {@code Cleaner}
+ *
+ * @throws SecurityException if the current thread is not allowed to
+ * create or start the thread.
+ */
+ public static Cleaner create() {
+ Cleaner cleaner = new Cleaner();
+ cleaner.impl.start(cleaner, null);
+ return cleaner;
+ }
+
+ /**
+ * Returns a new {@code Cleaner} using a {@code Thread} from the {@code ThreadFactory}.
+ * <p>
+ * A thread from the thread factory's {@link ThreadFactory#newThread(Runnable) newThread}
+ * method is set to be a {@link Thread#setDaemon(boolean) daemon thread}
+ * and started to process phantom reachable objects and invoke cleaning actions.
+ * On each call the {@link ThreadFactory#newThread(Runnable) thread factory}
+ * must provide a Thread that is suitable for performing the cleaning actions.
+ * <p>
+ * The cleaner terminates when it is phantom reachable and all of the
+ * registered cleaning actions are complete.
+ *
+ * @param threadFactory a {@code ThreadFactory} to return a new {@code Thread}
+ * to process cleaning actions
+ * @return a new {@code Cleaner}
+ *
+ * @throws IllegalThreadStateException if the thread from the thread
+ * factory was {@link Thread.State#NEW not a new thread}.
+ * @throws SecurityException if the current thread is not allowed to
+ * create or start the thread.
+ */
+ public static Cleaner create(ThreadFactory threadFactory) {
+ Objects.requireNonNull(threadFactory, "threadFactory");
+ Cleaner cleaner = new Cleaner();
+ cleaner.impl.start(cleaner, threadFactory);
+ return cleaner;
+ }
+
+ /**
+ * Registers an object and a cleaning action to run when the object
+ * becomes phantom reachable.
+ * Refer to the <a href="#compatible-cleaners">API Note</a> above for
+ * cautions about the behavior of cleaning actions.
+ *
+ * @param obj the object to monitor
+ * @param action a {@code Runnable} to invoke when the object becomes phantom reachable
+ * @return a {@code Cleanable} instance
+ */
+ public Cleanable register(Object obj, Runnable action) {
+ Objects.requireNonNull(obj, "obj");
+ Objects.requireNonNull(action, "action");
+ return new CleanerImpl.PhantomCleanableRef(obj, this, action);
+ }
+
+ /**
+ * {@code Cleanable} represents an object and a
+ * cleaning action registered in a {@code Cleaner}.
+ * @since 9
+ */
+ public interface Cleanable {
+ /**
+ * Unregisters the cleanable and invokes the cleaning action.
+ * The cleanable's cleaning action is invoked at most once
+ * regardless of the number of calls to {@code clean}.
+ */
+ void clean();
+ }
+
+}
--- a/jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,7 +29,6 @@
import java.security.AccessController;
import jdk.internal.misc.JavaLangAccess;
import jdk.internal.misc.SharedSecrets;
-import sun.misc.ManagedLocalsThread;
import sun.misc.VM;
final class Finalizer extends FinalReference<Object> { /* Package-private; must be in
@@ -131,7 +130,7 @@
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
- Thread sft = new ManagedLocalsThread(tg, proc, "Secondary finalizer");
+ Thread sft = new Thread(tg, proc, "Secondary finalizer", 0, false);
sft.start();
try {
sft.join();
@@ -190,10 +189,10 @@
}}});
}
- private static class FinalizerThread extends ManagedLocalsThread {
+ private static class FinalizerThread extends Thread {
private volatile boolean running;
FinalizerThread(ThreadGroup g) {
- super(g, "Finalizer");
+ super(g, null, "Finalizer", 0, false);
}
public void run() {
// in case of recursive call to run()
--- a/jdk/src/java.base/share/classes/java/lang/ref/Reference.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/ref/Reference.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,7 +29,6 @@
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.misc.JavaLangRefAccess;
import jdk.internal.misc.SharedSecrets;
-import sun.misc.ManagedLocalsThread;
/**
* Abstract base class for reference objects. This class defines the
@@ -128,7 +127,7 @@
/* High-priority thread to enqueue pending References
*/
- private static class ReferenceHandler extends ManagedLocalsThread {
+ private static class ReferenceHandler extends Thread {
private static void ensureClassInitialized(Class<?> clazz) {
try {
@@ -147,7 +146,7 @@
}
ReferenceHandler(ThreadGroup g, String name) {
- super(g, name);
+ super(g, null, name, 0, false);
}
public void run() {
--- a/jdk/src/java.base/share/classes/java/lang/ref/package-info.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/ref/package-info.java Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2003, 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
@@ -45,6 +45,8 @@
* (or values) from being reclaimed, and phantom references are for
* scheduling pre-mortem cleanup actions in a more flexible way than
* is possible with the Java finalization mechanism.
+ * Post-mortem cleanup actions can be registered and managed by a
+ * {@link java.lang.ref.Cleaner}.
*
* <p> Each reference-object type is implemented by a subclass of the
* abstract base {@link java.lang.ref.Reference} class.
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AnnotatedArrayType.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AnnotatedArrayType.java Wed Jul 05 21:09:54 2017 +0200
@@ -42,4 +42,19 @@
* @see GenericArrayType#getGenericComponentType()
*/
AnnotatedType getAnnotatedGenericComponentType();
+
+ /**
+ * Returns the potentially annotated type that this type is a member of, if
+ * this type represents a nested type. For example, if this type is
+ * {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}.
+ *
+ * <p>Returns {@code null} for an {@code AnnotatedType} that is an instance
+ * of {@code AnnotatedArrayType}.
+ *
+ * @return {@code null}
+ *
+ * @since 1.9
+ */
+ @Override
+ AnnotatedType getAnnotatedOwnerType();
}
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AnnotatedParameterizedType.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AnnotatedParameterizedType.java Wed Jul 05 21:09:54 2017 +0200
@@ -41,4 +41,26 @@
* @see ParameterizedType#getActualTypeArguments()
*/
AnnotatedType[] getAnnotatedActualTypeArguments();
+
+ /**
+ * Returns the potentially annotated type that this type is a member of, if
+ * this type represents a nested type. For example, if this type is
+ * {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}.
+ *
+ * <p>Returns {@code null} if this {@code AnnotatedType} represents a
+ * top-level type, or a local or anonymous class, or a primitive type, or
+ * void.
+ *
+ * @return an {@code AnnotatedType} object representing the potentially
+ * annotated type that this type is a member of, or {@code null}
+ * @throws TypeNotPresentException if the owner type
+ * refers to a non-existent type declaration
+ * @throws MalformedParameterizedTypeException if the owner type
+ * refers to a parameterized type that cannot be instantiated
+ * for any reason
+ *
+ * @since 1.9
+ */
+ @Override
+ AnnotatedType getAnnotatedOwnerType();
}
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AnnotatedType.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AnnotatedType.java Wed Jul 05 21:09:54 2017 +0200
@@ -36,6 +36,37 @@
public interface AnnotatedType extends AnnotatedElement {
/**
+ * Returns the potentially annotated type that this type is a member of, if
+ * this type represents a nested type. For example, if this type is
+ * {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}.
+ *
+ * <p>Returns {@code null} if this {@code AnnotatedType} represents a
+ * top-level type, or a local or anonymous class, or a primitive type, or
+ * void.
+ *
+ * <p>Returns {@code null} if this {@code AnnotatedType} is an instance of
+ * {@code AnnotatedArrayType}, {@code AnnotatedTypeVariable}, or
+ * {@code AnnotatedWildcardType}.
+ *
+ * @implSpec
+ * This default implementation returns {@code null} and performs no other
+ * action.
+ *
+ * @return an {@code AnnotatedType} object representing the potentially
+ * annotated type that this type is a member of, or {@code null}
+ * @throws TypeNotPresentException if the owner type
+ * refers to a non-existent type declaration
+ * @throws MalformedParameterizedTypeException if the owner type
+ * refers to a parameterized type that cannot be instantiated
+ * for any reason
+ *
+ * @since 1.9
+ */
+ default AnnotatedType getAnnotatedOwnerType() {
+ return null;
+ }
+
+ /**
* Returns the underlying type that this annotated type represents.
*
* @return the type this annotated type represents
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AnnotatedTypeVariable.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AnnotatedTypeVariable.java Wed Jul 05 21:09:54 2017 +0200
@@ -43,4 +43,19 @@
* @see TypeVariable#getBounds()
*/
AnnotatedType[] getAnnotatedBounds();
+
+ /**
+ * Returns the potentially annotated type that this type is a member of, if
+ * this type represents a nested type. For example, if this type is
+ * {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}.
+ *
+ * <p>Returns {@code null} for an {@code AnnotatedType} that is an instance
+ * of {@code AnnotatedTypeVariable}.
+ *
+ * @return {@code null}
+ *
+ * @since 1.9
+ */
+ @Override
+ AnnotatedType getAnnotatedOwnerType();
}
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AnnotatedWildcardType.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AnnotatedWildcardType.java Wed Jul 05 21:09:54 2017 +0200
@@ -54,4 +54,19 @@
* @see WildcardType#getUpperBounds()
*/
AnnotatedType[] getAnnotatedUpperBounds();
+
+ /**
+ * Returns the potentially annotated type that this type is a member of, if
+ * this type represents a nested type. For example, if this type is
+ * {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}.
+ *
+ * <p>Returns {@code null} for an {@code AnnotatedType} that is an instance
+ * of {@code AnnotatedWildcardType}.
+ *
+ * @return {@code null}
+ *
+ * @since 1.9
+ */
+ @Override
+ AnnotatedType getAnnotatedOwnerType();
}
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java Wed Jul 05 21:09:54 2017 +0200
@@ -34,7 +34,6 @@
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiFunction;
-import sun.misc.ProxyGenerator;
import sun.misc.VM;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,2031 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 java.lang.reflect;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import sun.security.action.GetBooleanAction;
+
+/**
+ * ProxyGenerator contains the code to generate a dynamic proxy class
+ * for the java.lang.reflect.Proxy API.
+ *
+ * The external interfaces to ProxyGenerator is the static
+ * "generateProxyClass" method.
+ *
+ * @author Peter Jones
+ * @since 1.3
+ */
+class ProxyGenerator {
+ /*
+ * In the comments below, "JVMS" refers to The Java Virtual Machine
+ * Specification Second Edition and "JLS" refers to the original
+ * version of The Java Language Specification, unless otherwise
+ * specified.
+ */
+
+ /* generate 1.5-era class file version */
+ private static final int CLASSFILE_MAJOR_VERSION = 49;
+ private static final int CLASSFILE_MINOR_VERSION = 0;
+
+ /*
+ * beginning of constants copied from
+ * sun.tools.java.RuntimeConstants (which no longer exists):
+ */
+
+ /* constant pool tags */
+ private static final int CONSTANT_UTF8 = 1;
+ private static final int CONSTANT_UNICODE = 2;
+ private static final int CONSTANT_INTEGER = 3;
+ private static final int CONSTANT_FLOAT = 4;
+ private static final int CONSTANT_LONG = 5;
+ private static final int CONSTANT_DOUBLE = 6;
+ private static final int CONSTANT_CLASS = 7;
+ private static final int CONSTANT_STRING = 8;
+ private static final int CONSTANT_FIELD = 9;
+ private static final int CONSTANT_METHOD = 10;
+ private static final int CONSTANT_INTERFACEMETHOD = 11;
+ private static final int CONSTANT_NAMEANDTYPE = 12;
+
+ /* access and modifier flags */
+ private static final int ACC_PUBLIC = 0x00000001;
+ private static final int ACC_PRIVATE = 0x00000002;
+// private static final int ACC_PROTECTED = 0x00000004;
+ private static final int ACC_STATIC = 0x00000008;
+ private static final int ACC_FINAL = 0x00000010;
+// private static final int ACC_SYNCHRONIZED = 0x00000020;
+// private static final int ACC_VOLATILE = 0x00000040;
+// private static final int ACC_TRANSIENT = 0x00000080;
+// private static final int ACC_NATIVE = 0x00000100;
+// private static final int ACC_INTERFACE = 0x00000200;
+// private static final int ACC_ABSTRACT = 0x00000400;
+ private static final int ACC_SUPER = 0x00000020;
+// private static final int ACC_STRICT = 0x00000800;
+
+ /* opcodes */
+// private static final int opc_nop = 0;
+ private static final int opc_aconst_null = 1;
+// private static final int opc_iconst_m1 = 2;
+ private static final int opc_iconst_0 = 3;
+// private static final int opc_iconst_1 = 4;
+// private static final int opc_iconst_2 = 5;
+// private static final int opc_iconst_3 = 6;
+// private static final int opc_iconst_4 = 7;
+// private static final int opc_iconst_5 = 8;
+// private static final int opc_lconst_0 = 9;
+// private static final int opc_lconst_1 = 10;
+// private static final int opc_fconst_0 = 11;
+// private static final int opc_fconst_1 = 12;
+// private static final int opc_fconst_2 = 13;
+// private static final int opc_dconst_0 = 14;
+// private static final int opc_dconst_1 = 15;
+ private static final int opc_bipush = 16;
+ private static final int opc_sipush = 17;
+ private static final int opc_ldc = 18;
+ private static final int opc_ldc_w = 19;
+// private static final int opc_ldc2_w = 20;
+ private static final int opc_iload = 21;
+ private static final int opc_lload = 22;
+ private static final int opc_fload = 23;
+ private static final int opc_dload = 24;
+ private static final int opc_aload = 25;
+ private static final int opc_iload_0 = 26;
+// private static final int opc_iload_1 = 27;
+// private static final int opc_iload_2 = 28;
+// private static final int opc_iload_3 = 29;
+ private static final int opc_lload_0 = 30;
+// private static final int opc_lload_1 = 31;
+// private static final int opc_lload_2 = 32;
+// private static final int opc_lload_3 = 33;
+ private static final int opc_fload_0 = 34;
+// private static final int opc_fload_1 = 35;
+// private static final int opc_fload_2 = 36;
+// private static final int opc_fload_3 = 37;
+ private static final int opc_dload_0 = 38;
+// private static final int opc_dload_1 = 39;
+// private static final int opc_dload_2 = 40;
+// private static final int opc_dload_3 = 41;
+ private static final int opc_aload_0 = 42;
+// private static final int opc_aload_1 = 43;
+// private static final int opc_aload_2 = 44;
+// private static final int opc_aload_3 = 45;
+// private static final int opc_iaload = 46;
+// private static final int opc_laload = 47;
+// private static final int opc_faload = 48;
+// private static final int opc_daload = 49;
+// private static final int opc_aaload = 50;
+// private static final int opc_baload = 51;
+// private static final int opc_caload = 52;
+// private static final int opc_saload = 53;
+// private static final int opc_istore = 54;
+// private static final int opc_lstore = 55;
+// private static final int opc_fstore = 56;
+// private static final int opc_dstore = 57;
+ private static final int opc_astore = 58;
+// private static final int opc_istore_0 = 59;
+// private static final int opc_istore_1 = 60;
+// private static final int opc_istore_2 = 61;
+// private static final int opc_istore_3 = 62;
+// private static final int opc_lstore_0 = 63;
+// private static final int opc_lstore_1 = 64;
+// private static final int opc_lstore_2 = 65;
+// private static final int opc_lstore_3 = 66;
+// private static final int opc_fstore_0 = 67;
+// private static final int opc_fstore_1 = 68;
+// private static final int opc_fstore_2 = 69;
+// private static final int opc_fstore_3 = 70;
+// private static final int opc_dstore_0 = 71;
+// private static final int opc_dstore_1 = 72;
+// private static final int opc_dstore_2 = 73;
+// private static final int opc_dstore_3 = 74;
+ private static final int opc_astore_0 = 75;
+// private static final int opc_astore_1 = 76;
+// private static final int opc_astore_2 = 77;
+// private static final int opc_astore_3 = 78;
+// private static final int opc_iastore = 79;
+// private static final int opc_lastore = 80;
+// private static final int opc_fastore = 81;
+// private static final int opc_dastore = 82;
+ private static final int opc_aastore = 83;
+// private static final int opc_bastore = 84;
+// private static final int opc_castore = 85;
+// private static final int opc_sastore = 86;
+ private static final int opc_pop = 87;
+// private static final int opc_pop2 = 88;
+ private static final int opc_dup = 89;
+// private static final int opc_dup_x1 = 90;
+// private static final int opc_dup_x2 = 91;
+// private static final int opc_dup2 = 92;
+// private static final int opc_dup2_x1 = 93;
+// private static final int opc_dup2_x2 = 94;
+// private static final int opc_swap = 95;
+// private static final int opc_iadd = 96;
+// private static final int opc_ladd = 97;
+// private static final int opc_fadd = 98;
+// private static final int opc_dadd = 99;
+// private static final int opc_isub = 100;
+// private static final int opc_lsub = 101;
+// private static final int opc_fsub = 102;
+// private static final int opc_dsub = 103;
+// private static final int opc_imul = 104;
+// private static final int opc_lmul = 105;
+// private static final int opc_fmul = 106;
+// private static final int opc_dmul = 107;
+// private static final int opc_idiv = 108;
+// private static final int opc_ldiv = 109;
+// private static final int opc_fdiv = 110;
+// private static final int opc_ddiv = 111;
+// private static final int opc_irem = 112;
+// private static final int opc_lrem = 113;
+// private static final int opc_frem = 114;
+// private static final int opc_drem = 115;
+// private static final int opc_ineg = 116;
+// private static final int opc_lneg = 117;
+// private static final int opc_fneg = 118;
+// private static final int opc_dneg = 119;
+// private static final int opc_ishl = 120;
+// private static final int opc_lshl = 121;
+// private static final int opc_ishr = 122;
+// private static final int opc_lshr = 123;
+// private static final int opc_iushr = 124;
+// private static final int opc_lushr = 125;
+// private static final int opc_iand = 126;
+// private static final int opc_land = 127;
+// private static final int opc_ior = 128;
+// private static final int opc_lor = 129;
+// private static final int opc_ixor = 130;
+// private static final int opc_lxor = 131;
+// private static final int opc_iinc = 132;
+// private static final int opc_i2l = 133;
+// private static final int opc_i2f = 134;
+// private static final int opc_i2d = 135;
+// private static final int opc_l2i = 136;
+// private static final int opc_l2f = 137;
+// private static final int opc_l2d = 138;
+// private static final int opc_f2i = 139;
+// private static final int opc_f2l = 140;
+// private static final int opc_f2d = 141;
+// private static final int opc_d2i = 142;
+// private static final int opc_d2l = 143;
+// private static final int opc_d2f = 144;
+// private static final int opc_i2b = 145;
+// private static final int opc_i2c = 146;
+// private static final int opc_i2s = 147;
+// private static final int opc_lcmp = 148;
+// private static final int opc_fcmpl = 149;
+// private static final int opc_fcmpg = 150;
+// private static final int opc_dcmpl = 151;
+// private static final int opc_dcmpg = 152;
+// private static final int opc_ifeq = 153;
+// private static final int opc_ifne = 154;
+// private static final int opc_iflt = 155;
+// private static final int opc_ifge = 156;
+// private static final int opc_ifgt = 157;
+// private static final int opc_ifle = 158;
+// private static final int opc_if_icmpeq = 159;
+// private static final int opc_if_icmpne = 160;
+// private static final int opc_if_icmplt = 161;
+// private static final int opc_if_icmpge = 162;
+// private static final int opc_if_icmpgt = 163;
+// private static final int opc_if_icmple = 164;
+// private static final int opc_if_acmpeq = 165;
+// private static final int opc_if_acmpne = 166;
+// private static final int opc_goto = 167;
+// private static final int opc_jsr = 168;
+// private static final int opc_ret = 169;
+// private static final int opc_tableswitch = 170;
+// private static final int opc_lookupswitch = 171;
+ private static final int opc_ireturn = 172;
+ private static final int opc_lreturn = 173;
+ private static final int opc_freturn = 174;
+ private static final int opc_dreturn = 175;
+ private static final int opc_areturn = 176;
+ private static final int opc_return = 177;
+ private static final int opc_getstatic = 178;
+ private static final int opc_putstatic = 179;
+ private static final int opc_getfield = 180;
+// private static final int opc_putfield = 181;
+ private static final int opc_invokevirtual = 182;
+ private static final int opc_invokespecial = 183;
+ private static final int opc_invokestatic = 184;
+ private static final int opc_invokeinterface = 185;
+ private static final int opc_new = 187;
+// private static final int opc_newarray = 188;
+ private static final int opc_anewarray = 189;
+// private static final int opc_arraylength = 190;
+ private static final int opc_athrow = 191;
+ private static final int opc_checkcast = 192;
+// private static final int opc_instanceof = 193;
+// private static final int opc_monitorenter = 194;
+// private static final int opc_monitorexit = 195;
+ private static final int opc_wide = 196;
+// private static final int opc_multianewarray = 197;
+// private static final int opc_ifnull = 198;
+// private static final int opc_ifnonnull = 199;
+// private static final int opc_goto_w = 200;
+// private static final int opc_jsr_w = 201;
+
+ // end of constants copied from sun.tools.java.RuntimeConstants
+
+ /** name of the superclass of proxy classes */
+ private static final String superclassName = "java/lang/reflect/Proxy";
+
+ /** name of field for storing a proxy instance's invocation handler */
+ private static final String handlerFieldName = "h";
+
+ /** debugging flag for saving generated class files */
+ private static final boolean saveGeneratedFiles =
+ java.security.AccessController.doPrivileged(
+ new GetBooleanAction(
+ "jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue();
+
+ /**
+ * Generate a public proxy class given a name and a list of proxy interfaces.
+ */
+ static byte[] generateProxyClass(final String name,
+ Class<?>[] interfaces) {
+ return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER));
+ }
+
+ /**
+ * Generate a proxy class given a name and a list of proxy interfaces.
+ *
+ * @param name the class name of the proxy class
+ * @param interfaces proxy interfaces
+ * @param accessFlags access flags of the proxy class
+ */
+ static byte[] generateProxyClass(final String name,
+ Class<?>[] interfaces,
+ int accessFlags)
+ {
+ ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
+ final byte[] classFile = gen.generateClassFile();
+
+ if (saveGeneratedFiles) {
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<Void>() {
+ public Void run() {
+ try {
+ int i = name.lastIndexOf('.');
+ Path path;
+ if (i > 0) {
+ Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
+ Files.createDirectories(dir);
+ path = dir.resolve(name.substring(i+1, name.length()) + ".class");
+ } else {
+ path = Paths.get(name + ".class");
+ }
+ Files.write(path, classFile);
+ return null;
+ } catch (IOException e) {
+ throw new InternalError(
+ "I/O exception saving generated file: " + e);
+ }
+ }
+ });
+ }
+
+ return classFile;
+ }
+
+ /* preloaded Method objects for methods in java.lang.Object */
+ private static Method hashCodeMethod;
+ private static Method equalsMethod;
+ private static Method toStringMethod;
+ static {
+ try {
+ hashCodeMethod = Object.class.getMethod("hashCode");
+ equalsMethod =
+ Object.class.getMethod("equals", new Class<?>[] { Object.class });
+ toStringMethod = Object.class.getMethod("toString");
+ } catch (NoSuchMethodException e) {
+ throw new NoSuchMethodError(e.getMessage());
+ }
+ }
+
+ /** name of proxy class */
+ private String className;
+
+ /** proxy interfaces */
+ private Class<?>[] interfaces;
+
+ /** proxy class access flags */
+ private int accessFlags;
+
+ /** constant pool of class being generated */
+ private ConstantPool cp = new ConstantPool();
+
+ /** FieldInfo struct for each field of generated class */
+ private List<FieldInfo> fields = new ArrayList<>();
+
+ /** MethodInfo struct for each method of generated class */
+ private List<MethodInfo> methods = new ArrayList<>();
+
+ /**
+ * maps method signature string to list of ProxyMethod objects for
+ * proxy methods with that signature
+ */
+ private Map<String, List<ProxyMethod>> proxyMethods = new HashMap<>();
+
+ /** count of ProxyMethod objects added to proxyMethods */
+ private int proxyMethodCount = 0;
+
+ /**
+ * Construct a ProxyGenerator to generate a proxy class with the
+ * specified name and for the given interfaces.
+ *
+ * A ProxyGenerator object contains the state for the ongoing
+ * generation of a particular proxy class.
+ */
+ private ProxyGenerator(String className, Class<?>[] interfaces, int accessFlags) {
+ this.className = className;
+ this.interfaces = interfaces;
+ this.accessFlags = accessFlags;
+ }
+
+ /**
+ * Generate a class file for the proxy class. This method drives the
+ * class file generation process.
+ */
+ private byte[] generateClassFile() {
+
+ /* ============================================================
+ * Step 1: Assemble ProxyMethod objects for all methods to
+ * generate proxy dispatching code for.
+ */
+
+ /*
+ * Record that proxy methods are needed for the hashCode, equals,
+ * and toString methods of java.lang.Object. This is done before
+ * the methods from the proxy interfaces so that the methods from
+ * java.lang.Object take precedence over duplicate methods in the
+ * proxy interfaces.
+ */
+ addProxyMethod(hashCodeMethod, Object.class);
+ addProxyMethod(equalsMethod, Object.class);
+ addProxyMethod(toStringMethod, Object.class);
+
+ /*
+ * Now record all of the methods from the proxy interfaces, giving
+ * earlier interfaces precedence over later ones with duplicate
+ * methods.
+ */
+ for (Class<?> intf : interfaces) {
+ for (Method m : intf.getMethods()) {
+ addProxyMethod(m, intf);
+ }
+ }
+
+ /*
+ * For each set of proxy methods with the same signature,
+ * verify that the methods' return types are compatible.
+ */
+ for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
+ checkReturnTypes(sigmethods);
+ }
+
+ /* ============================================================
+ * Step 2: Assemble FieldInfo and MethodInfo structs for all of
+ * fields and methods in the class we are generating.
+ */
+ try {
+ methods.add(generateConstructor());
+
+ for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
+ for (ProxyMethod pm : sigmethods) {
+
+ // add static field for method's Method object
+ fields.add(new FieldInfo(pm.methodFieldName,
+ "Ljava/lang/reflect/Method;",
+ ACC_PRIVATE | ACC_STATIC));
+
+ // generate code for proxy method and add it
+ methods.add(pm.generateMethod());
+ }
+ }
+
+ methods.add(generateStaticInitializer());
+
+ } catch (IOException e) {
+ throw new InternalError("unexpected I/O Exception", e);
+ }
+
+ if (methods.size() > 65535) {
+ throw new IllegalArgumentException("method limit exceeded");
+ }
+ if (fields.size() > 65535) {
+ throw new IllegalArgumentException("field limit exceeded");
+ }
+
+ /* ============================================================
+ * Step 3: Write the final class file.
+ */
+
+ /*
+ * Make sure that constant pool indexes are reserved for the
+ * following items before starting to write the final class file.
+ */
+ cp.getClass(dotToSlash(className));
+ cp.getClass(superclassName);
+ for (Class<?> intf: interfaces) {
+ cp.getClass(dotToSlash(intf.getName()));
+ }
+
+ /*
+ * Disallow new constant pool additions beyond this point, since
+ * we are about to write the final constant pool table.
+ */
+ cp.setReadOnly();
+
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ DataOutputStream dout = new DataOutputStream(bout);
+
+ try {
+ /*
+ * Write all the items of the "ClassFile" structure.
+ * See JVMS section 4.1.
+ */
+ // u4 magic;
+ dout.writeInt(0xCAFEBABE);
+ // u2 minor_version;
+ dout.writeShort(CLASSFILE_MINOR_VERSION);
+ // u2 major_version;
+ dout.writeShort(CLASSFILE_MAJOR_VERSION);
+
+ cp.write(dout); // (write constant pool)
+
+ // u2 access_flags;
+ dout.writeShort(accessFlags);
+ // u2 this_class;
+ dout.writeShort(cp.getClass(dotToSlash(className)));
+ // u2 super_class;
+ dout.writeShort(cp.getClass(superclassName));
+
+ // u2 interfaces_count;
+ dout.writeShort(interfaces.length);
+ // u2 interfaces[interfaces_count];
+ for (Class<?> intf : interfaces) {
+ dout.writeShort(cp.getClass(
+ dotToSlash(intf.getName())));
+ }
+
+ // u2 fields_count;
+ dout.writeShort(fields.size());
+ // field_info fields[fields_count];
+ for (FieldInfo f : fields) {
+ f.write(dout);
+ }
+
+ // u2 methods_count;
+ dout.writeShort(methods.size());
+ // method_info methods[methods_count];
+ for (MethodInfo m : methods) {
+ m.write(dout);
+ }
+
+ // u2 attributes_count;
+ dout.writeShort(0); // (no ClassFile attributes for proxy classes)
+
+ } catch (IOException e) {
+ throw new InternalError("unexpected I/O Exception", e);
+ }
+
+ return bout.toByteArray();
+ }
+
+ /**
+ * Add another method to be proxied, either by creating a new
+ * ProxyMethod object or augmenting an old one for a duplicate
+ * method.
+ *
+ * "fromClass" indicates the proxy interface that the method was
+ * found through, which may be different from (a subinterface of)
+ * the method's "declaring class". Note that the first Method
+ * object passed for a given name and descriptor identifies the
+ * Method object (and thus the declaring class) that will be
+ * passed to the invocation handler's "invoke" method for a given
+ * set of duplicate methods.
+ */
+ private void addProxyMethod(Method m, Class<?> fromClass) {
+ String name = m.getName();
+ Class<?>[] parameterTypes = m.getParameterTypes();
+ Class<?> returnType = m.getReturnType();
+ Class<?>[] exceptionTypes = m.getExceptionTypes();
+
+ String sig = name + getParameterDescriptors(parameterTypes);
+ List<ProxyMethod> sigmethods = proxyMethods.get(sig);
+ if (sigmethods != null) {
+ for (ProxyMethod pm : sigmethods) {
+ if (returnType == pm.returnType) {
+ /*
+ * Found a match: reduce exception types to the
+ * greatest set of exceptions that can thrown
+ * compatibly with the throws clauses of both
+ * overridden methods.
+ */
+ List<Class<?>> legalExceptions = new ArrayList<>();
+ collectCompatibleTypes(
+ exceptionTypes, pm.exceptionTypes, legalExceptions);
+ collectCompatibleTypes(
+ pm.exceptionTypes, exceptionTypes, legalExceptions);
+ pm.exceptionTypes = new Class<?>[legalExceptions.size()];
+ pm.exceptionTypes =
+ legalExceptions.toArray(pm.exceptionTypes);
+ return;
+ }
+ }
+ } else {
+ sigmethods = new ArrayList<>(3);
+ proxyMethods.put(sig, sigmethods);
+ }
+ sigmethods.add(new ProxyMethod(name, parameterTypes, returnType,
+ exceptionTypes, fromClass));
+ }
+
+ /**
+ * For a given set of proxy methods with the same signature, check
+ * that their return types are compatible according to the Proxy
+ * specification.
+ *
+ * Specifically, if there is more than one such method, then all
+ * of the return types must be reference types, and there must be
+ * one return type that is assignable to each of the rest of them.
+ */
+ private static void checkReturnTypes(List<ProxyMethod> methods) {
+ /*
+ * If there is only one method with a given signature, there
+ * cannot be a conflict. This is the only case in which a
+ * primitive (or void) return type is allowed.
+ */
+ if (methods.size() < 2) {
+ return;
+ }
+
+ /*
+ * List of return types that are not yet known to be
+ * assignable from ("covered" by) any of the others.
+ */
+ LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<>();
+
+ nextNewReturnType:
+ for (ProxyMethod pm : methods) {
+ Class<?> newReturnType = pm.returnType;
+ if (newReturnType.isPrimitive()) {
+ throw new IllegalArgumentException(
+ "methods with same signature " +
+ getFriendlyMethodSignature(pm.methodName,
+ pm.parameterTypes) +
+ " but incompatible return types: " +
+ newReturnType.getName() + " and others");
+ }
+ boolean added = false;
+
+ /*
+ * Compare the new return type to the existing uncovered
+ * return types.
+ */
+ ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator();
+ while (liter.hasNext()) {
+ Class<?> uncoveredReturnType = liter.next();
+
+ /*
+ * If an existing uncovered return type is assignable
+ * to this new one, then we can forget the new one.
+ */
+ if (newReturnType.isAssignableFrom(uncoveredReturnType)) {
+ assert !added;
+ continue nextNewReturnType;
+ }
+
+ /*
+ * If the new return type is assignable to an existing
+ * uncovered one, then should replace the existing one
+ * with the new one (or just forget the existing one,
+ * if the new one has already be put in the list).
+ */
+ if (uncoveredReturnType.isAssignableFrom(newReturnType)) {
+ // (we can assume that each return type is unique)
+ if (!added) {
+ liter.set(newReturnType);
+ added = true;
+ } else {
+ liter.remove();
+ }
+ }
+ }
+
+ /*
+ * If we got through the list of existing uncovered return
+ * types without an assignability relationship, then add
+ * the new return type to the list of uncovered ones.
+ */
+ if (!added) {
+ uncoveredReturnTypes.add(newReturnType);
+ }
+ }
+
+ /*
+ * We shouldn't end up with more than one return type that is
+ * not assignable from any of the others.
+ */
+ if (uncoveredReturnTypes.size() > 1) {
+ ProxyMethod pm = methods.get(0);
+ throw new IllegalArgumentException(
+ "methods with same signature " +
+ getFriendlyMethodSignature(pm.methodName, pm.parameterTypes) +
+ " but incompatible return types: " + uncoveredReturnTypes);
+ }
+ }
+
+ /**
+ * A FieldInfo object contains information about a particular field
+ * in the class being generated. The class mirrors the data items of
+ * the "field_info" structure of the class file format (see JVMS 4.5).
+ */
+ private class FieldInfo {
+ public int accessFlags;
+ public String name;
+ public String descriptor;
+
+ public FieldInfo(String name, String descriptor, int accessFlags) {
+ this.name = name;
+ this.descriptor = descriptor;
+ this.accessFlags = accessFlags;
+
+ /*
+ * Make sure that constant pool indexes are reserved for the
+ * following items before starting to write the final class file.
+ */
+ cp.getUtf8(name);
+ cp.getUtf8(descriptor);
+ }
+
+ public void write(DataOutputStream out) throws IOException {
+ /*
+ * Write all the items of the "field_info" structure.
+ * See JVMS section 4.5.
+ */
+ // u2 access_flags;
+ out.writeShort(accessFlags);
+ // u2 name_index;
+ out.writeShort(cp.getUtf8(name));
+ // u2 descriptor_index;
+ out.writeShort(cp.getUtf8(descriptor));
+ // u2 attributes_count;
+ out.writeShort(0); // (no field_info attributes for proxy classes)
+ }
+ }
+
+ /**
+ * An ExceptionTableEntry object holds values for the data items of
+ * an entry in the "exception_table" item of the "Code" attribute of
+ * "method_info" structures (see JVMS 4.7.3).
+ */
+ private static class ExceptionTableEntry {
+ public short startPc;
+ public short endPc;
+ public short handlerPc;
+ public short catchType;
+
+ public ExceptionTableEntry(short startPc, short endPc,
+ short handlerPc, short catchType)
+ {
+ this.startPc = startPc;
+ this.endPc = endPc;
+ this.handlerPc = handlerPc;
+ this.catchType = catchType;
+ }
+ };
+
+ /**
+ * A MethodInfo object contains information about a particular method
+ * in the class being generated. This class mirrors the data items of
+ * the "method_info" structure of the class file format (see JVMS 4.6).
+ */
+ private class MethodInfo {
+ public int accessFlags;
+ public String name;
+ public String descriptor;
+ public short maxStack;
+ public short maxLocals;
+ public ByteArrayOutputStream code = new ByteArrayOutputStream();
+ public List<ExceptionTableEntry> exceptionTable =
+ new ArrayList<ExceptionTableEntry>();
+ public short[] declaredExceptions;
+
+ public MethodInfo(String name, String descriptor, int accessFlags) {
+ this.name = name;
+ this.descriptor = descriptor;
+ this.accessFlags = accessFlags;
+
+ /*
+ * Make sure that constant pool indexes are reserved for the
+ * following items before starting to write the final class file.
+ */
+ cp.getUtf8(name);
+ cp.getUtf8(descriptor);
+ cp.getUtf8("Code");
+ cp.getUtf8("Exceptions");
+ }
+
+ public void write(DataOutputStream out) throws IOException {
+ /*
+ * Write all the items of the "method_info" structure.
+ * See JVMS section 4.6.
+ */
+ // u2 access_flags;
+ out.writeShort(accessFlags);
+ // u2 name_index;
+ out.writeShort(cp.getUtf8(name));
+ // u2 descriptor_index;
+ out.writeShort(cp.getUtf8(descriptor));
+ // u2 attributes_count;
+ out.writeShort(2); // (two method_info attributes:)
+
+ // Write "Code" attribute. See JVMS section 4.7.3.
+
+ // u2 attribute_name_index;
+ out.writeShort(cp.getUtf8("Code"));
+ // u4 attribute_length;
+ out.writeInt(12 + code.size() + 8 * exceptionTable.size());
+ // u2 max_stack;
+ out.writeShort(maxStack);
+ // u2 max_locals;
+ out.writeShort(maxLocals);
+ // u2 code_length;
+ out.writeInt(code.size());
+ // u1 code[code_length];
+ code.writeTo(out);
+ // u2 exception_table_length;
+ out.writeShort(exceptionTable.size());
+ for (ExceptionTableEntry e : exceptionTable) {
+ // u2 start_pc;
+ out.writeShort(e.startPc);
+ // u2 end_pc;
+ out.writeShort(e.endPc);
+ // u2 handler_pc;
+ out.writeShort(e.handlerPc);
+ // u2 catch_type;
+ out.writeShort(e.catchType);
+ }
+ // u2 attributes_count;
+ out.writeShort(0);
+
+ // write "Exceptions" attribute. See JVMS section 4.7.4.
+
+ // u2 attribute_name_index;
+ out.writeShort(cp.getUtf8("Exceptions"));
+ // u4 attributes_length;
+ out.writeInt(2 + 2 * declaredExceptions.length);
+ // u2 number_of_exceptions;
+ out.writeShort(declaredExceptions.length);
+ // u2 exception_index_table[number_of_exceptions];
+ for (short value : declaredExceptions) {
+ out.writeShort(value);
+ }
+ }
+
+ }
+
+ /**
+ * A ProxyMethod object represents a proxy method in the proxy class
+ * being generated: a method whose implementation will encode and
+ * dispatch invocations to the proxy instance's invocation handler.
+ */
+ private class ProxyMethod {
+
+ public String methodName;
+ public Class<?>[] parameterTypes;
+ public Class<?> returnType;
+ public Class<?>[] exceptionTypes;
+ public Class<?> fromClass;
+ public String methodFieldName;
+
+ private ProxyMethod(String methodName, Class<?>[] parameterTypes,
+ Class<?> returnType, Class<?>[] exceptionTypes,
+ Class<?> fromClass)
+ {
+ this.methodName = methodName;
+ this.parameterTypes = parameterTypes;
+ this.returnType = returnType;
+ this.exceptionTypes = exceptionTypes;
+ this.fromClass = fromClass;
+ this.methodFieldName = "m" + proxyMethodCount++;
+ }
+
+ /**
+ * Return a MethodInfo object for this method, including generating
+ * the code and exception table entry.
+ */
+ private MethodInfo generateMethod() throws IOException {
+ String desc = getMethodDescriptor(parameterTypes, returnType);
+ MethodInfo minfo = new MethodInfo(methodName, desc,
+ ACC_PUBLIC | ACC_FINAL);
+
+ int[] parameterSlot = new int[parameterTypes.length];
+ int nextSlot = 1;
+ for (int i = 0; i < parameterSlot.length; i++) {
+ parameterSlot[i] = nextSlot;
+ nextSlot += getWordsPerType(parameterTypes[i]);
+ }
+ int localSlot0 = nextSlot;
+ short pc, tryBegin = 0, tryEnd;
+
+ DataOutputStream out = new DataOutputStream(minfo.code);
+
+ code_aload(0, out);
+
+ out.writeByte(opc_getfield);
+ out.writeShort(cp.getFieldRef(
+ superclassName,
+ handlerFieldName, "Ljava/lang/reflect/InvocationHandler;"));
+
+ code_aload(0, out);
+
+ out.writeByte(opc_getstatic);
+ out.writeShort(cp.getFieldRef(
+ dotToSlash(className),
+ methodFieldName, "Ljava/lang/reflect/Method;"));
+
+ if (parameterTypes.length > 0) {
+
+ code_ipush(parameterTypes.length, out);
+
+ out.writeByte(opc_anewarray);
+ out.writeShort(cp.getClass("java/lang/Object"));
+
+ for (int i = 0; i < parameterTypes.length; i++) {
+
+ out.writeByte(opc_dup);
+
+ code_ipush(i, out);
+
+ codeWrapArgument(parameterTypes[i], parameterSlot[i], out);
+
+ out.writeByte(opc_aastore);
+ }
+ } else {
+
+ out.writeByte(opc_aconst_null);
+ }
+
+ out.writeByte(opc_invokeinterface);
+ out.writeShort(cp.getInterfaceMethodRef(
+ "java/lang/reflect/InvocationHandler",
+ "invoke",
+ "(Ljava/lang/Object;Ljava/lang/reflect/Method;" +
+ "[Ljava/lang/Object;)Ljava/lang/Object;"));
+ out.writeByte(4);
+ out.writeByte(0);
+
+ if (returnType == void.class) {
+
+ out.writeByte(opc_pop);
+
+ out.writeByte(opc_return);
+
+ } else {
+
+ codeUnwrapReturnValue(returnType, out);
+ }
+
+ tryEnd = pc = (short) minfo.code.size();
+
+ List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes);
+ if (catchList.size() > 0) {
+
+ for (Class<?> ex : catchList) {
+ minfo.exceptionTable.add(new ExceptionTableEntry(
+ tryBegin, tryEnd, pc,
+ cp.getClass(dotToSlash(ex.getName()))));
+ }
+
+ out.writeByte(opc_athrow);
+
+ pc = (short) minfo.code.size();
+
+ minfo.exceptionTable.add(new ExceptionTableEntry(
+ tryBegin, tryEnd, pc, cp.getClass("java/lang/Throwable")));
+
+ code_astore(localSlot0, out);
+
+ out.writeByte(opc_new);
+ out.writeShort(cp.getClass(
+ "java/lang/reflect/UndeclaredThrowableException"));
+
+ out.writeByte(opc_dup);
+
+ code_aload(localSlot0, out);
+
+ out.writeByte(opc_invokespecial);
+
+ out.writeShort(cp.getMethodRef(
+ "java/lang/reflect/UndeclaredThrowableException",
+ "<init>", "(Ljava/lang/Throwable;)V"));
+
+ out.writeByte(opc_athrow);
+ }
+
+ if (minfo.code.size() > 65535) {
+ throw new IllegalArgumentException("code size limit exceeded");
+ }
+
+ minfo.maxStack = 10;
+ minfo.maxLocals = (short) (localSlot0 + 1);
+ minfo.declaredExceptions = new short[exceptionTypes.length];
+ for (int i = 0; i < exceptionTypes.length; i++) {
+ minfo.declaredExceptions[i] = cp.getClass(
+ dotToSlash(exceptionTypes[i].getName()));
+ }
+
+ return minfo;
+ }
+
+ /**
+ * Generate code for wrapping an argument of the given type
+ * whose value can be found at the specified local variable
+ * index, in order for it to be passed (as an Object) to the
+ * invocation handler's "invoke" method. The code is written
+ * to the supplied stream.
+ */
+ private void codeWrapArgument(Class<?> type, int slot,
+ DataOutputStream out)
+ throws IOException
+ {
+ if (type.isPrimitive()) {
+ PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
+
+ if (type == int.class ||
+ type == boolean.class ||
+ type == byte.class ||
+ type == char.class ||
+ type == short.class)
+ {
+ code_iload(slot, out);
+ } else if (type == long.class) {
+ code_lload(slot, out);
+ } else if (type == float.class) {
+ code_fload(slot, out);
+ } else if (type == double.class) {
+ code_dload(slot, out);
+ } else {
+ throw new AssertionError();
+ }
+
+ out.writeByte(opc_invokestatic);
+ out.writeShort(cp.getMethodRef(
+ prim.wrapperClassName,
+ "valueOf", prim.wrapperValueOfDesc));
+
+ } else {
+
+ code_aload(slot, out);
+ }
+ }
+
+ /**
+ * Generate code for unwrapping a return value of the given
+ * type from the invocation handler's "invoke" method (as type
+ * Object) to its correct type. The code is written to the
+ * supplied stream.
+ */
+ private void codeUnwrapReturnValue(Class<?> type, DataOutputStream out)
+ throws IOException
+ {
+ if (type.isPrimitive()) {
+ PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
+
+ out.writeByte(opc_checkcast);
+ out.writeShort(cp.getClass(prim.wrapperClassName));
+
+ out.writeByte(opc_invokevirtual);
+ out.writeShort(cp.getMethodRef(
+ prim.wrapperClassName,
+ prim.unwrapMethodName, prim.unwrapMethodDesc));
+
+ if (type == int.class ||
+ type == boolean.class ||
+ type == byte.class ||
+ type == char.class ||
+ type == short.class)
+ {
+ out.writeByte(opc_ireturn);
+ } else if (type == long.class) {
+ out.writeByte(opc_lreturn);
+ } else if (type == float.class) {
+ out.writeByte(opc_freturn);
+ } else if (type == double.class) {
+ out.writeByte(opc_dreturn);
+ } else {
+ throw new AssertionError();
+ }
+
+ } else {
+
+ out.writeByte(opc_checkcast);
+ out.writeShort(cp.getClass(dotToSlash(type.getName())));
+
+ out.writeByte(opc_areturn);
+ }
+ }
+
+ /**
+ * Generate code for initializing the static field that stores
+ * the Method object for this proxy method. The code is written
+ * to the supplied stream.
+ */
+ private void codeFieldInitialization(DataOutputStream out)
+ throws IOException
+ {
+ codeClassForName(fromClass, out);
+
+ code_ldc(cp.getString(methodName), out);
+
+ code_ipush(parameterTypes.length, out);
+
+ out.writeByte(opc_anewarray);
+ out.writeShort(cp.getClass("java/lang/Class"));
+
+ for (int i = 0; i < parameterTypes.length; i++) {
+
+ out.writeByte(opc_dup);
+
+ code_ipush(i, out);
+
+ if (parameterTypes[i].isPrimitive()) {
+ PrimitiveTypeInfo prim =
+ PrimitiveTypeInfo.get(parameterTypes[i]);
+
+ out.writeByte(opc_getstatic);
+ out.writeShort(cp.getFieldRef(
+ prim.wrapperClassName, "TYPE", "Ljava/lang/Class;"));
+
+ } else {
+ codeClassForName(parameterTypes[i], out);
+ }
+
+ out.writeByte(opc_aastore);
+ }
+
+ out.writeByte(opc_invokevirtual);
+ out.writeShort(cp.getMethodRef(
+ "java/lang/Class",
+ "getMethod",
+ "(Ljava/lang/String;[Ljava/lang/Class;)" +
+ "Ljava/lang/reflect/Method;"));
+
+ out.writeByte(opc_putstatic);
+ out.writeShort(cp.getFieldRef(
+ dotToSlash(className),
+ methodFieldName, "Ljava/lang/reflect/Method;"));
+ }
+ }
+
+ /**
+ * Generate the constructor method for the proxy class.
+ */
+ private MethodInfo generateConstructor() throws IOException {
+ MethodInfo minfo = new MethodInfo(
+ "<init>", "(Ljava/lang/reflect/InvocationHandler;)V",
+ ACC_PUBLIC);
+
+ DataOutputStream out = new DataOutputStream(minfo.code);
+
+ code_aload(0, out);
+
+ code_aload(1, out);
+
+ out.writeByte(opc_invokespecial);
+ out.writeShort(cp.getMethodRef(
+ superclassName,
+ "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
+
+ out.writeByte(opc_return);
+
+ minfo.maxStack = 10;
+ minfo.maxLocals = 2;
+ minfo.declaredExceptions = new short[0];
+
+ return minfo;
+ }
+
+ /**
+ * Generate the static initializer method for the proxy class.
+ */
+ private MethodInfo generateStaticInitializer() throws IOException {
+ MethodInfo minfo = new MethodInfo(
+ "<clinit>", "()V", ACC_STATIC);
+
+ int localSlot0 = 1;
+ short pc, tryBegin = 0, tryEnd;
+
+ DataOutputStream out = new DataOutputStream(minfo.code);
+
+ for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
+ for (ProxyMethod pm : sigmethods) {
+ pm.codeFieldInitialization(out);
+ }
+ }
+
+ out.writeByte(opc_return);
+
+ tryEnd = pc = (short) minfo.code.size();
+
+ minfo.exceptionTable.add(new ExceptionTableEntry(
+ tryBegin, tryEnd, pc,
+ cp.getClass("java/lang/NoSuchMethodException")));
+
+ code_astore(localSlot0, out);
+
+ out.writeByte(opc_new);
+ out.writeShort(cp.getClass("java/lang/NoSuchMethodError"));
+
+ out.writeByte(opc_dup);
+
+ code_aload(localSlot0, out);
+
+ out.writeByte(opc_invokevirtual);
+ out.writeShort(cp.getMethodRef(
+ "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
+
+ out.writeByte(opc_invokespecial);
+ out.writeShort(cp.getMethodRef(
+ "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V"));
+
+ out.writeByte(opc_athrow);
+
+ pc = (short) minfo.code.size();
+
+ minfo.exceptionTable.add(new ExceptionTableEntry(
+ tryBegin, tryEnd, pc,
+ cp.getClass("java/lang/ClassNotFoundException")));
+
+ code_astore(localSlot0, out);
+
+ out.writeByte(opc_new);
+ out.writeShort(cp.getClass("java/lang/NoClassDefFoundError"));
+
+ out.writeByte(opc_dup);
+
+ code_aload(localSlot0, out);
+
+ out.writeByte(opc_invokevirtual);
+ out.writeShort(cp.getMethodRef(
+ "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
+
+ out.writeByte(opc_invokespecial);
+ out.writeShort(cp.getMethodRef(
+ "java/lang/NoClassDefFoundError",
+ "<init>", "(Ljava/lang/String;)V"));
+
+ out.writeByte(opc_athrow);
+
+ if (minfo.code.size() > 65535) {
+ throw new IllegalArgumentException("code size limit exceeded");
+ }
+
+ minfo.maxStack = 10;
+ minfo.maxLocals = (short) (localSlot0 + 1);
+ minfo.declaredExceptions = new short[0];
+
+ return minfo;
+ }
+
+
+ /*
+ * =============== Code Generation Utility Methods ===============
+ */
+
+ /*
+ * The following methods generate code for the load or store operation
+ * indicated by their name for the given local variable. The code is
+ * written to the supplied stream.
+ */
+
+ private void code_iload(int lvar, DataOutputStream out)
+ throws IOException
+ {
+ codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out);
+ }
+
+ private void code_lload(int lvar, DataOutputStream out)
+ throws IOException
+ {
+ codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out);
+ }
+
+ private void code_fload(int lvar, DataOutputStream out)
+ throws IOException
+ {
+ codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out);
+ }
+
+ private void code_dload(int lvar, DataOutputStream out)
+ throws IOException
+ {
+ codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out);
+ }
+
+ private void code_aload(int lvar, DataOutputStream out)
+ throws IOException
+ {
+ codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out);
+ }
+
+// private void code_istore(int lvar, DataOutputStream out)
+// throws IOException
+// {
+// codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out);
+// }
+
+// private void code_lstore(int lvar, DataOutputStream out)
+// throws IOException
+// {
+// codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out);
+// }
+
+// private void code_fstore(int lvar, DataOutputStream out)
+// throws IOException
+// {
+// codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out);
+// }
+
+// private void code_dstore(int lvar, DataOutputStream out)
+// throws IOException
+// {
+// codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out);
+// }
+
+ private void code_astore(int lvar, DataOutputStream out)
+ throws IOException
+ {
+ codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out);
+ }
+
+ /**
+ * Generate code for a load or store instruction for the given local
+ * variable. The code is written to the supplied stream.
+ *
+ * "opcode" indicates the opcode form of the desired load or store
+ * instruction that takes an explicit local variable index, and
+ * "opcode_0" indicates the corresponding form of the instruction
+ * with the implicit index 0.
+ */
+ private void codeLocalLoadStore(int lvar, int opcode, int opcode_0,
+ DataOutputStream out)
+ throws IOException
+ {
+ assert lvar >= 0 && lvar <= 0xFFFF;
+ if (lvar <= 3) {
+ out.writeByte(opcode_0 + lvar);
+ } else if (lvar <= 0xFF) {
+ out.writeByte(opcode);
+ out.writeByte(lvar & 0xFF);
+ } else {
+ /*
+ * Use the "wide" instruction modifier for local variable
+ * indexes that do not fit into an unsigned byte.
+ */
+ out.writeByte(opc_wide);
+ out.writeByte(opcode);
+ out.writeShort(lvar & 0xFFFF);
+ }
+ }
+
+ /**
+ * Generate code for an "ldc" instruction for the given constant pool
+ * index (the "ldc_w" instruction is used if the index does not fit
+ * into an unsigned byte). The code is written to the supplied stream.
+ */
+ private void code_ldc(int index, DataOutputStream out)
+ throws IOException
+ {
+ assert index >= 0 && index <= 0xFFFF;
+ if (index <= 0xFF) {
+ out.writeByte(opc_ldc);
+ out.writeByte(index & 0xFF);
+ } else {
+ out.writeByte(opc_ldc_w);
+ out.writeShort(index & 0xFFFF);
+ }
+ }
+
+ /**
+ * Generate code to push a constant integer value on to the operand
+ * stack, using the "iconst_<i>", "bipush", or "sipush" instructions
+ * depending on the size of the value. The code is written to the
+ * supplied stream.
+ */
+ private void code_ipush(int value, DataOutputStream out)
+ throws IOException
+ {
+ if (value >= -1 && value <= 5) {
+ out.writeByte(opc_iconst_0 + value);
+ } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
+ out.writeByte(opc_bipush);
+ out.writeByte(value & 0xFF);
+ } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
+ out.writeByte(opc_sipush);
+ out.writeShort(value & 0xFFFF);
+ } else {
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Generate code to invoke the Class.forName with the name of the given
+ * class to get its Class object at runtime. The code is written to
+ * the supplied stream. Note that the code generated by this method
+ * may caused the checked ClassNotFoundException to be thrown.
+ */
+ private void codeClassForName(Class<?> cl, DataOutputStream out)
+ throws IOException
+ {
+ code_ldc(cp.getString(cl.getName()), out);
+
+ out.writeByte(opc_invokestatic);
+ out.writeShort(cp.getMethodRef(
+ "java/lang/Class",
+ "forName", "(Ljava/lang/String;)Ljava/lang/Class;"));
+ }
+
+
+ /*
+ * ==================== General Utility Methods ====================
+ */
+
+ /**
+ * Convert a fully qualified class name that uses '.' as the package
+ * separator, the external representation used by the Java language
+ * and APIs, to a fully qualified class name that uses '/' as the
+ * package separator, the representation used in the class file
+ * format (see JVMS section 4.2).
+ */
+ private static String dotToSlash(String name) {
+ return name.replace('.', '/');
+ }
+
+ /**
+ * Return the "method descriptor" string for a method with the given
+ * parameter types and return type. See JVMS section 4.3.3.
+ */
+ private static String getMethodDescriptor(Class<?>[] parameterTypes,
+ Class<?> returnType)
+ {
+ return getParameterDescriptors(parameterTypes) +
+ ((returnType == void.class) ? "V" : getFieldType(returnType));
+ }
+
+ /**
+ * Return the list of "parameter descriptor" strings enclosed in
+ * parentheses corresponding to the given parameter types (in other
+ * words, a method descriptor without a return descriptor). This
+ * string is useful for constructing string keys for methods without
+ * regard to their return type.
+ */
+ private static String getParameterDescriptors(Class<?>[] parameterTypes) {
+ StringBuilder desc = new StringBuilder("(");
+ for (int i = 0; i < parameterTypes.length; i++) {
+ desc.append(getFieldType(parameterTypes[i]));
+ }
+ desc.append(')');
+ return desc.toString();
+ }
+
+ /**
+ * Return the "field type" string for the given type, appropriate for
+ * a field descriptor, a parameter descriptor, or a return descriptor
+ * other than "void". See JVMS section 4.3.2.
+ */
+ private static String getFieldType(Class<?> type) {
+ if (type.isPrimitive()) {
+ return PrimitiveTypeInfo.get(type).baseTypeString;
+ } else if (type.isArray()) {
+ /*
+ * According to JLS 20.3.2, the getName() method on Class does
+ * return the VM type descriptor format for array classes (only);
+ * using that should be quicker than the otherwise obvious code:
+ *
+ * return "[" + getTypeDescriptor(type.getComponentType());
+ */
+ return type.getName().replace('.', '/');
+ } else {
+ return "L" + dotToSlash(type.getName()) + ";";
+ }
+ }
+
+ /**
+ * Returns a human-readable string representing the signature of a
+ * method with the given name and parameter types.
+ */
+ private static String getFriendlyMethodSignature(String name,
+ Class<?>[] parameterTypes)
+ {
+ StringBuilder sig = new StringBuilder(name);
+ sig.append('(');
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (i > 0) {
+ sig.append(',');
+ }
+ Class<?> parameterType = parameterTypes[i];
+ int dimensions = 0;
+ while (parameterType.isArray()) {
+ parameterType = parameterType.getComponentType();
+ dimensions++;
+ }
+ sig.append(parameterType.getName());
+ while (dimensions-- > 0) {
+ sig.append("[]");
+ }
+ }
+ sig.append(')');
+ return sig.toString();
+ }
+
+ /**
+ * Return the number of abstract "words", or consecutive local variable
+ * indexes, required to contain a value of the given type. See JVMS
+ * section 3.6.1.
+ *
+ * Note that the original version of the JVMS contained a definition of
+ * this abstract notion of a "word" in section 3.4, but that definition
+ * was removed for the second edition.
+ */
+ private static int getWordsPerType(Class<?> type) {
+ if (type == long.class || type == double.class) {
+ return 2;
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Add to the given list all of the types in the "from" array that
+ * are not already contained in the list and are assignable to at
+ * least one of the types in the "with" array.
+ *
+ * This method is useful for computing the greatest common set of
+ * declared exceptions from duplicate methods inherited from
+ * different interfaces.
+ */
+ private static void collectCompatibleTypes(Class<?>[] from,
+ Class<?>[] with,
+ List<Class<?>> list)
+ {
+ for (Class<?> fc: from) {
+ if (!list.contains(fc)) {
+ for (Class<?> wc: with) {
+ if (wc.isAssignableFrom(fc)) {
+ list.add(fc);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Given the exceptions declared in the throws clause of a proxy method,
+ * compute the exceptions that need to be caught from the invocation
+ * handler's invoke method and rethrown intact in the method's
+ * implementation before catching other Throwables and wrapping them
+ * in UndeclaredThrowableExceptions.
+ *
+ * The exceptions to be caught are returned in a List object. Each
+ * exception in the returned list is guaranteed to not be a subclass of
+ * any of the other exceptions in the list, so the catch blocks for
+ * these exceptions may be generated in any order relative to each other.
+ *
+ * Error and RuntimeException are each always contained by the returned
+ * list (if none of their superclasses are contained), since those
+ * unchecked exceptions should always be rethrown intact, and thus their
+ * subclasses will never appear in the returned list.
+ *
+ * The returned List will be empty if java.lang.Throwable is in the
+ * given list of declared exceptions, indicating that no exceptions
+ * need to be caught.
+ */
+ private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) {
+ List<Class<?>> uniqueList = new ArrayList<>();
+ // unique exceptions to catch
+
+ uniqueList.add(Error.class); // always catch/rethrow these
+ uniqueList.add(RuntimeException.class);
+
+ nextException:
+ for (Class<?> ex: exceptions) {
+ if (ex.isAssignableFrom(Throwable.class)) {
+ /*
+ * If Throwable is declared to be thrown by the proxy method,
+ * then no catch blocks are necessary, because the invoke
+ * can, at most, throw Throwable anyway.
+ */
+ uniqueList.clear();
+ break;
+ } else if (!Throwable.class.isAssignableFrom(ex)) {
+ /*
+ * Ignore types that cannot be thrown by the invoke method.
+ */
+ continue;
+ }
+ /*
+ * Compare this exception against the current list of
+ * exceptions that need to be caught:
+ */
+ for (int j = 0; j < uniqueList.size();) {
+ Class<?> ex2 = uniqueList.get(j);
+ if (ex2.isAssignableFrom(ex)) {
+ /*
+ * if a superclass of this exception is already on
+ * the list to catch, then ignore this one and continue;
+ */
+ continue nextException;
+ } else if (ex.isAssignableFrom(ex2)) {
+ /*
+ * if a subclass of this exception is on the list
+ * to catch, then remove it;
+ */
+ uniqueList.remove(j);
+ } else {
+ j++; // else continue comparing.
+ }
+ }
+ // This exception is unique (so far): add it to the list to catch.
+ uniqueList.add(ex);
+ }
+ return uniqueList;
+ }
+
+ /**
+ * A PrimitiveTypeInfo object contains assorted information about
+ * a primitive type in its public fields. The struct for a particular
+ * primitive type can be obtained using the static "get" method.
+ */
+ private static class PrimitiveTypeInfo {
+
+ /** "base type" used in various descriptors (see JVMS section 4.3.2) */
+ public String baseTypeString;
+
+ /** name of corresponding wrapper class */
+ public String wrapperClassName;
+
+ /** method descriptor for wrapper class "valueOf" factory method */
+ public String wrapperValueOfDesc;
+
+ /** name of wrapper class method for retrieving primitive value */
+ public String unwrapMethodName;
+
+ /** descriptor of same method */
+ public String unwrapMethodDesc;
+
+ private static Map<Class<?>,PrimitiveTypeInfo> table = new HashMap<>();
+ static {
+ add(byte.class, Byte.class);
+ add(char.class, Character.class);
+ add(double.class, Double.class);
+ add(float.class, Float.class);
+ add(int.class, Integer.class);
+ add(long.class, Long.class);
+ add(short.class, Short.class);
+ add(boolean.class, Boolean.class);
+ }
+
+ private static void add(Class<?> primitiveClass, Class<?> wrapperClass) {
+ table.put(primitiveClass,
+ new PrimitiveTypeInfo(primitiveClass, wrapperClass));
+ }
+
+ private PrimitiveTypeInfo(Class<?> primitiveClass, Class<?> wrapperClass) {
+ assert primitiveClass.isPrimitive();
+
+ baseTypeString =
+ Array.newInstance(primitiveClass, 0)
+ .getClass().getName().substring(1);
+ wrapperClassName = dotToSlash(wrapperClass.getName());
+ wrapperValueOfDesc =
+ "(" + baseTypeString + ")L" + wrapperClassName + ";";
+ unwrapMethodName = primitiveClass.getName() + "Value";
+ unwrapMethodDesc = "()" + baseTypeString;
+ }
+
+ public static PrimitiveTypeInfo get(Class<?> cl) {
+ return table.get(cl);
+ }
+ }
+
+
+ /**
+ * A ConstantPool object represents the constant pool of a class file
+ * being generated. This representation of a constant pool is designed
+ * specifically for use by ProxyGenerator; in particular, it assumes
+ * that constant pool entries will not need to be resorted (for example,
+ * by their type, as the Java compiler does), so that the final index
+ * value can be assigned and used when an entry is first created.
+ *
+ * Note that new entries cannot be created after the constant pool has
+ * been written to a class file. To prevent such logic errors, a
+ * ConstantPool instance can be marked "read only", so that further
+ * attempts to add new entries will fail with a runtime exception.
+ *
+ * See JVMS section 4.4 for more information about the constant pool
+ * of a class file.
+ */
+ private static class ConstantPool {
+
+ /**
+ * list of constant pool entries, in constant pool index order.
+ *
+ * This list is used when writing the constant pool to a stream
+ * and for assigning the next index value. Note that element 0
+ * of this list corresponds to constant pool index 1.
+ */
+ private List<Entry> pool = new ArrayList<>(32);
+
+ /**
+ * maps constant pool data of all types to constant pool indexes.
+ *
+ * This map is used to look up the index of an existing entry for
+ * values of all types.
+ */
+ private Map<Object,Short> map = new HashMap<>(16);
+
+ /** true if no new constant pool entries may be added */
+ private boolean readOnly = false;
+
+ /**
+ * Get or assign the index for a CONSTANT_Utf8 entry.
+ */
+ public short getUtf8(String s) {
+ if (s == null) {
+ throw new NullPointerException();
+ }
+ return getValue(s);
+ }
+
+ /**
+ * Get or assign the index for a CONSTANT_Integer entry.
+ */
+ public short getInteger(int i) {
+ return getValue(i);
+ }
+
+ /**
+ * Get or assign the index for a CONSTANT_Float entry.
+ */
+ public short getFloat(float f) {
+ return getValue(new Float(f));
+ }
+
+ /**
+ * Get or assign the index for a CONSTANT_Class entry.
+ */
+ public short getClass(String name) {
+ short utf8Index = getUtf8(name);
+ return getIndirect(new IndirectEntry(
+ CONSTANT_CLASS, utf8Index));
+ }
+
+ /**
+ * Get or assign the index for a CONSTANT_String entry.
+ */
+ public short getString(String s) {
+ short utf8Index = getUtf8(s);
+ return getIndirect(new IndirectEntry(
+ CONSTANT_STRING, utf8Index));
+ }
+
+ /**
+ * Get or assign the index for a CONSTANT_FieldRef entry.
+ */
+ public short getFieldRef(String className,
+ String name, String descriptor)
+ {
+ short classIndex = getClass(className);
+ short nameAndTypeIndex = getNameAndType(name, descriptor);
+ return getIndirect(new IndirectEntry(
+ CONSTANT_FIELD, classIndex, nameAndTypeIndex));
+ }
+
+ /**
+ * Get or assign the index for a CONSTANT_MethodRef entry.
+ */
+ public short getMethodRef(String className,
+ String name, String descriptor)
+ {
+ short classIndex = getClass(className);
+ short nameAndTypeIndex = getNameAndType(name, descriptor);
+ return getIndirect(new IndirectEntry(
+ CONSTANT_METHOD, classIndex, nameAndTypeIndex));
+ }
+
+ /**
+ * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
+ */
+ public short getInterfaceMethodRef(String className, String name,
+ String descriptor)
+ {
+ short classIndex = getClass(className);
+ short nameAndTypeIndex = getNameAndType(name, descriptor);
+ return getIndirect(new IndirectEntry(
+ CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));
+ }
+
+ /**
+ * Get or assign the index for a CONSTANT_NameAndType entry.
+ */
+ public short getNameAndType(String name, String descriptor) {
+ short nameIndex = getUtf8(name);
+ short descriptorIndex = getUtf8(descriptor);
+ return getIndirect(new IndirectEntry(
+ CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));
+ }
+
+ /**
+ * Set this ConstantPool instance to be "read only".
+ *
+ * After this method has been called, further requests to get
+ * an index for a non-existent entry will cause an InternalError
+ * to be thrown instead of creating of the entry.
+ */
+ public void setReadOnly() {
+ readOnly = true;
+ }
+
+ /**
+ * Write this constant pool to a stream as part of
+ * the class file format.
+ *
+ * This consists of writing the "constant_pool_count" and
+ * "constant_pool[]" items of the "ClassFile" structure, as
+ * described in JVMS section 4.1.
+ */
+ public void write(OutputStream out) throws IOException {
+ DataOutputStream dataOut = new DataOutputStream(out);
+
+ // constant_pool_count: number of entries plus one
+ dataOut.writeShort(pool.size() + 1);
+
+ for (Entry e : pool) {
+ e.write(dataOut);
+ }
+ }
+
+ /**
+ * Add a new constant pool entry and return its index.
+ */
+ private short addEntry(Entry entry) {
+ pool.add(entry);
+ /*
+ * Note that this way of determining the index of the
+ * added entry is wrong if this pool supports
+ * CONSTANT_Long or CONSTANT_Double entries.
+ */
+ if (pool.size() >= 65535) {
+ throw new IllegalArgumentException(
+ "constant pool size limit exceeded");
+ }
+ return (short) pool.size();
+ }
+
+ /**
+ * Get or assign the index for an entry of a type that contains
+ * a direct value. The type of the given object determines the
+ * type of the desired entry as follows:
+ *
+ * java.lang.String CONSTANT_Utf8
+ * java.lang.Integer CONSTANT_Integer
+ * java.lang.Float CONSTANT_Float
+ * java.lang.Long CONSTANT_Long
+ * java.lang.Double CONSTANT_DOUBLE
+ */
+ private short getValue(Object key) {
+ Short index = map.get(key);
+ if (index != null) {
+ return index.shortValue();
+ } else {
+ if (readOnly) {
+ throw new InternalError(
+ "late constant pool addition: " + key);
+ }
+ short i = addEntry(new ValueEntry(key));
+ map.put(key, i);
+ return i;
+ }
+ }
+
+ /**
+ * Get or assign the index for an entry of a type that contains
+ * references to other constant pool entries.
+ */
+ private short getIndirect(IndirectEntry e) {
+ Short index = map.get(e);
+ if (index != null) {
+ return index.shortValue();
+ } else {
+ if (readOnly) {
+ throw new InternalError("late constant pool addition");
+ }
+ short i = addEntry(e);
+ map.put(e, i);
+ return i;
+ }
+ }
+
+ /**
+ * Entry is the abstact superclass of all constant pool entry types
+ * that can be stored in the "pool" list; its purpose is to define a
+ * common method for writing constant pool entries to a class file.
+ */
+ private abstract static class Entry {
+ public abstract void write(DataOutputStream out)
+ throws IOException;
+ }
+
+ /**
+ * ValueEntry represents a constant pool entry of a type that
+ * contains a direct value (see the comments for the "getValue"
+ * method for a list of such types).
+ *
+ * ValueEntry objects are not used as keys for their entries in the
+ * Map "map", so no useful hashCode or equals methods are defined.
+ */
+ private static class ValueEntry extends Entry {
+ private Object value;
+
+ public ValueEntry(Object value) {
+ this.value = value;
+ }
+
+ public void write(DataOutputStream out) throws IOException {
+ if (value instanceof String) {
+ out.writeByte(CONSTANT_UTF8);
+ out.writeUTF((String) value);
+ } else if (value instanceof Integer) {
+ out.writeByte(CONSTANT_INTEGER);
+ out.writeInt(((Integer) value).intValue());
+ } else if (value instanceof Float) {
+ out.writeByte(CONSTANT_FLOAT);
+ out.writeFloat(((Float) value).floatValue());
+ } else if (value instanceof Long) {
+ out.writeByte(CONSTANT_LONG);
+ out.writeLong(((Long) value).longValue());
+ } else if (value instanceof Double) {
+ out.writeDouble(CONSTANT_DOUBLE);
+ out.writeDouble(((Double) value).doubleValue());
+ } else {
+ throw new InternalError("bogus value entry: " + value);
+ }
+ }
+ }
+
+ /**
+ * IndirectEntry represents a constant pool entry of a type that
+ * references other constant pool entries, i.e., the following types:
+ *
+ * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
+ * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
+ * CONSTANT_NameAndType.
+ *
+ * Each of these entry types contains either one or two indexes of
+ * other constant pool entries.
+ *
+ * IndirectEntry objects are used as the keys for their entries in
+ * the Map "map", so the hashCode and equals methods are overridden
+ * to allow matching.
+ */
+ private static class IndirectEntry extends Entry {
+ private int tag;
+ private short index0;
+ private short index1;
+
+ /**
+ * Construct an IndirectEntry for a constant pool entry type
+ * that contains one index of another entry.
+ */
+ public IndirectEntry(int tag, short index) {
+ this.tag = tag;
+ this.index0 = index;
+ this.index1 = 0;
+ }
+
+ /**
+ * Construct an IndirectEntry for a constant pool entry type
+ * that contains two indexes for other entries.
+ */
+ public IndirectEntry(int tag, short index0, short index1) {
+ this.tag = tag;
+ this.index0 = index0;
+ this.index1 = index1;
+ }
+
+ public void write(DataOutputStream out) throws IOException {
+ out.writeByte(tag);
+ out.writeShort(index0);
+ /*
+ * If this entry type contains two indexes, write
+ * out the second, too.
+ */
+ if (tag == CONSTANT_FIELD ||
+ tag == CONSTANT_METHOD ||
+ tag == CONSTANT_INTERFACEMETHOD ||
+ tag == CONSTANT_NAMEANDTYPE)
+ {
+ out.writeShort(index1);
+ }
+ }
+
+ public int hashCode() {
+ return tag + index0 + index1;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof IndirectEntry) {
+ IndirectEntry other = (IndirectEntry) obj;
+ if (tag == other.tag &&
+ index0 == other.index0 && index1 == other.index1)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ }
+}
--- a/jdk/src/java.base/share/classes/java/security/cert/PolicyQualifierInfo.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/security/cert/PolicyQualifierInfo.java Wed Jul 05 21:09:54 2017 +0200
@@ -27,7 +27,7 @@
import java.io.IOException;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.DerValue;
/**
--- a/jdk/src/java.base/share/classes/java/security/cert/X509CertSelector.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/security/cert/X509CertSelector.java Wed Jul 05 21:09:54 2017 +0200
@@ -31,7 +31,7 @@
import java.util.*;
import javax.security.auth.x500.X500Principal;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.Debug;
import sun.security.util.DerInputStream;
import sun.security.util.DerValue;
--- a/jdk/src/java.base/share/classes/java/text/SimpleDateFormat.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/text/SimpleDateFormat.java Wed Jul 05 21:09:54 2017 +0200
@@ -1856,6 +1856,7 @@
if (patternCharIndex == PATTERN_HOUR_OF_DAY1 ||
patternCharIndex == PATTERN_HOUR1 ||
(patternCharIndex == PATTERN_MONTH && count <= 2) ||
+ (patternCharIndex == PATTERN_MONTH_STANDALONE && count <= 2) ||
patternCharIndex == PATTERN_YEAR ||
patternCharIndex == PATTERN_WEEK_YEAR) {
// It would be good to unify this with the obeyCount logic below,
@@ -1976,6 +1977,20 @@
}
break parsing;
+ case PATTERN_MONTH_STANDALONE: // 'L'
+ if (count <= 2) {
+ // Don't want to parse the month if it is a string
+ // while pattern uses numeric style: L or LL
+ //[we computed 'value' above.]
+ calb.set(Calendar.MONTH, value - 1);
+ return pos.index;
+ }
+ Map<String, Integer> maps = getDisplayNamesMap(field, locale);
+ if ((index = matchString(text, start, field, maps, calb)) > 0) {
+ return index;
+ }
+ break parsing;
+
case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59
if (!isLenient()) {
// Validate the hour value in non-lenient
--- a/jdk/src/java.base/share/classes/java/time/Duration.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/time/Duration.java Wed Jul 05 21:09:54 2017 +0200
@@ -997,6 +997,24 @@
}
/**
+ * Returns number of whole times a specified Duration occurs within this Duration.
+ * <p>
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param divisor the value to divide the duration by, positive or negative, not null
+ * @return number of whole times, rounded toward zero, a specified
+ * {@code Duration} occurs within this Duration, may be negative
+ * @throws ArithmeticException if the divisor is zero, or if numeric overflow occurs
+ * @since 9
+ */
+ public long dividedBy(Duration divisor) {
+ Objects.requireNonNull(divisor, "divisor");
+ BigDecimal dividendBigD = toBigDecimalSeconds();
+ BigDecimal divisorBigD = divisor.toBigDecimalSeconds();
+ return dividendBigD.divideToIntegralValue(divisorBigD).longValueExact();
+ }
+
+ /**
* Converts this duration to the total length in seconds and
* fractional nanoseconds expressed as a {@code BigDecimal}.
*
--- a/jdk/src/java.base/share/classes/java/util/AbstractMap.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/AbstractMap.java Wed Jul 05 21:09:54 2017 +0200
@@ -304,9 +304,28 @@
* Each of these fields are initialized to contain an instance of the
* appropriate view the first time this view is requested. The views are
* stateless, so there's no reason to create more than one of each.
+ *
+ * <p>Since there is no synchronization performed while accessing these fields,
+ * it is expected that java.util.Map view classes using these fields have
+ * no non-final fields (or any fields at all except for outer-this). Adhering
+ * to this rule would make the races on these fields benign.
+ *
+ * <p>It is also imperative that implementations read the field only once,
+ * as in:
+ *
+ * <pre> {@code
+ * public Set<K> keySet() {
+ * Set<K> ks = keySet; // single racy read
+ * if (ks == null) {
+ * ks = new KeySet();
+ * keySet = ks;
+ * }
+ * return ks;
+ * }
+ *}</pre>
*/
- transient volatile Set<K> keySet;
- transient volatile Collection<V> values;
+ transient Set<K> keySet;
+ transient Collection<V> values;
/**
* {@inheritDoc}
@@ -325,8 +344,9 @@
* method will not all return the same set.
*/
public Set<K> keySet() {
- if (keySet == null) {
- keySet = new AbstractSet<K>() {
+ Set<K> ks = keySet;
+ if (ks == null) {
+ ks = new AbstractSet<K>() {
public Iterator<K> iterator() {
return new Iterator<K>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();
@@ -361,8 +381,9 @@
return AbstractMap.this.containsKey(k);
}
};
+ keySet = ks;
}
- return keySet;
+ return ks;
}
/**
@@ -382,8 +403,9 @@
* method will not all return the same collection.
*/
public Collection<V> values() {
- if (values == null) {
- values = new AbstractCollection<V>() {
+ Collection<V> vals = values;
+ if (vals == null) {
+ vals = new AbstractCollection<V>() {
public Iterator<V> iterator() {
return new Iterator<V>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();
@@ -418,8 +440,9 @@
return AbstractMap.this.containsValue(v);
}
};
+ values = vals;
}
- return values;
+ return vals;
}
public abstract Set<Entry<K,V>> entrySet();
--- a/jdk/src/java.base/share/classes/java/util/Collections.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/Collections.java Wed Jul 05 21:09:54 2017 +0200
@@ -5530,7 +5530,7 @@
* @since 1.6
*/
public static <T> Queue<T> asLifoQueue(Deque<T> deque) {
- return new AsLIFOQueue<>(deque);
+ return new AsLIFOQueue<>(Objects.requireNonNull(deque));
}
/**
--- a/jdk/src/java.base/share/classes/java/util/EnumMap.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/EnumMap.java Wed Jul 05 21:09:54 2017 +0200
@@ -380,10 +380,11 @@
*/
public Set<K> keySet() {
Set<K> ks = keySet;
- if (ks != null)
- return ks;
- else
- return keySet = new KeySet();
+ if (ks == null) {
+ ks = new KeySet();
+ keySet = ks;
+ }
+ return ks;
}
private class KeySet extends AbstractSet<K> {
@@ -418,10 +419,11 @@
*/
public Collection<V> values() {
Collection<V> vs = values;
- if (vs != null)
- return vs;
- else
- return values = new Values();
+ if (vs == null) {
+ vs = new Values();
+ values = vs;
+ }
+ return vs;
}
private class Values extends AbstractCollection<V> {
--- a/jdk/src/java.base/share/classes/java/util/HashMap.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/HashMap.java Wed Jul 05 21:09:54 2017 +0200
@@ -902,8 +902,12 @@
* @return a set view of the keys contained in this map
*/
public Set<K> keySet() {
- Set<K> ks;
- return (ks = keySet) == null ? (keySet = new KeySet()) : ks;
+ Set<K> ks = keySet;
+ if (ks == null) {
+ ks = new KeySet();
+ keySet = ks;
+ }
+ return ks;
}
final class KeySet extends AbstractSet<K> {
@@ -949,8 +953,12 @@
* @return a view of the values contained in this map
*/
public Collection<V> values() {
- Collection<V> vs;
- return (vs = values) == null ? (values = new Values()) : vs;
+ Collection<V> vs = values;
+ if (vs == null) {
+ vs = new Values();
+ values = vs;
+ }
+ return vs;
}
final class Values extends AbstractCollection<V> {
--- a/jdk/src/java.base/share/classes/java/util/IdentityHashMap.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/IdentityHashMap.java Wed Jul 05 21:09:54 2017 +0200
@@ -964,10 +964,11 @@
*/
public Set<K> keySet() {
Set<K> ks = keySet;
- if (ks != null)
- return ks;
- else
- return keySet = new KeySet();
+ if (ks == null) {
+ ks = new KeySet();
+ keySet = ks;
+ }
+ return ks;
}
private class KeySet extends AbstractSet<K> {
@@ -1069,10 +1070,11 @@
*/
public Collection<V> values() {
Collection<V> vs = values;
- if (vs != null)
- return vs;
- else
- return values = new Values();
+ if (vs == null) {
+ vs = new Values();
+ values = vs;
+ }
+ return vs;
}
private class Values extends AbstractCollection<V> {
--- a/jdk/src/java.base/share/classes/java/util/LinkedHashMap.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/LinkedHashMap.java Wed Jul 05 21:09:54 2017 +0200
@@ -528,8 +528,12 @@
* @return a set view of the keys contained in this map
*/
public Set<K> keySet() {
- Set<K> ks;
- return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : ks;
+ Set<K> ks = keySet;
+ if (ks == null) {
+ ks = new LinkedKeySet();
+ keySet = ks;
+ }
+ return ks;
}
final class LinkedKeySet extends AbstractSet<K> {
@@ -577,8 +581,12 @@
* @return a view of the values contained in this map
*/
public Collection<V> values() {
- Collection<V> vs;
- return (vs = values) == null ? (values = new LinkedValues()) : vs;
+ Collection<V> vs = values;
+ if (vs == null) {
+ vs = new LinkedValues();
+ values = vs;
+ }
+ return vs;
}
final class LinkedValues extends AbstractCollection<V> {
--- a/jdk/src/java.base/share/classes/java/util/Map.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/Map.java Wed Jul 05 21:09:54 2017 +0200
@@ -1670,9 +1670,9 @@
*/
@SafeVarargs
@SuppressWarnings("varargs")
- static <K, V> Map<K, V> ofEntries(Entry<K, V>... entries) {
+ static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
Map<K, V> map = new HashMap<>(entries.length * 4 / 3 + 1); // throws NPE if entries is null
- for (Entry<K, V> e : entries) {
+ for (Entry<? extends K, ? extends V> e : entries) {
// next line throws NPE if e is null
map.put(Objects.requireNonNull(e.getKey()), Objects.requireNonNull(e.getValue()));
}
--- a/jdk/src/java.base/share/classes/java/util/TreeMap.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/TreeMap.java Wed Jul 05 21:09:54 2017 +0200
@@ -852,7 +852,11 @@
*/
public Collection<V> values() {
Collection<V> vs = values;
- return (vs != null) ? vs : (values = new Values());
+ if (vs == null) {
+ vs = new Values();
+ values = vs;
+ }
+ return vs;
}
/**
--- a/jdk/src/java.base/share/classes/java/util/WeakHashMap.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/WeakHashMap.java Wed Jul 05 21:09:54 2017 +0200
@@ -866,7 +866,11 @@
*/
public Set<K> keySet() {
Set<K> ks = keySet;
- return (ks != null ? ks : (keySet = new KeySet()));
+ if (ks == null) {
+ ks = new KeySet();
+ keySet = ks;
+ }
+ return ks;
}
private class KeySet extends AbstractSet<K> {
@@ -915,7 +919,11 @@
*/
public Collection<V> values() {
Collection<V> vs = values;
- return (vs != null) ? vs : (values = new Values());
+ if (vs == null) {
+ vs = new Values();
+ values = vs;
+ }
+ return vs;
}
private class Values extends AbstractCollection<V> {
--- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java Wed Jul 05 21:09:54 2017 +0200
@@ -203,7 +203,10 @@
return man;
}
- private native String[] getMetaInfEntryNames();
+ private String[] getMetaInfEntryNames() {
+ return jdk.internal.misc.SharedSecrets.getJavaUtilZipFileAccess()
+ .getMetaInfEntryNames((ZipFile)this);
+ }
/**
* Returns the {@code JarEntry} for the given entry name or
--- a/jdk/src/java.base/share/classes/java/util/regex/Pattern.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/regex/Pattern.java Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, 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
@@ -5814,7 +5814,7 @@
*/
public Stream<String> splitAsStream(final CharSequence input) {
class MatcherIterator implements Iterator<String> {
- private final Matcher matcher;
+ private Matcher matcher;
// The start position of the next sub-sequence of input
// when current == input.length there are no more elements
private int current;
@@ -5823,14 +5823,6 @@
// > 0 if there are N next empty elements
private int emptyElementCount;
- MatcherIterator() {
- this.matcher = matcher(input);
- // If the input is an empty string then the result can only be a
- // stream of the input. Induce that by setting the empty
- // element count to 1
- this.emptyElementCount = input.length() == 0 ? 1 : 0;
- }
-
public String next() {
if (!hasNext())
throw new NoSuchElementException();
@@ -5846,6 +5838,13 @@
}
public boolean hasNext() {
+ if (matcher == null) {
+ matcher = matcher(input);
+ // If the input is an empty string then the result can only be a
+ // stream of the input. Induce that by setting the empty
+ // element count to 1
+ emptyElementCount = input.length() == 0 ? 1 : 0;
+ }
if (nextElement != null || emptyElementCount > 0)
return true;
--- a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java Wed Jul 05 21:09:54 2017 +0200
@@ -434,7 +434,7 @@
* stream returned by mapper
* @return a collector which applies the mapping function to the input
* elements and provides the flat mapped results to the downstream collector
- * @since 1.9
+ * @since 9
*/
public static <T, U, A, R>
Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper,
@@ -452,6 +452,53 @@
}
/**
+ * Adapts a {@code Collector} to one accepting elements of the same type
+ * {@code T} by applying the predicate to each input element and only
+ * accumulating if the predicate returns {@code true}.
+ *
+ * @apiNote
+ * The {@code filtering()} collectors are most useful when used in a
+ * multi-level reduction, such as downstream of a {@code groupingBy} or
+ * {@code partitioningBy}. For example, given a stream of
+ * {@code Employee}, to accumulate the employees in each department that have a
+ * salary above a certain threshold:
+ * <pre>{@code
+ * Map<Department, Set<Employee>> wellPaidEmployeesByDepartment
+ * = employees.stream().collect(groupingBy(Employee::getDepartment,
+ * filtering(e -> e.getSalary() > 2000, toSet())));
+ * }</pre>
+ * A filtering collector differs from a stream's {@code filter()} operation.
+ * In this example, suppose there are no employees whose salary is above the
+ * threshold in some department. Using a filtering collector as shown above
+ * would result in a mapping from that department to an empty {@code Set}.
+ * If a stream {@code filter()} operation were done instead, there would be
+ * no mapping for that department at all.
+ *
+ * @param <T> the type of the input elements
+ * @param <A> intermediate accumulation type of the downstream collector
+ * @param <R> result type of collector
+ * @param predicate a predicate to be applied to the input elements
+ * @param downstream a collector which will accept values that match the
+ * predicate
+ * @return a collector which applies the predicate to the input elements
+ * and provides matching elements to the downstream collector
+ * @since 9
+ */
+ public static <T, A, R>
+ Collector<T, ?, R> filtering(Predicate<? super T> predicate,
+ Collector<? super T, A, R> downstream) {
+ BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+ return new CollectorImpl<>(downstream.supplier(),
+ (r, t) -> {
+ if (predicate.test(t)) {
+ downstreamAccumulator.accept(r, t);
+ }
+ },
+ downstream.combiner(), downstream.finisher(),
+ downstream.characteristics());
+ }
+
+ /**
* Adapts a {@code Collector} to perform an additional finishing
* transformation. For example, one could adapt the {@link #toList()}
* collector to always produce an immutable list with:
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipCoder.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipCoder.java Wed Jul 05 21:09:54 2017 +0200
@@ -43,7 +43,7 @@
final class ZipCoder {
- String toString(byte[] ba, int length) {
+ String toString(byte[] ba, int off, int length) {
CharsetDecoder cd = decoder().reset();
int len = (int)(length * cd.maxCharsPerByte());
char[] ca = new char[len];
@@ -53,12 +53,12 @@
// CodingErrorAction.REPLACE mode. ZipCoder uses
// REPORT mode.
if (isUTF8 && cd instanceof ArrayDecoder) {
- int clen = ((ArrayDecoder)cd).decode(ba, 0, length, ca);
+ int clen = ((ArrayDecoder)cd).decode(ba, off, length, ca);
if (clen == -1) // malformed
throw new IllegalArgumentException("MALFORMED");
return new String(ca, 0, clen);
}
- ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
+ ByteBuffer bb = ByteBuffer.wrap(ba, off, length);
CharBuffer cb = CharBuffer.wrap(ca);
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
@@ -69,8 +69,12 @@
return new String(ca, 0, cb.position());
}
+ String toString(byte[] ba, int length) {
+ return toString(ba, 0, length);
+ }
+
String toString(byte[] ba) {
- return toString(ba, ba.length);
+ return toString(ba, 0, ba.length);
}
byte[] getBytes(String s) {
@@ -111,13 +115,16 @@
return utf8.getBytes(s);
}
+ String toStringUTF8(byte[] ba, int len) {
+ return toStringUTF8(ba, 0, len);
+ }
- String toStringUTF8(byte[] ba, int len) {
+ String toStringUTF8(byte[] ba, int off, int len) {
if (isUTF8)
- return toString(ba, len);
+ return toString(ba, off, len);
if (utf8 == null)
utf8 = new ZipCoder(StandardCharsets.UTF_8);
- return utf8.toString(ba, len);
+ return utf8.toString(ba, off, len);
}
boolean isUTF8() {
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java Wed Jul 05 21:09:54 2017 +0200
@@ -30,14 +30,22 @@
import java.io.IOException;
import java.io.EOFException;
import java.io.File;
+import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.Path;
+import java.nio.file.Files;
+
import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.Objects;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.Spliterators;
@@ -47,7 +55,9 @@
import jdk.internal.misc.JavaUtilZipFileAccess;
import jdk.internal.misc.SharedSecrets;
+import static java.util.zip.ZipConstants.*;
import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
/**
* This class is used to read entries from a zip file.
@@ -60,11 +70,11 @@
*/
public
class ZipFile implements ZipConstants, Closeable {
- private long jzfile; // address of jzfile data
+
private final String name; // zip file name
- private final int total; // total number of entries
- private final boolean locsig; // if zip file starts with LOCSIG (usually true)
private volatile boolean closeRequested = false;
+ private Source zsrc;
+ private ZipCoder zc;
private static final int STORED = ZipEntry.STORED;
private static final int DEFLATED = ZipEntry.DEFLATED;
@@ -83,23 +93,6 @@
*/
public static final int OPEN_DELETE = 0x4;
- static {
- /* Zip library is loaded from System.initializeSystemClass */
- initIDs();
- }
-
- private static native void initIDs();
-
- private static final boolean usemmap;
-
- static {
- // A system prpperty to disable mmap use to avoid vm crash when
- // in-use zip file is accidently overwritten by others.
- String prop = sun.misc.VM.getSavedProperty("sun.zip.disableMemoryMapping");
- usemmap = (prop == null ||
- !(prop.length() == 0 || prop.equalsIgnoreCase("true")));
- }
-
/**
* Opens a zip file for reading.
*
@@ -165,8 +158,6 @@
this(file, OPEN_READ);
}
- private ZipCoder zc;
-
/**
* Opens a new {@code ZipFile} to read from the specified
* {@code File} object in the specified mode. The mode argument
@@ -214,16 +205,13 @@
sm.checkDelete(name);
}
}
- if (charset == null)
- throw new NullPointerException("charset is null");
+ Objects.requireNonNull(charset, "charset");
this.zc = ZipCoder.get(charset);
+ this.name = name;
long t0 = System.nanoTime();
- jzfile = open(name, mode, file.lastModified(), usemmap);
+ this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0);
sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
sun.misc.PerfCounter.getZipFileCount().increment();
- this.name = name;
- this.total = getTotal(jzfile);
- this.locsig = startsWithLOC(jzfile);
}
/**
@@ -257,6 +245,7 @@
/**
* Opens a ZIP file for reading given the specified File object.
+ *
* @param file the ZIP file to be opened for reading
* @param charset
* The {@linkplain java.nio.charset.Charset charset} to be
@@ -287,10 +276,10 @@
public String getComment() {
synchronized (this) {
ensureOpen();
- byte[] bcomm = getCommentBytes(jzfile);
- if (bcomm == null)
+ if (zsrc.comment == null) {
return null;
- return zc.toString(bcomm, bcomm.length);
+ }
+ return zc.toString(zsrc.comment);
}
}
@@ -303,38 +292,28 @@
* @throws IllegalStateException if the zip file has been closed
*/
public ZipEntry getEntry(String name) {
- if (name == null) {
- throw new NullPointerException("name");
- }
- long jzentry = 0;
+
+ Objects.requireNonNull(name, "name");
synchronized (this) {
ensureOpen();
- jzentry = getEntry(jzfile, zc.getBytes(name), true);
- if (jzentry != 0) {
- ZipEntry ze = getZipEntry(name, jzentry);
- freeEntry(jzfile, jzentry);
- return ze;
+ int pos = zsrc.getEntryPos(zc.getBytes(name), true);
+ if (pos != -1) {
+ return getZipEntry(name, pos);
}
}
return null;
}
- private static native long getEntry(long jzfile, byte[] name,
- boolean addSlash);
-
- // freeEntry releases the C jzentry struct.
- private static native void freeEntry(long jzfile, long jzentry);
-
- // the outstanding inputstreams that need to be closed,
+ // The outstanding inputstreams that need to be closed,
// mapped to the inflater objects they use.
private final Map<InputStream, Inflater> streams = new WeakHashMap<>();
/**
* Returns an input stream for reading the contents of the specified
* zip file entry.
- *
- * <p> Closing this ZIP file will, in turn, close all input
- * streams that have been returned by invocations of this method.
+ * <p>
+ * Closing this ZIP file will, in turn, close all input streams that
+ * have been returned by invocations of this method.
*
* @param entry the zip file entry
* @return the input stream for reading the contents of the specified
@@ -344,37 +323,38 @@
* @throws IllegalStateException if the zip file has been closed
*/
public InputStream getInputStream(ZipEntry entry) throws IOException {
- if (entry == null) {
- throw new NullPointerException("entry");
- }
- long jzentry = 0;
+ Objects.requireNonNull(entry, "entry");
+ int pos = -1;
ZipFileInputStream in = null;
synchronized (this) {
ensureOpen();
if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
- jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false);
+ pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false);
} else {
- jzentry = getEntry(jzfile, zc.getBytes(entry.name), false);
+ pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
}
- if (jzentry == 0) {
+ if (pos == -1) {
return null;
}
- in = new ZipFileInputStream(jzentry);
-
- switch (getEntryMethod(jzentry)) {
+ in = new ZipFileInputStream(zsrc.cen, pos);
+ switch (CENHOW(zsrc.cen, pos)) {
case STORED:
synchronized (streams) {
streams.put(in, null);
}
return in;
case DEFLATED:
+ // Inflater likes a bit of slack
// MORE: Compute good size for inflater stream:
- long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
- if (size > 65536) size = 8192;
- if (size <= 0) size = 4096;
+ long size = CENLEN(zsrc.cen, pos) + 2;
+ if (size > 65536) {
+ size = 8192;
+ }
+ if (size <= 0) {
+ size = 4096;
+ }
Inflater inf = getInflater();
- InputStream is =
- new ZipFileInflaterInputStream(in, inf, (int)size);
+ InputStream is = new ZipFileInflaterInputStream(in, inf, (int)size);
synchronized (streams) {
streams.put(is, inf);
}
@@ -447,8 +427,8 @@
private Inflater getInflater() {
Inflater inf;
synchronized (inflaterCache) {
- while (null != (inf = inflaterCache.poll())) {
- if (false == inf.ended()) {
+ while ((inf = inflaterCache.poll()) != null) {
+ if (!inf.ended()) {
return inf;
}
}
@@ -460,7 +440,7 @@
* Releases the specified inflater to the list of available inflaters.
*/
private void releaseInflater(Inflater inf) {
- if (false == inf.ended()) {
+ if (!inf.ended()) {
inf.reset();
synchronized (inflaterCache) {
inflaterCache.add(inf);
@@ -469,7 +449,7 @@
}
// List of available Inflater objects for decompression
- private Deque<Inflater> inflaterCache = new ArrayDeque<>();
+ private final Deque<Inflater> inflaterCache = new ArrayDeque<>();
/**
* Returns the path name of the ZIP file.
@@ -493,7 +473,7 @@
public boolean hasNext() {
synchronized (ZipFile.this) {
ensureOpen();
- return i < total;
+ return i < zsrc.total;
}
}
@@ -504,28 +484,11 @@
public ZipEntry next() {
synchronized (ZipFile.this) {
ensureOpen();
- if (i >= total) {
+ if (i >= zsrc.total) {
throw new NoSuchElementException();
}
- long jzentry = getNextEntry(jzfile, i++);
- if (jzentry == 0) {
- String message;
- if (closeRequested) {
- message = "ZipFile concurrently closed";
- } else {
- message = getZipMessage(ZipFile.this.jzfile);
- }
- throw new ZipError("jzentry == 0" +
- ",\n jzfile = " + ZipFile.this.jzfile +
- ",\n total = " + ZipFile.this.total +
- ",\n name = " + ZipFile.this.name +
- ",\n i = " + i +
- ",\n message = " + message
- );
- }
- ZipEntry ze = getZipEntry(null, jzentry);
- freeEntry(jzfile, jzentry);
- return ze;
+ // each "entry" has 3 ints in table entries
+ return getZipEntry(null, zsrc.getEntryPos(i++ * 3));
}
}
@@ -559,48 +522,53 @@
Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
}
- private ZipEntry getZipEntry(String name, long jzentry) {
+ /* Checks ensureOpen() before invoke this method */
+ private ZipEntry getZipEntry(String name, int pos) {
+ byte[] cen = zsrc.cen;
ZipEntry e = new ZipEntry();
- e.flag = getEntryFlag(jzentry); // get the flag first
+ int nlen = CENNAM(cen, pos);
+ int elen = CENEXT(cen, pos);
+ int clen = CENCOM(cen, pos);
+ e.flag = CENFLG(cen, pos); // get the flag first
if (name != null) {
e.name = name;
} else {
- byte[] bname = getEntryBytes(jzentry, JZENTRY_NAME);
if (!zc.isUTF8() && (e.flag & EFS) != 0) {
- e.name = zc.toStringUTF8(bname, bname.length);
+ e.name = zc.toStringUTF8(cen, pos + CENHDR, nlen);
} else {
- e.name = zc.toString(bname, bname.length);
+ e.name = zc.toString(cen, pos + CENHDR, nlen);
}
}
- e.xdostime = getEntryTime(jzentry);
- e.crc = getEntryCrc(jzentry);
- e.size = getEntrySize(jzentry);
- e.csize = getEntryCSize(jzentry);
- e.method = getEntryMethod(jzentry);
- e.setExtra0(getEntryBytes(jzentry, JZENTRY_EXTRA), false);
- byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT);
- if (bcomm == null) {
- e.comment = null;
- } else {
+ e.xdostime = CENTIM(cen, pos);
+ e.crc = CENCRC(cen, pos);
+ e.size = CENLEN(cen, pos);
+ e.csize = CENSIZ(cen, pos);
+ e.method = CENHOW(cen, pos);
+ if (elen != 0) {
+ e.setExtra0(Arrays.copyOfRange(cen, pos + CENHDR + nlen,
+ pos + CENHDR + nlen + elen), true);
+ }
+ if (clen != 0) {
if (!zc.isUTF8() && (e.flag & EFS) != 0) {
- e.comment = zc.toStringUTF8(bcomm, bcomm.length);
+ e.comment = zc.toStringUTF8(cen, pos + CENHDR + nlen + elen, clen);
} else {
- e.comment = zc.toString(bcomm, bcomm.length);
+ e.comment = zc.toString(cen, pos + CENHDR + nlen + elen, clen);
}
}
return e;
}
- private static native long getNextEntry(long jzfile, int i);
-
/**
* Returns the number of entries in the ZIP file.
+ *
* @return the number of entries in the ZIP file
* @throws IllegalStateException if the zip file has been closed
*/
public int size() {
- ensureOpen();
- return total;
+ synchronized (this) {
+ ensureOpen();
+ return zsrc.total;
+ }
}
/**
@@ -612,14 +580,15 @@
* @throws IOException if an I/O error has occurred
*/
public void close() throws IOException {
- if (closeRequested)
+ if (closeRequested) {
return;
+ }
closeRequested = true;
synchronized (this) {
// Close streams, release their inflaters
synchronized (streams) {
- if (false == streams.isEmpty()) {
+ if (!streams.isEmpty()) {
Map<InputStream, Inflater> copy = new HashMap<>(streams);
streams.clear();
for (Map.Entry<InputStream, Inflater> e : copy.entrySet()) {
@@ -631,21 +600,17 @@
}
}
}
-
// Release cached inflaters
- Inflater inf;
synchronized (inflaterCache) {
- while (null != (inf = inflaterCache.poll())) {
+ Inflater inf;
+ while ((inf = inflaterCache.poll()) != null) {
inf.end();
}
}
-
- if (jzfile != 0) {
- // Close the zip file
- long zf = this.jzfile;
- jzfile = 0;
-
- close(zf);
+ // Release zip src
+ if (zsrc != null) {
+ Source.close(zsrc);
+ zsrc = null;
}
}
}
@@ -668,14 +633,11 @@
close();
}
- private static native void close(long jzfile);
-
private void ensureOpen() {
if (closeRequested) {
throw new IllegalStateException("zip file closed");
}
-
- if (jzfile == 0) {
+ if (zsrc == null) {
throw new IllegalStateException("The object is not initialized.");
}
}
@@ -691,40 +653,99 @@
* (possibly compressed) zip file entry.
*/
private class ZipFileInputStream extends InputStream {
- private volatile boolean zfisCloseRequested = false;
- protected long jzentry; // address of jzentry data
+ private volatile boolean closeRequested = false;
private long pos; // current position within entry data
protected long rem; // number of remaining bytes within entry
protected long size; // uncompressed size of this entry
- ZipFileInputStream(long jzentry) {
- pos = 0;
- rem = getEntryCSize(jzentry);
- size = getEntrySize(jzentry);
- this.jzentry = jzentry;
+ ZipFileInputStream(byte[] cen, int cenpos) throws IOException {
+ rem = CENSIZ(cen, cenpos);
+ size = CENLEN(cen, cenpos);
+ pos = CENOFF(cen, cenpos);
+ // zip64
+ if (rem == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL ||
+ pos == ZIP64_MAGICVAL) {
+ checkZIP64(cen, cenpos);
+ }
+ // negative for lazy initialization, see getDataOffset();
+ pos = - (pos + ZipFile.this.zsrc.locpos);
+ }
+
+ private void checkZIP64(byte[] cen, int cenpos) throws IOException {
+ int off = cenpos + CENHDR + CENNAM(cen, cenpos);
+ int end = off + CENEXT(cen, cenpos);
+ while (off + 4 < end) {
+ int tag = get16(cen, off);
+ int sz = get16(cen, off + 2);
+ off += 4;
+ if (off + sz > end) // invalid data
+ break;
+ if (tag == EXTID_ZIP64) {
+ if (size == ZIP64_MAGICVAL) {
+ if (sz < 8 || (off + 8) > end)
+ break;
+ size = get64(cen, off);
+ sz -= 8;
+ off += 8;
+ }
+ if (rem == ZIP64_MAGICVAL) {
+ if (sz < 8 || (off + 8) > end)
+ break;
+ rem = get64(cen, off);
+ sz -= 8;
+ off += 8;
+ }
+ if (pos == ZIP64_MAGICVAL) {
+ if (sz < 8 || (off + 8) > end)
+ break;
+ pos = get64(cen, off);
+ sz -= 8;
+ off += 8;
+ }
+ break;
+ }
+ off += sz;
+ }
+ }
+
+ /* The Zip file spec explicitly allows the LOC extra data size to
+ * be different from the CEN extra data size. Since we cannot trust
+ * the CEN extra data size, we need to read the LOC to determine
+ * the entry data offset.
+ */
+ private long initDataOffset() throws IOException {
+ if (pos <= 0) {
+ byte[] loc = new byte[LOCHDR];
+ pos = -pos;
+ int len = ZipFile.this.zsrc.readFullyAt(loc, 0, loc.length, pos);
+ if (len != LOCHDR) {
+ throw new ZipException("ZipFile error reading zip file");
+ }
+ if (LOCSIG(loc) != LOCSIG) {
+ throw new ZipException("ZipFile invalid LOC header (bad signature)");
+ }
+ pos += LOCHDR + LOCNAM(loc) + LOCEXT(loc);
+ }
+ return pos;
}
public int read(byte b[], int off, int len) throws IOException {
synchronized (ZipFile.this) {
- long rem = this.rem;
- long pos = this.pos;
+ ensureOpenOrZipException();
+ initDataOffset();
if (rem == 0) {
return -1;
}
+ if (len > rem) {
+ len = (int) rem;
+ }
if (len <= 0) {
return 0;
}
- if (len > rem) {
- len = (int) rem;
- }
-
- // Check if ZipFile open
- ensureOpenOrZipException();
- len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
- off, len);
+ len = ZipFile.this.zsrc.readAt(b, off, len, pos);
if (len > 0) {
- this.pos = (pos + len);
- this.rem = (rem - len);
+ pos += len;
+ rem -= len;
}
}
if (rem == 0) {
@@ -742,11 +763,16 @@
}
}
- public long skip(long n) {
- if (n > rem)
- n = rem;
- pos += n;
- rem -= n;
+ public long skip(long n) throws IOException {
+ synchronized (ZipFile.this) {
+ ensureOpenOrZipException();
+ initDataOffset();
+ if (n > rem) {
+ n = rem;
+ }
+ pos += n;
+ rem -= n;
+ }
if (rem == 0) {
close();
}
@@ -762,17 +788,11 @@
}
public void close() {
- if (zfisCloseRequested)
+ if (closeRequested) {
return;
- zfisCloseRequested = true;
-
+ }
+ closeRequested = true;
rem = 0;
- synchronized (ZipFile.this) {
- if (jzentry != 0 && ZipFile.this.jzfile != 0) {
- freeEntry(ZipFile.this.jzfile, jzentry);
- jzentry = 0;
- }
- }
synchronized (streams) {
streams.remove(this);
}
@@ -787,40 +807,502 @@
SharedSecrets.setJavaUtilZipFileAccess(
new JavaUtilZipFileAccess() {
public boolean startsWithLocHeader(ZipFile zip) {
- return zip.startsWithLocHeader();
+ return zip.zsrc.startsWithLoc;
}
- }
+ public String[] getMetaInfEntryNames(ZipFile zip) {
+ return zip.getMetaInfEntryNames();
+ }
+ }
);
}
- /**
- * Returns {@code true} if, and only if, the zip file begins with {@code
- * LOCSIG}.
+ /*
+ * Returns an array of strings representing the names of all entries
+ * that begin with "META-INF/" (case ignored). This method is used
+ * in JarFile, via SharedSecrets, as an optimization when looking up
+ * manifest and signature file entries. Returns null if no entries
+ * were found.
*/
- private boolean startsWithLocHeader() {
- return locsig;
+ private String[] getMetaInfEntryNames() {
+ synchronized (this) {
+ ensureOpen();
+ if (zsrc.metanames.size() == 0) {
+ return null;
+ }
+ String[] names = new String[zsrc.metanames.size()];
+ byte[] cen = zsrc.cen;
+ for (int i = 0; i < names.length; i++) {
+ int pos = zsrc.metanames.get(i);
+ names[i] = new String(cen, pos + CENHDR, CENNAM(cen, pos),
+ StandardCharsets.UTF_8);
+ }
+ return names;
+ }
}
- private static native long open(String name, int mode, long lastModified,
- boolean usemmap) throws IOException;
- private static native int getTotal(long jzfile);
- private static native boolean startsWithLOC(long jzfile);
- private static native int read(long jzfile, long jzentry,
- long pos, byte[] b, int off, int len);
+ private static class Source {
+ private final Key key; // the key in files
+ private int refs = 1;
+
+ private RandomAccessFile zfile; // zfile of the underlying zip file
+ private byte[] cen; // CEN & ENDHDR
+ private long locpos; // position of first LOC header (usually 0)
+ private byte[] comment; // zip file comment
+ // list of meta entries in META-INF dir
+ private ArrayList<Integer> metanames = new ArrayList<>();
+ private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true)
+
+ // A Hashmap for all entries.
+ //
+ // A cen entry of Zip/JAR file. As we have one for every entry in every active Zip/JAR,
+ // We might have a lot of these in a typical system. In order to save space we don't
+ // keep the name in memory, but merely remember a 32 bit {@code hash} value of the
+ // entry name and its offset {@code pos} in the central directory hdeader.
+ //
+ // private static class Entry {
+ // int hash; // 32 bit hashcode on name
+ // int next; // hash chain: index into entries
+ // int pos; // Offset of central directory file header
+ // }
+ // private Entry[] entries; // array of hashed cen entry
+ //
+ // To reduce the total size of entries further, we use a int[] here to store 3 "int"
+ // {@code hash}, {@code next and {@code "pos for each entry. The entry can then be
+ // referred by their index of their positions in the {@code entries}.
+ //
+ private int[] entries; // array of hashed cen entry
+ private int addEntry(int index, int hash, int next, int pos) {
+ entries[index++] = hash;
+ entries[index++] = next;
+ entries[index++] = pos;
+ return index;
+ }
+ private int getEntryHash(int index) { return entries[index]; }
+ private int getEntryNext(int index) { return entries[index + 1]; }
+ private int getEntryPos(int index) { return entries[index + 2]; }
+ private static final int ZIP_ENDCHAIN = -1;
+ private int total; // total number of entries
+ private int[] table; // Hash chain heads: indexes into entries
+ private int tablelen; // number of hash heads
+
+ private static class Key {
+ BasicFileAttributes attrs;
+ File file;
+
+ public Key(File file, BasicFileAttributes attrs) {
+ this.attrs = attrs;
+ this.file = file;
+ }
+
+ public int hashCode() {
+ long t = attrs.lastModifiedTime().toMillis();
+ return ((int)(t ^ (t >>> 32))) + file.hashCode();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof Key) {
+ Key key = (Key)obj;
+ if (!attrs.lastModifiedTime().equals(key.attrs.lastModifiedTime())) {
+ return false;
+ }
+ Object fk = attrs.fileKey();
+ if (fk != null) {
+ return fk.equals(key.attrs.fileKey());
+ } else {
+ return file.equals(key.file);
+ }
+ }
+ return false;
+ }
+ }
+ private static final HashMap<Key, Source> files = new HashMap<>();
+
+
+ public static Source get(File file, boolean toDelete) throws IOException {
+ Key key = new Key(file,
+ Files.readAttributes(file.toPath(), BasicFileAttributes.class));
+ Source src = null;
+ synchronized (files) {
+ src = files.get(key);
+ if (src != null) {
+ src.refs++;
+ return src;
+ }
+ }
+ src = new Source(key, toDelete);
+
+ synchronized (files) {
+ if (files.containsKey(key)) { // someone else put in first
+ src.close(); // close the newly created one
+ src = files.get(key);
+ src.refs++;
+ return src;
+ }
+ files.put(key, src);
+ return src;
+ }
+ }
+
+ private static void close(Source src) throws IOException {
+ synchronized (files) {
+ if (--src.refs == 0) {
+ files.remove(src.key);
+ src.close();
+ }
+ }
+ }
+
+ private Source(Key key, boolean toDelete) throws IOException {
+ this.key = key;
+ this.zfile = new RandomAccessFile(key.file, "r");
+ if (toDelete) {
+ key.file.delete();
+ }
+ try {
+ initCEN(-1);
+ byte[] buf = new byte[4];
+ readFullyAt(buf, 0, 4, 0);
+ this.startsWithLoc = (LOCSIG(buf) == LOCSIG);
+ } catch (IOException x) {
+ try {
+ this.zfile.close();
+ } catch (IOException xx) {}
+ throw x;
+ }
+ }
+
+ private void close() throws IOException {
+ zfile.close();
+ zfile = null;
+ cen = null;
+ entries = null;
+ table = null;
+ metanames = null;
+ }
+
+ private static final int BUF_SIZE = 8192;
+ private final int readFullyAt(byte[] buf, int off, int len, long pos)
+ throws IOException
+ {
+ synchronized(zfile) {
+ zfile.seek(pos);
+ int N = len;
+ while (N > 0) {
+ int n = Math.min(BUF_SIZE, N);
+ zfile.readFully(buf, off, n);
+ off += n;
+ N -= n;
+ }
+ return len;
+ }
+ }
+
+ private final int readAt(byte[] buf, int off, int len, long pos)
+ throws IOException
+ {
+ synchronized(zfile) {
+ zfile.seek(pos);
+ return zfile.read(buf, off, len);
+ }
+ }
+
+ private static final int hashN(byte[] a, int off, int len) {
+ int h = 1;
+ while (len-- > 0) {
+ h = 31 * h + a[off++];
+ }
+ return h;
+ }
+
+ private static final int hash_append(int hash, byte b) {
+ return hash * 31 + b;
+ }
+
+ private static class End {
+ int centot; // 4 bytes
+ long cenlen; // 4 bytes
+ long cenoff; // 4 bytes
+ long endpos; // 4 bytes
+ }
- // access to the native zentry object
- private static native long getEntryTime(long jzentry);
- private static native long getEntryCrc(long jzentry);
- private static native long getEntryCSize(long jzentry);
- private static native long getEntrySize(long jzentry);
- private static native int getEntryMethod(long jzentry);
- private static native int getEntryFlag(long jzentry);
- private static native byte[] getCommentBytes(long jzfile);
+ /*
+ * Searches for end of central directory (END) header. The contents of
+ * the END header will be read and placed in endbuf. Returns the file
+ * position of the END header, otherwise returns -1 if the END header
+ * was not found or an error occurred.
+ */
+ private End findEND() throws IOException {
+ long ziplen = zfile.length();
+ if (ziplen <= 0)
+ zerror("zip file is empty");
+ End end = new End();
+ byte[] buf = new byte[READBLOCKSZ];
+ long minHDR = (ziplen - END_MAXLEN) > 0 ? ziplen - END_MAXLEN : 0;
+ long minPos = minHDR - (buf.length - ENDHDR);
+ for (long pos = ziplen - buf.length; pos >= minPos; pos -= (buf.length - ENDHDR)) {
+ int off = 0;
+ if (pos < 0) {
+ // Pretend there are some NUL bytes before start of file
+ off = (int)-pos;
+ Arrays.fill(buf, 0, off, (byte)0);
+ }
+ int len = buf.length - off;
+ if (readFullyAt(buf, off, len, pos + off) != len ) {
+ zerror("zip END header not found");
+ }
+ // Now scan the block backwards for END header signature
+ for (int i = buf.length - ENDHDR; i >= 0; i--) {
+ if (buf[i+0] == (byte)'P' &&
+ buf[i+1] == (byte)'K' &&
+ buf[i+2] == (byte)'\005' &&
+ buf[i+3] == (byte)'\006') {
+ // Found ENDSIG header
+ byte[] endbuf = Arrays.copyOfRange(buf, i, i + ENDHDR);
+ end.centot = ENDTOT(endbuf);
+ end.cenlen = ENDSIZ(endbuf);
+ end.cenoff = ENDOFF(endbuf);
+ end.endpos = pos + i;
+ int comlen = ENDCOM(endbuf);
+ if (end.endpos + ENDHDR + comlen != ziplen) {
+ // ENDSIG matched, however the size of file comment in it does
+ // not match the real size. One "common" cause for this problem
+ // is some "extra" bytes are padded at the end of the zipfile.
+ // Let's do some extra verification, we don't care about the
+ // performance in this situation.
+ byte[] sbuf = new byte[4];
+ long cenpos = end.endpos - end.cenlen;
+ long locpos = cenpos - end.cenoff;
+ if (cenpos < 0 ||
+ locpos < 0 ||
+ readFullyAt(sbuf, 0, sbuf.length, cenpos) != 4 ||
+ GETSIG(sbuf) != CENSIG ||
+ readFullyAt(sbuf, 0, sbuf.length, locpos) != 4 ||
+ GETSIG(sbuf) != LOCSIG) {
+ continue;
+ }
+ }
+ if (comlen > 0) { // this zip file has comlen
+ comment = new byte[comlen];
+ if (readFullyAt(comment, 0, comlen, end.endpos + ENDHDR) != comlen) {
+ zerror("zip comment read failed");
+ }
+ }
+ if (end.cenlen == ZIP64_MAGICVAL ||
+ end.cenoff == ZIP64_MAGICVAL ||
+ end.centot == ZIP64_MAGICCOUNT)
+ {
+ // need to find the zip64 end;
+ try {
+ byte[] loc64 = new byte[ZIP64_LOCHDR];
+ if (readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
+ != loc64.length || GETSIG(loc64) != ZIP64_LOCSIG) {
+ return end;
+ }
+ long end64pos = ZIP64_LOCOFF(loc64);
+ byte[] end64buf = new byte[ZIP64_ENDHDR];
+ if (readFullyAt(end64buf, 0, end64buf.length, end64pos)
+ != end64buf.length || GETSIG(end64buf) != ZIP64_ENDSIG) {
+ return end;
+ }
+ // end64 found, re-calcualte everything.
+ end.cenlen = ZIP64_ENDSIZ(end64buf);
+ end.cenoff = ZIP64_ENDOFF(end64buf);
+ end.centot = (int)ZIP64_ENDTOT(end64buf); // assume total < 2g
+ end.endpos = end64pos;
+ } catch (IOException x) {} // no zip64 loc/end
+ }
+ return end;
+ }
+ }
+ }
+ zerror("zip END header not found");
+ return null; //make compiler happy
+ }
+
+ // Reads zip file central directory.
+ private void initCEN(int knownTotal) throws IOException {
+ if (knownTotal == -1) {
+ End end = findEND();
+ if (end.endpos == 0) {
+ locpos = 0;
+ total = 0;
+ entries = new int[0];
+ cen = null;
+ return; // only END header present
+ }
+ if (end.cenlen > end.endpos)
+ zerror("invalid END header (bad central directory size)");
+ long cenpos = end.endpos - end.cenlen; // position of CEN table
+ // Get position of first local file (LOC) header, taking into
+ // account that there may be a stub prefixed to the zip file.
+ locpos = cenpos - end.cenoff;
+ if (locpos < 0) {
+ zerror("invalid END header (bad central directory offset)");
+ }
+ // read in the CEN and END
+ cen = new byte[(int)(end.cenlen + ENDHDR)];
+ if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) {
+ zerror("read CEN tables failed");
+ }
+ total = end.centot;
+ } else {
+ total = knownTotal;
+ }
+ // hash table for entries
+ entries = new int[total * 3];
+ tablelen = ((total/2) | 1); // Odd -> fewer collisions
+ table = new int[tablelen];
+ Arrays.fill(table, ZIP_ENDCHAIN);
+ int idx = 0;
+ int hash = 0;
+ int next = -1;
+
+ // list for all meta entries
+ metanames = new ArrayList<>();
- private static final int JZENTRY_NAME = 0;
- private static final int JZENTRY_EXTRA = 1;
- private static final int JZENTRY_COMMENT = 2;
- private static native byte[] getEntryBytes(long jzentry, int type);
+ // Iterate through the entries in the central directory
+ int i = 0;
+ int hsh = 0;
+ int pos = 0;
+ int limit = cen.length - ENDHDR;
+ while (pos + CENHDR <= limit) {
+ if (i >= total) {
+ // This will only happen if the zip file has an incorrect
+ // ENDTOT field, which usually means it contains more than
+ // 65535 entries.
+ initCEN(countCENHeaders(cen, limit));
+ return;
+ }
+ if (CENSIG(cen, pos) != CENSIG)
+ zerror("invalid CEN header (bad signature)");
+ int method = CENHOW(cen, pos);
+ int nlen = CENNAM(cen, pos);
+ int elen = CENEXT(cen, pos);
+ int clen = CENCOM(cen, pos);
+ if ((CENFLG(cen, pos) & 1) != 0)
+ zerror("invalid CEN header (encrypted entry)");
+ if (method != STORED && method != DEFLATED)
+ zerror("invalid CEN header (bad compression method: " + method + ")");
+ if (pos + CENHDR + nlen > limit)
+ zerror("invalid CEN header (bad header size)");
+ // Record the CEN offset and the name hash in our hash cell.
+ hash = hashN(cen, pos + CENHDR, nlen);
+ hsh = (hash & 0x7fffffff) % tablelen;
+ next = table[hsh];
+ table[hsh] = idx;
+ idx = addEntry(idx, hash, next, pos);
+ // Adds name to metanames.
+ if (isMetaName(cen, pos + CENHDR, nlen)) {
+ metanames.add(pos);
+ }
+ // skip ext and comment
+ pos += (CENHDR + nlen + elen + clen);
+ i++;
+ }
+ total = i;
+ if (pos + ENDHDR != cen.length) {
+ zerror("invalid CEN header (bad header size)");
+ }
+ }
+
+ private static void zerror(String msg) throws ZipException {
+ throw new ZipException(msg);
+ }
- private static native String getZipMessage(long jzfile);
+ /*
+ * Returns the {@code pos} of the zip cen entry corresponding to the
+ * specified entry name, or -1 if not found.
+ */
+ private int getEntryPos(byte[] name, boolean addSlash) {
+ if (total == 0) {
+ return -1;
+ }
+ int hsh = hashN(name, 0, name.length);
+ int idx = table[(hsh & 0x7fffffff) % tablelen];
+ /*
+ * This while loop is an optimization where a double lookup
+ * for name and name+/ is being performed. The name char
+ * array has enough room at the end to try again with a
+ * slash appended if the first table lookup does not succeed.
+ */
+ while(true) {
+ /*
+ * Search down the target hash chain for a entry whose
+ * 32 bit hash matches the hashed name.
+ */
+ while (idx != ZIP_ENDCHAIN) {
+ if (getEntryHash(idx) == hsh) {
+ // The CEN name must match the specfied one
+ int pos = getEntryPos(idx);
+ if (name.length == CENNAM(cen, pos)) {
+ boolean matched = true;
+ int nameoff = pos + CENHDR;
+ for (int i = 0; i < name.length; i++) {
+ if (name[i] != cen[nameoff++]) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) {
+ return pos;
+ }
+ }
+ }
+ idx = getEntryNext(idx);
+ }
+ /* If not addSlash, or slash is already there, we are done */
+ if (!addSlash || name[name.length - 1] == '/') {
+ return -1;
+ }
+ /* Add slash and try once more */
+ name = Arrays.copyOf(name, name.length + 1);
+ name[name.length - 1] = '/';
+ hsh = hash_append(hsh, (byte)'/');
+ //idx = table[hsh % tablelen];
+ idx = table[(hsh & 0x7fffffff) % tablelen];
+ addSlash = false;
+ }
+ }
+
+ private static byte[] metainf = new byte[] {
+ 'M', 'E', 'T', 'A', '-', 'I' , 'N', 'F', '/',
+ };
+
+ /*
+ * Returns true if the specified entry's name begins with the string
+ * "META-INF/" irrespective of case.
+ */
+ private static boolean isMetaName(byte[] name, int off, int len) {
+ if (len < 9 || (name[off] != 'M' && name[off] != 'm')) { // sizeof("META-INF/") - 1
+ return false;
+ }
+ off++;
+ for (int i = 1; i < metainf.length; i++) {
+ byte c = name[off++];
+ // Avoid toupper; it's locale-dependent
+ if (c >= 'a' && c <= 'z') {
+ c += 'A' - 'a';
+ }
+ if (metainf[i] != c) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * Counts the number of CEN headers in a central directory extending
+ * from BEG to END. Might return a bogus answer if the zip file is
+ * corrupt, but will not crash.
+ */
+ static int countCENHeaders(byte[] cen, int end) {
+ int count = 0;
+ int pos = 0;
+ while (pos + CENHDR <= end) {
+ count++;
+ pos += (CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos));
+ }
+ return count;
+ }
+ }
}
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipUtils.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipUtils.java Wed Jul 05 21:09:54 2017 +0200
@@ -31,6 +31,8 @@
import java.time.ZoneId;
import java.util.concurrent.TimeUnit;
+import static java.util.zip.ZipConstants.ENDHDR;
+
class ZipUtils {
// used to adjust values between Windows and java epoch
@@ -133,7 +135,7 @@
* The bytes are assumed to be in Intel (little-endian) byte order.
*/
public static final int get16(byte b[], int off) {
- return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
+ return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8);
}
/**
@@ -160,4 +162,79 @@
public static final int get32S(byte b[], int off) {
return (get16(b, off) | (get16(b, off+2) << 16));
}
+
+ // fields access methods
+ static final int CH(byte[] b, int n) {
+ return b[n] & 0xff ;
+ }
+
+ static final int SH(byte[] b, int n) {
+ return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8);
+ }
+
+ static final long LG(byte[] b, int n) {
+ return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL;
+ }
+
+ static final long LL(byte[] b, int n) {
+ return (LG(b, n)) | (LG(b, n + 4) << 32);
+ }
+
+ static final long GETSIG(byte[] b) {
+ return LG(b, 0);
+ }
+
+ // local file (LOC) header fields
+ static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature
+ static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract
+ static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags
+ static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method
+ static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time
+ static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data
+ static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size
+ static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size
+ static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length
+ static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length
+
+ // extra local (EXT) header fields
+ static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data
+ static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size
+ static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size
+
+ // end of central directory header (END) fields
+ static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk
+ static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries
+ static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size
+ static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset
+ static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment
+ static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);}
+
+ // zip64 end of central directory recoder fields
+ static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk
+ static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries
+ static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size
+ static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset
+ static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset
+
+ // central directory header (CEN) fields
+ static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); }
+ static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); }
+ static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); }
+ static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); }
+ static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);}
+ static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);}
+ static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);}
+ static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);}
+ static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);}
+ static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);}
+ static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);}
+ static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);}
+ static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);}
+ static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);}
+ static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);}
+ static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);}
+
+ // The END header is followed by a variable length comment of size < 64k.
+ static final long END_MAXLEN = 0xFFFF + ENDHDR;
+ static final int READBLOCKSZ = 128;
}
--- a/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java Wed Jul 05 21:09:54 2017 +0200
@@ -28,6 +28,7 @@
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.lang.StackWalker.StackFrame;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.time.ZonedDateTime;
@@ -180,7 +181,16 @@
* CallerFinder is a stateful predicate.
*/
static final class CallerFinder implements Predicate<StackWalker.StackFrame> {
- static final StackWalker WALKER = StackWalker.getInstance();
+ private static final StackWalker WALKER;
+ static {
+ final PrivilegedAction<StackWalker> action = new PrivilegedAction<>() {
+ @Override
+ public StackWalker run() {
+ return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
+ }
+ };
+ WALKER = AccessController.doPrivileged(action);
+ }
/**
* Returns StackFrame of the caller's frame.
@@ -210,8 +220,9 @@
lookingForLogger = !isLoggerImplFrame(cname);
return false;
}
- // We've found the relevant frame.
- return !skipLoggingFrame(cname) && !isLoggerImplFrame(cname);
+ // Continue walking until we've found the relevant calling frame.
+ // Skips logging/logger infrastructure.
+ return !isFilteredFrame(t);
}
private boolean isLoggerImplFrame(String cname) {
@@ -281,8 +292,8 @@
return Formatting.getSimpleFormat(defaultPropertyGetter);
}
- public static boolean skipLoggingFrame(String cname) {
- return Formatting.skipLoggingFrame(cname);
+ public static boolean isFilteredFrame(StackFrame st) {
+ return Formatting.isFilteredFrame(st);
}
@Override
@@ -393,16 +404,19 @@
}
- static boolean skipLoggingFrame(String cname) {
+ static boolean isFilteredFrame(StackFrame st) {
// skip logging/logger infrastructure
+ if (System.Logger.class.isAssignableFrom(st.getDeclaringClass())) {
+ return true;
+ }
// fast escape path: all the prefixes below start with 's' or 'j' and
// have more than 12 characters.
+ final String cname = st.getClassName();
char c = cname.length() < 12 ? 0 : cname.charAt(0);
if (c == 's') {
// skip internal machinery classes
if (cname.startsWith("sun.util.logging.")) return true;
- if (cname.startsWith("sun.reflect.")) return true;
if (cname.startsWith("sun.rmi.runtime.Log")) return true;
} else if (c == 'j') {
// Message delayed at Bootstrap: no need to go further up.
@@ -410,10 +424,7 @@
// skip public machinery classes
if (cname.startsWith("jdk.internal.logger.")) return true;
if (cname.startsWith("java.util.logging.")) return true;
- if (cname.startsWith("java.lang.System$Logger")) return true;
- if (cname.startsWith("java.lang.reflect.")) return true;
if (cname.startsWith("java.lang.invoke.MethodHandle")) return true;
- if (cname.startsWith("java.lang.invoke.LambdaForm")) return true;
if (cname.startsWith("java.security.AccessController")) return true;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,790 @@
+/*
+ * 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.misc;
+
+import java.lang.ref.Cleaner;
+import java.lang.ref.Cleaner.Cleanable;
+import java.lang.ref.PhantomReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Objects;
+import java.util.concurrent.ThreadFactory;
+import java.util.function.Function;
+
+import sun.misc.InnocuousThread;
+import sun.misc.ManagedLocalsThread;
+
+/**
+ * CleanerImpl manages a set of object references and corresponding cleaning actions.
+ * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
+ */
+public final class CleanerImpl implements Runnable {
+
+ /**
+ * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
+ */
+ private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
+
+ /**
+ * Heads of a CleanableList for each reference type.
+ */
+ final PhantomCleanable<?> phantomCleanableList;
+
+ final WeakCleanable<?> weakCleanableList;
+
+ final SoftCleanable<?> softCleanableList;
+
+ // The ReferenceQueue of pending cleaning actions
+ final ReferenceQueue<Object> queue;
+
+ /**
+ * Called by Cleaner static initialization to provide the function
+ * to map from Cleaner to CleanerImpl.
+ * @param access a function to map from Cleaner to CleanerImpl
+ */
+ public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) {
+ if (cleanerImplAccess == null) {
+ cleanerImplAccess = access;
+ }
+ }
+
+ /**
+ * Called to get the CleanerImpl for a Cleaner.
+ * @param cleaner the cleaner
+ * @return the corresponding CleanerImpl
+ */
+ private static CleanerImpl getCleanerImpl(Cleaner cleaner) {
+ return cleanerImplAccess.apply(cleaner);
+ }
+
+ /**
+ * Constructor for CleanerImpl.
+ */
+ public CleanerImpl() {
+ queue = new ReferenceQueue<>();
+ phantomCleanableList = new PhantomCleanableRef(this);
+ weakCleanableList = new WeakCleanableRef(this);
+ softCleanableList = new SoftCleanableRef(this);
+ }
+
+ /**
+ * Starts the Cleaner implementation.
+ * When started waits for Cleanables to be queued.
+ * @param service the cleaner
+ * @param threadFactory the thread factory
+ */
+ public void start(Cleaner service, ThreadFactory threadFactory) {
+ // schedule a nop cleaning action for the service, so the associated thread
+ // will continue to run at least until the service is reclaimable.
+ new PhantomCleanableRef(service, service, () -> {});
+
+ if (threadFactory == null) {
+ threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
+ }
+
+ // now that there's at least one cleaning action, for the service,
+ // we can start the associated thread, which runs until
+ // all cleaning actions have been run.
+ Thread thread = threadFactory.newThread(this);
+ thread.setDaemon(true);
+ thread.start();
+ }
+
+ /**
+ * Process queued Cleanables as long as the cleanable lists are not empty.
+ * A Cleanable is in one of the lists for each Object and for the Cleaner
+ * itself.
+ * Terminates when the Cleaner is no longer reachable and
+ * has been cleaned and there are no more Cleanable instances
+ * for which the object is reachable.
+ * <p>
+ * If the thread is a ManagedLocalsThread, the threadlocals
+ * are erased before each cleanup
+ */
+ public void run() {
+ Thread t = Thread.currentThread();
+ ManagedLocalsThread mlThread = (t instanceof ManagedLocalsThread)
+ ? (ManagedLocalsThread) t
+ : null;
+ while (!phantomCleanableList.isListEmpty() ||
+ !weakCleanableList.isListEmpty() ||
+ !softCleanableList.isListEmpty()) {
+ if (mlThread != null) {
+ // Clear the thread locals
+ mlThread.eraseThreadLocals();
+ }
+ try {
+ // Wait for a Ref, with a timeout to avoid getting hung
+ // due to a race with clear/clean
+ Cleanable ref = (Cleanable) queue.remove(60 * 1000L);
+ if (ref != null) {
+ ref.clean();
+ }
+ } catch (InterruptedException i) {
+ continue; // ignore the interruption
+ } catch (Throwable e) {
+ // ignore exceptions from the cleanup action
+ }
+ }
+ }
+
+ /**
+ * PhantomCleanable subclasses efficiently encapsulate cleanup state and
+ * the cleaning action.
+ * Subclasses implement the abstract {@link #performCleanup()} method
+ * to provide the cleaning action.
+ * When constructed, the object reference and the {@link Cleanable Cleanable}
+ * are registered with the {@link Cleaner}.
+ * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the
+ * referent becomes phantom reachable.
+ */
+ public static abstract class PhantomCleanable<T> extends PhantomReference<T>
+ implements Cleaner.Cleanable {
+
+ /**
+ * Links to previous and next in a doubly-linked list.
+ */
+ PhantomCleanable<?> prev = this, next = this;
+
+ /**
+ * The CleanerImpl for this Cleanable.
+ */
+ private final CleanerImpl cleanerImpl;
+
+ /**
+ * Constructs new {@code PhantomCleanable} with
+ * {@code non-null referent} and {@code non-null cleaner}.
+ * The {@code cleaner} is not retained; it is only used to
+ * register the newly constructed {@link Cleaner.Cleanable Cleanable}.
+ *
+ * @param referent the referent to track
+ * @param cleaner the {@code Cleaner} to register with
+ */
+ public PhantomCleanable(T referent, Cleaner cleaner) {
+ super(Objects.requireNonNull(referent), getCleanerImpl(cleaner).queue);
+ this.cleanerImpl = getCleanerImpl(cleaner);
+ insert();
+
+ // TODO: Replace getClass() with ReachabilityFence when it is available
+ cleaner.getClass();
+ referent.getClass();
+ }
+
+ /**
+ * Construct a new root of the list; not inserted.
+ */
+ PhantomCleanable(CleanerImpl cleanerImpl) {
+ super(null, null);
+ this.cleanerImpl = cleanerImpl;
+ }
+
+ /**
+ * Insert this PhantomCleanable after the list head.
+ */
+ private void insert() {
+ final PhantomCleanable<?> list = cleanerImpl.phantomCleanableList;
+ synchronized (list) {
+ prev = list;
+ next = list.next;
+ next.prev = this;
+ list.next = this;
+ }
+ }
+
+ /**
+ * Remove this PhantomCleanable from the list.
+ *
+ * @return true if Cleanable was removed or false if not because
+ * it had already been removed before
+ */
+ private boolean remove() {
+ PhantomCleanable<?> list = cleanerImpl.phantomCleanableList;
+ synchronized (list) {
+ if (next != this) {
+ next.prev = prev;
+ prev.next = next;
+ prev = this;
+ next = this;
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if the list's next reference refers to itself.
+ *
+ * @return true if the list is empty
+ */
+ boolean isListEmpty() {
+ PhantomCleanable<?> list = cleanerImpl.phantomCleanableList;
+ synchronized (list) {
+ return list == list.next;
+ }
+ }
+
+ /**
+ * Unregister this PhantomCleanable and invoke {@link #performCleanup()},
+ * ensuring at-most-once semantics.
+ */
+ @Override
+ public final void clean() {
+ if (remove()) {
+ super.clear();
+ performCleanup();
+ }
+ }
+
+ /**
+ * Unregister this PhantomCleanable and clear the reference.
+ * Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
+ */
+ @Override
+ public void clear() {
+ if (remove()) {
+ super.clear();
+ }
+ }
+
+ /**
+ * The {@code performCleanup} abstract method is overridden
+ * to implement the cleaning logic.
+ * The {@code performCleanup} method should not be called except
+ * by the {@link #clean} method which ensures at most once semantics.
+ */
+ protected abstract void performCleanup();
+
+ /**
+ * This method always throws {@link UnsupportedOperationException}.
+ * Enqueuing details of {@link Cleaner.Cleanable}
+ * are a private implementation detail.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean isEnqueued() {
+ throw new UnsupportedOperationException("isEnqueued");
+ }
+
+ /**
+ * This method always throws {@link UnsupportedOperationException}.
+ * Enqueuing details of {@link Cleaner.Cleanable}
+ * are a private implementation detail.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean enqueue() {
+ throw new UnsupportedOperationException("enqueue");
+ }
+ }
+
+ /**
+ * WeakCleanable subclasses efficiently encapsulate cleanup state and
+ * the cleaning action.
+ * Subclasses implement the abstract {@link #performCleanup()} method
+ * to provide the cleaning action.
+ * When constructed, the object reference and the {@link Cleanable Cleanable}
+ * are registered with the {@link Cleaner}.
+ * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the
+ * referent becomes weakly reachable.
+ */
+ public static abstract class WeakCleanable<T> extends WeakReference<T>
+ implements Cleaner.Cleanable {
+
+ /**
+ * Links to previous and next in a doubly-linked list.
+ */
+ WeakCleanable<?> prev = this, next = this;
+
+ /**
+ * The CleanerImpl for this Cleanable.
+ */
+ private final CleanerImpl cleanerImpl;
+
+ /**
+ * Constructs new {@code WeakCleanableReference} with
+ * {@code non-null referent} and {@code non-null cleaner}.
+ * The {@code cleaner} is not retained by this reference; it is only used
+ * to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
+ *
+ * @param referent the referent to track
+ * @param cleaner the {@code Cleaner} to register new reference with
+ */
+ public WeakCleanable(T referent, Cleaner cleaner) {
+ super(Objects.requireNonNull(referent), getCleanerImpl(cleaner).queue);
+ cleanerImpl = getCleanerImpl(cleaner);
+ insert();
+
+ // TODO: Replace getClass() with ReachabilityFence when it is available
+ cleaner.getClass();
+ referent.getClass();
+ }
+
+ /**
+ * Construct a new root of the list; not inserted.
+ */
+ WeakCleanable(CleanerImpl cleanerImpl) {
+ super(null, null);
+ this.cleanerImpl = cleanerImpl;
+ }
+
+ /**
+ * Insert this WeakCleanableReference after the list head.
+ */
+ private void insert() {
+ final WeakCleanable<?> list = cleanerImpl.weakCleanableList;
+ synchronized (list) {
+ prev = list;
+ next = list.next;
+ next.prev = this;
+ list.next = this;
+ }
+ }
+
+ /**
+ * Remove this WeakCleanableReference from the list.
+ *
+ * @return true if Cleanable was removed or false if not because
+ * it had already been removed before
+ */
+ private boolean remove() {
+ WeakCleanable<?> list = cleanerImpl.weakCleanableList;
+ synchronized (list) {
+ if (next != this) {
+ next.prev = prev;
+ prev.next = next;
+ prev = this;
+ next = this;
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if the list's next reference refers to itself.
+ *
+ * @return true if the list is empty
+ */
+ boolean isListEmpty() {
+ WeakCleanable<?> list = cleanerImpl.weakCleanableList;
+ synchronized (list) {
+ return list == list.next;
+ }
+ }
+
+ /**
+ * Unregister this WeakCleanable reference and invoke {@link #performCleanup()},
+ * ensuring at-most-once semantics.
+ */
+ @Override
+ public final void clean() {
+ if (remove()) {
+ super.clear();
+ performCleanup();
+ }
+ }
+
+ /**
+ * Unregister this WeakCleanable and clear the reference.
+ * Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
+ */
+ @Override
+ public void clear() {
+ if (remove()) {
+ super.clear();
+ }
+ }
+
+ /**
+ * The {@code performCleanup} abstract method is overridden
+ * to implement the cleaning logic.
+ * The {@code performCleanup} method should not be called except
+ * by the {@link #clean} method which ensures at most once semantics.
+ */
+ protected abstract void performCleanup();
+
+ /**
+ * This method always throws {@link UnsupportedOperationException}.
+ * Enqueuing details of {@link java.lang.ref.Cleaner.Cleanable}
+ * are a private implementation detail.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean isEnqueued() {
+ throw new UnsupportedOperationException("isEnqueued");
+ }
+
+ /**
+ * This method always throws {@link UnsupportedOperationException}.
+ * Enqueuing details of {@link java.lang.ref.Cleaner.Cleanable}
+ * are a private implementation detail.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean enqueue() {
+ throw new UnsupportedOperationException("enqueue");
+ }
+ }
+
+ /**
+ * SoftCleanable subclasses efficiently encapsulate cleanup state and
+ * the cleaning action.
+ * Subclasses implement the abstract {@link #performCleanup()} method
+ * to provide the cleaning action.
+ * When constructed, the object reference and the {@link Cleanable Cleanable}
+ * are registered with the {@link Cleaner}.
+ * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the
+ * referent becomes softly reachable.
+ */
+ public static abstract class SoftCleanable<T> extends SoftReference<T>
+ implements Cleaner.Cleanable {
+
+ /**
+ * Links to previous and next in a doubly-linked list.
+ */
+ SoftCleanable<?> prev = this, next = this;
+
+ /**
+ * The CleanerImpl for this Cleanable.
+ */
+ private final CleanerImpl cleanerImpl;
+
+ /**
+ * Constructs new {@code SoftCleanableReference} with
+ * {@code non-null referent} and {@code non-null cleaner}.
+ * The {@code cleaner} is not retained by this reference; it is only used
+ * to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
+ *
+ * @param referent the referent to track
+ * @param cleaner the {@code Cleaner} to register with
+ */
+ public SoftCleanable(T referent, Cleaner cleaner) {
+ super(Objects.requireNonNull(referent), getCleanerImpl(cleaner).queue);
+ cleanerImpl = getCleanerImpl(cleaner);
+ insert();
+
+ // TODO: Replace getClass() with ReachabilityFence when it is available
+ cleaner.getClass();
+ referent.getClass();
+ }
+
+ /**
+ * Construct a new root of the list; not inserted.
+ */
+ SoftCleanable(CleanerImpl cleanerImpl) {
+ super(null, null);
+ this.cleanerImpl = cleanerImpl;
+ }
+
+ /**
+ * Insert this SoftCleanableReference after the list head.
+ */
+ private void insert() {
+ final SoftCleanable<?> list = cleanerImpl.softCleanableList;
+ synchronized (list) {
+ prev = list;
+ next = list.next;
+ next.prev = this;
+ list.next = this;
+ }
+ }
+
+ /**
+ * Remove this SoftCleanableReference from the list.
+ *
+ * @return true if Cleanable was removed or false if not because
+ * it had already been removed before
+ */
+ private boolean remove() {
+ SoftCleanable<?> list = cleanerImpl.softCleanableList;
+ synchronized (list) {
+ if (next != this) {
+ next.prev = prev;
+ prev.next = next;
+ prev = this;
+ next = this;
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if the list's next reference refers to itself.
+ *
+ * @return true if the list is empty
+ */
+ boolean isListEmpty() {
+ SoftCleanable<?> list = cleanerImpl.softCleanableList;
+ synchronized (list) {
+ return list == list.next;
+ }
+ }
+
+ /**
+ * Unregister this SoftCleanable reference and invoke {@link #performCleanup()},
+ * ensuring at-most-once semantics.
+ */
+ @Override
+ public final void clean() {
+ if (remove()) {
+ super.clear();
+ performCleanup();
+ }
+ }
+
+ /**
+ * Unregister this SoftCleanable and clear the reference.
+ * Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
+ */
+ @Override
+ public void clear() {
+ if (remove()) {
+ super.clear();
+ }
+ }
+
+ /**
+ * The {@code performCleanup} abstract method is overridden
+ * to implement the cleaning logic.
+ * The {@code performCleanup} method should not be called except
+ * by the {@link #clean} method which ensures at most once semantics.
+ */
+ protected abstract void performCleanup();
+
+ /**
+ * This method always throws {@link UnsupportedOperationException}.
+ * Enqueuing details of {@link Cleaner.Cleanable}
+ * are a private implementation detail.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean isEnqueued() {
+ throw new UnsupportedOperationException("isEnqueued");
+ }
+
+ /**
+ * This method always throws {@link UnsupportedOperationException}.
+ * Enqueuing details of {@link Cleaner.Cleanable}
+ * are a private implementation detail.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean enqueue() {
+ throw new UnsupportedOperationException("enqueue");
+ }
+ }
+
+ /**
+ * Perform cleaning on an unreachable PhantomReference.
+ */
+ public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
+ private final Runnable action;
+
+ /**
+ * Constructor for a phantom cleanable reference.
+ * @param obj the object to monitor
+ * @param cleaner the cleaner
+ * @param action the action Runnable
+ */
+ public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
+ super(obj, cleaner);
+ this.action = action;
+ }
+
+ /**
+ * Constructor used only for root of phantom cleanable list.
+ * @param cleanerImpl the cleanerImpl
+ */
+ PhantomCleanableRef(CleanerImpl cleanerImpl) {
+ super(cleanerImpl);
+ this.action = null;
+ }
+
+ @Override
+ protected void performCleanup() {
+ action.run();
+ }
+
+ /**
+ * Prevent access to referent even when it is still alive.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public Object get() {
+ throw new UnsupportedOperationException("get");
+ }
+
+ /**
+ * Direct clearing of the referent is not supported.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("clear");
+ }
+ }
+
+ /**
+ * Perform cleaning on an unreachable WeakReference.
+ */
+ public static final class WeakCleanableRef extends WeakCleanable<Object> {
+ private final Runnable action;
+
+ /**
+ * Constructor for a weak cleanable reference.
+ * @param obj the object to monitor
+ * @param cleaner the cleaner
+ * @param action the action Runnable
+ */
+ WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
+ super(obj, cleaner);
+ this.action = action;
+ }
+
+ /**
+ * Constructor used only for root of weak cleanable list.
+ * @param cleanerImpl the cleanerImpl
+ */
+ WeakCleanableRef(CleanerImpl cleanerImpl) {
+ super(cleanerImpl);
+ this.action = null;
+ }
+
+ @Override
+ protected void performCleanup() {
+ action.run();
+ }
+
+ /**
+ * Prevent access to referent even when it is still alive.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public Object get() {
+ throw new UnsupportedOperationException("get");
+ }
+
+ /**
+ * Direct clearing of the referent is not supported.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("clear");
+ }
+ }
+
+ /**
+ * Perform cleaning on an unreachable SoftReference.
+ */
+ public static final class SoftCleanableRef extends SoftCleanable<Object> {
+ private final Runnable action;
+
+ /**
+ * Constructor for a soft cleanable reference.
+ * @param obj the object to monitor
+ * @param cleaner the cleaner
+ * @param action the action Runnable
+ */
+ SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
+ super(obj, cleaner);
+ this.action = action;
+ }
+
+ /**
+ * Constructor used only for root of soft cleanable list.
+ * @param cleanerImpl the cleanerImpl
+ */
+ SoftCleanableRef(CleanerImpl cleanerImpl) {
+ super(cleanerImpl);
+ this.action = null;
+ }
+
+ @Override
+ protected void performCleanup() {
+ action.run();
+ }
+
+ /**
+ * Prevent access to referent even when it is still alive.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public Object get() {
+ throw new UnsupportedOperationException("get");
+ }
+
+ /**
+ * Direct clearing of the referent is not supported.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("clear");
+ }
+
+ }
+
+ /**
+ * A ThreadFactory for InnocuousThreads.
+ * The factory is a singleton.
+ */
+ static final class InnocuousThreadFactory implements ThreadFactory {
+ final static ThreadFactory factory = new InnocuousThreadFactory();
+
+ static ThreadFactory factory() {
+ return factory;
+ }
+
+ public Thread newThread(Runnable r) {
+ return AccessController.doPrivileged((PrivilegedAction<Thread>) () -> {
+ Thread t = new InnocuousThread(r);
+ t.setPriority(Thread.MAX_PRIORITY - 2);
+ t.setName("Cleaner-" + t.getId());
+ return t;
+ });
+ }
+ }
+
+}
+
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilZipFileAccess.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilZipFileAccess.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,5 +29,6 @@
public interface JavaUtilZipFileAccess {
public boolean startsWithLocHeader(ZipFile zip);
+ public String[] getMetaInfEntryNames(ZipFile zip);
}
--- a/jdk/src/java.base/share/classes/sun/misc/BASE64Decoder.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/*
- * Copyright (c) 1995, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.misc;
-
-import java.io.OutputStream;
-import java.io.PushbackInputStream;
-import java.io.PrintStream;
-
-/**
- * This class implements a BASE64 Character decoder as specified in RFC1521.
- *
- * This RFC is part of the MIME specification which is published by the
- * Internet Engineering Task Force (IETF). Unlike some other encoding
- * schemes there is nothing in this encoding that tells the decoder
- * where a buffer starts or stops, so to use it you will need to isolate
- * your encoded data into a single chunk and then feed them this decoder.
- * The simplest way to do that is to read all of the encoded data into a
- * string and then use:
- * <pre>
- * byte mydata[];
- * BASE64Decoder base64 = new BASE64Decoder();
- *
- * mydata = base64.decodeBuffer(bufferString);
- * </pre>
- * This will decode the String in <i>bufferString</i> and give you an array
- * of bytes in the array <i>myData</i>.
- *
- * On errors, this class throws a CEFormatException with the following detail
- * strings:
- * <pre>
- * "BASE64Decoder: Not enough bytes for an atom."
- * </pre>
- *
- * @author Chuck McManis
- * @see CharacterEncoder
- * @see BASE64Decoder
- */
-
-public class BASE64Decoder extends CharacterDecoder {
-
- /** This class has 4 bytes per atom */
- protected int bytesPerAtom() {
- return (4);
- }
-
- /** Any multiple of 4 will do, 72 might be common */
- protected int bytesPerLine() {
- return (72);
- }
-
- /**
- * This character array provides the character to value map
- * based on RFC1521.
- */
- private static final char pem_array[] = {
- // 0 1 2 3 4 5 6 7
- 'A','B','C','D','E','F','G','H', // 0
- 'I','J','K','L','M','N','O','P', // 1
- 'Q','R','S','T','U','V','W','X', // 2
- 'Y','Z','a','b','c','d','e','f', // 3
- 'g','h','i','j','k','l','m','n', // 4
- 'o','p','q','r','s','t','u','v', // 5
- 'w','x','y','z','0','1','2','3', // 6
- '4','5','6','7','8','9','+','/' // 7
- };
-
- private static final byte pem_convert_array[] = new byte[256];
-
- static {
- for (int i = 0; i < 255; i++) {
- pem_convert_array[i] = -1;
- }
- for (int i = 0; i < pem_array.length; i++) {
- pem_convert_array[pem_array[i]] = (byte) i;
- }
- }
-
- byte decode_buffer[] = new byte[4];
-
- /**
- * Decode one BASE64 atom into 1, 2, or 3 bytes of data.
- */
- @SuppressWarnings("fallthrough")
- protected void decodeAtom(PushbackInputStream inStream, OutputStream outStream, int rem)
- throws java.io.IOException
- {
- int i;
- byte a = -1, b = -1, c = -1, d = -1;
-
- if (rem < 2) {
- throw new CEFormatException("BASE64Decoder: Not enough bytes for an atom.");
- }
- do {
- i = inStream.read();
- if (i == -1) {
- throw new CEStreamExhausted();
- }
- } while (i == '\n' || i == '\r');
- decode_buffer[0] = (byte) i;
-
- i = readFully(inStream, decode_buffer, 1, rem-1);
- if (i == -1) {
- throw new CEStreamExhausted();
- }
-
- if (rem > 3 && decode_buffer[3] == '=') {
- rem = 3;
- }
- if (rem > 2 && decode_buffer[2] == '=') {
- rem = 2;
- }
- switch (rem) {
- case 4:
- d = pem_convert_array[decode_buffer[3] & 0xff];
- // NOBREAK
- case 3:
- c = pem_convert_array[decode_buffer[2] & 0xff];
- // NOBREAK
- case 2:
- b = pem_convert_array[decode_buffer[1] & 0xff];
- a = pem_convert_array[decode_buffer[0] & 0xff];
- break;
- }
-
- switch (rem) {
- case 2:
- outStream.write( (byte)(((a << 2) & 0xfc) | ((b >>> 4) & 3)) );
- break;
- case 3:
- outStream.write( (byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)) );
- outStream.write( (byte) (((b << 4) & 0xf0) | ((c >>> 2) & 0xf)) );
- break;
- case 4:
- outStream.write( (byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)) );
- outStream.write( (byte) (((b << 4) & 0xf0) | ((c >>> 2) & 0xf)) );
- outStream.write( (byte) (((c << 6) & 0xc0) | (d & 0x3f)) );
- break;
- }
- return;
- }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/BASE64Encoder.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-/*
- * Copyright (c) 1995, 1997, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.misc;
-
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.io.IOException;
-
-/**
- * This class implements a BASE64 Character encoder as specified in RFC1521.
- * This RFC is part of the MIME specification as published by the Internet
- * Engineering Task Force (IETF). Unlike some other encoding schemes there
- * is nothing in this encoding that indicates
- * where a buffer starts or ends.
- *
- * This means that the encoded text will simply start with the first line
- * of encoded text and end with the last line of encoded text.
- *
- * @author Chuck McManis
- * @see CharacterEncoder
- * @see BASE64Decoder
- */
-
-public class BASE64Encoder extends CharacterEncoder {
-
- /** this class encodes three bytes per atom. */
- protected int bytesPerAtom() {
- return (3);
- }
-
- /**
- * this class encodes 57 bytes per line. This results in a maximum
- * of 57/3 * 4 or 76 characters per output line. Not counting the
- * line termination.
- */
- protected int bytesPerLine() {
- return (57);
- }
-
- /** This array maps the characters to their 6 bit values */
- private static final char pem_array[] = {
- // 0 1 2 3 4 5 6 7
- 'A','B','C','D','E','F','G','H', // 0
- 'I','J','K','L','M','N','O','P', // 1
- 'Q','R','S','T','U','V','W','X', // 2
- 'Y','Z','a','b','c','d','e','f', // 3
- 'g','h','i','j','k','l','m','n', // 4
- 'o','p','q','r','s','t','u','v', // 5
- 'w','x','y','z','0','1','2','3', // 6
- '4','5','6','7','8','9','+','/' // 7
- };
-
- /**
- * encodeAtom - Take three bytes of input and encode it as 4
- * printable characters. Note that if the length in len is less
- * than three is encodes either one or two '=' signs to indicate
- * padding characters.
- */
- protected void encodeAtom(OutputStream outStream, byte data[], int offset, int len)
- throws IOException {
- byte a, b, c;
-
- if (len == 1) {
- a = data[offset];
- b = 0;
- c = 0;
- outStream.write(pem_array[(a >>> 2) & 0x3F]);
- outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
- outStream.write('=');
- outStream.write('=');
- } else if (len == 2) {
- a = data[offset];
- b = data[offset+1];
- c = 0;
- outStream.write(pem_array[(a >>> 2) & 0x3F]);
- outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
- outStream.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
- outStream.write('=');
- } else {
- a = data[offset];
- b = data[offset+1];
- c = data[offset+2];
- outStream.write(pem_array[(a >>> 2) & 0x3F]);
- outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
- outStream.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
- outStream.write(pem_array[c & 0x3F]);
- }
- }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/CharacterDecoder.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,218 +0,0 @@
-/*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.io.OutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.PushbackInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * This class defines the decoding half of character encoders.
- * A character decoder is an algorithim for transforming 8 bit
- * binary data that has been encoded into text by a character
- * encoder, back into original binary form.
- *
- * The character encoders, in general, have been structured
- * around a central theme that binary data can be encoded into
- * text that has the form:
- *
- * <pre>
- * [Buffer Prefix]
- * [Line Prefix][encoded data atoms][Line Suffix]
- * [Buffer Suffix]
- * </pre>
- *
- * Of course in the simplest encoding schemes, the buffer has no
- * distinct prefix of suffix, however all have some fixed relationship
- * between the text in an 'atom' and the binary data itself.
- *
- * In the CharacterEncoder and CharacterDecoder classes, one complete
- * chunk of data is referred to as a <i>buffer</i>. Encoded buffers
- * are all text, and decoded buffers (sometimes just referred to as
- * buffers) are binary octets.
- *
- * To create a custom decoder, you must, at a minimum, overide three
- * abstract methods in this class.
- * <DL>
- * <DD>bytesPerAtom which tells the decoder how many bytes to
- * expect from decodeAtom
- * <DD>decodeAtom which decodes the bytes sent to it as text.
- * <DD>bytesPerLine which tells the encoder the maximum number of
- * bytes per line.
- * </DL>
- *
- * In general, the character decoders return error in the form of a
- * CEFormatException. The syntax of the detail string is
- * <pre>
- * DecoderClassName: Error message.
- * </pre>
- *
- * Several useful decoders have already been written and are
- * referenced in the See Also list below.
- *
- * @author Chuck McManis
- * @see CEFormatException
- * @see CharacterEncoder
- * @see UCDecoder
- * @see UUDecoder
- * @see BASE64Decoder
- */
-
-public abstract class CharacterDecoder {
-
- /** Return the number of bytes per atom of decoding */
- protected abstract int bytesPerAtom();
-
- /** Return the maximum number of bytes that can be encoded per line */
- protected abstract int bytesPerLine();
-
- /** decode the beginning of the buffer, by default this is a NOP. */
- protected void decodeBufferPrefix(PushbackInputStream aStream, OutputStream bStream) throws IOException { }
-
- /** decode the buffer suffix, again by default it is a NOP. */
- protected void decodeBufferSuffix(PushbackInputStream aStream, OutputStream bStream) throws IOException { }
-
- /**
- * This method should return, if it knows, the number of bytes
- * that will be decoded. Many formats such as uuencoding provide
- * this information. By default we return the maximum bytes that
- * could have been encoded on the line.
- */
- protected int decodeLinePrefix(PushbackInputStream aStream, OutputStream bStream) throws IOException {
- return (bytesPerLine());
- }
-
- /**
- * This method post processes the line, if there are error detection
- * or correction codes in a line, they are generally processed by
- * this method. The simplest version of this method looks for the
- * (newline) character.
- */
- protected void decodeLineSuffix(PushbackInputStream aStream, OutputStream bStream) throws IOException { }
-
- /**
- * This method does an actual decode. It takes the decoded bytes and
- * writes them to the OutputStream. The integer <i>l</i> tells the
- * method how many bytes are required. This is always {@literal <=} bytesPerAtom().
- */
- protected void decodeAtom(PushbackInputStream aStream, OutputStream bStream, int l) throws IOException {
- throw new CEStreamExhausted();
- }
-
- /**
- * This method works around the bizarre semantics of BufferedInputStream's
- * read method.
- */
- protected int readFully(InputStream in, byte buffer[], int offset, int len)
- throws java.io.IOException {
- for (int i = 0; i < len; i++) {
- int q = in.read();
- if (q == -1)
- return ((i == 0) ? -1 : i);
- buffer[i+offset] = (byte)q;
- }
- return len;
- }
-
- /**
- * Decode the text from the InputStream and write the decoded
- * octets to the OutputStream. This method runs until the stream
- * is exhausted.
- * @exception CEFormatException An error has occurred while decoding
- * @exception CEStreamExhausted The input stream is unexpectedly out of data
- */
- public void decodeBuffer(InputStream aStream, OutputStream bStream) throws IOException {
- int i;
- int totalBytes = 0;
-
- PushbackInputStream ps = new PushbackInputStream (aStream);
- decodeBufferPrefix(ps, bStream);
- while (true) {
- int length;
-
- try {
- length = decodeLinePrefix(ps, bStream);
- for (i = 0; (i+bytesPerAtom()) < length; i += bytesPerAtom()) {
- decodeAtom(ps, bStream, bytesPerAtom());
- totalBytes += bytesPerAtom();
- }
- if ((i + bytesPerAtom()) == length) {
- decodeAtom(ps, bStream, bytesPerAtom());
- totalBytes += bytesPerAtom();
- } else {
- decodeAtom(ps, bStream, length - i);
- totalBytes += (length - i);
- }
- decodeLineSuffix(ps, bStream);
- } catch (CEStreamExhausted e) {
- break;
- }
- }
- decodeBufferSuffix(ps, bStream);
- }
-
- /**
- * Alternate decode interface that takes a String containing the encoded
- * buffer and returns a byte array containing the data.
- * @exception CEFormatException An error has occurred while decoding
- */
- public byte[] decodeBuffer(String inputString) throws IOException {
- byte inputBuffer[] = inputString.getBytes("ISO-8859-1");
- ByteArrayInputStream inStream = new ByteArrayInputStream(inputBuffer);
- ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- decodeBuffer(inStream, outStream);
- return outStream.toByteArray();
- }
-
- /**
- * Decode the contents of the inputstream into a buffer.
- */
- public byte[] decodeBuffer(InputStream in) throws IOException {
- ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- decodeBuffer(in, outStream);
- return outStream.toByteArray();
- }
-
- /**
- * Decode the contents of the String into a ByteBuffer.
- */
- public ByteBuffer decodeBufferToByteBuffer(String inputString)
- throws IOException {
- return ByteBuffer.wrap(decodeBuffer(inputString));
- }
-
- /**
- * Decode the contents of the inputStream into a ByteBuffer.
- */
- public ByteBuffer decodeBufferToByteBuffer(InputStream in)
- throws IOException {
- return ByteBuffer.wrap(decodeBuffer(in));
- }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/CharacterEncoder.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,354 +0,0 @@
-/*
- * Copyright (c) 1995, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.io.InputStream;
-import java.io.ByteArrayInputStream;
-import java.io.OutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-
-/**
- * This class defines the encoding half of character encoders.
- * A character encoder is an algorithim for transforming 8 bit binary
- * data into text (generally 7 bit ASCII or 8 bit ISO-Latin-1 text)
- * for transmition over text channels such as e-mail and network news.
- *
- * The character encoders have been structured around a central theme
- * that, in general, the encoded text has the form:
- *
- * <pre>
- * [Buffer Prefix]
- * [Line Prefix][encoded data atoms][Line Suffix]
- * [Buffer Suffix]
- * </pre>
- *
- * In the CharacterEncoder and CharacterDecoder classes, one complete
- * chunk of data is referred to as a <i>buffer</i>. Encoded buffers
- * are all text, and decoded buffers (sometimes just referred to as
- * buffers) are binary octets.
- *
- * To create a custom encoder, you must, at a minimum, overide three
- * abstract methods in this class.
- * <DL>
- * <DD>bytesPerAtom which tells the encoder how many bytes to
- * send to encodeAtom
- * <DD>encodeAtom which encodes the bytes sent to it as text.
- * <DD>bytesPerLine which tells the encoder the maximum number of
- * bytes per line.
- * </DL>
- *
- * Several useful encoders have already been written and are
- * referenced in the See Also list below.
- *
- * @author Chuck McManis
- * @see CharacterDecoder
- * @see UCEncoder
- * @see UUEncoder
- * @see BASE64Encoder
- */
-public abstract class CharacterEncoder {
-
- /** Stream that understands "printing" */
- protected PrintStream pStream;
-
- /** Return the number of bytes per atom of encoding */
- protected abstract int bytesPerAtom();
-
- /** Return the number of bytes that can be encoded per line */
- protected abstract int bytesPerLine();
-
- /**
- * Encode the prefix for the entire buffer. By default is simply
- * opens the PrintStream for use by the other functions.
- */
- protected void encodeBufferPrefix(OutputStream aStream) throws IOException {
- pStream = new PrintStream(aStream);
- }
-
- /**
- * Encode the suffix for the entire buffer.
- */
- protected void encodeBufferSuffix(OutputStream aStream) throws IOException {
- }
-
- /**
- * Encode the prefix that starts every output line.
- */
- protected void encodeLinePrefix(OutputStream aStream, int aLength)
- throws IOException {
- }
-
- /**
- * Encode the suffix that ends every output line. By default
- * this method just prints a newline into the output stream.
- */
- protected void encodeLineSuffix(OutputStream aStream) throws IOException {
- pStream.println();
- }
-
- /** Encode one "atom" of information into characters. */
- protected abstract void encodeAtom(OutputStream aStream, byte someBytes[],
- int anOffset, int aLength) throws IOException;
-
- /**
- * This method works around the bizarre semantics of BufferedInputStream's
- * read method.
- */
- protected int readFully(InputStream in, byte buffer[])
- throws java.io.IOException {
- for (int i = 0; i < buffer.length; i++) {
- int q = in.read();
- if (q == -1)
- return i;
- buffer[i] = (byte)q;
- }
- return buffer.length;
- }
-
- /**
- * Encode bytes from the input stream, and write them as text characters
- * to the output stream. This method will run until it exhausts the
- * input stream, but does not print the line suffix for a final
- * line that is shorter than bytesPerLine().
- */
- public void encode(InputStream inStream, OutputStream outStream)
- throws IOException {
- int j;
- int numBytes;
- byte tmpbuffer[] = new byte[bytesPerLine()];
-
- encodeBufferPrefix(outStream);
-
- while (true) {
- numBytes = readFully(inStream, tmpbuffer);
- if (numBytes == 0) {
- break;
- }
- encodeLinePrefix(outStream, numBytes);
- for (j = 0; j < numBytes; j += bytesPerAtom()) {
-
- if ((j + bytesPerAtom()) <= numBytes) {
- encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
- } else {
- encodeAtom(outStream, tmpbuffer, j, (numBytes)- j);
- }
- }
- if (numBytes < bytesPerLine()) {
- break;
- } else {
- encodeLineSuffix(outStream);
- }
- }
- encodeBufferSuffix(outStream);
- }
-
- /**
- * Encode the buffer in <i>aBuffer</i> and write the encoded
- * result to the OutputStream <i>aStream</i>.
- */
- public void encode(byte aBuffer[], OutputStream aStream)
- throws IOException {
- ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
- encode(inStream, aStream);
- }
-
- /**
- * A 'streamless' version of encode that simply takes a buffer of
- * bytes and returns a string containing the encoded buffer.
- */
- public String encode(byte aBuffer[]) {
- ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
- String retVal = null;
- try {
- encode(inStream, outStream);
- // explicit ascii->unicode conversion
- retVal = outStream.toString("ISO-8859-1");
- } catch (Exception IOException) {
- // This should never happen.
- throw new Error("CharacterEncoder.encode internal error");
- }
- return (retVal);
- }
-
- /**
- * Return a byte array from the remaining bytes in this ByteBuffer.
- * <P>
- * The ByteBuffer's position will be advanced to ByteBuffer's limit.
- * <P>
- * To avoid an extra copy, the implementation will attempt to return the
- * byte array backing the ByteBuffer. If this is not possible, a
- * new byte array will be created.
- */
- private byte [] getBytes(ByteBuffer bb) {
- /*
- * This should never return a BufferOverflowException, as we're
- * careful to allocate just the right amount.
- */
- byte [] buf = null;
-
- /*
- * If it has a usable backing byte buffer, use it. Use only
- * if the array exactly represents the current ByteBuffer.
- */
- if (bb.hasArray()) {
- byte [] tmp = bb.array();
- if ((tmp.length == bb.capacity()) &&
- (tmp.length == bb.remaining())) {
- buf = tmp;
- bb.position(bb.limit());
- }
- }
-
- if (buf == null) {
- /*
- * This class doesn't have a concept of encode(buf, len, off),
- * so if we have a partial buffer, we must reallocate
- * space.
- */
- buf = new byte[bb.remaining()];
-
- /*
- * position() automatically updated
- */
- bb.get(buf);
- }
-
- return buf;
- }
-
- /**
- * Encode the <i>aBuffer</i> ByteBuffer and write the encoded
- * result to the OutputStream <i>aStream</i>.
- * <P>
- * The ByteBuffer's position will be advanced to ByteBuffer's limit.
- */
- public void encode(ByteBuffer aBuffer, OutputStream aStream)
- throws IOException {
- byte [] buf = getBytes(aBuffer);
- encode(buf, aStream);
- }
-
- /**
- * A 'streamless' version of encode that simply takes a ByteBuffer
- * and returns a string containing the encoded buffer.
- * <P>
- * The ByteBuffer's position will be advanced to ByteBuffer's limit.
- */
- public String encode(ByteBuffer aBuffer) {
- byte [] buf = getBytes(aBuffer);
- return encode(buf);
- }
-
- /**
- * Encode bytes from the input stream, and write them as text characters
- * to the output stream. This method will run until it exhausts the
- * input stream. It differs from encode in that it will add the
- * line at the end of a final line that is shorter than bytesPerLine().
- */
- public void encodeBuffer(InputStream inStream, OutputStream outStream)
- throws IOException {
- int j;
- int numBytes;
- byte tmpbuffer[] = new byte[bytesPerLine()];
-
- encodeBufferPrefix(outStream);
-
- while (true) {
- numBytes = readFully(inStream, tmpbuffer);
- if (numBytes == 0) {
- break;
- }
- encodeLinePrefix(outStream, numBytes);
- for (j = 0; j < numBytes; j += bytesPerAtom()) {
- if ((j + bytesPerAtom()) <= numBytes) {
- encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
- } else {
- encodeAtom(outStream, tmpbuffer, j, (numBytes)- j);
- }
- }
- encodeLineSuffix(outStream);
- if (numBytes < bytesPerLine()) {
- break;
- }
- }
- encodeBufferSuffix(outStream);
- }
-
- /**
- * Encode the buffer in <i>aBuffer</i> and write the encoded
- * result to the OutputStream <i>aStream</i>.
- */
- public void encodeBuffer(byte aBuffer[], OutputStream aStream)
- throws IOException {
- ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
- encodeBuffer(inStream, aStream);
- }
-
- /**
- * A 'streamless' version of encode that simply takes a buffer of
- * bytes and returns a string containing the encoded buffer.
- */
- public String encodeBuffer(byte aBuffer[]) {
- ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
- try {
- encodeBuffer(inStream, outStream);
- } catch (Exception IOException) {
- // This should never happen.
- throw new Error("CharacterEncoder.encodeBuffer internal error");
- }
- return (outStream.toString());
- }
-
- /**
- * Encode the <i>aBuffer</i> ByteBuffer and write the encoded
- * result to the OutputStream <i>aStream</i>.
- * <P>
- * The ByteBuffer's position will be advanced to ByteBuffer's limit.
- */
- public void encodeBuffer(ByteBuffer aBuffer, OutputStream aStream)
- throws IOException {
- byte [] buf = getBytes(aBuffer);
- encodeBuffer(buf, aStream);
- }
-
- /**
- * A 'streamless' version of encode that simply takes a ByteBuffer
- * and returns a string containing the encoded buffer.
- * <P>
- * The ByteBuffer's position will be advanced to ByteBuffer's limit.
- */
- public String encodeBuffer(ByteBuffer aBuffer) {
- byte [] buf = getBytes(aBuffer);
- return encodeBuffer(buf);
- }
-
-}
--- a/jdk/src/java.base/share/classes/sun/misc/GC.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/misc/GC.java Wed Jul 05 21:09:54 2017 +0200
@@ -82,7 +82,7 @@
*/
public static native long maxObjectInspectionAge();
- private static class Daemon extends ManagedLocalsThread {
+ private static class Daemon extends Thread {
public void run() {
for (;;) {
@@ -122,7 +122,7 @@
}
private Daemon(ThreadGroup tg) {
- super(tg, "GC Daemon");
+ super(tg, null, "GC Daemon", 0L, false);
}
/* Create a new daemon thread in the root thread group */
--- a/jdk/src/java.base/share/classes/sun/misc/HexDumpEncoder.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) 1995, 1997, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.misc;
-import java.io.PrintStream;
-import java.io.OutputStream;
-import java.io.IOException;
-
-/**
- * This class encodes a buffer into the classic: "Hexadecimal Dump" format of
- * the past. It is useful for analyzing the contents of binary buffers.
- * The format produced is as follows:
- * <pre>
- * xxxx: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff ................
- * </pre>
- * Where xxxx is the offset into the buffer in 16 byte chunks, followed
- * by ascii coded hexadecimal bytes followed by the ASCII representation of
- * the bytes or '.' if they are not valid bytes.
- *
- * @author Chuck McManis
- */
-
-public class HexDumpEncoder extends CharacterEncoder {
-
- private int offset;
- private int thisLineLength;
- private int currentByte;
- private byte thisLine[] = new byte[16];
-
- static void hexDigit(PrintStream p, byte x) {
- char c;
-
- c = (char) ((x >> 4) & 0xf);
- if (c > 9)
- c = (char) ((c-10) + 'A');
- else
- c = (char)(c + '0');
- p.write(c);
- c = (char) (x & 0xf);
- if (c > 9)
- c = (char)((c-10) + 'A');
- else
- c = (char)(c + '0');
- p.write(c);
- }
-
- protected int bytesPerAtom() {
- return (1);
- }
-
- protected int bytesPerLine() {
- return (16);
- }
-
- protected void encodeBufferPrefix(OutputStream o) throws IOException {
- offset = 0;
- super.encodeBufferPrefix(o);
- }
-
- protected void encodeLinePrefix(OutputStream o, int len) throws IOException {
- hexDigit(pStream, (byte)((offset >>> 8) & 0xff));
- hexDigit(pStream, (byte)(offset & 0xff));
- pStream.print(": ");
- currentByte = 0;
- thisLineLength = len;
- }
-
- protected void encodeAtom(OutputStream o, byte buf[], int off, int len) throws IOException {
- thisLine[currentByte] = buf[off];
- hexDigit(pStream, buf[off]);
- pStream.print(" ");
- currentByte++;
- if (currentByte == 8)
- pStream.print(" ");
- }
-
- protected void encodeLineSuffix(OutputStream o) throws IOException {
- if (thisLineLength < 16) {
- for (int i = thisLineLength; i < 16; i++) {
- pStream.print(" ");
- if (i == 7)
- pStream.print(" ");
- }
- }
- pStream.print(" ");
- for (int i = 0; i < thisLineLength; i++) {
- if ((thisLine[i] < ' ') || (thisLine[i] > 'z')) {
- pStream.print(".");
- } else {
- pStream.write(thisLine[i]);
- }
- }
- pStream.println();
- offset += thisLineLength;
- }
-
-}
--- a/jdk/src/java.base/share/classes/sun/misc/InnocuousThread.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/misc/InnocuousThread.java Wed Jul 05 21:09:54 2017 +0200
@@ -35,8 +35,10 @@
* A thread that has no permissions, is not a member of any user-defined
* ThreadGroup and supports the ability to erase ThreadLocals.
*/
-public final class InnocuousThread extends ManagedLocalsThread {
+public final class InnocuousThread extends Thread {
private static final jdk.internal.misc.Unsafe UNSAFE;
+ private static final long THREAD_LOCALS;
+ private static final long INHERITABLE_THREAD_LOCALS;
private static final ThreadGroup INNOCUOUSTHREADGROUP;
private static final AccessControlContext ACC;
private static final long INHERITEDACCESSCONTROLCONTEXT;
@@ -54,7 +56,7 @@
}
public InnocuousThread(ThreadGroup group, Runnable target, String name) {
- super(group, target, name);
+ super(group, target, name, 0L, false);
UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC);
UNSAFE.putOrderedObject(this, CONTEXTCLASSLOADER, ClassLoader.getSystemClassLoader());
}
@@ -73,6 +75,14 @@
throw new SecurityException("setContextClassLoader");
}
+ /**
+ * Drops all thread locals (and inherited thread locals).
+ */
+ public final void eraseThreadLocals() {
+ UNSAFE.putObject(this, THREAD_LOCALS, null);
+ UNSAFE.putObject(this, INHERITABLE_THREAD_LOCALS, null);
+ }
+
// ensure run method is run only once
private volatile boolean hasRun;
@@ -96,6 +106,10 @@
Class<?> tk = Thread.class;
Class<?> gk = ThreadGroup.class;
+ THREAD_LOCALS = UNSAFE.objectFieldOffset
+ (tk.getDeclaredField("threadLocals"));
+ INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset
+ (tk.getDeclaredField("inheritableThreadLocals"));
INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset
(tk.getDeclaredField("inheritedAccessControlContext"));
CONTEXTCLASSLOADER = UNSAFE.objectFieldOffset
--- a/jdk/src/java.base/share/classes/sun/misc/ProxyGenerator.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2031 +0,0 @@
-/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.reflect.Array;
-import java.lang.reflect.Method;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import sun.security.action.GetBooleanAction;
-
-/**
- * ProxyGenerator contains the code to generate a dynamic proxy class
- * for the java.lang.reflect.Proxy API.
- *
- * The external interfaces to ProxyGenerator is the static
- * "generateProxyClass" method.
- *
- * @author Peter Jones
- * @since 1.3
- */
-public class ProxyGenerator {
- /*
- * In the comments below, "JVMS" refers to The Java Virtual Machine
- * Specification Second Edition and "JLS" refers to the original
- * version of The Java Language Specification, unless otherwise
- * specified.
- */
-
- /* generate 1.5-era class file version */
- private static final int CLASSFILE_MAJOR_VERSION = 49;
- private static final int CLASSFILE_MINOR_VERSION = 0;
-
- /*
- * beginning of constants copied from
- * sun.tools.java.RuntimeConstants (which no longer exists):
- */
-
- /* constant pool tags */
- private static final int CONSTANT_UTF8 = 1;
- private static final int CONSTANT_UNICODE = 2;
- private static final int CONSTANT_INTEGER = 3;
- private static final int CONSTANT_FLOAT = 4;
- private static final int CONSTANT_LONG = 5;
- private static final int CONSTANT_DOUBLE = 6;
- private static final int CONSTANT_CLASS = 7;
- private static final int CONSTANT_STRING = 8;
- private static final int CONSTANT_FIELD = 9;
- private static final int CONSTANT_METHOD = 10;
- private static final int CONSTANT_INTERFACEMETHOD = 11;
- private static final int CONSTANT_NAMEANDTYPE = 12;
-
- /* access and modifier flags */
- private static final int ACC_PUBLIC = 0x00000001;
- private static final int ACC_PRIVATE = 0x00000002;
-// private static final int ACC_PROTECTED = 0x00000004;
- private static final int ACC_STATIC = 0x00000008;
- private static final int ACC_FINAL = 0x00000010;
-// private static final int ACC_SYNCHRONIZED = 0x00000020;
-// private static final int ACC_VOLATILE = 0x00000040;
-// private static final int ACC_TRANSIENT = 0x00000080;
-// private static final int ACC_NATIVE = 0x00000100;
-// private static final int ACC_INTERFACE = 0x00000200;
-// private static final int ACC_ABSTRACT = 0x00000400;
- private static final int ACC_SUPER = 0x00000020;
-// private static final int ACC_STRICT = 0x00000800;
-
- /* opcodes */
-// private static final int opc_nop = 0;
- private static final int opc_aconst_null = 1;
-// private static final int opc_iconst_m1 = 2;
- private static final int opc_iconst_0 = 3;
-// private static final int opc_iconst_1 = 4;
-// private static final int opc_iconst_2 = 5;
-// private static final int opc_iconst_3 = 6;
-// private static final int opc_iconst_4 = 7;
-// private static final int opc_iconst_5 = 8;
-// private static final int opc_lconst_0 = 9;
-// private static final int opc_lconst_1 = 10;
-// private static final int opc_fconst_0 = 11;
-// private static final int opc_fconst_1 = 12;
-// private static final int opc_fconst_2 = 13;
-// private static final int opc_dconst_0 = 14;
-// private static final int opc_dconst_1 = 15;
- private static final int opc_bipush = 16;
- private static final int opc_sipush = 17;
- private static final int opc_ldc = 18;
- private static final int opc_ldc_w = 19;
-// private static final int opc_ldc2_w = 20;
- private static final int opc_iload = 21;
- private static final int opc_lload = 22;
- private static final int opc_fload = 23;
- private static final int opc_dload = 24;
- private static final int opc_aload = 25;
- private static final int opc_iload_0 = 26;
-// private static final int opc_iload_1 = 27;
-// private static final int opc_iload_2 = 28;
-// private static final int opc_iload_3 = 29;
- private static final int opc_lload_0 = 30;
-// private static final int opc_lload_1 = 31;
-// private static final int opc_lload_2 = 32;
-// private static final int opc_lload_3 = 33;
- private static final int opc_fload_0 = 34;
-// private static final int opc_fload_1 = 35;
-// private static final int opc_fload_2 = 36;
-// private static final int opc_fload_3 = 37;
- private static final int opc_dload_0 = 38;
-// private static final int opc_dload_1 = 39;
-// private static final int opc_dload_2 = 40;
-// private static final int opc_dload_3 = 41;
- private static final int opc_aload_0 = 42;
-// private static final int opc_aload_1 = 43;
-// private static final int opc_aload_2 = 44;
-// private static final int opc_aload_3 = 45;
-// private static final int opc_iaload = 46;
-// private static final int opc_laload = 47;
-// private static final int opc_faload = 48;
-// private static final int opc_daload = 49;
-// private static final int opc_aaload = 50;
-// private static final int opc_baload = 51;
-// private static final int opc_caload = 52;
-// private static final int opc_saload = 53;
-// private static final int opc_istore = 54;
-// private static final int opc_lstore = 55;
-// private static final int opc_fstore = 56;
-// private static final int opc_dstore = 57;
- private static final int opc_astore = 58;
-// private static final int opc_istore_0 = 59;
-// private static final int opc_istore_1 = 60;
-// private static final int opc_istore_2 = 61;
-// private static final int opc_istore_3 = 62;
-// private static final int opc_lstore_0 = 63;
-// private static final int opc_lstore_1 = 64;
-// private static final int opc_lstore_2 = 65;
-// private static final int opc_lstore_3 = 66;
-// private static final int opc_fstore_0 = 67;
-// private static final int opc_fstore_1 = 68;
-// private static final int opc_fstore_2 = 69;
-// private static final int opc_fstore_3 = 70;
-// private static final int opc_dstore_0 = 71;
-// private static final int opc_dstore_1 = 72;
-// private static final int opc_dstore_2 = 73;
-// private static final int opc_dstore_3 = 74;
- private static final int opc_astore_0 = 75;
-// private static final int opc_astore_1 = 76;
-// private static final int opc_astore_2 = 77;
-// private static final int opc_astore_3 = 78;
-// private static final int opc_iastore = 79;
-// private static final int opc_lastore = 80;
-// private static final int opc_fastore = 81;
-// private static final int opc_dastore = 82;
- private static final int opc_aastore = 83;
-// private static final int opc_bastore = 84;
-// private static final int opc_castore = 85;
-// private static final int opc_sastore = 86;
- private static final int opc_pop = 87;
-// private static final int opc_pop2 = 88;
- private static final int opc_dup = 89;
-// private static final int opc_dup_x1 = 90;
-// private static final int opc_dup_x2 = 91;
-// private static final int opc_dup2 = 92;
-// private static final int opc_dup2_x1 = 93;
-// private static final int opc_dup2_x2 = 94;
-// private static final int opc_swap = 95;
-// private static final int opc_iadd = 96;
-// private static final int opc_ladd = 97;
-// private static final int opc_fadd = 98;
-// private static final int opc_dadd = 99;
-// private static final int opc_isub = 100;
-// private static final int opc_lsub = 101;
-// private static final int opc_fsub = 102;
-// private static final int opc_dsub = 103;
-// private static final int opc_imul = 104;
-// private static final int opc_lmul = 105;
-// private static final int opc_fmul = 106;
-// private static final int opc_dmul = 107;
-// private static final int opc_idiv = 108;
-// private static final int opc_ldiv = 109;
-// private static final int opc_fdiv = 110;
-// private static final int opc_ddiv = 111;
-// private static final int opc_irem = 112;
-// private static final int opc_lrem = 113;
-// private static final int opc_frem = 114;
-// private static final int opc_drem = 115;
-// private static final int opc_ineg = 116;
-// private static final int opc_lneg = 117;
-// private static final int opc_fneg = 118;
-// private static final int opc_dneg = 119;
-// private static final int opc_ishl = 120;
-// private static final int opc_lshl = 121;
-// private static final int opc_ishr = 122;
-// private static final int opc_lshr = 123;
-// private static final int opc_iushr = 124;
-// private static final int opc_lushr = 125;
-// private static final int opc_iand = 126;
-// private static final int opc_land = 127;
-// private static final int opc_ior = 128;
-// private static final int opc_lor = 129;
-// private static final int opc_ixor = 130;
-// private static final int opc_lxor = 131;
-// private static final int opc_iinc = 132;
-// private static final int opc_i2l = 133;
-// private static final int opc_i2f = 134;
-// private static final int opc_i2d = 135;
-// private static final int opc_l2i = 136;
-// private static final int opc_l2f = 137;
-// private static final int opc_l2d = 138;
-// private static final int opc_f2i = 139;
-// private static final int opc_f2l = 140;
-// private static final int opc_f2d = 141;
-// private static final int opc_d2i = 142;
-// private static final int opc_d2l = 143;
-// private static final int opc_d2f = 144;
-// private static final int opc_i2b = 145;
-// private static final int opc_i2c = 146;
-// private static final int opc_i2s = 147;
-// private static final int opc_lcmp = 148;
-// private static final int opc_fcmpl = 149;
-// private static final int opc_fcmpg = 150;
-// private static final int opc_dcmpl = 151;
-// private static final int opc_dcmpg = 152;
-// private static final int opc_ifeq = 153;
-// private static final int opc_ifne = 154;
-// private static final int opc_iflt = 155;
-// private static final int opc_ifge = 156;
-// private static final int opc_ifgt = 157;
-// private static final int opc_ifle = 158;
-// private static final int opc_if_icmpeq = 159;
-// private static final int opc_if_icmpne = 160;
-// private static final int opc_if_icmplt = 161;
-// private static final int opc_if_icmpge = 162;
-// private static final int opc_if_icmpgt = 163;
-// private static final int opc_if_icmple = 164;
-// private static final int opc_if_acmpeq = 165;
-// private static final int opc_if_acmpne = 166;
-// private static final int opc_goto = 167;
-// private static final int opc_jsr = 168;
-// private static final int opc_ret = 169;
-// private static final int opc_tableswitch = 170;
-// private static final int opc_lookupswitch = 171;
- private static final int opc_ireturn = 172;
- private static final int opc_lreturn = 173;
- private static final int opc_freturn = 174;
- private static final int opc_dreturn = 175;
- private static final int opc_areturn = 176;
- private static final int opc_return = 177;
- private static final int opc_getstatic = 178;
- private static final int opc_putstatic = 179;
- private static final int opc_getfield = 180;
-// private static final int opc_putfield = 181;
- private static final int opc_invokevirtual = 182;
- private static final int opc_invokespecial = 183;
- private static final int opc_invokestatic = 184;
- private static final int opc_invokeinterface = 185;
- private static final int opc_new = 187;
-// private static final int opc_newarray = 188;
- private static final int opc_anewarray = 189;
-// private static final int opc_arraylength = 190;
- private static final int opc_athrow = 191;
- private static final int opc_checkcast = 192;
-// private static final int opc_instanceof = 193;
-// private static final int opc_monitorenter = 194;
-// private static final int opc_monitorexit = 195;
- private static final int opc_wide = 196;
-// private static final int opc_multianewarray = 197;
-// private static final int opc_ifnull = 198;
-// private static final int opc_ifnonnull = 199;
-// private static final int opc_goto_w = 200;
-// private static final int opc_jsr_w = 201;
-
- // end of constants copied from sun.tools.java.RuntimeConstants
-
- /** name of the superclass of proxy classes */
- private static final String superclassName = "java/lang/reflect/Proxy";
-
- /** name of field for storing a proxy instance's invocation handler */
- private static final String handlerFieldName = "h";
-
- /** debugging flag for saving generated class files */
- private static final boolean saveGeneratedFiles =
- java.security.AccessController.doPrivileged(
- new GetBooleanAction(
- "sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue();
-
- /**
- * Generate a public proxy class given a name and a list of proxy interfaces.
- */
- public static byte[] generateProxyClass(final String name,
- Class<?>[] interfaces) {
- return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER));
- }
-
- /**
- * Generate a proxy class given a name and a list of proxy interfaces.
- *
- * @param name the class name of the proxy class
- * @param interfaces proxy interfaces
- * @param accessFlags access flags of the proxy class
- */
- public static byte[] generateProxyClass(final String name,
- Class<?>[] interfaces,
- int accessFlags)
- {
- ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
- final byte[] classFile = gen.generateClassFile();
-
- if (saveGeneratedFiles) {
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<Void>() {
- public Void run() {
- try {
- int i = name.lastIndexOf('.');
- Path path;
- if (i > 0) {
- Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
- Files.createDirectories(dir);
- path = dir.resolve(name.substring(i+1, name.length()) + ".class");
- } else {
- path = Paths.get(name + ".class");
- }
- Files.write(path, classFile);
- return null;
- } catch (IOException e) {
- throw new InternalError(
- "I/O exception saving generated file: " + e);
- }
- }
- });
- }
-
- return classFile;
- }
-
- /* preloaded Method objects for methods in java.lang.Object */
- private static Method hashCodeMethod;
- private static Method equalsMethod;
- private static Method toStringMethod;
- static {
- try {
- hashCodeMethod = Object.class.getMethod("hashCode");
- equalsMethod =
- Object.class.getMethod("equals", new Class<?>[] { Object.class });
- toStringMethod = Object.class.getMethod("toString");
- } catch (NoSuchMethodException e) {
- throw new NoSuchMethodError(e.getMessage());
- }
- }
-
- /** name of proxy class */
- private String className;
-
- /** proxy interfaces */
- private Class<?>[] interfaces;
-
- /** proxy class access flags */
- private int accessFlags;
-
- /** constant pool of class being generated */
- private ConstantPool cp = new ConstantPool();
-
- /** FieldInfo struct for each field of generated class */
- private List<FieldInfo> fields = new ArrayList<>();
-
- /** MethodInfo struct for each method of generated class */
- private List<MethodInfo> methods = new ArrayList<>();
-
- /**
- * maps method signature string to list of ProxyMethod objects for
- * proxy methods with that signature
- */
- private Map<String, List<ProxyMethod>> proxyMethods = new HashMap<>();
-
- /** count of ProxyMethod objects added to proxyMethods */
- private int proxyMethodCount = 0;
-
- /**
- * Construct a ProxyGenerator to generate a proxy class with the
- * specified name and for the given interfaces.
- *
- * A ProxyGenerator object contains the state for the ongoing
- * generation of a particular proxy class.
- */
- private ProxyGenerator(String className, Class<?>[] interfaces, int accessFlags) {
- this.className = className;
- this.interfaces = interfaces;
- this.accessFlags = accessFlags;
- }
-
- /**
- * Generate a class file for the proxy class. This method drives the
- * class file generation process.
- */
- private byte[] generateClassFile() {
-
- /* ============================================================
- * Step 1: Assemble ProxyMethod objects for all methods to
- * generate proxy dispatching code for.
- */
-
- /*
- * Record that proxy methods are needed for the hashCode, equals,
- * and toString methods of java.lang.Object. This is done before
- * the methods from the proxy interfaces so that the methods from
- * java.lang.Object take precedence over duplicate methods in the
- * proxy interfaces.
- */
- addProxyMethod(hashCodeMethod, Object.class);
- addProxyMethod(equalsMethod, Object.class);
- addProxyMethod(toStringMethod, Object.class);
-
- /*
- * Now record all of the methods from the proxy interfaces, giving
- * earlier interfaces precedence over later ones with duplicate
- * methods.
- */
- for (Class<?> intf : interfaces) {
- for (Method m : intf.getMethods()) {
- addProxyMethod(m, intf);
- }
- }
-
- /*
- * For each set of proxy methods with the same signature,
- * verify that the methods' return types are compatible.
- */
- for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
- checkReturnTypes(sigmethods);
- }
-
- /* ============================================================
- * Step 2: Assemble FieldInfo and MethodInfo structs for all of
- * fields and methods in the class we are generating.
- */
- try {
- methods.add(generateConstructor());
-
- for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
- for (ProxyMethod pm : sigmethods) {
-
- // add static field for method's Method object
- fields.add(new FieldInfo(pm.methodFieldName,
- "Ljava/lang/reflect/Method;",
- ACC_PRIVATE | ACC_STATIC));
-
- // generate code for proxy method and add it
- methods.add(pm.generateMethod());
- }
- }
-
- methods.add(generateStaticInitializer());
-
- } catch (IOException e) {
- throw new InternalError("unexpected I/O Exception", e);
- }
-
- if (methods.size() > 65535) {
- throw new IllegalArgumentException("method limit exceeded");
- }
- if (fields.size() > 65535) {
- throw new IllegalArgumentException("field limit exceeded");
- }
-
- /* ============================================================
- * Step 3: Write the final class file.
- */
-
- /*
- * Make sure that constant pool indexes are reserved for the
- * following items before starting to write the final class file.
- */
- cp.getClass(dotToSlash(className));
- cp.getClass(superclassName);
- for (Class<?> intf: interfaces) {
- cp.getClass(dotToSlash(intf.getName()));
- }
-
- /*
- * Disallow new constant pool additions beyond this point, since
- * we are about to write the final constant pool table.
- */
- cp.setReadOnly();
-
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- DataOutputStream dout = new DataOutputStream(bout);
-
- try {
- /*
- * Write all the items of the "ClassFile" structure.
- * See JVMS section 4.1.
- */
- // u4 magic;
- dout.writeInt(0xCAFEBABE);
- // u2 minor_version;
- dout.writeShort(CLASSFILE_MINOR_VERSION);
- // u2 major_version;
- dout.writeShort(CLASSFILE_MAJOR_VERSION);
-
- cp.write(dout); // (write constant pool)
-
- // u2 access_flags;
- dout.writeShort(accessFlags);
- // u2 this_class;
- dout.writeShort(cp.getClass(dotToSlash(className)));
- // u2 super_class;
- dout.writeShort(cp.getClass(superclassName));
-
- // u2 interfaces_count;
- dout.writeShort(interfaces.length);
- // u2 interfaces[interfaces_count];
- for (Class<?> intf : interfaces) {
- dout.writeShort(cp.getClass(
- dotToSlash(intf.getName())));
- }
-
- // u2 fields_count;
- dout.writeShort(fields.size());
- // field_info fields[fields_count];
- for (FieldInfo f : fields) {
- f.write(dout);
- }
-
- // u2 methods_count;
- dout.writeShort(methods.size());
- // method_info methods[methods_count];
- for (MethodInfo m : methods) {
- m.write(dout);
- }
-
- // u2 attributes_count;
- dout.writeShort(0); // (no ClassFile attributes for proxy classes)
-
- } catch (IOException e) {
- throw new InternalError("unexpected I/O Exception", e);
- }
-
- return bout.toByteArray();
- }
-
- /**
- * Add another method to be proxied, either by creating a new
- * ProxyMethod object or augmenting an old one for a duplicate
- * method.
- *
- * "fromClass" indicates the proxy interface that the method was
- * found through, which may be different from (a subinterface of)
- * the method's "declaring class". Note that the first Method
- * object passed for a given name and descriptor identifies the
- * Method object (and thus the declaring class) that will be
- * passed to the invocation handler's "invoke" method for a given
- * set of duplicate methods.
- */
- private void addProxyMethod(Method m, Class<?> fromClass) {
- String name = m.getName();
- Class<?>[] parameterTypes = m.getParameterTypes();
- Class<?> returnType = m.getReturnType();
- Class<?>[] exceptionTypes = m.getExceptionTypes();
-
- String sig = name + getParameterDescriptors(parameterTypes);
- List<ProxyMethod> sigmethods = proxyMethods.get(sig);
- if (sigmethods != null) {
- for (ProxyMethod pm : sigmethods) {
- if (returnType == pm.returnType) {
- /*
- * Found a match: reduce exception types to the
- * greatest set of exceptions that can thrown
- * compatibly with the throws clauses of both
- * overridden methods.
- */
- List<Class<?>> legalExceptions = new ArrayList<>();
- collectCompatibleTypes(
- exceptionTypes, pm.exceptionTypes, legalExceptions);
- collectCompatibleTypes(
- pm.exceptionTypes, exceptionTypes, legalExceptions);
- pm.exceptionTypes = new Class<?>[legalExceptions.size()];
- pm.exceptionTypes =
- legalExceptions.toArray(pm.exceptionTypes);
- return;
- }
- }
- } else {
- sigmethods = new ArrayList<>(3);
- proxyMethods.put(sig, sigmethods);
- }
- sigmethods.add(new ProxyMethod(name, parameterTypes, returnType,
- exceptionTypes, fromClass));
- }
-
- /**
- * For a given set of proxy methods with the same signature, check
- * that their return types are compatible according to the Proxy
- * specification.
- *
- * Specifically, if there is more than one such method, then all
- * of the return types must be reference types, and there must be
- * one return type that is assignable to each of the rest of them.
- */
- private static void checkReturnTypes(List<ProxyMethod> methods) {
- /*
- * If there is only one method with a given signature, there
- * cannot be a conflict. This is the only case in which a
- * primitive (or void) return type is allowed.
- */
- if (methods.size() < 2) {
- return;
- }
-
- /*
- * List of return types that are not yet known to be
- * assignable from ("covered" by) any of the others.
- */
- LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<>();
-
- nextNewReturnType:
- for (ProxyMethod pm : methods) {
- Class<?> newReturnType = pm.returnType;
- if (newReturnType.isPrimitive()) {
- throw new IllegalArgumentException(
- "methods with same signature " +
- getFriendlyMethodSignature(pm.methodName,
- pm.parameterTypes) +
- " but incompatible return types: " +
- newReturnType.getName() + " and others");
- }
- boolean added = false;
-
- /*
- * Compare the new return type to the existing uncovered
- * return types.
- */
- ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator();
- while (liter.hasNext()) {
- Class<?> uncoveredReturnType = liter.next();
-
- /*
- * If an existing uncovered return type is assignable
- * to this new one, then we can forget the new one.
- */
- if (newReturnType.isAssignableFrom(uncoveredReturnType)) {
- assert !added;
- continue nextNewReturnType;
- }
-
- /*
- * If the new return type is assignable to an existing
- * uncovered one, then should replace the existing one
- * with the new one (or just forget the existing one,
- * if the new one has already be put in the list).
- */
- if (uncoveredReturnType.isAssignableFrom(newReturnType)) {
- // (we can assume that each return type is unique)
- if (!added) {
- liter.set(newReturnType);
- added = true;
- } else {
- liter.remove();
- }
- }
- }
-
- /*
- * If we got through the list of existing uncovered return
- * types without an assignability relationship, then add
- * the new return type to the list of uncovered ones.
- */
- if (!added) {
- uncoveredReturnTypes.add(newReturnType);
- }
- }
-
- /*
- * We shouldn't end up with more than one return type that is
- * not assignable from any of the others.
- */
- if (uncoveredReturnTypes.size() > 1) {
- ProxyMethod pm = methods.get(0);
- throw new IllegalArgumentException(
- "methods with same signature " +
- getFriendlyMethodSignature(pm.methodName, pm.parameterTypes) +
- " but incompatible return types: " + uncoveredReturnTypes);
- }
- }
-
- /**
- * A FieldInfo object contains information about a particular field
- * in the class being generated. The class mirrors the data items of
- * the "field_info" structure of the class file format (see JVMS 4.5).
- */
- private class FieldInfo {
- public int accessFlags;
- public String name;
- public String descriptor;
-
- public FieldInfo(String name, String descriptor, int accessFlags) {
- this.name = name;
- this.descriptor = descriptor;
- this.accessFlags = accessFlags;
-
- /*
- * Make sure that constant pool indexes are reserved for the
- * following items before starting to write the final class file.
- */
- cp.getUtf8(name);
- cp.getUtf8(descriptor);
- }
-
- public void write(DataOutputStream out) throws IOException {
- /*
- * Write all the items of the "field_info" structure.
- * See JVMS section 4.5.
- */
- // u2 access_flags;
- out.writeShort(accessFlags);
- // u2 name_index;
- out.writeShort(cp.getUtf8(name));
- // u2 descriptor_index;
- out.writeShort(cp.getUtf8(descriptor));
- // u2 attributes_count;
- out.writeShort(0); // (no field_info attributes for proxy classes)
- }
- }
-
- /**
- * An ExceptionTableEntry object holds values for the data items of
- * an entry in the "exception_table" item of the "Code" attribute of
- * "method_info" structures (see JVMS 4.7.3).
- */
- private static class ExceptionTableEntry {
- public short startPc;
- public short endPc;
- public short handlerPc;
- public short catchType;
-
- public ExceptionTableEntry(short startPc, short endPc,
- short handlerPc, short catchType)
- {
- this.startPc = startPc;
- this.endPc = endPc;
- this.handlerPc = handlerPc;
- this.catchType = catchType;
- }
- };
-
- /**
- * A MethodInfo object contains information about a particular method
- * in the class being generated. This class mirrors the data items of
- * the "method_info" structure of the class file format (see JVMS 4.6).
- */
- private class MethodInfo {
- public int accessFlags;
- public String name;
- public String descriptor;
- public short maxStack;
- public short maxLocals;
- public ByteArrayOutputStream code = new ByteArrayOutputStream();
- public List<ExceptionTableEntry> exceptionTable =
- new ArrayList<ExceptionTableEntry>();
- public short[] declaredExceptions;
-
- public MethodInfo(String name, String descriptor, int accessFlags) {
- this.name = name;
- this.descriptor = descriptor;
- this.accessFlags = accessFlags;
-
- /*
- * Make sure that constant pool indexes are reserved for the
- * following items before starting to write the final class file.
- */
- cp.getUtf8(name);
- cp.getUtf8(descriptor);
- cp.getUtf8("Code");
- cp.getUtf8("Exceptions");
- }
-
- public void write(DataOutputStream out) throws IOException {
- /*
- * Write all the items of the "method_info" structure.
- * See JVMS section 4.6.
- */
- // u2 access_flags;
- out.writeShort(accessFlags);
- // u2 name_index;
- out.writeShort(cp.getUtf8(name));
- // u2 descriptor_index;
- out.writeShort(cp.getUtf8(descriptor));
- // u2 attributes_count;
- out.writeShort(2); // (two method_info attributes:)
-
- // Write "Code" attribute. See JVMS section 4.7.3.
-
- // u2 attribute_name_index;
- out.writeShort(cp.getUtf8("Code"));
- // u4 attribute_length;
- out.writeInt(12 + code.size() + 8 * exceptionTable.size());
- // u2 max_stack;
- out.writeShort(maxStack);
- // u2 max_locals;
- out.writeShort(maxLocals);
- // u2 code_length;
- out.writeInt(code.size());
- // u1 code[code_length];
- code.writeTo(out);
- // u2 exception_table_length;
- out.writeShort(exceptionTable.size());
- for (ExceptionTableEntry e : exceptionTable) {
- // u2 start_pc;
- out.writeShort(e.startPc);
- // u2 end_pc;
- out.writeShort(e.endPc);
- // u2 handler_pc;
- out.writeShort(e.handlerPc);
- // u2 catch_type;
- out.writeShort(e.catchType);
- }
- // u2 attributes_count;
- out.writeShort(0);
-
- // write "Exceptions" attribute. See JVMS section 4.7.4.
-
- // u2 attribute_name_index;
- out.writeShort(cp.getUtf8("Exceptions"));
- // u4 attributes_length;
- out.writeInt(2 + 2 * declaredExceptions.length);
- // u2 number_of_exceptions;
- out.writeShort(declaredExceptions.length);
- // u2 exception_index_table[number_of_exceptions];
- for (short value : declaredExceptions) {
- out.writeShort(value);
- }
- }
-
- }
-
- /**
- * A ProxyMethod object represents a proxy method in the proxy class
- * being generated: a method whose implementation will encode and
- * dispatch invocations to the proxy instance's invocation handler.
- */
- private class ProxyMethod {
-
- public String methodName;
- public Class<?>[] parameterTypes;
- public Class<?> returnType;
- public Class<?>[] exceptionTypes;
- public Class<?> fromClass;
- public String methodFieldName;
-
- private ProxyMethod(String methodName, Class<?>[] parameterTypes,
- Class<?> returnType, Class<?>[] exceptionTypes,
- Class<?> fromClass)
- {
- this.methodName = methodName;
- this.parameterTypes = parameterTypes;
- this.returnType = returnType;
- this.exceptionTypes = exceptionTypes;
- this.fromClass = fromClass;
- this.methodFieldName = "m" + proxyMethodCount++;
- }
-
- /**
- * Return a MethodInfo object for this method, including generating
- * the code and exception table entry.
- */
- private MethodInfo generateMethod() throws IOException {
- String desc = getMethodDescriptor(parameterTypes, returnType);
- MethodInfo minfo = new MethodInfo(methodName, desc,
- ACC_PUBLIC | ACC_FINAL);
-
- int[] parameterSlot = new int[parameterTypes.length];
- int nextSlot = 1;
- for (int i = 0; i < parameterSlot.length; i++) {
- parameterSlot[i] = nextSlot;
- nextSlot += getWordsPerType(parameterTypes[i]);
- }
- int localSlot0 = nextSlot;
- short pc, tryBegin = 0, tryEnd;
-
- DataOutputStream out = new DataOutputStream(minfo.code);
-
- code_aload(0, out);
-
- out.writeByte(opc_getfield);
- out.writeShort(cp.getFieldRef(
- superclassName,
- handlerFieldName, "Ljava/lang/reflect/InvocationHandler;"));
-
- code_aload(0, out);
-
- out.writeByte(opc_getstatic);
- out.writeShort(cp.getFieldRef(
- dotToSlash(className),
- methodFieldName, "Ljava/lang/reflect/Method;"));
-
- if (parameterTypes.length > 0) {
-
- code_ipush(parameterTypes.length, out);
-
- out.writeByte(opc_anewarray);
- out.writeShort(cp.getClass("java/lang/Object"));
-
- for (int i = 0; i < parameterTypes.length; i++) {
-
- out.writeByte(opc_dup);
-
- code_ipush(i, out);
-
- codeWrapArgument(parameterTypes[i], parameterSlot[i], out);
-
- out.writeByte(opc_aastore);
- }
- } else {
-
- out.writeByte(opc_aconst_null);
- }
-
- out.writeByte(opc_invokeinterface);
- out.writeShort(cp.getInterfaceMethodRef(
- "java/lang/reflect/InvocationHandler",
- "invoke",
- "(Ljava/lang/Object;Ljava/lang/reflect/Method;" +
- "[Ljava/lang/Object;)Ljava/lang/Object;"));
- out.writeByte(4);
- out.writeByte(0);
-
- if (returnType == void.class) {
-
- out.writeByte(opc_pop);
-
- out.writeByte(opc_return);
-
- } else {
-
- codeUnwrapReturnValue(returnType, out);
- }
-
- tryEnd = pc = (short) minfo.code.size();
-
- List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes);
- if (catchList.size() > 0) {
-
- for (Class<?> ex : catchList) {
- minfo.exceptionTable.add(new ExceptionTableEntry(
- tryBegin, tryEnd, pc,
- cp.getClass(dotToSlash(ex.getName()))));
- }
-
- out.writeByte(opc_athrow);
-
- pc = (short) minfo.code.size();
-
- minfo.exceptionTable.add(new ExceptionTableEntry(
- tryBegin, tryEnd, pc, cp.getClass("java/lang/Throwable")));
-
- code_astore(localSlot0, out);
-
- out.writeByte(opc_new);
- out.writeShort(cp.getClass(
- "java/lang/reflect/UndeclaredThrowableException"));
-
- out.writeByte(opc_dup);
-
- code_aload(localSlot0, out);
-
- out.writeByte(opc_invokespecial);
-
- out.writeShort(cp.getMethodRef(
- "java/lang/reflect/UndeclaredThrowableException",
- "<init>", "(Ljava/lang/Throwable;)V"));
-
- out.writeByte(opc_athrow);
- }
-
- if (minfo.code.size() > 65535) {
- throw new IllegalArgumentException("code size limit exceeded");
- }
-
- minfo.maxStack = 10;
- minfo.maxLocals = (short) (localSlot0 + 1);
- minfo.declaredExceptions = new short[exceptionTypes.length];
- for (int i = 0; i < exceptionTypes.length; i++) {
- minfo.declaredExceptions[i] = cp.getClass(
- dotToSlash(exceptionTypes[i].getName()));
- }
-
- return minfo;
- }
-
- /**
- * Generate code for wrapping an argument of the given type
- * whose value can be found at the specified local variable
- * index, in order for it to be passed (as an Object) to the
- * invocation handler's "invoke" method. The code is written
- * to the supplied stream.
- */
- private void codeWrapArgument(Class<?> type, int slot,
- DataOutputStream out)
- throws IOException
- {
- if (type.isPrimitive()) {
- PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
-
- if (type == int.class ||
- type == boolean.class ||
- type == byte.class ||
- type == char.class ||
- type == short.class)
- {
- code_iload(slot, out);
- } else if (type == long.class) {
- code_lload(slot, out);
- } else if (type == float.class) {
- code_fload(slot, out);
- } else if (type == double.class) {
- code_dload(slot, out);
- } else {
- throw new AssertionError();
- }
-
- out.writeByte(opc_invokestatic);
- out.writeShort(cp.getMethodRef(
- prim.wrapperClassName,
- "valueOf", prim.wrapperValueOfDesc));
-
- } else {
-
- code_aload(slot, out);
- }
- }
-
- /**
- * Generate code for unwrapping a return value of the given
- * type from the invocation handler's "invoke" method (as type
- * Object) to its correct type. The code is written to the
- * supplied stream.
- */
- private void codeUnwrapReturnValue(Class<?> type, DataOutputStream out)
- throws IOException
- {
- if (type.isPrimitive()) {
- PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
-
- out.writeByte(opc_checkcast);
- out.writeShort(cp.getClass(prim.wrapperClassName));
-
- out.writeByte(opc_invokevirtual);
- out.writeShort(cp.getMethodRef(
- prim.wrapperClassName,
- prim.unwrapMethodName, prim.unwrapMethodDesc));
-
- if (type == int.class ||
- type == boolean.class ||
- type == byte.class ||
- type == char.class ||
- type == short.class)
- {
- out.writeByte(opc_ireturn);
- } else if (type == long.class) {
- out.writeByte(opc_lreturn);
- } else if (type == float.class) {
- out.writeByte(opc_freturn);
- } else if (type == double.class) {
- out.writeByte(opc_dreturn);
- } else {
- throw new AssertionError();
- }
-
- } else {
-
- out.writeByte(opc_checkcast);
- out.writeShort(cp.getClass(dotToSlash(type.getName())));
-
- out.writeByte(opc_areturn);
- }
- }
-
- /**
- * Generate code for initializing the static field that stores
- * the Method object for this proxy method. The code is written
- * to the supplied stream.
- */
- private void codeFieldInitialization(DataOutputStream out)
- throws IOException
- {
- codeClassForName(fromClass, out);
-
- code_ldc(cp.getString(methodName), out);
-
- code_ipush(parameterTypes.length, out);
-
- out.writeByte(opc_anewarray);
- out.writeShort(cp.getClass("java/lang/Class"));
-
- for (int i = 0; i < parameterTypes.length; i++) {
-
- out.writeByte(opc_dup);
-
- code_ipush(i, out);
-
- if (parameterTypes[i].isPrimitive()) {
- PrimitiveTypeInfo prim =
- PrimitiveTypeInfo.get(parameterTypes[i]);
-
- out.writeByte(opc_getstatic);
- out.writeShort(cp.getFieldRef(
- prim.wrapperClassName, "TYPE", "Ljava/lang/Class;"));
-
- } else {
- codeClassForName(parameterTypes[i], out);
- }
-
- out.writeByte(opc_aastore);
- }
-
- out.writeByte(opc_invokevirtual);
- out.writeShort(cp.getMethodRef(
- "java/lang/Class",
- "getMethod",
- "(Ljava/lang/String;[Ljava/lang/Class;)" +
- "Ljava/lang/reflect/Method;"));
-
- out.writeByte(opc_putstatic);
- out.writeShort(cp.getFieldRef(
- dotToSlash(className),
- methodFieldName, "Ljava/lang/reflect/Method;"));
- }
- }
-
- /**
- * Generate the constructor method for the proxy class.
- */
- private MethodInfo generateConstructor() throws IOException {
- MethodInfo minfo = new MethodInfo(
- "<init>", "(Ljava/lang/reflect/InvocationHandler;)V",
- ACC_PUBLIC);
-
- DataOutputStream out = new DataOutputStream(minfo.code);
-
- code_aload(0, out);
-
- code_aload(1, out);
-
- out.writeByte(opc_invokespecial);
- out.writeShort(cp.getMethodRef(
- superclassName,
- "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
-
- out.writeByte(opc_return);
-
- minfo.maxStack = 10;
- minfo.maxLocals = 2;
- minfo.declaredExceptions = new short[0];
-
- return minfo;
- }
-
- /**
- * Generate the static initializer method for the proxy class.
- */
- private MethodInfo generateStaticInitializer() throws IOException {
- MethodInfo minfo = new MethodInfo(
- "<clinit>", "()V", ACC_STATIC);
-
- int localSlot0 = 1;
- short pc, tryBegin = 0, tryEnd;
-
- DataOutputStream out = new DataOutputStream(minfo.code);
-
- for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
- for (ProxyMethod pm : sigmethods) {
- pm.codeFieldInitialization(out);
- }
- }
-
- out.writeByte(opc_return);
-
- tryEnd = pc = (short) minfo.code.size();
-
- minfo.exceptionTable.add(new ExceptionTableEntry(
- tryBegin, tryEnd, pc,
- cp.getClass("java/lang/NoSuchMethodException")));
-
- code_astore(localSlot0, out);
-
- out.writeByte(opc_new);
- out.writeShort(cp.getClass("java/lang/NoSuchMethodError"));
-
- out.writeByte(opc_dup);
-
- code_aload(localSlot0, out);
-
- out.writeByte(opc_invokevirtual);
- out.writeShort(cp.getMethodRef(
- "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
-
- out.writeByte(opc_invokespecial);
- out.writeShort(cp.getMethodRef(
- "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V"));
-
- out.writeByte(opc_athrow);
-
- pc = (short) minfo.code.size();
-
- minfo.exceptionTable.add(new ExceptionTableEntry(
- tryBegin, tryEnd, pc,
- cp.getClass("java/lang/ClassNotFoundException")));
-
- code_astore(localSlot0, out);
-
- out.writeByte(opc_new);
- out.writeShort(cp.getClass("java/lang/NoClassDefFoundError"));
-
- out.writeByte(opc_dup);
-
- code_aload(localSlot0, out);
-
- out.writeByte(opc_invokevirtual);
- out.writeShort(cp.getMethodRef(
- "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
-
- out.writeByte(opc_invokespecial);
- out.writeShort(cp.getMethodRef(
- "java/lang/NoClassDefFoundError",
- "<init>", "(Ljava/lang/String;)V"));
-
- out.writeByte(opc_athrow);
-
- if (minfo.code.size() > 65535) {
- throw new IllegalArgumentException("code size limit exceeded");
- }
-
- minfo.maxStack = 10;
- minfo.maxLocals = (short) (localSlot0 + 1);
- minfo.declaredExceptions = new short[0];
-
- return minfo;
- }
-
-
- /*
- * =============== Code Generation Utility Methods ===============
- */
-
- /*
- * The following methods generate code for the load or store operation
- * indicated by their name for the given local variable. The code is
- * written to the supplied stream.
- */
-
- private void code_iload(int lvar, DataOutputStream out)
- throws IOException
- {
- codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out);
- }
-
- private void code_lload(int lvar, DataOutputStream out)
- throws IOException
- {
- codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out);
- }
-
- private void code_fload(int lvar, DataOutputStream out)
- throws IOException
- {
- codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out);
- }
-
- private void code_dload(int lvar, DataOutputStream out)
- throws IOException
- {
- codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out);
- }
-
- private void code_aload(int lvar, DataOutputStream out)
- throws IOException
- {
- codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out);
- }
-
-// private void code_istore(int lvar, DataOutputStream out)
-// throws IOException
-// {
-// codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out);
-// }
-
-// private void code_lstore(int lvar, DataOutputStream out)
-// throws IOException
-// {
-// codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out);
-// }
-
-// private void code_fstore(int lvar, DataOutputStream out)
-// throws IOException
-// {
-// codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out);
-// }
-
-// private void code_dstore(int lvar, DataOutputStream out)
-// throws IOException
-// {
-// codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out);
-// }
-
- private void code_astore(int lvar, DataOutputStream out)
- throws IOException
- {
- codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out);
- }
-
- /**
- * Generate code for a load or store instruction for the given local
- * variable. The code is written to the supplied stream.
- *
- * "opcode" indicates the opcode form of the desired load or store
- * instruction that takes an explicit local variable index, and
- * "opcode_0" indicates the corresponding form of the instruction
- * with the implicit index 0.
- */
- private void codeLocalLoadStore(int lvar, int opcode, int opcode_0,
- DataOutputStream out)
- throws IOException
- {
- assert lvar >= 0 && lvar <= 0xFFFF;
- if (lvar <= 3) {
- out.writeByte(opcode_0 + lvar);
- } else if (lvar <= 0xFF) {
- out.writeByte(opcode);
- out.writeByte(lvar & 0xFF);
- } else {
- /*
- * Use the "wide" instruction modifier for local variable
- * indexes that do not fit into an unsigned byte.
- */
- out.writeByte(opc_wide);
- out.writeByte(opcode);
- out.writeShort(lvar & 0xFFFF);
- }
- }
-
- /**
- * Generate code for an "ldc" instruction for the given constant pool
- * index (the "ldc_w" instruction is used if the index does not fit
- * into an unsigned byte). The code is written to the supplied stream.
- */
- private void code_ldc(int index, DataOutputStream out)
- throws IOException
- {
- assert index >= 0 && index <= 0xFFFF;
- if (index <= 0xFF) {
- out.writeByte(opc_ldc);
- out.writeByte(index & 0xFF);
- } else {
- out.writeByte(opc_ldc_w);
- out.writeShort(index & 0xFFFF);
- }
- }
-
- /**
- * Generate code to push a constant integer value on to the operand
- * stack, using the "iconst_<i>", "bipush", or "sipush" instructions
- * depending on the size of the value. The code is written to the
- * supplied stream.
- */
- private void code_ipush(int value, DataOutputStream out)
- throws IOException
- {
- if (value >= -1 && value <= 5) {
- out.writeByte(opc_iconst_0 + value);
- } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
- out.writeByte(opc_bipush);
- out.writeByte(value & 0xFF);
- } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
- out.writeByte(opc_sipush);
- out.writeShort(value & 0xFFFF);
- } else {
- throw new AssertionError();
- }
- }
-
- /**
- * Generate code to invoke the Class.forName with the name of the given
- * class to get its Class object at runtime. The code is written to
- * the supplied stream. Note that the code generated by this method
- * may caused the checked ClassNotFoundException to be thrown.
- */
- private void codeClassForName(Class<?> cl, DataOutputStream out)
- throws IOException
- {
- code_ldc(cp.getString(cl.getName()), out);
-
- out.writeByte(opc_invokestatic);
- out.writeShort(cp.getMethodRef(
- "java/lang/Class",
- "forName", "(Ljava/lang/String;)Ljava/lang/Class;"));
- }
-
-
- /*
- * ==================== General Utility Methods ====================
- */
-
- /**
- * Convert a fully qualified class name that uses '.' as the package
- * separator, the external representation used by the Java language
- * and APIs, to a fully qualified class name that uses '/' as the
- * package separator, the representation used in the class file
- * format (see JVMS section 4.2).
- */
- private static String dotToSlash(String name) {
- return name.replace('.', '/');
- }
-
- /**
- * Return the "method descriptor" string for a method with the given
- * parameter types and return type. See JVMS section 4.3.3.
- */
- private static String getMethodDescriptor(Class<?>[] parameterTypes,
- Class<?> returnType)
- {
- return getParameterDescriptors(parameterTypes) +
- ((returnType == void.class) ? "V" : getFieldType(returnType));
- }
-
- /**
- * Return the list of "parameter descriptor" strings enclosed in
- * parentheses corresponding to the given parameter types (in other
- * words, a method descriptor without a return descriptor). This
- * string is useful for constructing string keys for methods without
- * regard to their return type.
- */
- private static String getParameterDescriptors(Class<?>[] parameterTypes) {
- StringBuilder desc = new StringBuilder("(");
- for (int i = 0; i < parameterTypes.length; i++) {
- desc.append(getFieldType(parameterTypes[i]));
- }
- desc.append(')');
- return desc.toString();
- }
-
- /**
- * Return the "field type" string for the given type, appropriate for
- * a field descriptor, a parameter descriptor, or a return descriptor
- * other than "void". See JVMS section 4.3.2.
- */
- private static String getFieldType(Class<?> type) {
- if (type.isPrimitive()) {
- return PrimitiveTypeInfo.get(type).baseTypeString;
- } else if (type.isArray()) {
- /*
- * According to JLS 20.3.2, the getName() method on Class does
- * return the VM type descriptor format for array classes (only);
- * using that should be quicker than the otherwise obvious code:
- *
- * return "[" + getTypeDescriptor(type.getComponentType());
- */
- return type.getName().replace('.', '/');
- } else {
- return "L" + dotToSlash(type.getName()) + ";";
- }
- }
-
- /**
- * Returns a human-readable string representing the signature of a
- * method with the given name and parameter types.
- */
- private static String getFriendlyMethodSignature(String name,
- Class<?>[] parameterTypes)
- {
- StringBuilder sig = new StringBuilder(name);
- sig.append('(');
- for (int i = 0; i < parameterTypes.length; i++) {
- if (i > 0) {
- sig.append(',');
- }
- Class<?> parameterType = parameterTypes[i];
- int dimensions = 0;
- while (parameterType.isArray()) {
- parameterType = parameterType.getComponentType();
- dimensions++;
- }
- sig.append(parameterType.getName());
- while (dimensions-- > 0) {
- sig.append("[]");
- }
- }
- sig.append(')');
- return sig.toString();
- }
-
- /**
- * Return the number of abstract "words", or consecutive local variable
- * indexes, required to contain a value of the given type. See JVMS
- * section 3.6.1.
- *
- * Note that the original version of the JVMS contained a definition of
- * this abstract notion of a "word" in section 3.4, but that definition
- * was removed for the second edition.
- */
- private static int getWordsPerType(Class<?> type) {
- if (type == long.class || type == double.class) {
- return 2;
- } else {
- return 1;
- }
- }
-
- /**
- * Add to the given list all of the types in the "from" array that
- * are not already contained in the list and are assignable to at
- * least one of the types in the "with" array.
- *
- * This method is useful for computing the greatest common set of
- * declared exceptions from duplicate methods inherited from
- * different interfaces.
- */
- private static void collectCompatibleTypes(Class<?>[] from,
- Class<?>[] with,
- List<Class<?>> list)
- {
- for (Class<?> fc: from) {
- if (!list.contains(fc)) {
- for (Class<?> wc: with) {
- if (wc.isAssignableFrom(fc)) {
- list.add(fc);
- break;
- }
- }
- }
- }
- }
-
- /**
- * Given the exceptions declared in the throws clause of a proxy method,
- * compute the exceptions that need to be caught from the invocation
- * handler's invoke method and rethrown intact in the method's
- * implementation before catching other Throwables and wrapping them
- * in UndeclaredThrowableExceptions.
- *
- * The exceptions to be caught are returned in a List object. Each
- * exception in the returned list is guaranteed to not be a subclass of
- * any of the other exceptions in the list, so the catch blocks for
- * these exceptions may be generated in any order relative to each other.
- *
- * Error and RuntimeException are each always contained by the returned
- * list (if none of their superclasses are contained), since those
- * unchecked exceptions should always be rethrown intact, and thus their
- * subclasses will never appear in the returned list.
- *
- * The returned List will be empty if java.lang.Throwable is in the
- * given list of declared exceptions, indicating that no exceptions
- * need to be caught.
- */
- private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) {
- List<Class<?>> uniqueList = new ArrayList<>();
- // unique exceptions to catch
-
- uniqueList.add(Error.class); // always catch/rethrow these
- uniqueList.add(RuntimeException.class);
-
- nextException:
- for (Class<?> ex: exceptions) {
- if (ex.isAssignableFrom(Throwable.class)) {
- /*
- * If Throwable is declared to be thrown by the proxy method,
- * then no catch blocks are necessary, because the invoke
- * can, at most, throw Throwable anyway.
- */
- uniqueList.clear();
- break;
- } else if (!Throwable.class.isAssignableFrom(ex)) {
- /*
- * Ignore types that cannot be thrown by the invoke method.
- */
- continue;
- }
- /*
- * Compare this exception against the current list of
- * exceptions that need to be caught:
- */
- for (int j = 0; j < uniqueList.size();) {
- Class<?> ex2 = uniqueList.get(j);
- if (ex2.isAssignableFrom(ex)) {
- /*
- * if a superclass of this exception is already on
- * the list to catch, then ignore this one and continue;
- */
- continue nextException;
- } else if (ex.isAssignableFrom(ex2)) {
- /*
- * if a subclass of this exception is on the list
- * to catch, then remove it;
- */
- uniqueList.remove(j);
- } else {
- j++; // else continue comparing.
- }
- }
- // This exception is unique (so far): add it to the list to catch.
- uniqueList.add(ex);
- }
- return uniqueList;
- }
-
- /**
- * A PrimitiveTypeInfo object contains assorted information about
- * a primitive type in its public fields. The struct for a particular
- * primitive type can be obtained using the static "get" method.
- */
- private static class PrimitiveTypeInfo {
-
- /** "base type" used in various descriptors (see JVMS section 4.3.2) */
- public String baseTypeString;
-
- /** name of corresponding wrapper class */
- public String wrapperClassName;
-
- /** method descriptor for wrapper class "valueOf" factory method */
- public String wrapperValueOfDesc;
-
- /** name of wrapper class method for retrieving primitive value */
- public String unwrapMethodName;
-
- /** descriptor of same method */
- public String unwrapMethodDesc;
-
- private static Map<Class<?>,PrimitiveTypeInfo> table = new HashMap<>();
- static {
- add(byte.class, Byte.class);
- add(char.class, Character.class);
- add(double.class, Double.class);
- add(float.class, Float.class);
- add(int.class, Integer.class);
- add(long.class, Long.class);
- add(short.class, Short.class);
- add(boolean.class, Boolean.class);
- }
-
- private static void add(Class<?> primitiveClass, Class<?> wrapperClass) {
- table.put(primitiveClass,
- new PrimitiveTypeInfo(primitiveClass, wrapperClass));
- }
-
- private PrimitiveTypeInfo(Class<?> primitiveClass, Class<?> wrapperClass) {
- assert primitiveClass.isPrimitive();
-
- baseTypeString =
- Array.newInstance(primitiveClass, 0)
- .getClass().getName().substring(1);
- wrapperClassName = dotToSlash(wrapperClass.getName());
- wrapperValueOfDesc =
- "(" + baseTypeString + ")L" + wrapperClassName + ";";
- unwrapMethodName = primitiveClass.getName() + "Value";
- unwrapMethodDesc = "()" + baseTypeString;
- }
-
- public static PrimitiveTypeInfo get(Class<?> cl) {
- return table.get(cl);
- }
- }
-
-
- /**
- * A ConstantPool object represents the constant pool of a class file
- * being generated. This representation of a constant pool is designed
- * specifically for use by ProxyGenerator; in particular, it assumes
- * that constant pool entries will not need to be resorted (for example,
- * by their type, as the Java compiler does), so that the final index
- * value can be assigned and used when an entry is first created.
- *
- * Note that new entries cannot be created after the constant pool has
- * been written to a class file. To prevent such logic errors, a
- * ConstantPool instance can be marked "read only", so that further
- * attempts to add new entries will fail with a runtime exception.
- *
- * See JVMS section 4.4 for more information about the constant pool
- * of a class file.
- */
- private static class ConstantPool {
-
- /**
- * list of constant pool entries, in constant pool index order.
- *
- * This list is used when writing the constant pool to a stream
- * and for assigning the next index value. Note that element 0
- * of this list corresponds to constant pool index 1.
- */
- private List<Entry> pool = new ArrayList<>(32);
-
- /**
- * maps constant pool data of all types to constant pool indexes.
- *
- * This map is used to look up the index of an existing entry for
- * values of all types.
- */
- private Map<Object,Short> map = new HashMap<>(16);
-
- /** true if no new constant pool entries may be added */
- private boolean readOnly = false;
-
- /**
- * Get or assign the index for a CONSTANT_Utf8 entry.
- */
- public short getUtf8(String s) {
- if (s == null) {
- throw new NullPointerException();
- }
- return getValue(s);
- }
-
- /**
- * Get or assign the index for a CONSTANT_Integer entry.
- */
- public short getInteger(int i) {
- return getValue(i);
- }
-
- /**
- * Get or assign the index for a CONSTANT_Float entry.
- */
- public short getFloat(float f) {
- return getValue(new Float(f));
- }
-
- /**
- * Get or assign the index for a CONSTANT_Class entry.
- */
- public short getClass(String name) {
- short utf8Index = getUtf8(name);
- return getIndirect(new IndirectEntry(
- CONSTANT_CLASS, utf8Index));
- }
-
- /**
- * Get or assign the index for a CONSTANT_String entry.
- */
- public short getString(String s) {
- short utf8Index = getUtf8(s);
- return getIndirect(new IndirectEntry(
- CONSTANT_STRING, utf8Index));
- }
-
- /**
- * Get or assign the index for a CONSTANT_FieldRef entry.
- */
- public short getFieldRef(String className,
- String name, String descriptor)
- {
- short classIndex = getClass(className);
- short nameAndTypeIndex = getNameAndType(name, descriptor);
- return getIndirect(new IndirectEntry(
- CONSTANT_FIELD, classIndex, nameAndTypeIndex));
- }
-
- /**
- * Get or assign the index for a CONSTANT_MethodRef entry.
- */
- public short getMethodRef(String className,
- String name, String descriptor)
- {
- short classIndex = getClass(className);
- short nameAndTypeIndex = getNameAndType(name, descriptor);
- return getIndirect(new IndirectEntry(
- CONSTANT_METHOD, classIndex, nameAndTypeIndex));
- }
-
- /**
- * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
- */
- public short getInterfaceMethodRef(String className, String name,
- String descriptor)
- {
- short classIndex = getClass(className);
- short nameAndTypeIndex = getNameAndType(name, descriptor);
- return getIndirect(new IndirectEntry(
- CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));
- }
-
- /**
- * Get or assign the index for a CONSTANT_NameAndType entry.
- */
- public short getNameAndType(String name, String descriptor) {
- short nameIndex = getUtf8(name);
- short descriptorIndex = getUtf8(descriptor);
- return getIndirect(new IndirectEntry(
- CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));
- }
-
- /**
- * Set this ConstantPool instance to be "read only".
- *
- * After this method has been called, further requests to get
- * an index for a non-existent entry will cause an InternalError
- * to be thrown instead of creating of the entry.
- */
- public void setReadOnly() {
- readOnly = true;
- }
-
- /**
- * Write this constant pool to a stream as part of
- * the class file format.
- *
- * This consists of writing the "constant_pool_count" and
- * "constant_pool[]" items of the "ClassFile" structure, as
- * described in JVMS section 4.1.
- */
- public void write(OutputStream out) throws IOException {
- DataOutputStream dataOut = new DataOutputStream(out);
-
- // constant_pool_count: number of entries plus one
- dataOut.writeShort(pool.size() + 1);
-
- for (Entry e : pool) {
- e.write(dataOut);
- }
- }
-
- /**
- * Add a new constant pool entry and return its index.
- */
- private short addEntry(Entry entry) {
- pool.add(entry);
- /*
- * Note that this way of determining the index of the
- * added entry is wrong if this pool supports
- * CONSTANT_Long or CONSTANT_Double entries.
- */
- if (pool.size() >= 65535) {
- throw new IllegalArgumentException(
- "constant pool size limit exceeded");
- }
- return (short) pool.size();
- }
-
- /**
- * Get or assign the index for an entry of a type that contains
- * a direct value. The type of the given object determines the
- * type of the desired entry as follows:
- *
- * java.lang.String CONSTANT_Utf8
- * java.lang.Integer CONSTANT_Integer
- * java.lang.Float CONSTANT_Float
- * java.lang.Long CONSTANT_Long
- * java.lang.Double CONSTANT_DOUBLE
- */
- private short getValue(Object key) {
- Short index = map.get(key);
- if (index != null) {
- return index.shortValue();
- } else {
- if (readOnly) {
- throw new InternalError(
- "late constant pool addition: " + key);
- }
- short i = addEntry(new ValueEntry(key));
- map.put(key, i);
- return i;
- }
- }
-
- /**
- * Get or assign the index for an entry of a type that contains
- * references to other constant pool entries.
- */
- private short getIndirect(IndirectEntry e) {
- Short index = map.get(e);
- if (index != null) {
- return index.shortValue();
- } else {
- if (readOnly) {
- throw new InternalError("late constant pool addition");
- }
- short i = addEntry(e);
- map.put(e, i);
- return i;
- }
- }
-
- /**
- * Entry is the abstact superclass of all constant pool entry types
- * that can be stored in the "pool" list; its purpose is to define a
- * common method for writing constant pool entries to a class file.
- */
- private abstract static class Entry {
- public abstract void write(DataOutputStream out)
- throws IOException;
- }
-
- /**
- * ValueEntry represents a constant pool entry of a type that
- * contains a direct value (see the comments for the "getValue"
- * method for a list of such types).
- *
- * ValueEntry objects are not used as keys for their entries in the
- * Map "map", so no useful hashCode or equals methods are defined.
- */
- private static class ValueEntry extends Entry {
- private Object value;
-
- public ValueEntry(Object value) {
- this.value = value;
- }
-
- public void write(DataOutputStream out) throws IOException {
- if (value instanceof String) {
- out.writeByte(CONSTANT_UTF8);
- out.writeUTF((String) value);
- } else if (value instanceof Integer) {
- out.writeByte(CONSTANT_INTEGER);
- out.writeInt(((Integer) value).intValue());
- } else if (value instanceof Float) {
- out.writeByte(CONSTANT_FLOAT);
- out.writeFloat(((Float) value).floatValue());
- } else if (value instanceof Long) {
- out.writeByte(CONSTANT_LONG);
- out.writeLong(((Long) value).longValue());
- } else if (value instanceof Double) {
- out.writeDouble(CONSTANT_DOUBLE);
- out.writeDouble(((Double) value).doubleValue());
- } else {
- throw new InternalError("bogus value entry: " + value);
- }
- }
- }
-
- /**
- * IndirectEntry represents a constant pool entry of a type that
- * references other constant pool entries, i.e., the following types:
- *
- * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
- * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
- * CONSTANT_NameAndType.
- *
- * Each of these entry types contains either one or two indexes of
- * other constant pool entries.
- *
- * IndirectEntry objects are used as the keys for their entries in
- * the Map "map", so the hashCode and equals methods are overridden
- * to allow matching.
- */
- private static class IndirectEntry extends Entry {
- private int tag;
- private short index0;
- private short index1;
-
- /**
- * Construct an IndirectEntry for a constant pool entry type
- * that contains one index of another entry.
- */
- public IndirectEntry(int tag, short index) {
- this.tag = tag;
- this.index0 = index;
- this.index1 = 0;
- }
-
- /**
- * Construct an IndirectEntry for a constant pool entry type
- * that contains two indexes for other entries.
- */
- public IndirectEntry(int tag, short index0, short index1) {
- this.tag = tag;
- this.index0 = index0;
- this.index1 = index1;
- }
-
- public void write(DataOutputStream out) throws IOException {
- out.writeByte(tag);
- out.writeShort(index0);
- /*
- * If this entry type contains two indexes, write
- * out the second, too.
- */
- if (tag == CONSTANT_FIELD ||
- tag == CONSTANT_METHOD ||
- tag == CONSTANT_INTERFACEMETHOD ||
- tag == CONSTANT_NAMEANDTYPE)
- {
- out.writeShort(index1);
- }
- }
-
- public int hashCode() {
- return tag + index0 + index1;
- }
-
- public boolean equals(Object obj) {
- if (obj instanceof IndirectEntry) {
- IndirectEntry other = (IndirectEntry) obj;
- if (tag == other.tag &&
- index0 == other.index0 && index1 == other.index1)
- {
- return true;
- }
- }
- return false;
- }
- }
- }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/Queue.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,214 +0,0 @@
-/*
- * Copyright (c) 1996, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.util.Enumeration;
-import java.util.NoSuchElementException;
-
-/**
- * Queue: implements a simple queue mechanism. Allows for enumeration of the
- * elements.
- *
- * @author Herb Jellinek
- */
-
-public class Queue<T> {
-
- int length = 0;
-
- QueueElement<T> head = null;
- QueueElement<T> tail = null;
-
- public Queue() {
- }
-
- /**
- * Enqueue an object.
- */
- public synchronized void enqueue(T obj) {
-
- QueueElement<T> newElt = new QueueElement<>(obj);
-
- if (head == null) {
- head = newElt;
- tail = newElt;
- length = 1;
- } else {
- newElt.next = head;
- head.prev = newElt;
- head = newElt;
- length++;
- }
- notify();
- }
-
- /**
- * Dequeue the oldest object on the queue. Will wait indefinitely.
- *
- * @return the oldest object on the queue.
- * @exception java.lang.InterruptedException if any thread has
- * interrupted this thread.
- */
- public T dequeue() throws InterruptedException {
- return dequeue(0L);
- }
-
- /**
- * Dequeue the oldest object on the queue.
- * @param timeOut the number of milliseconds to wait for something
- * to arrive.
- *
- * @return the oldest object on the queue.
- * @exception java.lang.InterruptedException if any thread has
- * interrupted this thread.
- */
- public synchronized T dequeue(long timeOut)
- throws InterruptedException {
-
- while (tail == null) {
- wait(timeOut);
- }
- QueueElement<T> elt = tail;
- tail = elt.prev;
- if (tail == null) {
- head = null;
- } else {
- tail.next = null;
- }
- length--;
- return elt.obj;
- }
-
- /**
- * Is the queue empty?
- * @return true if the queue is empty.
- */
- public synchronized boolean isEmpty() {
- return (tail == null);
- }
-
- /**
- * Returns an enumeration of the elements in Last-In, First-Out
- * order. Use the Enumeration methods on the returned object to
- * fetch the elements sequentially.
- */
- public final synchronized Enumeration<T> elements() {
- return new LIFOQueueEnumerator<>(this);
- }
-
- /**
- * Returns an enumeration of the elements in First-In, First-Out
- * order. Use the Enumeration methods on the returned object to
- * fetch the elements sequentially.
- */
- public final synchronized Enumeration<T> reverseElements() {
- return new FIFOQueueEnumerator<>(this);
- }
-
- public synchronized void dump(String msg) {
- System.err.println(">> "+msg);
- System.err.println("["+length+" elt(s); head = "+
- (head == null ? "null" : (head.obj)+"")+
- " tail = "+(tail == null ? "null" : (tail.obj)+""));
- QueueElement<T> cursor = head;
- QueueElement<T> last = null;
- while (cursor != null) {
- System.err.println(" "+cursor);
- last = cursor;
- cursor = cursor.next;
- }
- if (last != tail) {
- System.err.println(" tail != last: "+tail+", "+last);
- }
- System.err.println("]");
- }
-}
-
-final class FIFOQueueEnumerator<T> implements Enumeration<T> {
- Queue<T> queue;
- QueueElement<T> cursor;
-
- FIFOQueueEnumerator(Queue<T> q) {
- queue = q;
- cursor = q.tail;
- }
-
- public boolean hasMoreElements() {
- return (cursor != null);
- }
-
- public T nextElement() {
- synchronized (queue) {
- if (cursor != null) {
- QueueElement<T> result = cursor;
- cursor = cursor.prev;
- return result.obj;
- }
- }
- throw new NoSuchElementException("FIFOQueueEnumerator");
- }
-}
-
-final class LIFOQueueEnumerator<T> implements Enumeration<T> {
- Queue<T> queue;
- QueueElement<T> cursor;
-
- LIFOQueueEnumerator(Queue<T> q) {
- queue = q;
- cursor = q.head;
- }
-
- public boolean hasMoreElements() {
- return (cursor != null);
- }
-
- public T nextElement() {
- synchronized (queue) {
- if (cursor != null) {
- QueueElement<T> result = cursor;
- cursor = cursor.next;
- return result.obj;
- }
- }
- throw new NoSuchElementException("LIFOQueueEnumerator");
- }
-}
-
-class QueueElement<T> {
- QueueElement<T> next = null;
- QueueElement<T> prev = null;
-
- T obj = null;
-
- QueueElement(T obj) {
- this.obj = obj;
- }
-
- public String toString() {
- return "QueueElement[obj="+obj+(prev == null ? " null" : " prev")+
- (next == null ? " null" : " next")+"]";
- }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/Request.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-/**
- * Requests are functor objects; that is, they provide part of the mechanism
- * for deferred function application.
- *
- * @author Steven B. Byrne
- */
-
-public abstract class Request {
- /**
- * The main task of the Request object is to be exectuted from a request
- * queue.
- */
- public abstract void execute();
-}
--- a/jdk/src/java.base/share/classes/sun/misc/RequestProcessor.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 1996, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-/**
- * The request processor allows functors (Request instances) to be created
- * in arbitrary threads, and to be posted for execution in a non-restricted
- * thread.
- *
- * @author Steven B. Byrne
- */
-
-
-public class RequestProcessor implements Runnable {
-
- private static Queue<Request> requestQueue;
- private static Thread dispatcher;
-
- /**
- * Queues a Request instance for execution by the request procesor
- * thread.
- */
- public static void postRequest(Request req) {
- lazyInitialize();
- requestQueue.enqueue(req);
- }
-
- /**
- * Process requests as they are queued.
- */
- public void run() {
- lazyInitialize();
- while (true) {
- try {
- Request req = requestQueue.dequeue();
- try {
- req.execute();
- } catch (Throwable t) {
- // do nothing at the moment...maybe report an error
- // in the future
- }
- } catch (InterruptedException e) {
- // do nothing at the present time.
- }
- }
- }
-
-
- /**
- * This method initiates the request processor thread. It is safe
- * to call it after the thread has been started. It provides a way for
- * clients to deliberately control the context in which the request
- * processor thread is created
- */
- public static synchronized void startProcessing() {
- if (dispatcher == null) {
- dispatcher = new ManagedLocalsThread(new RequestProcessor(), "Request Processor");
- dispatcher.setPriority(Thread.NORM_PRIORITY + 2);
- dispatcher.start();
- }
- }
-
-
- /**
- * This method performs lazy initialization.
- */
- private static synchronized void lazyInitialize() {
- if (requestQueue == null) {
- requestQueue = new Queue<Request>();
- }
- }
-
-}
--- a/jdk/src/java.base/share/classes/sun/misc/Signal.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/misc/Signal.java Wed Jul 05 21:09:54 2017 +0200
@@ -213,7 +213,7 @@
}
};
if (handler != null) {
- new ManagedLocalsThread(runnable, sig + " handler").start();
+ new Thread(null, runnable, sig + " handler", 0, false).start();
}
}
--- a/jdk/src/java.base/share/classes/sun/misc/UCDecoder.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +0,0 @@
-/*
- * Copyright (c) 1995, 2000, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.misc;
-
-import java.io.OutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.PushbackInputStream;
-import java.io.PrintStream;
-import java.io.IOException;
-
-/**
- * This class implements a robust character decoder. The decoder will
- * converted encoded text into binary data.
- *
- * The basic encoding unit is a 3 character atom. It encodes two bytes
- * of data. Bytes are encoded into a 64 character set, the characters
- * were chosen specifically because they appear in all codesets.
- * We don't care what their numerical equivalent is because
- * we use a character array to map them. This is like UUencoding
- * with the dependency on ASCII removed.
- *
- * The three chars that make up an atom are encoded as follows:
- * <pre>
- * 00xxxyyy 00axxxxx 00byyyyy
- * 00 = leading zeros, all values are 0 - 63
- * xxxyyy - Top 3 bits of X, Top 3 bits of Y
- * axxxxx - a = X parity bit, xxxxx lower 5 bits of X
- * byyyyy - b = Y parity bit, yyyyy lower 5 bits of Y
- * </pre>
- *
- * The atoms are arranged into lines suitable for inclusion into an
- * email message or text file. The number of bytes that are encoded
- * per line is 48 which keeps the total line length under 80 chars)
- *
- * Each line has the form(
- * <pre>
- * *(LLSS)(DDDD)(DDDD)(DDDD)...(CRC)
- * Where each (xxx) represents a three character atom.
- * (LLSS) - 8 bit length (high byte), and sequence number
- * modulo 256;
- * (DDDD) - Data byte atoms, if length is odd, last data
- * atom has (DD00) (high byte data, low byte 0)
- * (CRC) - 16 bit CRC for the line, includes length,
- * sequence, and all data bytes. If there is a
- * zero pad byte (odd length) it is _NOT_
- * included in the CRC.
- * </pre>
- *
- * If an error is encountered during decoding this class throws a
- * CEFormatException. The specific detail messages are:
- *
- * <pre>
- * "UCDecoder: High byte parity error."
- * "UCDecoder: Low byte parity error."
- * "UCDecoder: Out of sequence line."
- * "UCDecoder: CRC check failed."
- * </pre>
- *
- * @author Chuck McManis
- * @see CharacterEncoder
- * @see UCEncoder
- */
-public class UCDecoder extends CharacterDecoder {
-
- /** This class encodes two bytes per atom. */
- protected int bytesPerAtom() {
- return (2);
- }
-
- /** this class encodes 48 bytes per line */
- protected int bytesPerLine() {
- return (48);
- }
-
- /* this is the UCE mapping of 0-63 to characters .. */
- private static final byte map_array[] = {
- // 0 1 2 3 4 5 6 7
- (byte)'0',(byte)'1',(byte)'2',(byte)'3',(byte)'4',(byte)'5',(byte)'6',(byte)'7', // 0
- (byte)'8',(byte)'9',(byte)'A',(byte)'B',(byte)'C',(byte)'D',(byte)'E',(byte)'F', // 1
- (byte)'G',(byte)'H',(byte)'I',(byte)'J',(byte)'K',(byte)'L',(byte)'M',(byte)'N', // 2
- (byte)'O',(byte)'P',(byte)'Q',(byte)'R',(byte)'S',(byte)'T',(byte)'U',(byte)'V', // 3
- (byte)'W',(byte)'X',(byte)'Y',(byte)'Z',(byte)'a',(byte)'b',(byte)'c',(byte)'d', // 4
- (byte)'e',(byte)'f',(byte)'g',(byte)'h',(byte)'i',(byte)'j',(byte)'k',(byte)'l', // 5
- (byte)'m',(byte)'n',(byte)'o',(byte)'p',(byte)'q',(byte)'r',(byte)'s',(byte)'t', // 6
- (byte)'u',(byte)'v',(byte)'w',(byte)'x',(byte)'y',(byte)'z',(byte)'(',(byte)')' // 7
- };
-
- private int sequence;
- private byte tmp[] = new byte[2];
- private CRC16 crc = new CRC16();
-
- /**
- * Decode one atom - reads the characters from the input stream, decodes
- * them, and checks for valid parity.
- */
- protected void decodeAtom(PushbackInputStream inStream, OutputStream outStream, int l) throws IOException {
- int i, p1, p2, np1, np2;
- byte a = -1, b = -1, c = -1;
- byte high_byte, low_byte;
- byte tmp[] = new byte[3];
-
- i = inStream.read(tmp);
- if (i != 3) {
- throw new CEStreamExhausted();
- }
- for (i = 0; (i < 64) && ((a == -1) || (b == -1) || (c == -1)); i++) {
- if (tmp[0] == map_array[i]) {
- a = (byte) i;
- }
- if (tmp[1] == map_array[i]) {
- b = (byte) i;
- }
- if (tmp[2] == map_array[i]) {
- c = (byte) i;
- }
- }
- high_byte = (byte) (((a & 0x38) << 2) + (b & 0x1f));
- low_byte = (byte) (((a & 0x7) << 5) + (c & 0x1f));
- p1 = 0;
- p2 = 0;
- for (i = 1; i < 256; i = i * 2) {
- if ((high_byte & i) != 0)
- p1++;
- if ((low_byte & i) != 0)
- p2++;
- }
- np1 = (b & 32) / 32;
- np2 = (c & 32) / 32;
- if ((p1 & 1) != np1) {
- throw new CEFormatException("UCDecoder: High byte parity error.");
- }
- if ((p2 & 1) != np2) {
- throw new CEFormatException("UCDecoder: Low byte parity error.");
- }
- outStream.write(high_byte);
- crc.update(high_byte);
- if (l == 2) {
- outStream.write(low_byte);
- crc.update(low_byte);
- }
- }
-
- private ByteArrayOutputStream lineAndSeq = new ByteArrayOutputStream(2);
-
- /**
- * decodeBufferPrefix initializes the sequence number to zero.
- */
- protected void decodeBufferPrefix(PushbackInputStream inStream, OutputStream outStream) {
- sequence = 0;
- }
-
- /**
- * decodeLinePrefix reads the sequence number and the number of
- * encoded bytes from the line. If the sequence number is not the
- * previous sequence number + 1 then an exception is thrown.
- * UCE lines are line terminator immune, they all start with *
- * so the other thing this method does is scan for the next line
- * by looking for the * character.
- *
- * @exception CEFormatException out of sequence lines detected.
- */
- protected int decodeLinePrefix(PushbackInputStream inStream, OutputStream outStream) throws IOException {
- int i;
- int nLen, nSeq;
- byte xtmp[];
- int c;
-
- crc.value = 0;
- while (true) {
- c = inStream.read(tmp, 0, 1);
- if (c == -1) {
- throw new CEStreamExhausted();
- }
- if (tmp[0] == '*') {
- break;
- }
- }
- lineAndSeq.reset();
- decodeAtom(inStream, lineAndSeq, 2);
- xtmp = lineAndSeq.toByteArray();
- nLen = xtmp[0] & 0xff;
- nSeq = xtmp[1] & 0xff;
- if (nSeq != sequence) {
- throw new CEFormatException("UCDecoder: Out of sequence line.");
- }
- sequence = (sequence + 1) & 0xff;
- return (nLen);
- }
-
-
- /**
- * this method reads the CRC that is at the end of every line and
- * verifies that it matches the computed CRC.
- *
- * @exception CEFormatException if CRC check fails.
- */
- protected void decodeLineSuffix(PushbackInputStream inStream, OutputStream outStream) throws IOException {
- int i;
- int lineCRC = crc.value;
- int readCRC;
- byte tmp[];
-
- lineAndSeq.reset();
- decodeAtom(inStream, lineAndSeq, 2);
- tmp = lineAndSeq.toByteArray();
- readCRC = ((tmp[0] << 8) & 0xFF00) + (tmp[1] & 0xff);
- if (readCRC != lineCRC) {
- throw new CEFormatException("UCDecoder: CRC check failed.");
- }
- }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/UCEncoder.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 1995, 1997, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.misc;
-
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.io.IOException;
-
-/**
- * This class implements a robust character encoder. The encoder is designed
- * to convert binary data into printable characters. The characters are
- * assumed to exist but they are not assumed to be ASCII, the complete set
- * is 0-9, A-Z, a-z, "(", and ")".
- *
- * The basic encoding unit is a 3 character atom. It encodes two bytes
- * of data. Bytes are encoded into a 64 character set, the characters
- * were chosen specifically because they appear in all codesets.
- * We don't care what their numerical equivalent is because
- * we use a character array to map them. This is like UUencoding
- * with the dependency on ASCII removed.
- *
- * The three chars that make up an atom are encoded as follows:
- * <pre>
- * 00xxxyyy 00axxxxx 00byyyyy
- * 00 = leading zeros, all values are 0 - 63
- * xxxyyy - Top 3 bits of X, Top 3 bits of Y
- * axxxxx - a = X parity bit, xxxxx lower 5 bits of X
- * byyyyy - b = Y parity bit, yyyyy lower 5 bits of Y
- * </pre>
- *
- * The atoms are arranged into lines suitable for inclusion into an
- * email message or text file. The number of bytes that are encoded
- * per line is 48 which keeps the total line length under 80 chars)
- *
- * Each line has the form(
- * <pre>
- * *(LLSS)(DDDD)(DDDD)(DDDD)...(CRC)
- * Where each (xxx) represents a three character atom.
- * (LLSS) - 8 bit length (high byte), and sequence number
- * modulo 256;
- * (DDDD) - Data byte atoms, if length is odd, last data
- * atom has (DD00) (high byte data, low byte 0)
- * (CRC) - 16 bit CRC for the line, includes length,
- * sequence, and all data bytes. If there is a
- * zero pad byte (odd length) it is _NOT_
- * included in the CRC.
- * </pre>
- *
- * @author Chuck McManis
- * @see CharacterEncoder
- * @see UCDecoder
- */
-public class UCEncoder extends CharacterEncoder {
-
- /** this clase encodes two bytes per atom */
- protected int bytesPerAtom() {
- return (2);
- }
-
- /** this class encodes 48 bytes per line */
- protected int bytesPerLine() {
- return (48);
- }
-
- /* this is the UCE mapping of 0-63 to characters .. */
- private static final byte map_array[] = {
- // 0 1 2 3 4 5 6 7
- (byte)'0',(byte)'1',(byte)'2',(byte)'3',(byte)'4',(byte)'5',(byte)'6',(byte)'7', // 0
- (byte)'8',(byte)'9',(byte)'A',(byte)'B',(byte)'C',(byte)'D',(byte)'E',(byte)'F', // 1
- (byte)'G',(byte)'H',(byte)'I',(byte)'J',(byte)'K',(byte)'L',(byte)'M',(byte)'N', // 2
- (byte)'O',(byte)'P',(byte)'Q',(byte)'R',(byte)'S',(byte)'T',(byte)'U',(byte)'V', // 3
- (byte)'W',(byte)'X',(byte)'Y',(byte)'Z',(byte)'a',(byte)'b',(byte)'c',(byte)'d', // 4
- (byte)'e',(byte)'f',(byte)'g',(byte)'h',(byte)'i',(byte)'j',(byte)'k',(byte)'l', // 5
- (byte)'m',(byte)'n',(byte)'o',(byte)'p',(byte)'q',(byte)'r',(byte)'s',(byte)'t', // 6
- (byte)'u',(byte)'v',(byte)'w',(byte)'x',(byte)'y',(byte)'z',(byte)'(',(byte)')' // 7
- };
-
- private int sequence;
- private byte tmp[] = new byte[2];
- private CRC16 crc = new CRC16();
-
- /**
- * encodeAtom - take two bytes and encode them into the correct
- * three characters. If only one byte is to be encoded, the other
- * must be zero. The padding byte is not included in the CRC computation.
- */
- protected void encodeAtom(OutputStream outStream, byte data[], int offset, int len) throws IOException
- {
- int i;
- int p1, p2; // parity bits
- byte a, b;
-
- a = data[offset];
- if (len == 2) {
- b = data[offset+1];
- } else {
- b = 0;
- }
- crc.update(a);
- if (len == 2) {
- crc.update(b);
- }
- outStream.write(map_array[((a >>> 2) & 0x38) + ((b >>> 5) & 0x7)]);
- p1 = 0; p2 = 0;
- for (i = 1; i < 256; i = i * 2) {
- if ((a & i) != 0) {
- p1++;
- }
- if ((b & i) != 0) {
- p2++;
- }
- }
- p1 = (p1 & 1) * 32;
- p2 = (p2 & 1) * 32;
- outStream.write(map_array[(a & 31) + p1]);
- outStream.write(map_array[(b & 31) + p2]);
- return;
- }
-
- /**
- * Each UCE encoded line starts with a prefix of '*[XXX]', where
- * the sequence number and the length are encoded in the first
- * atom.
- */
- protected void encodeLinePrefix(OutputStream outStream, int length) throws IOException {
- outStream.write('*');
- crc.value = 0;
- tmp[0] = (byte) length;
- tmp[1] = (byte) sequence;
- sequence = (sequence + 1) & 0xff;
- encodeAtom(outStream, tmp, 0, 2);
- }
-
-
- /**
- * each UCE encoded line ends with YYY and encoded version of the
- * 16 bit checksum. The most significant byte of the check sum
- * is always encoded FIRST.
- */
- protected void encodeLineSuffix(OutputStream outStream) throws IOException {
- tmp[0] = (byte) ((crc.value >>> 8) & 0xff);
- tmp[1] = (byte) (crc.value & 0xff);
- encodeAtom(outStream, tmp, 0, 2);
- super.pStream.println();
- }
-
- /**
- * The buffer prefix code is used to initialize the sequence number
- * to zero.
- */
- protected void encodeBufferPrefix(OutputStream a) throws IOException {
- sequence = 0;
- super.encodeBufferPrefix(a);
- }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/UUDecoder.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,274 +0,0 @@
-/*
- * Copyright (c) 1995, 2001, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.misc;
-
-import java.io.PushbackInputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.IOException;
-
-/**
- * This class implements a Berkeley uu character decoder. This decoder
- * was made famous by the uudecode program.
- *
- * The basic character coding is algorithmic, taking 6 bits of binary
- * data and adding it to an ASCII ' ' (space) character. This converts
- * these six bits into a printable representation. Note that it depends
- * on the ASCII character encoding standard for english. Groups of three
- * bytes are converted into 4 characters by treating the three bytes
- * a four 6 bit groups, group 1 is byte 1's most significant six bits,
- * group 2 is byte 1's least significant two bits plus byte 2's four
- * most significant bits. etc.
- *
- * In this encoding, the buffer prefix is:
- * <pre>
- * begin [mode] [filename]
- * </pre>
- *
- * This is followed by one or more lines of the form:
- * <pre>
- * (len)(data)(data)(data) ...
- * </pre>
- * where (len) is the number of bytes on this line. Note that groupings
- * are always four characters, even if length is not a multiple of three
- * bytes. When less than three characters are encoded, the values of the
- * last remaining bytes is undefined and should be ignored.
- *
- * The last line of data in a uuencoded buffer is represented by a single
- * space character. This is translated by the decoding engine to a line
- * length of zero. This is immediately followed by a line which contains
- * the word 'end[newline]'
- *
- * If an error is encountered during decoding this class throws a
- * CEFormatException. The specific detail messages are:
- *
- * <pre>
- * "UUDecoder: No begin line."
- * "UUDecoder: Malformed begin line."
- * "UUDecoder: Short Buffer."
- * "UUDecoder: Bad Line Length."
- * "UUDecoder: Missing 'end' line."
- * </pre>
- *
- * @author Chuck McManis
- * @see CharacterDecoder
- * @see UUEncoder
- */
-public class UUDecoder extends CharacterDecoder {
-
- /**
- * This string contains the name that was in the buffer being decoded.
- */
- public String bufferName;
-
- /**
- * Represents UNIX(tm) mode bits. Generally three octal digits
- * representing read, write, and execute permission of the owner,
- * group owner, and others. They should be interpreted as the bit groups:
- * <pre>
- * (owner) (group) (others)
- * rwx rwx rwx (r = read, w = write, x = execute)
- *</pre>
- *
- */
- public int mode;
-
-
- /**
- * UU encoding specifies 3 bytes per atom.
- */
- protected int bytesPerAtom() {
- return (3);
- }
-
- /**
- * All UU lines have 45 bytes on them, for line length of 15*4+1 or 61
- * characters per line.
- */
- protected int bytesPerLine() {
- return (45);
- }
-
- /** This is used to decode the atoms */
- private byte decoderBuffer[] = new byte[4];
-
- /**
- * Decode a UU atom. Note that if l is less than 3 we don't write
- * the extra bits, however the encoder always encodes 4 character
- * groups even when they are not needed.
- */
- protected void decodeAtom(PushbackInputStream inStream, OutputStream outStream, int l)
- throws IOException {
- int i, c1, c2, c3, c4;
- int a, b, c;
- StringBuilder x = new StringBuilder();
-
- for (i = 0; i < 4; i++) {
- c1 = inStream.read();
- if (c1 == -1) {
- throw new CEStreamExhausted();
- }
- x.append((char)c1);
- decoderBuffer[i] = (byte) ((c1 - ' ') & 0x3f);
- }
- a = ((decoderBuffer[0] << 2) & 0xfc) | ((decoderBuffer[1] >>> 4) & 3);
- b = ((decoderBuffer[1] << 4) & 0xf0) | ((decoderBuffer[2] >>> 2) & 0xf);
- c = ((decoderBuffer[2] << 6) & 0xc0) | (decoderBuffer[3] & 0x3f);
- outStream.write((byte)(a & 0xff));
- if (l > 1) {
- outStream.write((byte)( b & 0xff));
- }
- if (l > 2) {
- outStream.write((byte)(c&0xff));
- }
- }
-
- /**
- * For uuencoded buffers, the data begins with a line of the form:
- * begin MODE FILENAME
- * This line always starts in column 1.
- */
- protected void decodeBufferPrefix(PushbackInputStream inStream, OutputStream outStream) throws IOException {
- int c;
- StringBuilder q = new StringBuilder(32);
- String r;
- boolean sawNewLine;
-
- /*
- * This works by ripping through the buffer until it finds a 'begin'
- * line or the end of the buffer.
- */
- sawNewLine = true;
- while (true) {
- c = inStream.read();
- if (c == -1) {
- throw new CEFormatException("UUDecoder: No begin line.");
- }
- if ((c == 'b') && sawNewLine){
- c = inStream.read();
- if (c == 'e') {
- break;
- }
- }
- sawNewLine = (c == '\n') || (c == '\r');
- }
-
- /*
- * Now we think its begin, (we've seen ^be) so verify it here.
- */
- while ((c != '\n') && (c != '\r')) {
- c = inStream.read();
- if (c == -1) {
- throw new CEFormatException("UUDecoder: No begin line.");
- }
- if ((c != '\n') && (c != '\r')) {
- q.append((char)c);
- }
- }
- r = q.toString();
- if (r.indexOf(' ') != 3) {
- throw new CEFormatException("UUDecoder: Malformed begin line.");
- }
- mode = Integer.parseInt(r.substring(4,7));
- bufferName = r.substring(r.indexOf(' ',6)+1);
- /*
- * Check for \n after \r
- */
- if (c == '\r') {
- c = inStream.read ();
- if ((c != '\n') && (c != -1))
- inStream.unread (c);
- }
- }
-
- /**
- * In uuencoded buffers, encoded lines start with a character that
- * represents the number of bytes encoded in this line. The last
- * line of input is always a line that starts with a single space
- * character, which would be a zero length line.
- */
- protected int decodeLinePrefix(PushbackInputStream inStream, OutputStream outStream) throws IOException {
- int c;
-
- c = inStream.read();
- if (c == ' ') {
- c = inStream.read(); /* discard the (first)trailing CR or LF */
- c = inStream.read(); /* check for a second one */
- if ((c != '\n') && (c != -1))
- inStream.unread (c);
- throw new CEStreamExhausted();
- } else if (c == -1) {
- throw new CEFormatException("UUDecoder: Short Buffer.");
- }
-
- c = (c - ' ') & 0x3f;
- if (c > bytesPerLine()) {
- throw new CEFormatException("UUDecoder: Bad Line Length.");
- }
- return (c);
- }
-
-
- /**
- * Find the end of the line for the next operation.
- * The following sequences are recognized as end-of-line
- * CR, CR LF, or LF
- */
- protected void decodeLineSuffix(PushbackInputStream inStream, OutputStream outStream) throws IOException {
- int c;
- while (true) {
- c = inStream.read();
- if (c == -1) {
- throw new CEStreamExhausted();
- }
- if (c == '\n') {
- break;
- }
- if (c == '\r') {
- c = inStream.read();
- if ((c != '\n') && (c != -1)) {
- inStream.unread (c);
- }
- break;
- }
- }
- }
-
- /**
- * UUencoded files have a buffer suffix which consists of the word
- * end. This line should immediately follow the line with a single
- * space in it.
- */
- protected void decodeBufferSuffix(PushbackInputStream inStream, OutputStream outStream) throws IOException {
- int c;
-
- c = inStream.read(decoderBuffer);
- if ((decoderBuffer[0] != 'e') || (decoderBuffer[1] != 'n') ||
- (decoderBuffer[2] != 'd')) {
- throw new CEFormatException("UUDecoder: Missing 'end' line.");
- }
- }
-
-}
--- a/jdk/src/java.base/share/classes/sun/misc/UUEncoder.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,200 +0,0 @@
-/*
- * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.misc;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.IOException;
-
-/**
- * This class implements a Berkeley uu character encoder. This encoder
- * was made famous by uuencode program.
- *
- * The basic character coding is algorithmic, taking 6 bits of binary
- * data and adding it to an ASCII ' ' (space) character. This converts
- * these six bits into a printable representation. Note that it depends
- * on the ASCII character encoding standard for english. Groups of three
- * bytes are converted into 4 characters by treating the three bytes
- * a four 6 bit groups, group 1 is byte 1's most significant six bits,
- * group 2 is byte 1's least significant two bits plus byte 2's four
- * most significant bits. etc.
- *
- * In this encoding, the buffer prefix is:
- * <pre>
- * begin [mode] [filename]
- * </pre>
- *
- * This is followed by one or more lines of the form:
- * <pre>
- * (len)(data)(data)(data) ...
- * </pre>
- * where (len) is the number of bytes on this line. Note that groupings
- * are always four characters, even if length is not a multiple of three
- * bytes. When less than three characters are encoded, the values of the
- * last remaining bytes is undefined and should be ignored.
- *
- * The last line of data in a uuencoded file is represented by a single
- * space character. This is translated by the decoding engine to a line
- * length of zero. This is immediately followed by a line which contains
- * the word 'end[newline]'
- *
- * @author Chuck McManis
- * @see CharacterEncoder
- * @see UUDecoder
- */
-public class UUEncoder extends CharacterEncoder {
-
- /**
- * This name is stored in the begin line.
- */
- private String bufferName;
-
- /**
- * Represents UNIX(tm) mode bits. Generally three octal digits representing
- * read, write, and execute permission of the owner, group owner, and
- * others. They should be interpreted as the bit groups:
- * (owner) (group) (others)
- * rwx rwx rwx (r = read, w = write, x = execute)
- *
- * By default these are set to 644 (UNIX rw-r--r-- permissions).
- */
- private int mode;
-
-
- /**
- * Default - buffer begin line will be:
- * <pre>
- * begin 644 encoder.buf
- * </pre>
- */
- public UUEncoder() {
- bufferName = "encoder.buf";
- mode = 644;
- }
-
- /**
- * Specifies a name for the encoded buffer, begin line will be:
- * <pre>
- * begin 644 [FNAME]
- * </pre>
- */
- public UUEncoder(String fname) {
- bufferName = fname;
- mode = 644;
- }
-
- /**
- * Specifies a name and mode for the encoded buffer, begin line will be:
- * <pre>
- * begin [MODE] [FNAME]
- * </pre>
- */
- public UUEncoder(String fname, int newMode) {
- bufferName = fname;
- mode = newMode;
- }
-
- /** number of bytes per atom in uuencoding is 3 */
- protected int bytesPerAtom() {
- return (3);
- }
-
- /** number of bytes per line in uuencoding is 45 */
- protected int bytesPerLine() {
- return (45);
- }
-
- /**
- * encodeAtom - take three bytes and encodes them into 4 characters
- * If len is less than 3 then remaining bytes are filled with '1'.
- * This insures that the last line won't end in spaces and potentiallly
- * be truncated.
- */
- protected void encodeAtom(OutputStream outStream, byte data[], int offset, int len)
- throws IOException {
- byte a, b = 1, c = 1;
- int c1, c2, c3, c4;
-
- a = data[offset];
- if (len > 1) {
- b = data[offset+1];
- }
- if (len > 2) {
- c = data[offset+2];
- }
-
- c1 = (a >>> 2) & 0x3f;
- c2 = ((a << 4) & 0x30) | ((b >>> 4) & 0xf);
- c3 = ((b << 2) & 0x3c) | ((c >>> 6) & 0x3);
- c4 = c & 0x3f;
- outStream.write(c1 + ' ');
- outStream.write(c2 + ' ');
- outStream.write(c3 + ' ');
- outStream.write(c4 + ' ');
- return;
- }
-
- /**
- * Encode the line prefix which consists of the single character. The
- * lenght is added to the value of ' ' (32 decimal) and printed.
- */
- protected void encodeLinePrefix(OutputStream outStream, int length)
- throws IOException {
- outStream.write((length & 0x3f) + ' ');
- }
-
-
- /**
- * The line suffix for uuencoded files is simply a new line.
- */
- protected void encodeLineSuffix(OutputStream outStream) throws IOException {
- pStream.println();
- }
-
- /**
- * encodeBufferPrefix writes the begin line to the output stream.
- */
- protected void encodeBufferPrefix(OutputStream a) throws IOException {
- super.pStream = new PrintStream(a);
- super.pStream.print("begin "+mode+" ");
- if (bufferName != null) {
- super.pStream.println(bufferName);
- } else {
- super.pStream.println("encoder.bin");
- }
- super.pStream.flush();
- }
-
- /**
- * encodeBufferSuffix writes the single line containing space (' ') and
- * the line containing the word 'end' to the output stream.
- */
- protected void encodeBufferSuffix(OutputStream a) throws IOException {
- super.pStream.println(" \nend");
- super.pStream.flush();
- }
-
-}
--- a/jdk/src/java.base/share/classes/sun/misc/VM.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/misc/VM.java Wed Jul 05 21:09:54 2017 +0200
@@ -274,9 +274,6 @@
// used by java.lang.Integer.IntegerCache
props.remove("java.lang.Integer.IntegerCache.high");
- // used by java.util.zip.ZipFile
- props.remove("sun.zip.disableMemoryMapping");
-
// used by sun.launcher.LauncherHelper
props.remove("sun.java.launcher.diag");
}
--- a/jdk/src/java.base/share/classes/sun/net/NetworkServer.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/net/NetworkServer.java Wed Jul 05 21:09:54 2017 +0200
@@ -27,7 +27,6 @@
import java.io.*;
import java.net.Socket;
import java.net.ServerSocket;
-import sun.misc.ManagedLocalsThread;
/**
* This is the base class for network servers. To define a new type
@@ -73,7 +72,7 @@
NetworkServer n = (NetworkServer)clone();
n.serverSocket = null;
n.clientSocket = ns;
- new ManagedLocalsThread(n).start();
+ new Thread(null, n, "NetworkServer", 0, false).start();
} catch(Exception e) {
System.out.print("Server failure\n");
e.printStackTrace();
@@ -108,7 +107,7 @@
for each new connection. */
public final void startServer(int port) throws IOException {
serverSocket = new ServerSocket(port, 50);
- serverInstance = new ManagedLocalsThread(this);
+ serverInstance = new Thread(null, this, "NetworkServer", 0, false);
serverInstance.start();
}
--- a/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java Wed Jul 05 21:09:54 2017 +0200
@@ -27,9 +27,8 @@
import java.net.URL;
import java.io.*;
import java.util.StringTokenizer;
-import sun.misc.ManagedLocalsThread;
-class MimeLauncher extends ManagedLocalsThread {
+class MimeLauncher extends Thread {
java.net.URLConnection uc;
MimeEntry m;
String genericTempFileTemplate;
@@ -38,7 +37,7 @@
MimeLauncher (MimeEntry M, java.net.URLConnection uc,
InputStream is, String tempFileTemplate, String threadName) throws ApplicationLaunchException {
- super(threadName);
+ super(null, null, threadName, 0, false);
m = M;
this.uc = uc;
this.is = is;
--- a/jdk/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java Wed Jul 05 21:09:54 2017 +0200
@@ -30,7 +30,6 @@
import java.security.PrivilegedAction;
import java.io.IOException;
import java.util.*;
-import sun.misc.ManagedLocalsThread;
/**
* Base implementation of background poller thread used in watch service
@@ -60,7 +59,7 @@
AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Object run() {
- Thread thr = new ManagedLocalsThread(thisRunnable);
+ Thread thr = new Thread(null, thisRunnable, "FileSystemWatchService", 0, false);
thr.setDaemon(true);
thr.start();
return null;
--- a/jdk/src/java.base/share/classes/sun/nio/fs/Cancellable.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/nio/fs/Cancellable.java Wed Jul 05 21:09:54 2017 +0200
@@ -25,7 +25,6 @@
package sun.nio.fs;
-import sun.misc.ManagedLocalsThread;
import jdk.internal.misc.Unsafe;
import java.util.concurrent.ExecutionException;
@@ -118,7 +117,7 @@
* thread by writing into the memory location that it polls cooperatively.
*/
static void runInterruptibly(Cancellable task) throws ExecutionException {
- Thread t = new ManagedLocalsThread(task);
+ Thread t = new Thread(null, task, "NIO-Task", 0, false);
t.start();
boolean cancelledByInterrupt = false;
while (t.isAlive()) {
--- a/jdk/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java Wed Jul 05 21:09:54 2017 +0200
@@ -35,7 +35,6 @@
import java.util.*;
import java.util.concurrent.*;
import com.sun.nio.file.SensitivityWatchEventModifier;
-import sun.misc.ManagedLocalsThread;
/**
* Simple WatchService implementation that uses periodic tasks to poll
@@ -59,7 +58,7 @@
.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
- Thread t = new ManagedLocalsThread(r);
+ Thread t = new Thread(null, r, "FileSystemWatchService", 0, false);
t.setDaemon(true);
return t;
}});
--- a/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Wed Jul 05 21:09:54 2017 +0200
@@ -62,7 +62,7 @@
decl);
if (type instanceof Class) {
return new AnnotatedTypeBaseImpl(type,
- addNesting(type, currentLoc),
+ currentLoc,
actualTypeAnnos,
allOnSameTarget,
decl);
@@ -74,7 +74,7 @@
decl);
} else if (type instanceof ParameterizedType) {
return new AnnotatedParameterizedTypeImpl((ParameterizedType)type,
- addNesting(type, currentLoc),
+ currentLoc,
actualTypeAnnos,
allOnSameTarget,
decl);
@@ -88,7 +88,7 @@
throw new AssertionError("Unknown instance of Type: " + type + "\nThis should not happen.");
}
- private static LocationInfo addNesting(Type type, LocationInfo addTo) {
+ public static LocationInfo nestingForType(Type type, LocationInfo addTo) {
if (isArray(type))
return addTo;
if (type instanceof Class) {
@@ -96,13 +96,13 @@
if (clz.getEnclosingClass() == null)
return addTo;
if (Modifier.isStatic(clz.getModifiers()))
- return addNesting(clz.getEnclosingClass(), addTo);
- return addNesting(clz.getEnclosingClass(), addTo.pushInner());
+ return nestingForType(clz.getEnclosingClass(), addTo);
+ return nestingForType(clz.getEnclosingClass(), addTo.pushInner());
} else if (type instanceof ParameterizedType) {
ParameterizedType t = (ParameterizedType)type;
if (t.getOwnerType() == null)
return addTo;
- return addNesting(t.getOwnerType(), addTo.pushInner());
+ return nestingForType(t.getOwnerType(), addTo.pushInner());
}
return addTo;
}
@@ -118,8 +118,9 @@
return false;
}
+ static final TypeAnnotation[] EMPTY_TYPE_ANNOTATION_ARRAY = new TypeAnnotation[0];
static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
- new TypeAnnotation[0], new TypeAnnotation[0], null);
+ EMPTY_TYPE_ANNOTATION_ARRAY, EMPTY_TYPE_ANNOTATION_ARRAY, null);
static final AnnotatedType[] EMPTY_ANNOTATED_TYPE_ARRAY = new AnnotatedType[0];
private static class AnnotatedTypeBaseImpl implements AnnotatedType {
@@ -177,6 +178,30 @@
return type;
}
+ @Override
+ public AnnotatedType getAnnotatedOwnerType() {
+ if (!(type instanceof Class<?>))
+ throw new IllegalStateException("Can't compute owner");
+
+ Class<?> inner = (Class<?>)type;
+ Class<?> owner = inner.getDeclaringClass();
+ if (owner == null) // top-level, local or anonymous
+ return null;
+ if (inner.isPrimitive() || inner == Void.TYPE)
+ return null;
+
+ LocationInfo outerLoc = nestingForType(owner, getLocation().popAllLocations((byte)1));
+ TypeAnnotation[]all = getTypeAnnotations();
+ List<TypeAnnotation> l = new ArrayList<>(all.length);
+
+ for (TypeAnnotation t : all)
+ if (t.getLocationInfo().isSameLocationInfo(outerLoc))
+ l.add(t);
+
+ return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl());
+
+ }
+
// Implementation details
final LocationInfo getLocation() {
return location;
@@ -198,11 +223,17 @@
@Override
public AnnotatedType getAnnotatedGenericComponentType() {
- return AnnotatedTypeFactory.buildAnnotatedType(getComponentType(),
- getLocation().pushArray(),
- getTypeAnnotations(),
- getTypeAnnotations(),
- getDecl());
+ Type t = getComponentType();
+ return AnnotatedTypeFactory.buildAnnotatedType(t,
+ nestingForType(t, getLocation().pushArray()),
+ getTypeAnnotations(),
+ getTypeAnnotations(),
+ getDecl());
+ }
+
+ @Override
+ public AnnotatedType getAnnotatedOwnerType() {
+ return null;
}
private Type getComponentType() {
@@ -227,6 +258,11 @@
return getTypeVariable().getAnnotatedBounds();
}
+ @Override
+ public AnnotatedType getAnnotatedOwnerType() {
+ return null;
+ }
+
private TypeVariable<?> getTypeVariable() {
return (TypeVariable)getType();
}
@@ -248,19 +284,35 @@
int initialCapacity = getTypeAnnotations().length;
for (int i = 0; i < res.length; i++) {
List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
- LocationInfo newLoc = getLocation().pushTypeArg((byte)i);
+ LocationInfo newLoc = nestingForType(arguments[i], getLocation().pushTypeArg((byte)i));
for (TypeAnnotation t : getTypeAnnotations())
if (t.getLocationInfo().isSameLocationInfo(newLoc))
l.add(t);
res[i] = buildAnnotatedType(arguments[i],
- newLoc,
- l.toArray(new TypeAnnotation[0]),
- getTypeAnnotations(),
- getDecl());
+ newLoc,
+ l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
+ getTypeAnnotations(),
+ getDecl());
}
return res;
}
+ @Override
+ public AnnotatedType getAnnotatedOwnerType() {
+ Type owner = getParameterizedType().getOwnerType();
+ if (owner == null)
+ return null;
+ LocationInfo outerLoc = nestingForType(owner, getLocation().popAllLocations((byte)1));
+ TypeAnnotation[]all = getTypeAnnotations();
+ List<TypeAnnotation> l = new ArrayList<>(all.length);
+
+ for (TypeAnnotation t : all)
+ if (t.getLocationInfo().isSameLocationInfo(outerLoc))
+ l.add(t);
+
+ return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl());
+ }
+
private ParameterizedType getParameterizedType() {
return (ParameterizedType)getType();
}
@@ -279,11 +331,11 @@
public AnnotatedType[] getAnnotatedUpperBounds() {
if (!hasUpperBounds()) {
return new AnnotatedType[] { buildAnnotatedType(Object.class,
- LocationInfo.BASE_LOCATION,
- new TypeAnnotation[0],
- new TypeAnnotation[0],
- null)
- };
+ LocationInfo.BASE_LOCATION,
+ EMPTY_TYPE_ANNOTATION_ARRAY,
+ EMPTY_TYPE_ANNOTATION_ARRAY,
+ null)
+ };
}
return getAnnotatedBounds(getWildcardType().getUpperBounds());
}
@@ -295,21 +347,26 @@
return getAnnotatedBounds(getWildcardType().getLowerBounds());
}
+ @Override
+ public AnnotatedType getAnnotatedOwnerType() {
+ return null;
+ }
+
private AnnotatedType[] getAnnotatedBounds(Type[] bounds) {
AnnotatedType[] res = new AnnotatedType[bounds.length];
Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
- LocationInfo newLoc = getLocation().pushWildcard();
int initialCapacity = getTypeAnnotations().length;
for (int i = 0; i < res.length; i++) {
+ LocationInfo newLoc = nestingForType(bounds[i], getLocation().pushWildcard());
List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
for (TypeAnnotation t : getTypeAnnotations())
if (t.getLocationInfo().isSameLocationInfo(newLoc))
l.add(t);
res[i] = buildAnnotatedType(bounds[i],
- newLoc,
- l.toArray(new TypeAnnotation[0]),
- getTypeAnnotations(),
- getDecl());
+ newLoc,
+ l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
+ getTypeAnnotations(),
+ getDecl());
}
return res;
}
--- a/jdk/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -187,13 +187,28 @@
return new LocationInfo(newDepth, res);
}
+ /** Pop a series of locations matching {@code tag}. Stop poping as soon as a non-matching tag is found. */
+ public LocationInfo popAllLocations(byte tag) {
+ LocationInfo l = this;
+ int newDepth = l.depth;
+ while(newDepth > 0 && l.locations[newDepth - 1].tag == tag) {
+ newDepth--;
+ }
+ if (newDepth != l.depth) {
+ Location[] res = new Location[newDepth];
+ System.arraycopy(this.locations, 0, res, 0, newDepth);
+ return new LocationInfo(newDepth, res);
+ } else
+ return l;
+ }
+
public TypeAnnotation[] filter(TypeAnnotation[] ta) {
ArrayList<TypeAnnotation> l = new ArrayList<>(ta.length);
for (TypeAnnotation t : ta) {
if (isSameLocationInfo(t.getLocationInfo()))
l.add(t);
}
- return l.toArray(new TypeAnnotation[0]);
+ return l.toArray(AnnotatedTypeFactory.EMPTY_TYPE_ANNOTATION_ARRAY);
}
boolean isSameLocationInfo(LocationInfo other) {
--- a/jdk/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -32,7 +32,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import jdk.internal.misc.SharedSecrets;
@@ -67,9 +66,8 @@
Type type,
TypeAnnotationTarget filter) {
TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations,
- cp,
- decl,
- container);
+ cp, decl, container);
+
List<TypeAnnotation> l = new ArrayList<>(tas.length);
for (TypeAnnotation t : tas) {
TypeAnnotationTargetInfo ti = t.getTargetInfo();
@@ -78,10 +76,10 @@
}
TypeAnnotation[] typeAnnotations = l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY);
return AnnotatedTypeFactory.buildAnnotatedType(type,
- LocationInfo.BASE_LOCATION,
- typeAnnotations,
- typeAnnotations,
- decl);
+ AnnotatedTypeFactory.nestingForType(type, LocationInfo.BASE_LOCATION),
+ typeAnnotations,
+ typeAnnotations,
+ decl);
}
/**
@@ -110,9 +108,8 @@
ArrayList[] l = new ArrayList[size]; // array of ArrayList<TypeAnnotation>
TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations,
- cp,
- decl,
- container);
+ cp, decl, container);
+
for (TypeAnnotation t : tas) {
TypeAnnotationTargetInfo ti = t.getTargetInfo();
if (ti.getTarget() == filter) {
@@ -136,10 +133,10 @@
typeAnnotations = EMPTY_TYPE_ANNOTATION_ARRAY;
}
result[i] = AnnotatedTypeFactory.buildAnnotatedType(types[i],
- LocationInfo.BASE_LOCATION,
- typeAnnotations,
- typeAnnotations,
- decl);
+ AnnotatedTypeFactory.nestingForType(types[i], LocationInfo.BASE_LOCATION),
+ typeAnnotations,
+ typeAnnotations,
+ decl);
}
return result;
@@ -278,7 +275,7 @@
}
}
res[i] = AnnotatedTypeFactory.buildAnnotatedType(bounds[i],
- loc,
+ AnnotatedTypeFactory.nestingForType(bounds[i], loc),
l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
candidates.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
(AnnotatedElement)decl);
--- a/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java Wed Jul 05 21:09:54 2017 +0200
@@ -39,7 +39,7 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.x509.*;
import sun.security.util.*;
--- a/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS9Attribute.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS9Attribute.java Wed Jul 05 21:09:54 2017 +0200
@@ -38,7 +38,7 @@
import sun.security.util.DerInputStream;
import sun.security.util.DerOutputStream;
import sun.security.util.ObjectIdentifier;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
* Class supporting any PKCS9 attributes.
--- a/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java Wed Jul 05 21:09:54 2017 +0200
@@ -41,7 +41,7 @@
import sun.security.x509.AlgorithmId;
import sun.security.x509.X500Name;
import sun.security.x509.KeyUsageExtension;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
* A SignerInfo, as defined in PKCS#7's signedData type.
--- a/jdk/src/java.base/share/classes/sun/security/pkcs/SigningCertificateInfo.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/SigningCertificateInfo.java Wed Jul 05 21:09:54 2017 +0200
@@ -28,7 +28,7 @@
import java.io.IOException;
import java.util.ArrayList;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.DerInputStream;
import sun.security.util.DerValue;
import sun.security.x509.GeneralNames;
--- a/jdk/src/java.base/share/classes/sun/security/provider/SeedGenerator.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/provider/SeedGenerator.java Wed Jul 05 21:09:54 2017 +0200
@@ -75,7 +75,6 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Random;
-import sun.misc.ManagedLocalsThread;
import sun.security.util.Debug;
abstract class SeedGenerator {
@@ -305,9 +304,11 @@
}
finalsg[0] = new ThreadGroup
(group, "SeedGenerator ThreadGroup");
- Thread newT = new ManagedLocalsThread(finalsg[0],
+ Thread newT = new Thread(finalsg[0],
ThreadedSeedGenerator.this,
- "SeedGenerator Thread");
+ "SeedGenerator Thread",
+ 0,
+ false);
newT.setPriority(Thread.MIN_PRIORITY);
newT.setDaemon(true);
return newT;
@@ -342,8 +343,8 @@
// Start some noisy threads
try {
BogusThread bt = new BogusThread();
- Thread t = new ManagedLocalsThread
- (seedGroup, bt, "SeedGenerator Thread");
+ Thread t = new Thread
+ (seedGroup, bt, "SeedGenerator Thread", 0, false);
t.start();
} catch (Exception e) {
throw new InternalError("internal error: " +
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/CertId.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/CertId.java Wed Jul 05 21:09:54 2017 +0200
@@ -33,7 +33,7 @@
import java.security.cert.X509Certificate;
import java.util.Arrays;
import javax.security.auth.x500.X500Principal;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.x509.*;
import sun.security.util.*;
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPRequest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPRequest.java Wed Jul 05 21:09:54 2017 +0200
@@ -30,7 +30,7 @@
import java.util.Collections;
import java.util.List;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.*;
import sun.security.x509.PKIXExtensions;
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java Wed Jul 05 21:09:54 2017 +0200
@@ -44,7 +44,7 @@
import java.util.Set;
import javax.security.auth.x500.X500Principal;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.action.GetIntegerAction;
import sun.security.x509.*;
import sun.security.util.*;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherBox.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherBox.java Wed Jul 05 21:09:54 2017 +0200
@@ -42,7 +42,7 @@
import static sun.security.ssl.CipherSuite.*;
import static sun.security.ssl.CipherSuite.CipherType.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
--- a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java Wed Jul 05 21:09:54 2017 +0200
@@ -32,7 +32,7 @@
import javax.net.ssl.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import static sun.security.ssl.HandshakeMessage.*;
/**
--- a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java Wed Jul 05 21:09:54 2017 +0200
@@ -33,7 +33,7 @@
import javax.net.ssl.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import static sun.security.ssl.Ciphertext.RecordType;
/**
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,7 +29,7 @@
import java.security.AccessController;
import java.util.Locale;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import java.nio.ByteBuffer;
import sun.security.action.GetPropertyAction;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java Wed Jul 05 21:09:54 2017 +0200
@@ -41,7 +41,7 @@
import javax.crypto.spec.*;
import javax.net.ssl.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.internal.spec.*;
import sun.security.internal.interfaces.TlsMasterSecret;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/InputRecord.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/InputRecord.java Wed Jul 05 21:09:54 2017 +0200
@@ -33,7 +33,7 @@
import javax.net.ssl.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
--- a/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java Wed Jul 05 21:09:54 2017 +0200
@@ -30,7 +30,7 @@
import java.util.Arrays;
import javax.net.ssl.SSLException;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java Wed Jul 05 21:09:54 2017 +0200
@@ -32,7 +32,7 @@
import javax.net.ssl.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java Wed Jul 05 21:09:54 2017 +0200
@@ -31,7 +31,7 @@
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import static sun.security.ssl.Ciphertext.RecordType;
/**
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -40,7 +40,6 @@
import javax.crypto.BadPaddingException;
import javax.net.ssl.*;
-import sun.misc.ManagedLocalsThread;
import jdk.internal.misc.JavaNetInetAddressAccess;
import jdk.internal.misc.SharedSecrets;
@@ -1153,10 +1152,13 @@
HandshakeCompletedEvent event =
new HandshakeCompletedEvent(this, sess);
- Thread thread = new ManagedLocalsThread(
+ Thread thread = new Thread(
+ null,
new NotifyHandshake(
handshakeListeners.entrySet(), event),
- "HandshakeCompletedNotify-Thread");
+ "HandshakeCompletedNotify-Thread",
+ 0,
+ false);
thread.start();
}
}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java Wed Jul 05 21:09:54 2017 +0200
@@ -32,7 +32,7 @@
import javax.net.ssl.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java Wed Jul 05 21:09:54 2017 +0200
@@ -31,7 +31,7 @@
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2013, 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
@@ -416,12 +416,18 @@
"SHA1withRSA", --p);
supports(HashAlgorithm.SHA1, SignatureAlgorithm.ECDSA,
"SHA1withECDSA", --p);
+
if (Security.getProvider("SunMSCAPI") == null) {
+ supports(HashAlgorithm.SHA224, SignatureAlgorithm.DSA,
+ "SHA224withDSA", --p);
supports(HashAlgorithm.SHA224, SignatureAlgorithm.RSA,
"SHA224withRSA", --p);
supports(HashAlgorithm.SHA224, SignatureAlgorithm.ECDSA,
"SHA224withECDSA", --p);
}
+
+ supports(HashAlgorithm.SHA256, SignatureAlgorithm.DSA,
+ "SHA256withDSA", --p);
supports(HashAlgorithm.SHA256, SignatureAlgorithm.RSA,
"SHA256withRSA", --p);
supports(HashAlgorithm.SHA256, SignatureAlgorithm.ECDSA,
--- a/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java Wed Jul 05 21:09:54 2017 +0200
@@ -2956,7 +2956,7 @@
if (v.length == 0) {
out.println(rb.getString(".Empty.value."));
} else {
- new sun.misc.HexDumpEncoder().encodeBuffer(ext.getExtensionValue(), out);
+ new sun.security.util.HexDumpEncoder().encodeBuffer(ext.getExtensionValue(), out);
out.println();
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/util/HexDumpEncoder.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package sun.security.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * This class encodes a buffer into the classic: "Hexadecimal Dump" format of
+ * the past. It is useful for analyzing the contents of binary buffers.
+ * The format produced is as follows:
+ * <pre>
+ * xxxx: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff ................
+ * </pre>
+ * Where xxxx is the offset into the buffer in 16 byte chunks, followed
+ * by ascii coded hexadecimal bytes followed by the ASCII representation of
+ * the bytes or '.' if they are not valid bytes.
+ *
+ * @author Chuck McManis
+ */
+
+public class HexDumpEncoder {
+
+ private int offset;
+ private int thisLineLength;
+ private int currentByte;
+ private byte thisLine[] = new byte[16];
+
+ static void hexDigit(PrintStream p, byte x) {
+ char c;
+
+ c = (char) ((x >> 4) & 0xf);
+ if (c > 9)
+ c = (char) ((c-10) + 'A');
+ else
+ c = (char)(c + '0');
+ p.write(c);
+ c = (char) (x & 0xf);
+ if (c > 9)
+ c = (char)((c-10) + 'A');
+ else
+ c = (char)(c + '0');
+ p.write(c);
+ }
+
+ protected int bytesPerAtom() {
+ return (1);
+ }
+
+ protected int bytesPerLine() {
+ return (16);
+ }
+
+ protected void encodeBufferPrefix(OutputStream o) throws IOException {
+ offset = 0;
+ pStream = new PrintStream(o);
+ }
+
+ protected void encodeLinePrefix(OutputStream o, int len) throws IOException {
+ hexDigit(pStream, (byte)((offset >>> 8) & 0xff));
+ hexDigit(pStream, (byte)(offset & 0xff));
+ pStream.print(": ");
+ currentByte = 0;
+ thisLineLength = len;
+ }
+
+ protected void encodeAtom(OutputStream o, byte buf[], int off, int len) throws IOException {
+ thisLine[currentByte] = buf[off];
+ hexDigit(pStream, buf[off]);
+ pStream.print(" ");
+ currentByte++;
+ if (currentByte == 8)
+ pStream.print(" ");
+ }
+
+ protected void encodeLineSuffix(OutputStream o) throws IOException {
+ if (thisLineLength < 16) {
+ for (int i = thisLineLength; i < 16; i++) {
+ pStream.print(" ");
+ if (i == 7)
+ pStream.print(" ");
+ }
+ }
+ pStream.print(" ");
+ for (int i = 0; i < thisLineLength; i++) {
+ if ((thisLine[i] < ' ') || (thisLine[i] > 'z')) {
+ pStream.print(".");
+ } else {
+ pStream.write(thisLine[i]);
+ }
+ }
+ pStream.println();
+ offset += thisLineLength;
+ }
+
+ /** Stream that understands "printing" */
+ protected PrintStream pStream;
+
+ /**
+ * This method works around the bizarre semantics of BufferedInputStream's
+ * read method.
+ */
+ protected int readFully(InputStream in, byte buffer[])
+ throws java.io.IOException {
+ for (int i = 0; i < buffer.length; i++) {
+ int q = in.read();
+ if (q == -1)
+ return i;
+ buffer[i] = (byte)q;
+ }
+ return buffer.length;
+ }
+
+ /**
+ * Encode bytes from the input stream, and write them as text characters
+ * to the output stream. This method will run until it exhausts the
+ * input stream, but does not print the line suffix for a final
+ * line that is shorter than bytesPerLine().
+ */
+ public void encode(InputStream inStream, OutputStream outStream)
+ throws IOException
+ {
+ int j;
+ int numBytes;
+ byte tmpbuffer[] = new byte[bytesPerLine()];
+
+ encodeBufferPrefix(outStream);
+
+ while (true) {
+ numBytes = readFully(inStream, tmpbuffer);
+ if (numBytes == 0) {
+ break;
+ }
+ encodeLinePrefix(outStream, numBytes);
+ for (j = 0; j < numBytes; j += bytesPerAtom()) {
+
+ if ((j + bytesPerAtom()) <= numBytes) {
+ encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
+ } else {
+ encodeAtom(outStream, tmpbuffer, j, (numBytes)- j);
+ }
+ }
+ if (numBytes < bytesPerLine()) {
+ break;
+ } else {
+ encodeLineSuffix(outStream);
+ }
+ }
+ }
+
+ /**
+ * A 'streamless' version of encode that simply takes a buffer of
+ * bytes and returns a string containing the encoded buffer.
+ */
+ public String encode(byte aBuffer[]) {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+ String retVal = null;
+ try {
+ encode(inStream, outStream);
+ // explicit ascii->unicode conversion
+ retVal = outStream.toString("ISO-8859-1");
+ } catch (Exception IOException) {
+ // This should never happen.
+ throw new Error("CharacterEncoder.encode internal error");
+ }
+ return (retVal);
+ }
+
+ /**
+ * Return a byte array from the remaining bytes in this ByteBuffer.
+ * <P>
+ * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+ * <P>
+ * To avoid an extra copy, the implementation will attempt to return the
+ * byte array backing the ByteBuffer. If this is not possible, a
+ * new byte array will be created.
+ */
+ private byte [] getBytes(ByteBuffer bb) {
+ /*
+ * This should never return a BufferOverflowException, as we're
+ * careful to allocate just the right amount.
+ */
+ byte [] buf = null;
+
+ /*
+ * If it has a usable backing byte buffer, use it. Use only
+ * if the array exactly represents the current ByteBuffer.
+ */
+ if (bb.hasArray()) {
+ byte [] tmp = bb.array();
+ if ((tmp.length == bb.capacity()) &&
+ (tmp.length == bb.remaining())) {
+ buf = tmp;
+ bb.position(bb.limit());
+ }
+ }
+
+ if (buf == null) {
+ /*
+ * This class doesn't have a concept of encode(buf, len, off),
+ * so if we have a partial buffer, we must reallocate
+ * space.
+ */
+ buf = new byte[bb.remaining()];
+
+ /*
+ * position() automatically updated
+ */
+ bb.get(buf);
+ }
+
+ return buf;
+ }
+
+ /**
+ * A 'streamless' version of encode that simply takes a ByteBuffer
+ * and returns a string containing the encoded buffer.
+ * <P>
+ * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+ */
+ public String encode(ByteBuffer aBuffer) {
+ byte [] buf = getBytes(aBuffer);
+ return encode(buf);
+ }
+
+ /**
+ * Encode bytes from the input stream, and write them as text characters
+ * to the output stream. This method will run until it exhausts the
+ * input stream. It differs from encode in that it will add the
+ * line at the end of a final line that is shorter than bytesPerLine().
+ */
+ public void encodeBuffer(InputStream inStream, OutputStream outStream)
+ throws IOException
+ {
+ int j;
+ int numBytes;
+ byte tmpbuffer[] = new byte[bytesPerLine()];
+
+ encodeBufferPrefix(outStream);
+
+ while (true) {
+ numBytes = readFully(inStream, tmpbuffer);
+ if (numBytes == 0) {
+ break;
+ }
+ encodeLinePrefix(outStream, numBytes);
+ for (j = 0; j < numBytes; j += bytesPerAtom()) {
+ if ((j + bytesPerAtom()) <= numBytes) {
+ encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
+ } else {
+ encodeAtom(outStream, tmpbuffer, j, (numBytes)- j);
+ }
+ }
+ encodeLineSuffix(outStream);
+ if (numBytes < bytesPerLine()) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Encode the buffer in <i>aBuffer</i> and write the encoded
+ * result to the OutputStream <i>aStream</i>.
+ */
+ public void encodeBuffer(byte aBuffer[], OutputStream aStream)
+ throws IOException
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+ encodeBuffer(inStream, aStream);
+ }
+
+ /**
+ * A 'streamless' version of encode that simply takes a buffer of
+ * bytes and returns a string containing the encoded buffer.
+ */
+ public String encodeBuffer(byte aBuffer[]) {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+ try {
+ encodeBuffer(inStream, outStream);
+ } catch (Exception IOException) {
+ // This should never happen.
+ throw new Error("CharacterEncoder.encodeBuffer internal error");
+ }
+ return (outStream.toString());
+ }
+
+ /**
+ * Encode the <i>aBuffer</i> ByteBuffer and write the encoded
+ * result to the OutputStream <i>aStream</i>.
+ * <P>
+ * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+ */
+ public void encodeBuffer(ByteBuffer aBuffer, OutputStream aStream)
+ throws IOException
+ {
+ byte [] buf = getBytes(aBuffer);
+ encodeBuffer(buf, aStream);
+ }
+
+}
--- a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java Wed Jul 05 21:09:54 2017 +0200
@@ -443,7 +443,7 @@
if (sfAttr != null) {
- //sun.misc.HexDumpEncoder hex = new sun.misc.HexDumpEncoder();
+ //sun.security.util.HexDumpEncoder hex = new sun.security.util.HexDumpEncoder();
//hex.encodeBuffer(data, System.out);
// go through all the attributes and process *-Digest entries
--- a/jdk/src/java.base/share/classes/sun/security/x509/CertificateExtensions.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/x509/CertificateExtensions.java Wed Jul 05 21:09:54 2017 +0200
@@ -33,7 +33,7 @@
import java.security.cert.CertificateException;
import java.util.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.*;
@@ -376,6 +376,6 @@
@Override public String toString() {
return super.toString() +
"Unparseable " + name + "extension due to\n" + why + "\n\n" +
- new sun.misc.HexDumpEncoder().encodeBuffer(getExtensionValue());
+ new HexDumpEncoder().encodeBuffer(getExtensionValue());
}
}
--- a/jdk/src/java.base/share/classes/sun/security/x509/IPAddressName.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/x509/IPAddressName.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,7 +29,7 @@
import java.lang.Integer;
import java.net.InetAddress;
import java.util.Arrays;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.BitArray;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
--- a/jdk/src/java.base/share/classes/sun/security/x509/KeyIdentifier.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/x509/KeyIdentifier.java Wed Jul 05 21:09:54 2017 +0200
@@ -30,7 +30,7 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.*;
/**
--- a/jdk/src/java.base/share/classes/sun/security/x509/UniqueIdentity.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/x509/UniqueIdentity.java Wed Jul 05 21:09:54 2017 +0200
@@ -27,7 +27,7 @@
import java.io.IOException;
import java.math.BigInteger;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.*;
/**
--- a/jdk/src/java.base/share/classes/sun/security/x509/X509CRLEntryImpl.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X509CRLEntryImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -35,7 +35,7 @@
import javax.security.auth.x500.X500Principal;
import sun.security.util.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
* <p>Abstract class for a revoked certificate in a CRL.
--- a/jdk/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -49,7 +49,7 @@
import sun.security.provider.X509Factory;
import sun.security.util.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
* <p>
--- a/jdk/src/java.base/share/classes/sun/security/x509/X509CertImpl.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X509CertImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -41,7 +41,7 @@
import javax.security.auth.x500.X500Principal;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import java.util.Base64;
import sun.security.util.*;
import sun.security.provider.X509Factory;
--- a/jdk/src/java.base/share/classes/sun/security/x509/X509CertInfo.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X509CertInfo.java Wed Jul 05 21:09:54 2017 +0200
@@ -32,7 +32,7 @@
import java.util.*;
import sun.security.util.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
--- a/jdk/src/java.base/share/classes/sun/security/x509/X509Key.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X509Key.java Wed Jul 05 21:09:54 2017 +0200
@@ -38,7 +38,7 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.util.*;
/**
--- a/jdk/src/java.base/share/conf/security/java.policy Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/share/conf/security/java.policy Wed Jul 05 21:09:54 2017 +0200
@@ -19,6 +19,10 @@
permission java.security.AllPermission;
};
+grant codeBase "jrt:/jdk.dynalink" {
+ permission java.security.AllPermission;
+};
+
grant codeBase "jrt:/jdk.scripting.nashorn" {
permission java.security.AllPermission;
};
--- a/jdk/src/java.base/share/native/libzip/ZipFile.c Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,406 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-/*
- * Native method support for java.util.zip.ZipFile
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-#include <assert.h>
-#include "jlong.h"
-#include "jvm.h"
-#include "jni.h"
-#include "jni_util.h"
-#include "zip_util.h"
-#ifdef WIN32
-#include "io_util_md.h"
-#else
-#include "io_util.h"
-#endif
-
-#include "java_util_zip_ZipFile.h"
-#include "java_util_jar_JarFile.h"
-
-#define DEFLATED 8
-#define STORED 0
-
-static jfieldID jzfileID;
-
-static int OPEN_READ = java_util_zip_ZipFile_OPEN_READ;
-static int OPEN_DELETE = java_util_zip_ZipFile_OPEN_DELETE;
-
-
-/*
- * Declare library specific JNI_Onload entry if static build
- */
-DEF_STATIC_JNI_OnLoad
-
-JNIEXPORT void JNICALL
-Java_java_util_zip_ZipFile_initIDs(JNIEnv *env, jclass cls)
-{
- jzfileID = (*env)->GetFieldID(env, cls, "jzfile", "J");
- assert(jzfileID != 0);
-}
-
-static void
-ThrowZipException(JNIEnv *env, const char *msg)
-{
- jstring s = NULL;
- jobject x;
-
- if (msg != NULL) {
- s = JNU_NewStringPlatform(env, msg);
- }
- if (s != NULL) {
- x = JNU_NewObjectByName(env,
- "java/util/zip/ZipException",
- "(Ljava/lang/String;)V", s);
- if (x != NULL) {
- (*env)->Throw(env, x);
- }
- }
-}
-
-JNIEXPORT jlong JNICALL
-Java_java_util_zip_ZipFile_open(JNIEnv *env, jclass cls, jstring name,
- jint mode, jlong lastModified,
- jboolean usemmap)
-{
- const char *path = JNU_GetStringPlatformChars(env, name, 0);
- char *msg = 0;
- jlong result = 0;
- int flag = 0;
- jzfile *zip = 0;
-
- if (mode & OPEN_READ) flag |= O_RDONLY;
-
- if (path != 0) {
- zip = ZIP_Get_From_Cache(path, &msg, lastModified);
- if (zip == 0 && msg == 0) {
- ZFILE zfd = 0;
-#ifdef WIN32
- if (mode & OPEN_DELETE) flag |= O_TEMPORARY;
- zfd = winFileHandleOpen(env, name, flag);
- if (zfd == -1) {
- /* Exception already pending. */
- goto finally;
- }
-#else
- zfd = open(path, flag, 0);
- if (zfd < 0) {
- throwFileNotFoundException(env, name);
- goto finally;
- }
- if (mode & OPEN_DELETE) {
- unlink(path);
- }
-#endif
- zip = ZIP_Put_In_Cache0(path, zfd, &msg, lastModified, usemmap);
- }
-
- if (zip != 0) {
- result = ptr_to_jlong(zip);
- } else if (msg != 0) {
- ThrowZipException(env, msg);
- free(msg);
- } else if (errno == ENOMEM) {
- JNU_ThrowOutOfMemoryError(env, 0);
- } else {
- ThrowZipException(env, "error in opening zip file");
- }
-finally:
- JNU_ReleaseStringPlatformChars(env, name, path);
- }
- return result;
-}
-
-JNIEXPORT jint JNICALL
-Java_java_util_zip_ZipFile_getTotal(JNIEnv *env, jclass cls, jlong zfile)
-{
- jzfile *zip = jlong_to_ptr(zfile);
-
- return zip->total;
-}
-
-JNIEXPORT jboolean JNICALL
-Java_java_util_zip_ZipFile_startsWithLOC(JNIEnv *env, jclass cls, jlong zfile)
-{
- jzfile *zip = jlong_to_ptr(zfile);
-
- return zip->locsig;
-}
-
-JNIEXPORT void JNICALL
-Java_java_util_zip_ZipFile_close(JNIEnv *env, jclass cls, jlong zfile)
-{
- ZIP_Close(jlong_to_ptr(zfile));
-}
-
-JNIEXPORT jlong JNICALL
-Java_java_util_zip_ZipFile_getEntry(JNIEnv *env, jclass cls, jlong zfile,
- jbyteArray name, jboolean addSlash)
-{
-#define MAXNAME 1024
- jzfile *zip = jlong_to_ptr(zfile);
- jsize ulen = (*env)->GetArrayLength(env, name);
- char buf[MAXNAME+2], *path;
- jzentry *ze;
-
- if (ulen > MAXNAME) {
- path = malloc(ulen + 2);
- if (path == 0) {
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
- } else {
- path = buf;
- }
- (*env)->GetByteArrayRegion(env, name, 0, ulen, (jbyte *)path);
- path[ulen] = '\0';
- ze = ZIP_GetEntry2(zip, path, (jint)ulen, addSlash);
- if (path != buf) {
- free(path);
- }
- return ptr_to_jlong(ze);
-}
-
-JNIEXPORT void JNICALL
-Java_java_util_zip_ZipFile_freeEntry(JNIEnv *env, jclass cls, jlong zfile,
- jlong zentry)
-{
- jzfile *zip = jlong_to_ptr(zfile);
- jzentry *ze = jlong_to_ptr(zentry);
- ZIP_FreeEntry(zip, ze);
-}
-
-JNIEXPORT jlong JNICALL
-Java_java_util_zip_ZipFile_getNextEntry(JNIEnv *env, jclass cls, jlong zfile,
- jint n)
-{
- jzentry *ze = ZIP_GetNextEntry(jlong_to_ptr(zfile), n);
- return ptr_to_jlong(ze);
-}
-
-JNIEXPORT jint JNICALL
-Java_java_util_zip_ZipFile_getEntryMethod(JNIEnv *env, jclass cls, jlong zentry)
-{
- jzentry *ze = jlong_to_ptr(zentry);
- return ze->csize != 0 ? DEFLATED : STORED;
-}
-
-JNIEXPORT jint JNICALL
-Java_java_util_zip_ZipFile_getEntryFlag(JNIEnv *env, jclass cls, jlong zentry)
-{
- jzentry *ze = jlong_to_ptr(zentry);
- return ze->flag;
-}
-
-JNIEXPORT jlong JNICALL
-Java_java_util_zip_ZipFile_getEntryCSize(JNIEnv *env, jclass cls, jlong zentry)
-{
- jzentry *ze = jlong_to_ptr(zentry);
- return ze->csize != 0 ? ze->csize : ze->size;
-}
-
-JNIEXPORT jlong JNICALL
-Java_java_util_zip_ZipFile_getEntrySize(JNIEnv *env, jclass cls, jlong zentry)
-{
- jzentry *ze = jlong_to_ptr(zentry);
- return ze->size;
-}
-
-JNIEXPORT jlong JNICALL
-Java_java_util_zip_ZipFile_getEntryTime(JNIEnv *env, jclass cls, jlong zentry)
-{
- jzentry *ze = jlong_to_ptr(zentry);
- return (jlong)ze->time & 0xffffffffUL;
-}
-
-JNIEXPORT jlong JNICALL
-Java_java_util_zip_ZipFile_getEntryCrc(JNIEnv *env, jclass cls, jlong zentry)
-{
- jzentry *ze = jlong_to_ptr(zentry);
- return (jlong)ze->crc & 0xffffffffUL;
-}
-
-JNIEXPORT jbyteArray JNICALL
-Java_java_util_zip_ZipFile_getCommentBytes(JNIEnv *env,
- jclass cls,
- jlong zfile)
-{
- jzfile *zip = jlong_to_ptr(zfile);
- jbyteArray jba = NULL;
-
- if (zip->comment != NULL) {
- if ((jba = (*env)->NewByteArray(env, zip->clen)) == NULL)
- return NULL;
- (*env)->SetByteArrayRegion(env, jba, 0, zip->clen, (jbyte*)zip->comment);
- }
- return jba;
-}
-
-JNIEXPORT jbyteArray JNICALL
-Java_java_util_zip_ZipFile_getEntryBytes(JNIEnv *env,
- jclass cls,
- jlong zentry, jint type)
-{
- jzentry *ze = jlong_to_ptr(zentry);
- int len = 0;
- jbyteArray jba = NULL;
- switch (type) {
- case java_util_zip_ZipFile_JZENTRY_NAME:
- if (ze->name != 0) {
- len = (int)ze->nlen;
- // Unlike for extra and comment, we never return null for
- // an (extremely rarely seen) empty name
- if ((jba = (*env)->NewByteArray(env, len)) == NULL)
- break;
- (*env)->SetByteArrayRegion(env, jba, 0, len, (jbyte *)ze->name);
- }
- break;
- case java_util_zip_ZipFile_JZENTRY_EXTRA:
- if (ze->extra != 0) {
- unsigned char *bp = (unsigned char *)&ze->extra[0];
- len = (bp[0] | (bp[1] << 8));
- if (len <= 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
- break;
- (*env)->SetByteArrayRegion(env, jba, 0, len, &ze->extra[2]);
- }
- break;
- case java_util_zip_ZipFile_JZENTRY_COMMENT:
- if (ze->comment != 0) {
- len = (int)strlen(ze->comment);
- if (len == 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
- break;
- (*env)->SetByteArrayRegion(env, jba, 0, len, (jbyte*)ze->comment);
- }
- break;
- }
- return jba;
-}
-
-JNIEXPORT jint JNICALL
-Java_java_util_zip_ZipFile_read(JNIEnv *env, jclass cls, jlong zfile,
- jlong zentry, jlong pos, jbyteArray bytes,
- jint off, jint len)
-{
- jzfile *zip = jlong_to_ptr(zfile);
- char *msg;
-
-#define BUFSIZE 8192
- /* copy via tmp stack buffer: */
- jbyte buf[BUFSIZE];
-
- if (len > BUFSIZE) {
- len = BUFSIZE;
- }
-
- ZIP_Lock(zip);
- len = ZIP_Read(zip, jlong_to_ptr(zentry), pos, buf, len);
- msg = zip->msg;
- ZIP_Unlock(zip);
- if (len != -1) {
- (*env)->SetByteArrayRegion(env, bytes, off, len, buf);
- }
-
- if (len == -1) {
- if (msg != 0) {
- ThrowZipException(env, msg);
- } else {
- char errmsg[128];
- sprintf(errmsg, "errno: %d, error: %s\n",
- errno, "Error reading ZIP file");
- JNU_ThrowIOExceptionWithLastError(env, errmsg);
- }
- }
-
- return len;
-}
-
-/*
- * Returns an array of strings representing the names of all entries
- * that begin with "META-INF/" (case ignored). This native method is
- * used in JarFile as an optimization when looking up manifest and
- * signature file entries. Returns null if no entries were found.
- */
-JNIEXPORT jobjectArray JNICALL
-Java_java_util_jar_JarFile_getMetaInfEntryNames(JNIEnv *env, jobject obj)
-{
- jlong zfile = (*env)->GetLongField(env, obj, jzfileID);
- jzfile *zip;
- int i, count;
- jobjectArray result = 0;
-
- if (zfile == 0) {
- JNU_ThrowByName(env,
- "java/lang/IllegalStateException", "zip file closed");
- return NULL;
- }
- zip = jlong_to_ptr(zfile);
-
- /* count the number of valid ZIP metanames */
- count = 0;
- if (zip->metanames != 0) {
- for (i = 0; i < zip->metacount; i++) {
- if (zip->metanames[i] != 0) {
- count++;
- }
- }
- }
-
- /* If some names were found then build array of java strings */
- if (count > 0) {
- jclass cls = JNU_ClassString(env);
- CHECK_NULL_RETURN(cls, NULL);
- result = (*env)->NewObjectArray(env, count, cls, 0);
- CHECK_NULL_RETURN(result, NULL);
- if (result != 0) {
- for (i = 0; i < count; i++) {
- jstring str = (*env)->NewStringUTF(env, zip->metanames[i]);
- if (str == 0) {
- break;
- }
- (*env)->SetObjectArrayElement(env, result, i, str);
- (*env)->DeleteLocalRef(env, str);
- }
- }
- }
- return result;
-}
-
-JNIEXPORT jstring JNICALL
-Java_java_util_zip_ZipFile_getZipMessage(JNIEnv *env, jclass cls, jlong zfile)
-{
- jzfile *zip = jlong_to_ptr(zfile);
- char *msg = zip->msg;
- if (msg == NULL) {
- return NULL;
- }
- return JNU_NewStringPlatform(env, msg);
-}
--- a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -40,7 +40,6 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
-import sun.misc.ManagedLocalsThread;
/**
* A multi-threaded implementation of Selector for Windows.
@@ -404,13 +403,14 @@
}
// Represents a helper thread used for select.
- private final class SelectThread extends ManagedLocalsThread {
+ private final class SelectThread extends Thread {
private final int index; // index of this thread
final SubSelector subSelector;
private long lastRun = 0; // last run number
private volatile boolean zombie;
// Creates a new thread
private SelectThread(int i) {
+ super(null, null, "SelectorHelper", 0, false);
this.index = i;
this.subSelector = new SubSelector(i);
//make sure we wait for next round of poll
--- a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java Wed Jul 05 21:09:54 2017 +0200
@@ -38,6 +38,7 @@
import java.security.*;
import java.util.*;
import java.util.Locale;
+import java.util.concurrent.LinkedBlockingQueue;
import sun.awt.AWTAccessor;
import sun.awt.AppContext;
import sun.awt.EmbeddedFrame;
@@ -45,7 +46,6 @@
import sun.misc.ManagedLocalsThread;
import sun.misc.MessageUtils;
import sun.misc.PerformanceLogger;
-import sun.misc.Queue;
import sun.security.util.SecurityConstants;
/**
@@ -247,8 +247,7 @@
/**
* AppletEvent Queue
*/
- private Queue<Integer> queue = null;
-
+ private LinkedBlockingQueue<Integer> queue = null;
public synchronized void addAppletListener(AppletListener l) {
listeners = AppletEventMulticaster.add(listeners, l);
@@ -276,10 +275,9 @@
synchronized(this) {
if (queue == null) {
//System.out.println("SEND0= " + id);
- queue = new Queue<>();
+ queue = new LinkedBlockingQueue<>();
}
- Integer eventId = Integer.valueOf(id);
- queue.enqueue(eventId);
+ boolean inserted = queue.add(id);
notifyAll();
}
if (id == APPLET_QUIT) {
@@ -303,8 +301,8 @@
while (queue == null || queue.isEmpty()) {
wait();
}
- Integer eventId = queue.dequeue();
- return new AppletEvent(this, eventId.intValue(), null);
+ int eventId = queue.take();
+ return new AppletEvent(this, eventId, null);
}
boolean emptyEventQueue() {
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java Wed Jul 05 21:09:54 2017 +0200
@@ -156,8 +156,6 @@
// rewritten to avoid division:
|| (width * heightSubPixel) >
((edgeSumDeltaY - heightSubPixel) << BLOCK_SIZE_LG);
-// ((edgeSumDeltaY - heightSubPixel) * RLE_THRESHOLD);
-// ((edgeSumDeltaY - heightSubPixel) << BLOCK_TH_LG);
if (doTrace && !useRLE) {
final float meanCrossings
@@ -293,8 +291,10 @@
// update row index to current position:
rowAAChunkIndex[row] = pos;
- // determine need array size (may overflow):
- final long needSize = pos + (px_bbox1 - px0);
+ // determine need array size:
+ // for RLE encoding, position must be aligned to 4 bytes (int):
+ // align - 1 = 3 so add +3 and round-off by mask ~3 = -4
+ final long needSize = pos + ((px_bbox1 - px0 + 3) & -4);
// update next position (bytes):
rowAAChunkPos = needSize;
@@ -401,8 +401,7 @@
// determine need array size:
// pessimistic: max needed size = deltaX x 4 (1 int)
- final int maxLen = (to - from);
- final long needSize = initialPos + (maxLen << 2);
+ final long needSize = initialPos + ((to - from) << 2);
// update row data:
OffHeapArray _rowAAChunk = rowAAChunk;
@@ -465,6 +464,13 @@
// note: last pixel exclusive (>= 0)
// note: it should check X is smaller than 23bits (overflow)!
+ // check address alignment to 4 bytes:
+ if (doCheckUnsafe) {
+ if ((addr_off & 3) != 0) {
+ MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off);
+ }
+ }
+
// special case to encode entries into a single int:
if (val == 0) {
_unsafe.putInt(addr_off,
@@ -521,6 +527,13 @@
// note: last pixel exclusive (>= 0)
// note: it should check X is smaller than 23bits (overflow)!
+ // check address alignment to 4 bytes:
+ if (doCheckUnsafe) {
+ if ((addr_off & 3) != 0) {
+ MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off);
+ }
+ }
+
// special case to encode entries into a single int:
if (val == 0) {
_unsafe.putInt(addr_off,
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java Wed Jul 05 21:09:54 2017 +0200
@@ -40,6 +40,8 @@
// log misc.Unsafe alloc/realloc/free
static final boolean logUnsafeMalloc = enableLogs
&& MarlinProperties.isLogUnsafeMalloc();
+ // do check unsafe alignment:
+ static final boolean doCheckUnsafe = false;
// do statistics
static final boolean doStats = enableLogs && MarlinProperties.isDoStats();
--- a/jdk/src/java.logging/share/classes/java/util/logging/LogRecord.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.logging/share/classes/java/util/logging/LogRecord.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,10 +29,12 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.io.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.time.Clock;
import java.util.function.Predicate;
-import static jdk.internal.logger.SimpleConsoleLogger.skipLoggingFrame;
+import static jdk.internal.logger.SimpleConsoleLogger.isFilteredFrame;
/**
* LogRecord objects are used to pass logging requests between
@@ -685,7 +687,12 @@
* CallerFinder is a stateful predicate.
*/
static final class CallerFinder implements Predicate<StackWalker.StackFrame> {
- static final StackWalker WALKER = StackWalker.getInstance();
+ private static final StackWalker WALKER;
+ static {
+ final PrivilegedAction<StackWalker> action =
+ () -> StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
+ WALKER = AccessController.doPrivileged(action);
+ }
/**
* Returns StackFrame of the caller's frame.
@@ -715,8 +722,9 @@
lookingForLogger = !isLoggerImplFrame(cname);
return false;
}
- // skip logging/logger infrastructure and reflection calls
- return !skipLoggingFrame(cname);
+ // Continue walking until we've found the relevant calling frame.
+ // Skips logging/logger infrastructure.
+ return !isFilteredFrame(t);
}
private boolean isLoggerImplFrame(String cname) {
--- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/Ber.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/Ber.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,7 +29,7 @@
import java.io.IOException;
import java.io.ByteArrayInputStream;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
* Base class that defines common fields, constants, and debug method.
--- a/jdk/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -44,7 +44,7 @@
import javax.naming.ldap.LdapContext;
import javax.security.auth.x500.X500Principal;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.provider.certpath.X509CertificatePair;
import sun.security.util.Cache;
import sun.security.util.Debug;
--- a/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java Wed Jul 05 21:09:54 2017 +0200
@@ -34,7 +34,7 @@
import javax.security.auth.Destroyable;
import javax.security.auth.RefreshFailedException;
import javax.security.auth.DestroyFailedException;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
* This class encapsulates a Kerberos ticket and associated
--- a/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -30,7 +30,7 @@
import javax.crypto.SecretKey;
import javax.security.auth.Destroyable;
import javax.security.auth.DestroyFailedException;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.krb5.Asn1Exception;
import sun.security.krb5.PrincipalName;
import sun.security.krb5.EncryptionKey;
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java Wed Jul 05 21:09:54 2017 +0200
@@ -26,7 +26,7 @@
package sun.security.jgss.krb5;
import org.ietf.jgss.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.jgss.GSSUtil;
import sun.security.jgss.GSSCaller;
import sun.security.jgss.spi.*;
@@ -1415,7 +1415,7 @@
@Override
public String toString() {
return "Kerberos session key: etype: " + key.getEType() + "\n" +
- new sun.misc.HexDumpEncoder().encodeBuffer(key.getBytes());
+ new HexDumpEncoder().encodeBuffer(key.getBytes());
}
}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java Wed Jul 05 21:09:54 2017 +0200
@@ -227,7 +227,7 @@
} catch (Exception e) {
if (DEBUG) {
System.out.println("Unable to parse eData field of KRB-ERROR:\n" +
- new sun.misc.HexDumpEncoder().encodeBuffer(data));
+ new sun.security.util.HexDumpEncoder().encodeBuffer(data));
}
IOException ioe = new IOException(
"Unable to parse eData field of KRB-ERROR");
@@ -237,7 +237,7 @@
} else {
if (DEBUG) {
System.out.println("Unknown eData field of KRB-ERROR:\n" +
- new sun.misc.HexDumpEncoder().encodeBuffer(data));
+ new sun.security.util.HexDumpEncoder().encodeBuffer(data));
}
}
}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java Wed Jul 05 21:09:54 2017 +0200
@@ -306,8 +306,8 @@
public static final boolean DEBUG =
java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction("sun.security.krb5.debug"));
- public static final sun.misc.HexDumpEncoder hexDumper =
- new sun.misc.HexDumpEncoder();
+ public static final sun.security.util.HexDumpEncoder hexDumper =
+ new sun.security.util.HexDumpEncoder();
static {
errMsgList = new Hashtable<Integer,String> ();
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java Wed Jul 05 21:09:54 2017 +0200
@@ -306,7 +306,7 @@
} else if (s2kparams.length == 0) {
sb.append("empty\n");
} else {
- sb.append(new sun.misc.HexDumpEncoder()
+ sb.append(new sun.security.util.HexDumpEncoder()
.encodeBuffer(s2kparams));
}
}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java Wed Jul 05 21:09:54 2017 +0200
@@ -40,7 +40,7 @@
import java.nio.charset.Charset;
import java.nio.CharBuffer;
import java.nio.ByteBuffer;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.krb5.Confounder;
import sun.security.krb5.internal.crypto.KeyUsage;
import sun.security.krb5.KrbCryptoException;
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/util/AbstractSaslImpl.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/util/AbstractSaslImpl.java Wed Jul 05 21:09:54 2017 +0200
@@ -33,7 +33,7 @@
import java.util.logging.Logger;
import java.util.logging.Level;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
* The base class used by client and server implementations of SASL
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java Wed Jul 05 21:09:54 2017 +0200
@@ -44,7 +44,7 @@
import sun.security.krb5.*;
import sun.security.jgss.krb5.Krb5Util;
import sun.security.krb5.Credentials;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
* This {@code LoginModule} authenticates users using
--- a/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java Wed Jul 05 21:09:54 2017 +0200
@@ -64,6 +64,6 @@
public String toString() {
return "AuthorizationDataEntry: type="+type+", data=" +
data.length + " bytes:\n" +
- new sun.misc.HexDumpEncoder().encodeBuffer(data);
+ new sun.security.util.HexDumpEncoder().encodeBuffer(data);
}
}
--- a/jdk/test/TEST.groups Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/TEST.groups Wed Jul 05 21:09:54 2017 +0200
@@ -95,16 +95,19 @@
-:jdk_concurrent \
-:jdk_stream
-# java.util.concurrent (JSR-166)
+# All collections, core and concurrent
+jdk_collections = \
+ :jdk_collections_core \
+ :jdk_concurrent
+
+# java.util.concurrent
+# Includes concurrent collections plus other stuff
# Maintained by JSR-166 EG (Doug Lea et al)
-# Deque and PriorityQueue are also generally maintained by JSR-166
jdk_concurrent = \
- java/util/concurrent \
- java/util/Deque \
- java/util/PriorityQueue
+ java/util/concurrent
-# Java Collections Framework
-jdk_collections = \
+# Java Collections Framework core classes
+jdk_collections_core = \
java/util/AbstractCollection \
java/util/AbstractList \
java/util/AbstractMap \
@@ -114,19 +117,22 @@
java/util/BitSet \
java/util/Collection \
java/util/Collections \
+ java/util/Comparator \
+ java/util/Deque \
java/util/EnumMap \
java/util/EnumSet \
- java/util/Comparator \
- java/util/Iterator \
java/util/HashMap \
+ java/util/HashSet \
java/util/Hashtable \
java/util/IdentityHashMap \
- java/util/List \
+ java/util/Iterator \
java/util/LinkedHashMap \
java/util/LinkedHashSet \
java/util/LinkedList \
+ java/util/List \
java/util/Map \
java/util/NavigableMap \
+ java/util/PriorityQueue \
java/util/TimSort \
java/util/TreeMap \
java/util/Vector \
--- a/jdk/test/com/oracle/security/ucrypto/TestCICOWithGCMAndAAD.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/com/oracle/security/ucrypto/TestCICOWithGCMAndAAD.java Wed Jul 05 21:09:54 2017 +0200
@@ -65,7 +65,10 @@
byte[] aad2 = aad.clone();
aad2[50]++;
- GCMParameterSpec spec = new GCMParameterSpec(128, new byte[16]);
+ byte[] iv = new byte[16];
+ rdm.nextBytes(iv);
+
+ GCMParameterSpec spec = new GCMParameterSpec(128, iv);
Cipher encCipher = Cipher.getInstance("AES/GCM/NoPadding", p);
encCipher.init(Cipher.ENCRYPT_MODE, key, spec);
encCipher.updateAAD(aad);
--- a/jdk/test/com/oracle/security/ucrypto/TestGCMKeyAndIvCheck.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/com/oracle/security/ucrypto/TestGCMKeyAndIvCheck.java Wed Jul 05 21:09:54 2017 +0200
@@ -126,7 +126,11 @@
}
// Now try to encrypt again using a different parameter; should work
- c.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, new byte[30]));
+ byte[] rdm_iv = new byte[30];
+ Random rdm = new Random();
+ rdm.nextBytes(rdm_iv);
+
+ c.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, rdm_iv));
c.updateAAD(AAD);
c.doFinal(PT);
// subsequent encryption should fail unless re-init w/ different key+iv
--- a/jdk/test/com/sun/crypto/provider/KeyAgreement/DHKeyAgreement2.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/com/sun/crypto/provider/KeyAgreement/DHKeyAgreement2.java Wed Jul 05 21:09:54 2017 +0200
@@ -25,7 +25,6 @@
* @test
* @bug 7146728
* @summary DHKeyAgreement2
- * @modules java.base/sun.misc
* @author Jan Luehe
*/
@@ -38,8 +37,6 @@
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
-import sun.misc.HexDumpEncoder;
-
/**
* This test utility executes the Diffie-Hellman key agreement protocol
* between 2 parties: Alice and Bob.
--- a/jdk/test/com/sun/jdi/SuspendThreadTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/com/sun/jdi/SuspendThreadTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -42,6 +42,7 @@
class SuspendThreadTarg {
public static long count;
+ public static boolean active = true;
public static void bkpt() {
count++;
@@ -53,7 +54,7 @@
// We need this to be running so the bkpt
// can be hit immediately when it is enabled
// in the back-end.
- while(count >= 0) {
+ while(active) {
bkpt();
}
System.out.println("Goodbye from SuspendThreadTarg, count = " + count);
@@ -82,9 +83,9 @@
// to guard against spurious wakeups from bkptSignal.wait()
boolean signalSent;
// signal that a breakpoint has happened
- Object bkptSignal = new Object() {};
+ final private Object bkptSignal = new Object() {};
BreakpointRequest bkptRequest;
- Field debuggeeCountField;
+ Field debuggeeCountField, debuggeeActiveField;
// When we get a bkpt we want to disable the request,
// resume the debuggee, and then re-enable the request
@@ -119,65 +120,71 @@
/********** test core **********/
protected void runTests() throws Exception {
- /*
- * Get to the top of main()
- * to determine targetClass and mainThread
- */
- BreakpointEvent bpe = startToMain("SuspendThreadTarg");
- targetClass = (ClassType)bpe.location().declaringType();
- mainThread = bpe.thread();
- EventRequestManager erm = vm().eventRequestManager();
+ try {
+ /*
+ * Get to the top of main()
+ * to determine targetClass and mainThread
+ */
+ BreakpointEvent bpe = startToMain("SuspendThreadTarg");
+ targetClass = (ClassType)bpe.location().declaringType();
+ mainThread = bpe.thread();
+ EventRequestManager erm = vm().eventRequestManager();
- Location loc1 = findMethod(targetClass, "bkpt", "()V").location();
+ Location loc1 = findMethod(targetClass, "bkpt", "()V").location();
- bkptRequest = erm.createBreakpointRequest(loc1);
+ bkptRequest = erm.createBreakpointRequest(loc1);
- // Without this, it is a SUSPEND_ALL bkpt and the test will pass
- bkptRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
- bkptRequest.enable();
+ // Without this, it is a SUSPEND_ALL bkpt and the test will pass
+ bkptRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+ bkptRequest.enable();
- debuggeeCountField = targetClass.fieldByName("count");
- try {
- addListener (this);
- } catch (Exception ex){
- ex.printStackTrace();
- failure("failure: Could not add listener");
- throw new Exception("SuspendThreadTest: failed", ex);
- }
+ debuggeeCountField = targetClass.fieldByName("count");
+ debuggeeActiveField = targetClass.fieldByName("active");
+ try {
+ addListener (this);
+ } catch (Exception ex){
+ ex.printStackTrace();
+ failure("failure: Could not add listener");
+ throw new Exception("SuspendThreadTest: failed", ex);
+ }
- int prevBkptCount;
- vm().resume();
- synchronized (bkptSignal) {
- while (bkptCount < maxBkpts) {
- prevBkptCount = bkptCount;
- // If we don't get a bkpt within 5 secs,
- // the test fails
- signalSent = false;
- do {
- try {
- bkptSignal.wait(5000);
- } catch (InterruptedException ee) {
+ int prevBkptCount;
+ vm().resume();
+ synchronized (bkptSignal) {
+ while (bkptCount < maxBkpts) {
+ prevBkptCount = bkptCount;
+ // If we don't get a bkpt within 5 secs,
+ // the test fails
+ signalSent = false;
+ do {
+ try {
+ bkptSignal.wait(5000);
+ } catch (InterruptedException ee) {
+ }
+ } while (signalSent == false);
+ if (prevBkptCount == bkptCount) {
+ failure("failure: test hung");
+ break;
}
- } while (signalSent == false);
- if (prevBkptCount == bkptCount) {
- failure("failure: test hung");
- break;
}
}
- }
- println("done with loop");
- bkptRequest.disable();
- removeListener(this);
-
+ println("done with loop");
+ bkptRequest.disable();
+ removeListener(this);
- /*
- * deal with results of test
- * if anything has called failure("foo") testFailed will be true
- */
- if (!testFailed) {
- println("SuspendThreadTest: passed");
- } else {
- throw new Exception("SuspendThreadTest: failed");
+ /*
+ * deal with results of test
+ * if anything has called failure("foo") testFailed will be true
+ */
+ if (!testFailed) {
+ println("SuspendThreadTest: passed");
+ } else {
+ throw new Exception("SuspendThreadTest: failed");
+ }
+ } finally {
+ if (targetClass != null && debuggeeActiveField != null) {
+ targetClass.setValue(debuggeeActiveField, vm().mirrorOf(false));
+ }
}
}
}
--- a/jdk/test/com/sun/jndi/ldap/Base64Test.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/com/sun/jndi/ldap/Base64Test.java Wed Jul 05 21:09:54 2017 +0200
@@ -164,7 +164,7 @@
private static void deserialize(byte[] bytes) throws Exception {
//System.out.println("\nSerialized RefAddr object: ");
- //System.out.println(new sun.misc.HexDumpEncoder().encode(bytes));
+ //System.out.println(new sun.security.util.HexDumpEncoder().encode(bytes));
ObjectInputStream objectStream =
new ObjectInputStream(new ByteArrayInputStream(bytes));
--- a/jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -25,13 +25,14 @@
* @test
* @bug 6911951 7150092
* @summary NTLM should be a supported Java SASL mechanism
- * @modules java.base/sun.misc
+ * @modules java.base/sun.security.util
* java.security.sasl
*/
import java.io.IOException;
import javax.security.sasl.*;
import javax.security.auth.callback.*;
import java.util.*;
+import sun.security.util.HexDumpEncoder;
public class NTLMTest {
@@ -311,7 +312,7 @@
byte[] response = (clnt.hasInitialResponse()
? clnt.evaluateChallenge(EMPTY) : EMPTY);
System.out.println("Initial:");
- new sun.misc.HexDumpEncoder().encodeBuffer(response, System.out);
+ new HexDumpEncoder().encodeBuffer(response, System.out);
byte[] challenge;
while (!clnt.isComplete() || !srv.isComplete()) {
@@ -319,12 +320,12 @@
response = null;
if (challenge != null) {
System.out.println("Challenge:");
- new sun.misc.HexDumpEncoder().encodeBuffer(challenge, System.out);
+ new HexDumpEncoder().encodeBuffer(challenge, System.out);
response = clnt.evaluateChallenge(challenge);
}
if (response != null) {
System.out.println("Response:");
- new sun.misc.HexDumpEncoder().encodeBuffer(response, System.out);
+ new HexDumpEncoder().encodeBuffer(response, System.out);
}
}
--- a/jdk/test/java/beans/EventHandler/Test6277246.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/beans/EventHandler/Test6277246.java Wed Jul 05 21:09:54 2017 +0200
@@ -39,7 +39,7 @@
Class container = Class.forName("java.lang.Class");
Class parameter = Class.forName("java.lang.String");
Method method = container.getMethod("forName", parameter);
- Object[] arglist = new Object[] {"sun.misc.BASE64Encoder"};
+ Object[] arglist = new Object[] {"sun.security.x509.X509CertInfo"};
EventHandler eh = new EventHandler(Test6277246.class, "forName", "", "forName");
Object object = eh.invoke(null, method, arglist);
throw new Error((object != null) ? "test failure" : "test error");
--- a/jdk/test/java/beans/Introspector/Test6277246.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/beans/Introspector/Test6277246.java Wed Jul 05 21:09:54 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 6277246
* @summary Tests problem with java.beans use of reflection
- * @modules java.base/sun.misc
+ * @modules java.base/sun.security.x509
* java.desktop
* @run main/othervm Test6277246
* @author Jeff Nisewanger
@@ -36,11 +36,10 @@
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.lang.reflect.Method;
-import sun.misc.BASE64Encoder;
public class Test6277246 {
public static void main(String[] args) throws IntrospectionException {
- Class type = BASE64Encoder.class;
+ Class type = sun.security.x509.X509CertInfo.class;
System.setSecurityManager(new SecurityManager());
BeanInfo info = Introspector.getBeanInfo(type);
for (MethodDescriptor md : info.getMethodDescriptors()) {
@@ -48,7 +47,7 @@
System.out.println(method);
String name = method.getDeclaringClass().getName();
- if (name.startsWith("sun.misc.")) {
+ if (name.startsWith("sun.")) {
throw new Error("found inaccessible method");
}
}
--- a/jdk/test/java/beans/Statement/Test6224433.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/beans/Statement/Test6224433.java Wed Jul 05 21:09:54 2017 +0200
@@ -36,7 +36,7 @@
System.setSecurityManager(new SecurityManager());
Class target = Test6224433.class;
String method = "forName";
- String[] params = {"sun.misc.BASE64Encoder"};
+ String[] params = {"sun.security.x509.X509CertInfo"};
if (null != new Expression(target, method, params).getValue())
throw new Error("failure: bug exists");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/PushbackReader/ReadCloseRaceNPE.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,115 @@
+/*
+ * 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 8143394
+ * @summary Check for NullPointerException in race between read() and close().
+ */
+import java.io.CharArrayReader;
+import java.io.IOException;
+import java.io.PushbackReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+public class ReadCloseRaceNPE {
+
+ private static final int BUF_SIZE = 1000;
+ private static final long TIMEOUT_MS = 3000;
+
+ private static final List<Exception> failures = new ArrayList<>();
+
+ private static void testReader(final Supplier<Reader> readerSupplier)
+ throws InterruptedException {
+ AtomicReference<Reader> readerRef =
+ new AtomicReference<>(readerSupplier.get());
+
+ AtomicBoolean isFinished = new AtomicBoolean();
+
+ Runnable readTask = () -> {
+ long startTime = System.currentTimeMillis();
+ while (System.currentTimeMillis() - startTime < TIMEOUT_MS) {
+ try {
+ readerRef.get().read();
+ } catch (Exception e) {
+ if (!(e instanceof IOException)) {
+ failures.add(e);
+ break;
+ }
+ readerRef.set(readerSupplier.get());
+ }
+ }
+ isFinished.set(true);
+ };
+
+ Runnable closeTask = () -> {
+ while (!isFinished.get()) {
+ try {
+ readerRef.get().close();
+ } catch (Exception e) {
+ if (!(e instanceof IOException)) {
+ e.printStackTrace();
+ }
+ }
+ }
+ };
+
+ Thread readThread = new Thread(readTask);
+ Thread closeThread = new Thread(closeTask);
+
+ readThread.start();
+ closeThread.start();
+ readThread.join();
+ closeThread.join();
+ }
+
+ public static void main(String[] args) throws Throwable {
+ final String s = "Two riders were approaching.\\n";
+
+ Supplier<Reader> charPushbackReaderSupplier = () -> {
+ char buf[] = new char[s.length()];
+ s.getChars(0, s.length(), buf, 0);
+ CharArrayReader in = new CharArrayReader(buf);
+ return new PushbackReader(in, BUF_SIZE);
+ };
+
+ testReader(charPushbackReaderSupplier);
+
+ Supplier<Reader> stringPushbackReaderSupplier = () -> {
+ StringReader in = new StringReader(s);
+ return new PushbackReader(in, BUF_SIZE);
+ };
+
+ testReader(stringPushbackReaderSupplier);
+
+ if (!failures.isEmpty()) {
+ failures.stream().forEach((x) -> ((Exception) x).printStackTrace());
+ throw new RuntimeException("PushbackReaderNPE failed");
+ }
+ }
+}
--- a/jdk/test/java/lang/StackWalker/MultiThreadStackWalk.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/lang/StackWalker/MultiThreadStackWalk.java Wed Jul 05 21:09:54 2017 +0200
@@ -328,7 +328,7 @@
public void run() {
try {
- Env env = runTest(test, 2000, 10);
+ Env env = runTest(test, 1000, 10);
//waitWalkers(env);
checkTest(env, test);
} catch(Throwable t) {
--- a/jdk/test/java/lang/StackWalker/StackWalkTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/lang/StackWalker/StackWalkTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -236,6 +236,8 @@
if (didWalk) {
throw new IllegalStateException("StackWalkTest already used");
}
+ // Test may run into StackOverflow when running in -Xcomp mode on deep stack
+ assert stackDepth <= 1000;
assert markAt <= stackDepth : "markAt(" + markAt + ") > stackDepth("
+ stackDepth + ")";
System.out.print("runTest(" + swOptions
@@ -297,15 +299,15 @@
// Long stack, default maxDepth
StackWalkTest swt;
swt = new StackWalkTest();
- swt.runTest(StackWalkTest.class, "main", 2000, 10);
+ swt.runTest(StackWalkTest.class, "main", 1000, 10);
// Long stack, matching maxDepth
swt = new StackWalkTest(2000);
- swt.runTest(StackWalkTest.class, "main", 2000, 10);
+ swt.runTest(StackWalkTest.class, "main", 1000, 10);
// Long stack, maximum maxDepth
swt = new StackWalkTest(Integer.MAX_VALUE);
- swt.runTest(StackWalkTest.class, "main", 2000, 10);
+ swt.runTest(StackWalkTest.class, "main", 1000, 10);
//
// Single batch
@@ -349,7 +351,7 @@
swt.runTest(StackWalkTest.class, "main", 80, 40);
swt = new StackWalkTest(EnumSet.of(RETAIN_CLASS_REFERENCE), 50);
- swt.runTest(StackWalkTest.class, "main", 2000, 1048);
+ swt.runTest(StackWalkTest.class, "main", 1000, 524);
}
}
}
--- a/jdk/test/java/lang/System/Logger/default/DefaultLoggerTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/lang/System/Logger/default/DefaultLoggerTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -43,13 +43,16 @@
import java.lang.System.LoggerFinder;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.function.Function;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.stream.Stream;
/**
* @test
- * @bug 8140364
+ * @bug 8140364 8145686
* @summary Tests default loggers returned by System.getLogger, and in
* particular the implementation of the the System.Logger method
* performed by the default binding.
@@ -59,6 +62,8 @@
* @run main/othervm -Xbootclasspath/a:boot DefaultLoggerTest NOSECURITY
* @run main/othervm -Xbootclasspath/a:boot DefaultLoggerTest NOPERMISSIONS
* @run main/othervm -Xbootclasspath/a:boot DefaultLoggerTest WITHPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot DefaultLoggerTest WITHCUSTOMWRAPPERS
+ * @run main/othervm -Xbootclasspath/a:boot DefaultLoggerTest WITHREFLECTION
* @author danielfuchs
*/
public class DefaultLoggerTest {
@@ -232,7 +237,8 @@
static final AccessSystemLogger accessSystemLogger = new AccessSystemLogger();
- static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS,
+ WITHCUSTOMWRAPPERS, WITHREFLECTION};
static void setSecurityManager() {
if (System.getSecurityManager() == null) {
@@ -240,12 +246,179 @@
System.setSecurityManager(new SecurityManager());
}
}
+
+ /**
+ * The CustomLoggerWrapper makes it possible to verify that classes
+ * which implements System.Logger will be skipped when looking for
+ * the calling method.
+ */
+ static class CustomLoggerWrapper implements Logger {
+
+ Logger impl;
+ public CustomLoggerWrapper(Logger logger) {
+ this.impl = Objects.requireNonNull(logger);
+ }
+
+
+ @Override
+ public String getName() {
+ return impl.getName();
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return impl.isLoggable(level);
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle rb, String string, Throwable thrwbl) {
+ impl.log(level, rb, string, thrwbl);
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle rb, String string, Object... os) {
+ impl.log(level, rb, string, os);
+ }
+
+ @Override
+ public void log(Level level, Object o) {
+ impl.log(level, o);
+ }
+
+ @Override
+ public void log(Level level, String string) {
+ impl.log(level, string);
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> splr) {
+ impl.log(level, splr);
+ }
+
+ @Override
+ public void log(Level level, String string, Object... os) {
+ impl.log(level, string, os);
+ }
+
+ @Override
+ public void log(Level level, String string, Throwable thrwbl) {
+ impl.log(level, string, thrwbl);
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> splr, Throwable thrwbl) {
+ Logger.super.log(level, splr, thrwbl);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "(impl=" + impl + ")";
+ }
+
+ }
+
+ /**
+ * The ReflectionLoggerWrapper additionally makes it possible to verify
+ * that code which use reflection to call System.Logger will be skipped
+ * when looking for the calling method.
+ */
+ static class ReflectionLoggerWrapper implements Logger {
+
+ Logger impl;
+ public ReflectionLoggerWrapper(Logger logger) {
+ this.impl = Objects.requireNonNull(logger);
+ }
+
+ private Object invoke(Method m, Object... params) {
+ try {
+ return m.invoke(impl, params);
+ } catch (IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return impl.getName();
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return impl.isLoggable(level);
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle rb, String string, Throwable thrwbl) {
+ try {
+ invoke(System.Logger.class.getMethod(
+ "log", Level.class, ResourceBundle.class, String.class, Throwable.class),
+ level, rb, string, thrwbl);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle rb, String string, Object... os) {
+ try {
+ invoke(System.Logger.class.getMethod(
+ "log", Level.class, ResourceBundle.class, String.class, Object[].class),
+ level, rb, string, os);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public void log(Level level, String string) {
+ try {
+ invoke(System.Logger.class.getMethod(
+ "log", Level.class, String.class),
+ level, string);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public void log(Level level, String string, Object... os) {
+ try {
+ invoke(System.Logger.class.getMethod(
+ "log", Level.class, String.class, Object[].class),
+ level, string, os);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public void log(Level level, String string, Throwable thrwbl) {
+ try {
+ invoke(System.Logger.class.getMethod(
+ "log", Level.class, String.class, Throwable.class),
+ level, string, thrwbl);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+
+ @Override
+ public String toString() {
+ return super.toString() + "(impl=" + impl + ")";
+ }
+
+ }
+
public static void main(String[] args) {
if (args.length == 0)
args = new String[] {
"NOSECURITY",
"NOPERMISSIONS",
- "WITHPERMISSIONS"
+ "WITHPERMISSIONS",
+ "WITHCUSTOMWRAPPERS",
+ "WITHREFLECTION"
};
// 1. Obtain destination loggers directly from the LoggerFinder
@@ -276,6 +449,31 @@
allowControl.get().set(control);
}
break;
+ case WITHCUSTOMWRAPPERS:
+ System.out.println("\n*** With Security Manager, with control permission, using custom Wrappers\n");
+ setSecurityManager();
+ final boolean previous = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ test(CustomLoggerWrapper::new, true);
+ } finally {
+ allowControl.get().set(previous);
+ }
+ break;
+ case WITHREFLECTION:
+ System.out.println("\n*** With Security Manager,"
+ + " with control permission,"
+ + " using reflection while logging\n");
+ setSecurityManager();
+ final boolean before = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ test(ReflectionLoggerWrapper::new, true);
+ } finally {
+ allowControl.get().set(before);
+ }
+ break;
+
default:
throw new RuntimeException("Unknown test case: " + testCase);
}
@@ -284,6 +482,10 @@
}
public static void test(boolean hasRequiredPermissions) {
+ test(Function.identity(), hasRequiredPermissions);
+ }
+
+ public static void test(Function<Logger, Logger> wrapper, boolean hasRequiredPermissions) {
ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
final Map<Logger, String> loggerDescMap = new HashMap<>();
@@ -294,7 +496,7 @@
// - and AccessSystemLogger.getLogger("foo")
Logger sysLogger1 = null;
try {
- sysLogger1 = accessSystemLogger.getLogger("foo");
+ sysLogger1 = wrapper.apply(accessSystemLogger.getLogger("foo"));
loggerDescMap.put(sysLogger1, "AccessSystemLogger.getLogger(\"foo\")");
} catch (AccessControlException acx) {
if (hasRequiredPermissions) {
@@ -306,7 +508,7 @@
throw new RuntimeException("unexpected exception: " + acx, acx);
}
- Logger appLogger1 = System.getLogger("foo");
+ Logger appLogger1 = wrapper.apply(System.getLogger("foo"));
loggerDescMap.put(appLogger1, "System.getLogger(\"foo\");");
if (appLogger1 == sysLogger1) {
@@ -316,13 +518,13 @@
// 2. Test loggers returned by:
// - System.getLogger(\"foo\", loggerBundle)
// - and AccessSystemLogger.getLogger(\"foo\", loggerBundle)
- Logger appLogger2 =
- System.getLogger("foo", loggerBundle);
+ Logger appLogger2 = wrapper.apply(
+ System.getLogger("foo", loggerBundle));
loggerDescMap.put(appLogger2, "System.getLogger(\"foo\", loggerBundle)");
Logger sysLogger2 = null;
try {
- sysLogger2 = accessSystemLogger.getLogger("foo", loggerBundle);
+ sysLogger2 = wrapper.apply(accessSystemLogger.getLogger("foo", loggerBundle));
loggerDescMap.put(sysLogger2, "AccessSystemLogger.getLogger(\"foo\", loggerBundle)");
} catch (AccessControlException acx) {
if (hasRequiredPermissions) {
--- a/jdk/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/BaseDefaultLoggerFinderTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/BaseDefaultLoggerFinderTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -44,17 +44,21 @@
import java.lang.System.LoggerFinder;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
import jdk.internal.logger.DefaultLoggerFinder;
import jdk.internal.logger.SimpleConsoleLogger;
import sun.util.logging.PlatformLogger;
/**
* @test
- * @bug 8140364
+ * @bug 8140364 8145686
* @summary JDK implementation specific unit test for the base DefaultLoggerFinder.
* Tests the behavior of DefaultLoggerFinder and SimpleConsoleLogger
* implementation.
@@ -65,6 +69,8 @@
* @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest NOSECURITY
* @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest NOPERMISSIONS
* @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest WITHPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest WITHCUSTOMWRAPPERS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest WITHREFLECTION
* @author danielfuchs
*/
public class BaseDefaultLoggerFinderTest {
@@ -172,7 +178,8 @@
}
- static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS,
+ WITHCUSTOMWRAPPERS, WITHREFLECTION};
static void setSecurityManager() {
if (System.getSecurityManager() == null) {
@@ -261,12 +268,173 @@
return b.append(name).append("=").append(value).append('\n');
}
+ static class CustomLoggerWrapper implements Logger {
+
+ Logger impl;
+ public CustomLoggerWrapper(Logger logger) {
+ this.impl = Objects.requireNonNull(logger);
+ }
+
+
+ @Override
+ public String getName() {
+ return impl.getName();
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return impl.isLoggable(level);
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle rb, String string, Throwable thrwbl) {
+ impl.log(level, rb, string, thrwbl);
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle rb, String string, Object... os) {
+ impl.log(level, rb, string, os);
+ }
+
+ @Override
+ public void log(Level level, Object o) {
+ impl.log(level, o);
+ }
+
+ @Override
+ public void log(Level level, String string) {
+ impl.log(level, string);
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> splr) {
+ impl.log(level, splr);
+ }
+
+ @Override
+ public void log(Level level, String string, Object... os) {
+ impl.log(level, string, os);
+ }
+
+ @Override
+ public void log(Level level, String string, Throwable thrwbl) {
+ impl.log(level, string, thrwbl);
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> splr, Throwable thrwbl) {
+ Logger.super.log(level, splr, thrwbl);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "(impl=" + impl + ")";
+ }
+
+ }
+ /**
+ * The ReflectionLoggerWrapper additionally makes it possible to verify
+ * that code which use reflection to call System.Logger will be skipped
+ * when looking for the calling method.
+ */
+ static class ReflectionLoggerWrapper implements Logger {
+
+ Logger impl;
+ public ReflectionLoggerWrapper(Logger logger) {
+ this.impl = Objects.requireNonNull(logger);
+ }
+
+ private Object invoke(Method m, Object... params) {
+ try {
+ return m.invoke(impl, params);
+ } catch (IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return impl.getName();
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return impl.isLoggable(level);
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle rb, String string, Throwable thrwbl) {
+ try {
+ invoke(System.Logger.class.getMethod(
+ "log", Level.class, ResourceBundle.class, String.class, Throwable.class),
+ level, rb, string, thrwbl);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle rb, String string, Object... os) {
+ try {
+ invoke(System.Logger.class.getMethod(
+ "log", Level.class, ResourceBundle.class, String.class, Object[].class),
+ level, rb, string, os);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public void log(Level level, String string) {
+ try {
+ invoke(System.Logger.class.getMethod(
+ "log", Level.class, String.class),
+ level, string);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public void log(Level level, String string, Object... os) {
+ try {
+ invoke(System.Logger.class.getMethod(
+ "log", Level.class, String.class, Object[].class),
+ level, string, os);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public void log(Level level, String string, Throwable thrwbl) {
+ try {
+ invoke(System.Logger.class.getMethod(
+ "log", Level.class, String.class, Throwable.class),
+ level, string, thrwbl);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+
+ @Override
+ public String toString() {
+ return super.toString() + "(impl=" + impl + ")";
+ }
+
+ }
+
+
public static void main(String[] args) {
if (args.length == 0) {
args = new String[] {
//"NOSECURITY",
"NOPERMISSIONS",
- "WITHPERMISSIONS"
+ "WITHPERMISSIONS",
+ "WITHCUSTOMWRAPPERS",
+ "WITHREFLECTION"
};
}
Locale.setDefault(Locale.ENGLISH);
@@ -355,6 +523,40 @@
allowControl.get().set(control);
}
break;
+ case WITHCUSTOMWRAPPERS:
+ System.out.println("\n*** With Security Manager, with control permission and custom Wrapper\n");
+ System.out.println(TestLoggerFinder.conf.get());
+ setSecurityManager();
+ final boolean previous = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = getLoggerFinder(expectedClass);
+ if (!provider.getClass().getName().equals("BaseDefaultLoggerFinderTest$BaseLoggerFinder")) {
+ throw new RuntimeException("Unexpected provider: " + provider.getClass().getName());
+ }
+ test(provider, CustomLoggerWrapper::new, true);
+ } finally {
+ allowControl.get().set(previous);
+ }
+ break;
+ case WITHREFLECTION:
+ System.out.println("\n*** With Security Manager,"
+ + " with control permission,"
+ + " using reflection while logging\n");
+ System.out.println(TestLoggerFinder.conf.get());
+ setSecurityManager();
+ final boolean before = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = getLoggerFinder(expectedClass);
+ if (!provider.getClass().getName().equals("BaseDefaultLoggerFinderTest$BaseLoggerFinder")) {
+ throw new RuntimeException("Unexpected provider: " + provider.getClass().getName());
+ }
+ test(provider, ReflectionLoggerWrapper::new, true);
+ } finally {
+ allowControl.get().set(before);
+ }
+ break;
default:
throw new RuntimeException("Unknown test case: " + testCase);
}
@@ -363,17 +565,21 @@
}
public static void test(TestLoggerFinder provider, boolean hasRequiredPermissions) {
+ test(provider, Function.identity(), hasRequiredPermissions);
+ }
+
+ public static void test(TestLoggerFinder provider, Function<Logger, Logger> wrapper, boolean hasRequiredPermissions) {
ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
final Map<Logger, String> loggerDescMap = new HashMap<>();
- System.Logger sysLogger = accessSystemLogger.getLogger("foo");
+ System.Logger sysLogger = wrapper.apply(accessSystemLogger.getLogger("foo"));
loggerDescMap.put(sysLogger, "accessSystemLogger.getLogger(\"foo\")");
- System.Logger localizedSysLogger = accessSystemLogger.getLogger("fox", loggerBundle);
+ System.Logger localizedSysLogger = wrapper.apply(accessSystemLogger.getLogger("fox", loggerBundle));
loggerDescMap.put(localizedSysLogger, "accessSystemLogger.getLogger(\"fox\", loggerBundle)");
- System.Logger appLogger = System.getLogger("bar");
+ System.Logger appLogger = wrapper.apply(System.getLogger("bar"));
loggerDescMap.put(appLogger,"System.getLogger(\"bar\")");
- System.Logger localizedAppLogger = System.getLogger("baz", loggerBundle);
+ System.Logger localizedAppLogger = wrapper.apply(System.getLogger("baz", loggerBundle));
loggerDescMap.put(localizedAppLogger,"System.getLogger(\"baz\", loggerBundle)");
testLogger(provider, loggerDescMap, "foo", null, sysLogger, accessSystemLogger.getClass());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Thread/ITLConstructor.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,100 @@
+/*
+ * 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
+ * @summary Basic test for Thread(ThreadGroup,Runnable,String,long,boolean)
+ */
+
+public class ITLConstructor {
+ static InheritableThreadLocal<Integer> n = new InheritableThreadLocal<>() {
+ protected Integer initialValue() {
+ return 0;
+ }
+
+ protected Integer childValue(Integer parentValue) {
+ return parentValue + 1;
+ }
+ };
+
+ static final int CHILD_THREAD_COUNT = 10;
+
+ public static void main(String args[]) throws Exception {
+ test(true);
+ test(false);
+ }
+
+ static void test(boolean inherit) throws Exception {
+ // concurrent access to separate indexes is ok
+ int[] x = new int[CHILD_THREAD_COUNT];
+ Thread child = new Thread(Thread.currentThread().getThreadGroup(),
+ new AnotherRunnable(0, x, inherit),
+ "ITLConstructor-thread-"+(0),
+ 0,
+ inherit);
+ child.start();
+ child.join(); // waits for *all* threads to complete
+
+ // Check results
+ for(int i=0; i<CHILD_THREAD_COUNT; i++) {
+ int expectedValue = 1;
+ if (inherit)
+ expectedValue = i+1;
+
+ if (x[i] != expectedValue)
+ throw (new Exception("Got x[" + i + "] = " + x[i]
+ + ", expected: " + expectedValue));
+ }
+ }
+
+ static class AnotherRunnable implements Runnable {
+ final int threadId;
+ final int[] x;
+ final boolean inherit;
+ AnotherRunnable(int threadId, int[] x, boolean inherit) {
+ this.threadId = threadId;
+ this.x = x;
+ this.inherit = inherit;
+ }
+
+ public void run() {
+ int itlValue = n.get();
+
+ if (threadId < CHILD_THREAD_COUNT-1) {
+ Thread child = new Thread(Thread.currentThread().getThreadGroup(),
+ new AnotherRunnable(threadId+1, x, inherit),
+ "ITLConstructor-thread-" + (threadId+1),
+ 0,
+ inherit);
+ child.start();
+ try {
+ child.join();
+ } catch(InterruptedException e) {
+ throw(new RuntimeException("Interrupted", e));
+ }
+ }
+
+ x[threadId] = itlValue+1;
+ }
+ }
+}
--- a/jdk/test/java/lang/annotation/TypeAnnotationReflection.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/lang/annotation/TypeAnnotationReflection.java Wed Jul 05 21:09:54 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8004698 8007073 8022343 8054304 8058595
+ * @bug 8004698 8007073 8022343 8054304 8057804 8058595
* @summary Unit test for type annotations
*/
@@ -358,6 +358,31 @@
check(annos.length == 2);
check(((TypeAnno)annos[0]).value().equals("I1"));
check(args[0].getAnnotation(TypeAnno2.class).value().equals("I2"));
+
+ // check type args
+ Field f = TestParameterizedType.class.getDeclaredField("theField");
+ AnnotatedParameterizedType fType = (AnnotatedParameterizedType)f.getAnnotatedType();
+ args = fType.getAnnotatedActualTypeArguments();
+ check(args.length == 1);
+ annos = args[0].getAnnotations();
+ check(annos.length == 1);
+ check(((TypeAnno2)annos[0]).value().equals("Map Arg"));
+ check(args[0].getAnnotation(TypeAnno2.class).value().equals("Map Arg"));
+
+ // check outer type type args
+ fType = (AnnotatedParameterizedType)fType.getAnnotatedOwnerType();
+ args = fType.getAnnotatedActualTypeArguments();
+ check(args.length == 1);
+ annos = args[0].getAnnotations();
+ check(annos.length == 1);
+ check(((TypeAnno2)annos[0]).value().equals("String Arg"));
+ check(args[0].getAnnotation(TypeAnno2.class).value().equals("String Arg"));
+
+ // check outer type normal type annotations
+ annos = fType.getAnnotations();
+ check(annos.length == 1);
+ check(((TypeAnno)annos[0]).value().equals("FieldOuter"));
+ check(fType.getAnnotation(TypeAnno.class).value().equals("FieldOuter"));
}
private static void testWildcardType() throws Exception {
@@ -563,9 +588,12 @@
abstract class TestParameterizedType implements @TypeAnno("M") Map<@TypeAnno("S")String, @TypeAnno("I") @TypeAnno2("I2")Integer> {
public ParameterizedOuter<String>.ParameterizedInner<Integer> foo() {return null;}
public @TypeAnno("O") ParameterizedOuter<@TypeAnno("S1") @TypeAnno2("S2") String>.
- @TypeAnno("I") ParameterizedInner<@TypeAnno("I1") @TypeAnno2("I2")Integer> foo2() {
+ @TypeAnno("I") ParameterizedInner<@TypeAnno("I1") @TypeAnno2("I2")Integer> foo2() {
return null;
}
+
+ public @TypeAnno("FieldOuter") ParameterizedOuter<@TypeAnno2("String Arg") String>.
+ @TypeAnno("FieldInner")ParameterizedInner<@TypeAnno2("Map Arg")Map> theField;
}
class ParameterizedOuter <T> {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedOwnerType.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,282 @@
+/*
+ * 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 8058595
+ * @summary Test that AnnotatedType.getAnnotatedOwnerType() works as expected
+ *
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.Asserts
+ * @run main GetAnnotatedOwnerType
+ */
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+
+import jdk.testlibrary.Asserts;
+
+public class GetAnnotatedOwnerType<Dummy> {
+ public @TA("generic") GetAnnotatedOwnerType<String> . @TB("generic") Nested<Integer> genericField;
+ public @TA("raw") GetAnnotatedOwnerType . @TB("raw") Nested rawField;
+ public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("non-generic") Inner nonGeneric;
+ public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("generic") InnerGeneric<String> innerGeneric;
+ public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("raw") InnerGeneric innerRaw;
+ public Object anonymous = new Object() {};
+ public @TA("array") Dummy[] dummy;
+ public @TA("wildcard") GetAnnotatedOwnerType<?> wildcard;
+ public @TA("typevariable") Dummy tv;
+ public @TA("bad") GetAnnotatedOwnerType<@TA("good") GetAnnotatedOwnerType<String> . @TB("tb") Nested<Integer> > typeArgument;
+ public GetAnnotatedOwnerType< GetAnnotatedOwnerType<String> .
+ B .
+ C<Class<?>, ? extends @TA("complicated") Exception> .
+ D<Number> > [] complicated;
+
+ public static void main(String[] args) throws Exception {
+ testGeneric();
+ testRaw();
+ testNonGeneric();
+ testInnerGeneric();
+ testInnerRaw();
+
+ testLocalClass();
+ testAnonymousClass();
+
+ testArray();
+ testWildcard();
+ testTypeParameter();
+
+ testTypeArgument();
+ testComplicated();
+ }
+
+ public static void testGeneric() throws Exception {
+ Field f = GetAnnotatedOwnerType.class.getField("genericField");
+
+ // make sure inner is correctly annotated
+ AnnotatedType inner = f.getAnnotatedType();
+ Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "generic");
+ Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + inner.getAnnotations().length);
+
+ // make sure owner is correctly annotated, on the correct type
+ AnnotatedType outer = inner.getAnnotatedOwnerType();
+ Asserts.assertEquals(outer.getType(), ((ParameterizedType) f.getGenericType()).getOwnerType());
+ Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "generic");
+ Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + outer.getAnnotations().length);
+ }
+
+ public static void testRaw() throws Exception {
+ Field f = GetAnnotatedOwnerType.class.getField("rawField");
+
+ // make sure inner is correctly annotated
+ AnnotatedType inner = f.getAnnotatedType();
+ Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "raw");
+ Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + inner.getAnnotations().length);
+
+ // make sure owner is correctly annotated, on the correct type
+ AnnotatedType outer = inner.getAnnotatedOwnerType();
+ Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
+ Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "raw");
+ Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + outer.getAnnotations().length);
+ }
+
+ public static void testNonGeneric() throws Exception {
+ Field f = GetAnnotatedOwnerType.class.getField("nonGeneric");
+
+ // make sure inner is correctly annotated
+ AnnotatedType inner = f.getAnnotatedType();
+ Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "non-generic");
+ Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + inner.getAnnotations().length);
+
+ // make sure owner is correctly annotated, on the correct type
+ AnnotatedType outer = inner.getAnnotatedOwnerType();
+ Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
+ Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
+ Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + outer.getAnnotations().length);
+ }
+
+ public static void testInnerGeneric() throws Exception {
+ Field f = GetAnnotatedOwnerType.class.getField("innerGeneric");
+
+ // make sure inner is correctly annotated
+ AnnotatedType inner = f.getAnnotatedType();
+ Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "generic");
+ Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + inner.getAnnotations().length);
+
+ // make sure owner is correctly annotated, on the correct type
+ AnnotatedType outer = inner.getAnnotatedOwnerType();
+ Asserts.assertEquals(outer.getType(), ((ParameterizedType) f.getGenericType()).getOwnerType());
+ Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
+ Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + outer.getAnnotations().length);
+ }
+
+ public static void testInnerRaw() throws Exception {
+ Field f = GetAnnotatedOwnerType.class.getField("innerRaw");
+
+ // make sure inner is correctly annotated
+ AnnotatedType inner = f.getAnnotatedType();
+ Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "raw");
+ Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + inner.getAnnotations().length);
+
+ // make sure owner is correctly annotated, on the correct type
+ AnnotatedType outer = inner.getAnnotatedOwnerType();
+ Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
+ Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
+ Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + outer.getAnnotations().length);
+ }
+
+ public static void testLocalClass() throws Exception {
+ class ALocalClass {}
+ class OneMore {
+ public @TA("null") ALocalClass c;
+ }
+ testNegative(OneMore.class.getField("c").getAnnotatedType(), "Local class should return null");
+ }
+
+ public static void testAnonymousClass() throws Exception {
+ testNegative(GetAnnotatedOwnerType.class.getField("anonymous").getAnnotatedType(),
+ "Anonymous class should return null");
+ }
+
+ public static void testArray() throws Exception {
+ AnnotatedType t = GetAnnotatedOwnerType.class.getField("dummy").getAnnotatedType();
+ Asserts.assertTrue((t instanceof AnnotatedArrayType),
+ "Was expecting an AnnotatedArrayType " + t);
+ testNegative(t, "" + t + " should not have an annotated owner type");
+ }
+
+ public static void testWildcard() throws Exception {
+ AnnotatedType tt = GetAnnotatedOwnerType.class.getField("wildcard").getAnnotatedType();
+ AnnotatedType t = ((AnnotatedParameterizedType)tt).getAnnotatedActualTypeArguments()[0];
+ Asserts.assertTrue((t instanceof AnnotatedWildcardType),
+ "Was expecting an AnnotatedWildcardType " + t);
+ testNegative(t, "" + t + " should not have an annotated owner type");
+ }
+
+ public static void testTypeParameter() throws Exception {
+ AnnotatedType t = GetAnnotatedOwnerType.class.getField("tv").getAnnotatedType();
+ Asserts.assertTrue((t instanceof AnnotatedTypeVariable),
+ "Was expecting an AnnotatedTypeVariable " + t);
+ testNegative(t, "" + t + " should not have an annotated owner type");
+ }
+
+ public static void testTypeArgument() throws Exception {
+ AnnotatedType tt = GetAnnotatedOwnerType.class.getField("typeArgument").getAnnotatedType();
+ Asserts.assertEquals(tt.getAnnotation(TA.class).value(), "bad");
+ Asserts.assertTrue(tt.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + tt.getAnnotations().length);
+
+ // make sure inner is correctly annotated
+ AnnotatedType inner = ((AnnotatedParameterizedType)tt).getAnnotatedActualTypeArguments()[0];
+ Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "tb");
+ Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + inner.getAnnotations().length);
+
+ // make sure owner is correctly annotated
+ AnnotatedType outer = inner.getAnnotatedOwnerType();
+ Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "good");
+ Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + outer.getAnnotations().length);
+ }
+
+ public static void testComplicated() throws Exception {
+ Field f = GetAnnotatedOwnerType.class.getField("complicated");
+
+ // Outermost level
+ AnnotatedType t = f.getAnnotatedType();
+ Asserts.assertTrue((t instanceof AnnotatedArrayType),
+ "Was expecting an AnnotatedArrayType " + t);
+ testNegative(t, "" + t + " should not have an annotated owner type");
+ Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
+ + t.getAnnotations().length);
+
+ // Component type
+ t = ((AnnotatedArrayType)t).getAnnotatedGenericComponentType();
+ testNegative(t, "" + t + " should not have an annotated owner type");
+ Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
+ + t.getAnnotations().length);
+
+ // Type arg GetAnnotatedOwnerType<String>...D<Number>
+ t = ((AnnotatedParameterizedType)t).getAnnotatedActualTypeArguments()[0];
+ Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
+ + t.getAnnotations().length);
+
+ // C<Class<?>, ? extends ...>
+ t = t.getAnnotatedOwnerType();
+ Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
+ + t.getAnnotations().length);
+
+ // ? extends
+ t = ((AnnotatedParameterizedType)t).getAnnotatedActualTypeArguments()[1];
+ testNegative(t, "" + t + " should not have an annotated owner type");
+ Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
+ + t.getAnnotations().length);
+
+ // @TA("complicated") Exception
+ t = ((AnnotatedWildcardType)t).getAnnotatedUpperBounds()[0];
+ testNegative(t, "" + t + " should not have an annotated owner type");
+ Asserts.assertEquals(t.getAnnotation(TA.class).value(), "complicated");
+ Asserts.assertTrue(t.getAnnotations().length == 1, "expecting one (1) annotation, got: "
+ + t.getAnnotations().length);
+ }
+
+ private static void testNegative(AnnotatedType t, String msg) {
+ Asserts.assertNull(t.getAnnotatedOwnerType(), msg);
+ }
+
+ public class Nested<AlsoDummy> {}
+ public class B {
+ public class C<R, S> {
+ public class D<T> {
+ }
+ }
+ }
+
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface TA {
+ String value();
+ }
+
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface TB {
+ String value();
+ }
+}
+
+class GetAnnotatedOwnerTypeAuxilliary {
+ class Inner {}
+
+ class InnerGeneric<Dummy> {}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ref/CleanerTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,735 @@
+/*
+ * 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.lang.ref.Cleaner;
+import java.lang.ref.Reference;
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.Objects;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Semaphore;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import jdk.internal.misc.CleanerImpl.PhantomCleanable;
+import jdk.internal.misc.CleanerImpl.WeakCleanable;
+import jdk.internal.misc.CleanerImpl.SoftCleanable;
+
+import org.testng.Assert;
+import org.testng.TestNG;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @run testng/othervm -Xmx4m CleanerTest
+ */
+
+@Test
+public class CleanerTest {
+ // A common CleaningService used by the test for notifications
+ static final Cleaner COMMON = Cleaner.create();
+
+ /**
+ * Test that sequences of the various actions on a Reference
+ * and on the Cleanable instance have the desired result.
+ * The test cases are generated for each of phantom, weak and soft
+ * references.
+ * The sequence of actions includes all permutations to an initial
+ * list of actions including clearing the ref and resulting garbage
+ * collection actions on the reference and explicitly performing
+ * the cleaning action.
+ */
+ @Test
+ @SuppressWarnings("unchecked")
+ void testCleanableActions() {
+ Cleaner cleaner = Cleaner.create();
+
+ // Individually
+ generateCases(cleaner, c -> c.clearRef());
+ generateCases(cleaner, c -> c.doClean());
+
+ // Pairs
+ generateCases(cleaner, c -> c.doClean(), c -> c.clearRef());
+
+ CleanableCase s = setupPhantom(COMMON, cleaner);
+ cleaner = null;
+ Assert.assertTrue(checkCleaned(s.getSemaphore()),
+ "Cleaner cleanup should have occurred");
+ }
+
+ /**
+ * Test the jdk.internal.misc APIs with sequences of the various actions
+ * on a Reference and on the Cleanable instance have the desired result.
+ * The test cases are generated for each of phantom, weak and soft
+ * references.
+ * The sequence of actions includes all permutations to an initial
+ * list of actions including clearing the ref and resulting garbage
+ * collection actions on the reference, explicitly performing
+ * the cleanup and explicitly clearing the cleaning action.
+ */
+ @Test
+ @SuppressWarnings("unchecked")
+ void testRefSubtypes() {
+ Cleaner cleaner = Cleaner.create();
+
+ // Individually
+ generateCasesInternal(cleaner, c -> c.clearRef());
+ generateCasesInternal(cleaner, c -> c.doClean());
+ generateCasesInternal(cleaner, c -> c.doClear());
+
+ // Pairs
+ generateCasesInternal(cleaner,
+ c -> c.doClear(), c -> c.doClean());
+
+ // Triplets
+ generateCasesInternal(cleaner,
+ c -> c.doClear(), c -> c.doClean(), c -> c.clearRef());
+
+ generateExceptionCasesInternal(cleaner);
+
+ CleanableCase s = setupPhantom(COMMON, cleaner);
+ cleaner = null;
+ Assert.assertTrue(checkCleaned(s.getSemaphore()),
+ "Cleaner cleanup should have occurred");
+ }
+
+ /**
+ * Generate tests using the runnables for each of phantom, weak,
+ * and soft references.
+ * @param cleaner the cleaner
+ * @param runnables the sequence of actions on the test case
+ */
+ @SuppressWarnings("unchecked")
+ void generateCases(Cleaner cleaner, Consumer<CleanableCase>... runnables) {
+ generateCases(() -> setupPhantom(cleaner, null), runnables.length, runnables);
+ }
+
+ @SuppressWarnings("unchecked")
+ void generateCasesInternal(Cleaner cleaner, Consumer<CleanableCase>... runnables) {
+ generateCases(() -> setupPhantomSubclass(cleaner, null),
+ runnables.length, runnables);
+ generateCases(() -> setupWeakSubclass(cleaner, null),
+ runnables.length, runnables);
+ generateCases(() -> setupSoftSubclass(cleaner, null),
+ runnables.length, runnables);
+ }
+
+ @SuppressWarnings("unchecked")
+ void generateExceptionCasesInternal(Cleaner cleaner) {
+ generateCases(() -> setupPhantomSubclassException(cleaner, null),
+ 1, c -> c.clearRef());
+ generateCases(() -> setupWeakSubclassException(cleaner, null),
+ 1, c -> c.clearRef());
+ generateCases(() -> setupSoftSubclassException(cleaner, null),
+ 1, c -> c.clearRef());
+ }
+
+ /**
+ * Generate all permutations of the sequence of runnables
+ * and test each one.
+ * The permutations are generated using Heap, B.R. (1963) Permutations by Interchanges.
+ * @param generator the supplier of a CleanableCase
+ * @param n the first index to interchange
+ * @param runnables the sequence of actions
+ */
+ @SuppressWarnings("unchecked")
+ void generateCases(Supplier<CleanableCase> generator, int n,
+ Consumer<CleanableCase> ... runnables) {
+ if (n == 1) {
+ CleanableCase test = generator.get();
+ try {
+ verifyGetRef(test);
+
+ // Apply the sequence of actions on the Ref
+ for (Consumer<CleanableCase> c : runnables) {
+ c.accept(test);
+ }
+ verify(test);
+ } catch (Exception e) {
+ Assert.fail(test.toString(), e);
+ }
+ } else {
+ for (int i = 0; i < n - 1; i += 1) {
+ generateCases(generator, n - 1, runnables);
+ Consumer<CleanableCase> t = runnables[n - 1];
+ int ndx = ((n & 1) == 0) ? i : 0;
+ runnables[n - 1] = runnables[ndx];
+ runnables[ndx] = t;
+ }
+ generateCases(generator, n - 1, runnables);
+ }
+ }
+
+ /**
+ * Verify the test case.
+ * Any actions directly on the Reference or Cleanable have been executed.
+ * The CleanableCase under test is given a chance to do the cleanup
+ * by forcing a GC.
+ * The result is compared with the expected result computed
+ * from the sequence of operations on the Cleanable.
+ * The Cleanable itself should have been cleanedup.
+ *
+ * @param test A CleanableCase containing the references
+ */
+ void verify(CleanableCase test) {
+ System.out.println(test);
+ int r = test.expectedResult();
+
+ CleanableCase cc = setupPhantom(COMMON, test.getCleanable());
+ test.clearCleanable(); // release this hard reference
+
+ boolean result = checkCleaned(test.getSemaphore());
+ if (result) {
+ Assert.assertEquals(r, CleanableCase.EV_CLEAN,
+ "cleaned; but not expected");
+ } else {
+ Assert.assertNotEquals(r, CleanableCase.EV_CLEAN,
+ "not cleaned; expected cleaning");
+ }
+ Assert.assertTrue(checkCleaned(cc.getSemaphore()),
+ "The reference to the Cleanable should have been freed");
+ }
+
+ /**
+ * Verify that the reference.get works (or not) as expected.
+ * It handles the cases where UnsupportedOperationException is expected.
+ *
+ * @param test the CleanableCase
+ */
+ void verifyGetRef(CleanableCase test) {
+ Reference<?> r = (Reference) test.getCleanable();
+ try {
+ Object o = r.get();
+ Reference<?> expectedRef = test.getRef();
+ Assert.assertEquals(expectedRef.get(), o,
+ "Object reference incorrect");
+ if (r.getClass().getName().endsWith("CleanableRef")) {
+ Assert.fail("should not be able to get referent");
+ }
+ } catch (UnsupportedOperationException uoe) {
+ if (r.getClass().getName().endsWith("CleanableRef")) {
+ // Expected exception
+ } else {
+ Assert.fail("Unexpected exception from subclassed cleanable: " +
+ uoe.getMessage() + ", class: " + r.getClass());
+ }
+ }
+ }
+
+ /**
+ * Test that releasing the reference to the Cleaner service allows it to be
+ * be freed.
+ */
+ @Test
+ void testCleanerTermination() {
+ ReferenceQueue<Object> queue = new ReferenceQueue<>();
+ Cleaner service = Cleaner.create();
+
+ PhantomReference<Object> ref = new PhantomReference<>(service, queue);
+ System.gc();
+ // Clear the Reference to the cleaning service and force a gc.
+ service = null;
+ System.gc();
+ try {
+ Reference<?> r = queue.remove(1000L);
+ Assert.assertNotNull(r, "queue.remove timeout,");
+ Assert.assertEquals(r, ref, "Wrong Reference dequeued");
+ } catch (InterruptedException ie) {
+ System.out.printf("queue.remove Interrupted%n");
+ }
+ }
+
+ /**
+ * Check a set of semaphores having been released by cleanup handlers.
+ * Force a number of GC cycles to give the GC a chance to process
+ * all the References and for the cleanup actions to be run.
+ *
+ * @param semaphore a varargs list of Semaphores
+ * @return true if all of the semaphores have at least 1 permit,
+ * false otherwise.
+ */
+ static boolean checkCleaned(Semaphore... semaphore) {
+ long[] cycles = new long[semaphore.length];
+ long total = 0;
+ for (int cycle = 0; cycle < 20; cycle++) {
+ for (int i = 0; i < semaphore.length; i++) {
+ long count = semaphore[i].availablePermits();
+ if (count > 0 && cycles[i] == 0) {
+ System.out.printf(" Cleanable[%d] cleaned in cycle: %d%n", i, cycle);
+ cycles[i] = cycle;
+ total += 1;
+ }
+ }
+
+ if (total == semaphore.length) {
+ System.out.printf(" All cleanups done in cycle: %d, total: %d%n",
+ cycle, total);
+ for (int i = 0; i < semaphore.length; i++) {
+ long count = semaphore[i].availablePermits();
+ Assert.assertEquals(count, 1,
+ "Cleanable invoked more than once, semaphore " + i);
+ }
+ return true; // all references freed
+ }
+ // Force GC
+ memoryPressure();
+ }
+ // Not all objects have been cleaned
+
+ for (int i = 0; i < semaphore.length; i++) {
+ if (cycles[i] != 0) {
+ System.out.printf(" Cleanable[%d] cleaned in cycle: %d%n", i, cycles[i]);
+ } else {
+ System.out.printf(" Cleanable[%d] not cleaned%n", i);
+ }
+ }
+
+ return false; // Failing result
+ }
+
+ /**
+ * Create a CleanableCase for a PhantomReference.
+ * @param cleaner the cleaner to use
+ * @param obj an object or null to create a new Object
+ * @return a new CleanableCase preset with the object, cleanup, and semaphore
+ */
+ static CleanableCase setupPhantom(Cleaner cleaner, Object obj) {
+ if (obj == null) {
+ obj = new Object();
+ }
+ Semaphore s1 = new Semaphore(0);
+ Cleaner.Cleanable c1 = cleaner.register(obj, () -> s1.release());
+
+ return new CleanableCase(new PhantomReference<>(obj, null), c1, s1);
+ }
+
+ /**
+ * Create a CleanableCase for a PhantomReference.
+ * @param cleaner the cleaner to use
+ * @param obj an object or null to create a new Object
+ * @return a new CleanableCase preset with the object, cleanup, and semaphore
+ */
+ static CleanableCase setupPhantomSubclass(Cleaner cleaner, Object obj) {
+ if (obj == null) {
+ obj = new Object();
+ }
+ Semaphore s1 = new Semaphore(0);
+
+ Cleaner.Cleanable c1 = new PhantomCleanable<Object>(obj, cleaner) {
+ protected void performCleanup() {
+ s1.release();
+ }
+ };
+
+ return new CleanableCase(new PhantomReference<>(obj, null), c1, s1);
+ }
+ /**
+ * Create a CleanableCase for a WeakReference.
+ * @param cleaner the cleaner to use
+ * @param obj an object or null to create a new Object
+ * @return a new CleanableCase preset with the object, cleanup, and semaphore
+ */
+ static CleanableCase setupWeakSubclass(Cleaner cleaner, Object obj) {
+ if (obj == null) {
+ obj = new Object();
+ }
+ Semaphore s1 = new Semaphore(0);
+
+ Cleaner.Cleanable c1 = new WeakCleanable<Object>(obj, cleaner) {
+ protected void performCleanup() {
+ s1.release();
+ }
+ };
+
+ return new CleanableCase(new WeakReference<>(obj, null), c1, s1);
+ }
+
+ /**
+ * Create a CleanableCase for a SoftReference.
+ * @param cleaner the cleaner to use
+ * @param obj an object or null to create a new Object
+ * @return a new CleanableCase preset with the object, cleanup, and semaphore
+ */
+ static CleanableCase setupSoftSubclass(Cleaner cleaner, Object obj) {
+ if (obj == null) {
+ obj = new Object();
+ }
+ Semaphore s1 = new Semaphore(0);
+
+ Cleaner.Cleanable c1 = new SoftCleanable<Object>(obj, cleaner) {
+ protected void performCleanup() {
+ s1.release();
+ }
+ };
+
+ return new CleanableCase(new SoftReference<>(obj, null), c1, s1);
+ }
+
+ /**
+ * Create a CleanableCase for a PhantomReference.
+ * @param cleaner the cleaner to use
+ * @param obj an object or null to create a new Object
+ * @return a new CleanableCase preset with the object, cleanup, and semaphore
+ */
+ static CleanableCase setupPhantomSubclassException(Cleaner cleaner, Object obj) {
+ if (obj == null) {
+ obj = new Object();
+ }
+ Semaphore s1 = new Semaphore(0);
+
+ Cleaner.Cleanable c1 = new PhantomCleanable<Object>(obj, cleaner) {
+ protected void performCleanup() {
+ s1.release();
+ throw new RuntimeException("Exception thrown to cleaner thread");
+ }
+ };
+
+ return new CleanableCase(new PhantomReference<>(obj, null), c1, s1, true);
+ }
+
+ /**
+ * Create a CleanableCase for a WeakReference.
+ * @param cleaner the cleaner to use
+ * @param obj an object or null to create a new Object
+ * @return a new CleanableCase preset with the object, cleanup, and semaphore
+ */
+ static CleanableCase setupWeakSubclassException(Cleaner cleaner, Object obj) {
+ if (obj == null) {
+ obj = new Object();
+ }
+ Semaphore s1 = new Semaphore(0);
+
+ Cleaner.Cleanable c1 = new WeakCleanable<Object>(obj, cleaner) {
+ protected void performCleanup() {
+ s1.release();
+ throw new RuntimeException("Exception thrown to cleaner thread");
+ }
+ };
+
+ return new CleanableCase(new WeakReference<>(obj, null), c1, s1, true);
+ }
+
+ /**
+ * Create a CleanableCase for a SoftReference.
+ * @param cleaner the cleaner to use
+ * @param obj an object or null to create a new Object
+ * @return a new CleanableCase preset with the object, cleanup, and semaphore
+ */
+ static CleanableCase setupSoftSubclassException(Cleaner cleaner, Object obj) {
+ if (obj == null) {
+ obj = new Object();
+ }
+ Semaphore s1 = new Semaphore(0);
+
+ Cleaner.Cleanable c1 = new SoftCleanable<Object>(obj, cleaner) {
+ protected void performCleanup() {
+ s1.release();
+ throw new RuntimeException("Exception thrown to cleaner thread");
+ }
+ };
+
+ return new CleanableCase(new SoftReference<>(obj, null), c1, s1, true);
+ }
+
+ /**
+ * MemoryPressure allocates memory to force a gc and to clear SoftReferences.
+ */
+ static void memoryPressure() {
+ SoftReference<Object> soft = new SoftReference<>(new Object(), null);
+ Vector<Object> root = new Vector<>();
+ try {
+ long free = 0;
+ while (soft.get() != null) {
+ long[] extra = new long[50_000];
+ root.addElement(extra);
+ }
+ } catch (OutOfMemoryError mem) {
+ // ignore
+ root = null;
+ }
+ }
+
+ /**
+ * CleanableCase encapsulates the objects used for a test.
+ * The reference to the object is not held directly,
+ * but in a Reference object that can be cleared.
+ * The semaphore is used to count whether the cleanup occurred.
+ * It can be awaited on to determine that the cleanup has occurred.
+ * It can be checked for non-zero to determine if it was
+ * invoked or if it was invoked twice (a bug).
+ */
+ static class CleanableCase {
+
+ private volatile Reference<?> ref;
+ private volatile Cleaner.Cleanable cleanup;
+ private final Semaphore semaphore;
+ private final boolean throwsEx;
+ private final int[] events; // Sequence of calls to clean, clear, etc.
+ private volatile int eventNdx;
+
+ public static int EV_UNKNOWN = 0;
+ public static int EV_CLEAR = 1;
+ public static int EV_CLEAN = 2;
+ public static int EV_UNREF = 3;
+ public static int EV_CLEAR_CLEANUP = 4;
+
+
+ CleanableCase(Reference<Object> ref, Cleaner.Cleanable cleanup,
+ Semaphore semaphore) {
+ this.ref = ref;
+ this.cleanup = cleanup;
+ this.semaphore = semaphore;
+ this.throwsEx = false;
+ this.events = new int[4];
+ this.eventNdx = 0;
+ }
+ CleanableCase(Reference<Object> ref, Cleaner.Cleanable cleanup,
+ Semaphore semaphore,
+ boolean throwsEx) {
+ this.ref = ref;
+ this.cleanup = cleanup;
+ this.semaphore = semaphore;
+ this.throwsEx = throwsEx;
+ this.events = new int[4];
+ this.eventNdx = 0;
+ }
+
+ public Reference<?> getRef() {
+ return ref;
+ }
+
+ public void clearRef() {
+ addEvent(EV_UNREF);
+ ref.clear();
+ }
+
+ public Cleaner.Cleanable getCleanable() {
+ return cleanup;
+ }
+
+ public void doClean() {
+ try {
+ addEvent(EV_CLEAN);
+ cleanup.clean();
+ } catch (RuntimeException ex) {
+ if (!throwsEx) {
+ // unless it is known this case throws an exception, rethrow
+ throw ex;
+ }
+ }
+ }
+
+ public void doClear() {
+ addEvent(EV_CLEAR);
+ ((Reference)cleanup).clear();
+ }
+
+ public void clearCleanable() {
+ addEvent(EV_CLEAR_CLEANUP);
+ cleanup = null;
+ }
+
+ public Semaphore getSemaphore() {
+ return semaphore;
+ }
+
+ public boolean isCleaned() {
+ return semaphore.availablePermits() != 0;
+ }
+
+ private synchronized void addEvent(int e) {
+ events[eventNdx++] = e;
+ }
+
+ /**
+ * Computed the expected result from the sequence of events.
+ * If EV_CLEAR appears before anything else, it is cleared.
+ * If EV_CLEAN appears before EV_UNREF, then it is cleaned.
+ * Anything else is Unknown.
+ * @return EV_CLEAR if the cleanup should occur;
+ * EV_CLEAN if the cleanup should occur;
+ * EV_UNKNOWN if it is unknown.
+ */
+ public synchronized int expectedResult() {
+ // Test if EV_CLEAR appears before anything else
+ int clearNdx = indexOfEvent(EV_CLEAR);
+ int cleanNdx = indexOfEvent(EV_CLEAN);
+ int unrefNdx = indexOfEvent(EV_UNREF);
+ if (clearNdx < cleanNdx) {
+ return EV_CLEAR;
+ }
+ if (cleanNdx < clearNdx || cleanNdx < unrefNdx) {
+ return EV_CLEAN;
+ }
+ if (unrefNdx < eventNdx) {
+ return EV_CLEAN;
+ }
+
+ return EV_UNKNOWN;
+ }
+
+ private synchronized int indexOfEvent(int e) {
+ for (int i = 0; i < eventNdx; i++) {
+ if (events[i] == e) {
+ return i;
+ }
+ }
+ return eventNdx;
+ }
+
+ private static final String[] names =
+ {"UNKNOWN", "EV_CLEAR", "EV_CLEAN", "EV_UNREF", "EV_CLEAR_CLEANUP"};
+
+ public String eventName(int event) {
+ return names[event];
+ }
+
+ public synchronized String eventsString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ for (int i = 0; i < eventNdx; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(eventName(events[i]));
+ }
+ sb.append(']');
+ sb.append(", throwEx: ");
+ sb.append(throwsEx);
+ return sb.toString();
+ }
+
+ public String toString() {
+ return String.format("Case: %s, expect: %s, events: %s",
+ getRef().getClass().getName(),
+ eventName(expectedResult()), eventsString());
+ }
+ }
+
+
+ /**
+ * Example using a Cleaner to remove WeakKey references from a Map.
+ */
+ @Test
+ void testWeakKey() {
+ ConcurrentHashMap<WeakKey<String>, String> map = new ConcurrentHashMap<>();
+ Cleaner cleaner = Cleaner.create();
+ String key = new String("foo"); // ensure it is not interned
+ String data = "bar";
+
+ map.put(new WeakKey<>(key, cleaner, map), data);
+
+ WeakKey<String> k2 = new WeakKey<>(key, cleaner, map);
+
+ Assert.assertEquals(map.get(k2), data, "value should be found in the map");
+ key = null;
+ System.gc();
+ Assert.assertNotEquals(map.get(k2), data, "value should not be found in the map");
+
+ final int CYCLE_MAX = 30;
+ for (int i = 1; map.size() > 0 && i < CYCLE_MAX; i++) {
+ map.forEach( (k, v) -> System.out.printf(" k: %s, v: %s%n", k, v));
+ try {
+ Thread.sleep(10L);
+ } catch (InterruptedException ie) {}
+ }
+ Assert.assertEquals(map.size(), 0, "Expected map to be empty;");
+ cleaner = null;
+ }
+
+ /**
+ * Test sample class for WeakKeys in Map.
+ * @param <K> A WeakKey of type K
+ */
+ class WeakKey<K> extends WeakReference<K> {
+ private final int hash;
+ private final ConcurrentHashMap<WeakKey<K>, ?> map;
+ Cleaner.Cleanable cleanable;
+
+ public WeakKey(K key, Cleaner c, ConcurrentHashMap<WeakKey<K>, ?> map) {
+ super(key);
+ this.hash = key.hashCode();
+ this.map = map;
+ cleanable = new WeakCleanable<Object>(key, c) {
+ protected void performCleanup() {
+ map.remove(WeakKey.this);
+ }
+ };
+ }
+ public int hashCode() { return hash; }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof WeakKey)) return false;
+ K key = get();
+ if (key == null) return obj == this;
+ return key == ((WeakKey<?>)obj).get();
+ }
+
+ public String toString() {
+ return "WeakKey:" + Objects.toString(get() + ", cleanableRef: " +
+ ((Reference)cleanable).get());
+ }
+ }
+
+ /**
+ * Verify that casting a Cleanup to a Reference is not allowed to
+ * get the referent or clear the reference.
+ */
+ @Test
+ @SuppressWarnings("rawtypes")
+ void testReferentNotAvailable() {
+ Cleaner cleaner = Cleaner.create();
+ Semaphore s1 = new Semaphore(0);
+
+ Object obj = new String("a new string");
+ Cleaner.Cleanable c = cleaner.register(obj, () -> s1.release());
+ Reference r = (Reference) c;
+ try {
+ Object o = r.get();
+ System.out.printf("r: %s%n", Objects.toString(o));
+ Assert.fail("should not be able to get the referent from Cleanable");
+ } catch (UnsupportedOperationException uoe) {
+ // expected
+ }
+
+ try {
+ r.clear();
+ Assert.fail("should not be able to clear the referent from Cleanable");
+ } catch (UnsupportedOperationException uoe) {
+ // expected
+ }
+
+ obj = null;
+ Assert.assertTrue(checkCleaned(s1), "reference should be cleaned;");
+ cleaner = null;
+ }
+
+}
--- a/jdk/test/java/lang/reflect/Proxy/CharType.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/lang/reflect/Proxy/CharType.java Wed Jul 05 21:09:54 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 4346224
- * @summary Test against a typo in sun.misc.ProxyGenerator:
+ * @summary Test against a typo in ProxyGenerator:
* "java/lang/Character" should be used instead of
* "java/lang/Char".
*/
--- a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -22,13 +22,12 @@
*/
/* @test
- * @bug 8081678
+ * @bug 8081678 8131155
* @summary Tests for stream returning methods
* @library ../../util/stream/bootlib/java.base
* @build java.util.stream.OpTestCase
* @run testng/othervm NetworkInterfaceStreamTest
* @run testng/othervm -Djava.net.preferIPv4Stack=true NetworkInterfaceStreamTest
- * @key intermittent
*/
import org.testng.annotations.Test;
@@ -46,6 +45,8 @@
public class NetworkInterfaceStreamTest extends OpTestCase {
+ private final static boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows");
+
@Test
public void testNetworkInterfaces() throws SocketException {
Supplier<Stream<NetworkInterface>> ss = () -> {
@@ -74,7 +75,9 @@
}
private void getAllSubNetworkInterfaces(NetworkInterface ni, Collection<NetworkInterface> result) {
- result.add(ni);
+ if (isIncluded(ni)) {
+ result.add(ni);
+ }
for (NetworkInterface sni : Collections.list(ni.getSubInterfaces())) {
getAllSubNetworkInterfaces(sni, result);
@@ -114,7 +117,9 @@
public void testInetAddresses() throws SocketException {
Supplier<Stream<InetAddress>> ss = () -> {
try {
- return NetworkInterface.networkInterfaces().flatMap(NetworkInterface::inetAddresses);
+ return NetworkInterface.networkInterfaces()
+ .filter(ni -> isIncluded(ni))
+ .flatMap(NetworkInterface::inetAddresses);
}
catch (SocketException e) {
throw new RuntimeException(e);
@@ -132,5 +137,21 @@
.exercise();
}
+ /**
+ * Check if the input network interface should be included in the test. It is necessary to exclude
+ * "Teredo Tunneling Pseudo-Interface" whose configuration can be variable during a test run.
+ *
+ * @param ni a network interace
+ * @return false if it is a "Teredo Tunneling Pseudo-Interface", otherwise true.
+ */
+ private boolean isIncluded(NetworkInterface ni) {
+ if (!IS_WINDOWS) {
+ return true;
+ }
+
+ String dName = ni.getDisplayName();
+ return dName == null || !dName.contains("Teredo");
+ }
}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/text/Format/DateFormat/Bug8139572.java Wed Jul 05 21:09:54 2017 +0200
@@ -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.
+ */
+
+/*
+ * @test
+ * @bug 8139572
+ * @summary SimpleDateFormat parse month stand-alone format bug
+ * @compile -encoding utf-8 Bug8139572.java
+ * @run main Bug8139572
+ */
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+
+public class Bug8139572 {
+
+ private static final Locale RUSSIAN = new Locale("ru");
+ private static final Date SEPT12 = new GregorianCalendar(2015, Calendar.SEPTEMBER, 12).getTime();
+
+ private static final String[] PATTERNS = {
+ "L",
+ "dd L",
+ "dd L yy",
+ "dd L yyyy",
+ "LL",
+ "dd LL",
+ "dd LL yy",
+ "dd LL yyyy",
+ "LLL",
+ "dd LLL",
+ "dd LLL yy",
+ "dd LLL yyyy",
+ "LLLL",
+ "dd LLLL",
+ "dd LLLL yy",
+ "dd LLLL yyyy"
+ };
+
+ private static final String[] APPLIED = {
+ "9",
+ "12 09",
+ "12 09 15",
+ "12 09 2015",
+ "09",
+ "12 09",
+ "12 09 15",
+ "12 09 2015",
+ "сентября",
+ "12 сентября",
+ "12 сентября 15",
+ "12 сентября 2015",
+ "сентября",
+ "12 сентября",
+ "12 сентября 15",
+ "12 сентября 2015"
+ };
+
+ private static final String[] EXPECTED = {
+ "9",
+ "12 9",
+ "12 9 15",
+ "12 9 2015",
+ "09",
+ "12 09",
+ "12 09 15",
+ "12 09 2015",
+ "сент.",
+ "12 сент.",
+ "12 сент. 15",
+ "12 сент. 2015",
+ "сентябрь",
+ "12 сентябрь",
+ "12 сентябрь 15",
+ "12 сентябрь 2015"
+ };
+
+ public static void main(String[] args) throws ParseException {
+
+ for (int i = 0; i < PATTERNS.length; i++) {
+ SimpleDateFormat fmt = new SimpleDateFormat(PATTERNS[i], RUSSIAN);
+ Date standAloneDate = fmt.parse(APPLIED[i]);
+ String str = fmt.format(standAloneDate);
+ if (!EXPECTED[i].equals(str)) {
+ throw new RuntimeException("bad result: got '" + str + "', expected '" + EXPECTED[i] + "'");
+ }
+ }
+
+ SimpleDateFormat fmt = new SimpleDateFormat("", RUSSIAN);
+ for (int j = 0; j < PATTERNS.length; j++) {
+ fmt.applyPattern(PATTERNS[j]);
+ String str = fmt.format(SEPT12);
+ if (!EXPECTED[j].equals(str)) {
+ throw new RuntimeException("bad result: got '" + str + "', expected '" + EXPECTED[j] + "'");
+ }
+ }
+ }
+}
--- a/jdk/test/java/time/tck/java/time/TCKDuration.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKDuration.java Wed Jul 05 21:09:54 2017 +0200
@@ -2393,6 +2393,65 @@
}
//-----------------------------------------------------------------------
+ // dividedbyDur()
+ //-----------------------------------------------------------------------
+
+ @DataProvider(name="dividedByDur_provider")
+ Object[][] provider_dividedByDur() {
+ return new Object[][] {
+ {Duration.ofSeconds(0, 0), Duration.ofSeconds(1, 0), 0},
+ {Duration.ofSeconds(1, 0), Duration.ofSeconds(1, 0), 1},
+ {Duration.ofSeconds(6, 0), Duration.ofSeconds(3, 0), 2},
+ {Duration.ofSeconds(3, 0), Duration.ofSeconds(6, 0), 0},
+ {Duration.ofSeconds(7, 0), Duration.ofSeconds(3, 0), 2},
+
+ {Duration.ofSeconds(0, 333_333_333), Duration.ofSeconds(0, 333_333_333), 1},
+ {Duration.ofSeconds(0, 666_666_666), Duration.ofSeconds(0, 333_333_333), 2},
+ {Duration.ofSeconds(0, 333_333_333), Duration.ofSeconds(0, 666_666_666), 0},
+ {Duration.ofSeconds(0, 777_777_777), Duration.ofSeconds(0, 333_333_333), 2},
+
+ {Duration.ofSeconds(-7, 0), Duration.ofSeconds(3, 0), -2},
+ {Duration.ofSeconds(0, 7), Duration.ofSeconds(0, -3), -2},
+ {Duration.ofSeconds(0, -777_777_777), Duration.ofSeconds(0, 333_333_333), -2},
+
+ {Duration.ofSeconds(432000L, -777_777_777L), Duration.ofSeconds(14400L, 333_333_333L), 29},
+ {Duration.ofSeconds(-432000L, 777_777_777L), Duration.ofSeconds(14400L, 333_333_333L), -29},
+ {Duration.ofSeconds(-432000L, -777_777_777L), Duration.ofSeconds(14400L, 333_333_333L), -29},
+ {Duration.ofSeconds(-432000L, -777_777_777L), Duration.ofSeconds(14400L, -333_333_333L), -30},
+ {Duration.ofSeconds(432000L, -777_777_777L), Duration.ofSeconds(-14400L, 333_333_333L), -30},
+ {Duration.ofSeconds(432000L, -777_777_777L), Duration.ofSeconds(-14400L, -333_333_333L), -29},
+ {Duration.ofSeconds(-432000L, -777_777_777L), Duration.ofSeconds(-14400L, -333_333_333L), 29},
+
+ {Duration.ofSeconds(Long.MAX_VALUE, 0), Duration.ofSeconds(1, 0), Long.MAX_VALUE},
+ {Duration.ofSeconds(Long.MAX_VALUE, 0), Duration.ofSeconds(Long.MAX_VALUE, 0), 1},
+ };
+ }
+
+ @Test(dataProvider="dividedByDur_provider")
+ public void test_dividedByDur(Duration dividend, Duration divisor, long expected) {
+ assertEquals(dividend.dividedBy(divisor), expected);
+ }
+
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void test_dividedByDur_zero() {
+ Duration t = Duration.ofSeconds(1, 0);
+ t.dividedBy(Duration.ZERO);
+ }
+
+ @Test(expectedExceptions=NullPointerException.class)
+ public void test_dividedByDur_null() {
+ Duration t = Duration.ofSeconds(1, 0);
+ t.dividedBy(null);
+ }
+
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void test_dividedByDur_overflow() {
+ Duration dur1 = Duration.ofSeconds(Long.MAX_VALUE, 0);
+ Duration dur2 = Duration.ofNanos(1);
+ dur1.dividedBy(dur2);
+ }
+
+ //-----------------------------------------------------------------------
// negated()
//-----------------------------------------------------------------------
@Test
--- a/jdk/test/java/util/Collections/AsLifoQueue.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/util/Collections/AsLifoQueue.java Wed Jul 05 21:09:54 2017 +0200
@@ -70,6 +70,8 @@
check(q.isEmpty());
equal(q.size(), 0);
} catch (Throwable t) { unexpected(t); }
+
+ THROWS(NullPointerException.class, () -> Collections.asLifoQueue(null));
}
//--------------------- Infrastructure ---------------------------
--- a/jdk/test/java/util/Map/MapFactories.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/util/Map/MapFactories.java Wed Jul 05 21:09:54 2017 +0200
@@ -377,4 +377,13 @@
assertEquals(sie.toString(), kvh1.toString());
}
+ // compile-time test of wildcards
+ @Test
+ public void entryWildcardTests() {
+ Map.Entry<Integer,Double> e1 = Map.entry(1, 2.0);
+ Map.Entry<Float,Long> e2 = Map.entry(3.0f, 4L);
+ Map<Number,Number> map = Map.ofEntries(e1, e2);
+ assertEquals(map.size(), 2);
+ }
+
}
--- a/jdk/test/java/util/regex/PatternStreamTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/util/regex/PatternStreamTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 8016846 8024341 8071479
+ * @bug 8016846 8024341 8071479 8145006
* @summary Unit tests stream and lambda-based methods on Pattern and Matcher
* @library ../stream/bootlib/java.base
* @build java.util.stream.OpTestCase
@@ -42,6 +42,7 @@
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import java.util.stream.LambdaTestHelpers;
import java.util.stream.OpTestCase;
import java.util.stream.Stream;
@@ -185,6 +186,20 @@
.exercise();
}
+ @Test
+ public void testLateBinding() {
+ Pattern pattern = Pattern.compile(",");
+
+ StringBuilder sb = new StringBuilder("a,b,c,d,e");
+ Stream<String> stream = pattern.splitAsStream(sb);
+ sb.setLength(3);
+ assertEquals(Arrays.asList("a", "b"), stream.collect(Collectors.toList()));
+
+ stream = pattern.splitAsStream(sb);
+ sb.append(",f,g");
+ assertEquals(Arrays.asList("a", "b", "f", "g"), stream.collect(Collectors.toList()));
+ }
+
public void testFailfastMatchResults() {
Pattern p = Pattern.compile("X");
Matcher m = p.matcher("XX");
--- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -56,6 +56,7 @@
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.flatMapping;
+import static java.util.stream.Collectors.filtering;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.groupingByConcurrent;
import static java.util.stream.Collectors.mapping;
@@ -72,7 +73,7 @@
/*
* @test
- * @bug 8071600
+ * @bug 8071600 8144675
* @summary Test for collectors.
*/
public class CollectorsTest extends OpTestCase {
@@ -118,6 +119,23 @@
}
}
+ static class FilteringAssertion<T, R> extends CollectorAssertion<T, R> {
+ private final Predicate<T> filter;
+ private final CollectorAssertion<T, R> downstream;
+
+ public FilteringAssertion(Predicate<T> filter, CollectorAssertion<T, R> downstream) {
+ this.filter = filter;
+ this.downstream = downstream;
+ }
+
+ @Override
+ void assertValue(R value, Supplier<Stream<T>> source, boolean ordered) throws ReflectiveOperationException {
+ downstream.assertValue(value,
+ () -> source.get().filter(filter),
+ ordered);
+ }
+ }
+
static class GroupingByAssertion<T, K, V, M extends Map<K, ? extends V>> extends CollectorAssertion<T, M> {
private final Class<? extends Map> clazz;
private final Function<T, K> classifier;
@@ -551,6 +569,36 @@
}
@Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+ public void testGroupingByWithFiltering(String name, TestData.OfRef<Integer> data) throws ReflectiveOperationException {
+ Function<Integer, Integer> classifier = i -> i % 3;
+ Predicate<Integer> filteringByMod2 = i -> i % 2 == 0;
+ Predicate<Integer> filteringByUnder100 = i -> i % 2 < 100;
+ Predicate<Integer> filteringByTrue = i -> true;
+ Predicate<Integer> filteringByFalse = i -> false;
+
+ exerciseMapCollection(data,
+ groupingBy(classifier, filtering(filteringByMod2, toList())),
+ new GroupingByAssertion<>(classifier, HashMap.class,
+ new FilteringAssertion<>(filteringByMod2,
+ new ToListAssertion<>())));
+ exerciseMapCollection(data,
+ groupingBy(classifier, filtering(filteringByUnder100, toList())),
+ new GroupingByAssertion<>(classifier, HashMap.class,
+ new FilteringAssertion<>(filteringByUnder100,
+ new ToListAssertion<>())));
+ exerciseMapCollection(data,
+ groupingBy(classifier, filtering(filteringByTrue, toList())),
+ new GroupingByAssertion<>(classifier, HashMap.class,
+ new FilteringAssertion<>(filteringByTrue,
+ new ToListAssertion<>())));
+ exerciseMapCollection(data,
+ groupingBy(classifier, filtering(filteringByFalse, toList())),
+ new GroupingByAssertion<>(classifier, HashMap.class,
+ new FilteringAssertion<>(filteringByFalse,
+ new ToListAssertion<>())));
+ }
+
+ @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
public void testTwoLevelGroupingBy(String name, TestData.OfRef<Integer> data) throws ReflectiveOperationException {
Function<Integer, Integer> classifier = i -> i % 6;
Function<Integer, Integer> classifier2 = i -> i % 23;
--- a/jdk/test/java/util/zip/TestZipError.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/util/zip/TestZipError.java Wed Jul 05 21:09:54 2017 +0200
@@ -84,9 +84,10 @@
try {
while (entries.hasMoreElements()) {
ze = entries.nextElement();
+ zf.getInputStream(ze).readAllBytes();
}
fail("Did not get expected exception");
- } catch (ZipError e) {
+ } catch (ZipException e) {
pass();
} catch (InternalError e) {
fail("Caught InternalError instead of expected ZipError");
--- a/jdk/test/java/util/zip/ZipFile/ReadZip.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/java/util/zip/ZipFile/ReadZip.java Wed Jul 05 21:09:54 2017 +0200
@@ -30,6 +30,7 @@
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
+import java.nio.file.NoSuchFileException;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.zip.*;
@@ -110,6 +111,6 @@
"input"
+ String.valueOf(new java.util.Random().nextInt())
+ ".zip")));
- } catch (FileNotFoundException fnfe) {}
+ } catch (NoSuchFileException nsfe) {}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/zip/ZipFile/TestZipFile.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,361 @@
+/*
+ * 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 8142508
+ * @summary Tests various ZipFile apis
+ * @run main/manual TestZipFile
+ */
+
+import java.io.*;
+import java.lang.reflect.Method;
+import java.nio.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.zip.*;
+
+public class TestZipFile {
+
+ private static Random r = new Random();
+ private static int N = 50;
+ private static int NN = 10;
+ private static int ENUM = 10000;
+ private static int ESZ = 10000;
+ private static ExecutorService executor = Executors.newFixedThreadPool(20);
+ private static Set<Path> paths = new HashSet<>();
+
+ static void realMain (String[] args) throws Throwable {
+
+ try {
+ for (int i = 0; i < N; i++) {
+ test(r.nextInt(ENUM), r.nextInt(ESZ), false, true);
+ test(r.nextInt(ENUM), r.nextInt(ESZ), true, true);
+ }
+
+ for (int i = 0; i < NN; i++) {
+ test(r.nextInt(ENUM), 100000 + r.nextInt(ESZ), false, true);
+ test(r.nextInt(ENUM), 100000 + r.nextInt(ESZ), true, true);
+ testCachedDelete();
+ testCachedOverwrite();
+ //test(r.nextInt(ENUM), r.nextInt(ESZ), false, true);
+ }
+
+ test(70000, 1000, false, true); // > 65536 entry number;
+ testDelete(); // OPEN_DELETE
+
+ executor.shutdown();
+ executor.awaitTermination(10, TimeUnit.MINUTES);
+ } finally {
+ for (Path path : paths) {
+ Files.deleteIfExists(path);
+ }
+ }
+ }
+
+ static void test(int numEntry, int szMax, boolean addPrefix, boolean cleanOld) {
+ String name = "zftest" + r.nextInt() + ".zip";
+ Zip zip = new Zip(name, numEntry, szMax, addPrefix, cleanOld);
+ for (int i = 0; i < NN; i++) {
+ executor.submit(() -> doTest(zip));
+ }
+ }
+
+ // test scenario:
+ // (1) open the ZipFile(zip) with OPEN_READ | OPEN_DELETE
+ // (2) test the ZipFile works correctly
+ // (3) check the zip is deleted after ZipFile gets closed
+ static void testDelete() throws Throwable {
+ String name = "zftest" + r.nextInt() + ".zip";
+ Zip zip = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
+ try (ZipFile zf = new ZipFile(new File(zip.name),
+ ZipFile.OPEN_READ | ZipFile.OPEN_DELETE ))
+ {
+ doTest0(zip, zf);
+ }
+ Path p = Paths.get(name);
+ if (Files.exists(p)) {
+ fail("Failed to delete " + name + " with OPEN_DELETE");
+ }
+ }
+
+ // test scenario:
+ // (1) keep a ZipFile(zip1) alive (in ZipFile's cache), dont close it
+ // (2) delete zip1 and create zip2 with the same name the zip1 with zip2
+ // (3) zip1 tests should fail, but no crash
+ // (4) zip2 tasks should all get zip2, then pass normal testing.
+ static void testCachedDelete() throws Throwable {
+ String name = "zftest" + r.nextInt() + ".zip";
+ Zip zip1 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
+
+ try (ZipFile zf = new ZipFile(zip1.name)) {
+ for (int i = 0; i < NN; i++) {
+ executor.submit(() -> verifyNoCrash(zip1));
+ }
+ // delete the "zip1" and create a new one to test
+ Zip zip2 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
+ /*
+ System.out.println("========================================");
+ System.out.printf(" zip1=%s, mt=%d, enum=%d%n ->attrs=[key=%s, sz=%d, mt=%d]%n",
+ zip1.name, zip1.lastModified, zip1.entries.size(),
+ zip1.attrs.fileKey(), zip1.attrs.size(), zip1.attrs.lastModifiedTime().toMillis());
+ System.out.printf(" zip2=%s, mt=%d, enum=%d%n ->attrs=[key=%s, sz=%d, mt=%d]%n",
+ zip2.name, zip2.lastModified, zip2.entries.size(),
+ zip2.attrs.fileKey(), zip2.attrs.size(), zip2.attrs.lastModifiedTime().toMillis());
+ */
+ for (int i = 0; i < NN; i++) {
+ executor.submit(() -> doTest(zip2));
+ }
+ }
+ }
+
+ // overwrite the "zip1" and create a new one to test. So the two zip files
+ // have the same fileKey, but probably different lastModified()
+ static void testCachedOverwrite() throws Throwable {
+ String name = "zftest" + r.nextInt() + ".zip";
+ Zip zip1 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
+ try (ZipFile zf = new ZipFile(zip1.name)) {
+ for (int i = 0; i < NN; i++) {
+ executor.submit(() -> verifyNoCrash(zip1));
+ }
+ // overwrite the "zip1" with new contents
+ Zip zip2 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, false);
+ for (int i = 0; i < NN; i++) {
+ executor.submit(() -> doTest(zip2));
+ }
+ }
+ }
+
+ // just check the entries and contents. since the file has been either overwritten
+ // or deleted/rewritten, we only care if it crahes or not.
+ static void verifyNoCrash(Zip zip) throws RuntimeException {
+ try (ZipFile zf = new ZipFile(zip.name)) {
+ List<ZipEntry> zlist = new ArrayList(zip.entries.keySet());
+ String[] elist = zf.stream().map( e -> e.getName()).toArray(String[]::new);
+ if (!Arrays.equals(elist,
+ zlist.stream().map( e -> e.getName()).toArray(String[]::new)))
+ {
+ //System.out.printf("++++++ LIST NG [%s] entries.len=%d, expected=%d+++++++%n",
+ // zf.getName(), elist.length, zlist.size());
+ return;
+ }
+ for (ZipEntry ze : zlist) {
+ byte[] zdata = zip.entries.get(ze);
+ ZipEntry e = zf.getEntry(ze.getName());
+ if (e != null) {
+ checkEqual(e, ze);
+ if (!e.isDirectory()) {
+ // check with readAllBytes
+ try (InputStream is = zf.getInputStream(e)) {
+ if (!Arrays.equals(zdata, is.readAllBytes())) {
+ //System.out.printf("++++++ BYTES NG [%s]/[%s] ++++++++%n",
+ // zf.getName(), ze.getName());
+ }
+ }
+ }
+ }
+ }
+ } catch (Throwable t) {
+ // t.printStackTrace();
+ // fail(t.toString());
+ }
+ }
+
+ static void checkEqual(ZipEntry x, ZipEntry y) {
+ if (x.getName().equals(y.getName()) &&
+ x.isDirectory() == y.isDirectory() &&
+ x.getMethod() == y.getMethod() &&
+ (x.getTime() / 2000) == y.getTime() / 2000 &&
+ x.getSize() == y.getSize() &&
+ x.getCompressedSize() == y.getCompressedSize() &&
+ x.getCrc() == y.getCrc() &&
+ x.getComment().equals(y.getComment())
+ ) {
+ pass();
+ } else {
+ fail(x + " not equal to " + y);
+ System.out.printf(" %s %s%n", x.getName(), y.getName());
+ System.out.printf(" %d %d%n", x.getMethod(), y.getMethod());
+ System.out.printf(" %d %d%n", x.getTime(), y.getTime());
+ System.out.printf(" %d %d%n", x.getSize(), y.getSize());
+ System.out.printf(" %d %d%n", x.getCompressedSize(), y.getCompressedSize());
+ System.out.printf(" %d %d%n", x.getCrc(), y.getCrc());
+ System.out.println("-----------------");
+ }
+ }
+
+ static void doTest(Zip zip) throws RuntimeException {
+ //Thread me = Thread.currentThread();
+ try (ZipFile zf = new ZipFile(zip.name)) {
+ doTest0(zip, zf);
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ static void doTest0(Zip zip, ZipFile zf) throws Throwable {
+ List<ZipEntry> list = new ArrayList(zip.entries.keySet());
+ // (1) check entry list, in expected order
+ if (!check(Arrays.equals(
+ list.stream().map( e -> e.getName()).toArray(String[]::new),
+ zf.stream().map( e -> e.getName()).toArray(String[]::new)))) {
+ return;
+ }
+ // (2) shuffle, and check each entry and its bytes
+ Collections.shuffle(list);
+ for (ZipEntry ze : list) {
+ byte[] data = zip.entries.get(ze);
+ ZipEntry e = zf.getEntry(ze.getName());
+ checkEqual(e, ze);
+ if (!e.isDirectory()) {
+ // check with readAllBytes
+ try (InputStream is = zf.getInputStream(e)) {
+ check(Arrays.equals(data, is.readAllBytes()));
+ }
+ // check with smaller sized buf
+ try (InputStream is = zf.getInputStream(e)) {
+ byte[] buf = new byte[(int)e.getSize()];
+ int sz = r.nextInt((int)e.getSize()/4 + 1) + 1;
+ int off = 0;
+ int n;
+ while ((n = is.read(buf, off, buf.length - off)) > 0) {
+ off += n;
+ }
+ check(is.read() == -1);
+ check(Arrays.equals(data, buf));
+ }
+ }
+ }
+ // (3) check getMetaInfEntryNames
+ String[] metas = list.stream()
+ .map( e -> e.getName())
+ .filter( s -> s.startsWith("META-INF/"))
+ .sorted()
+ .toArray(String[]::new);
+ if (metas.length > 0) {
+ // meta-inf entries
+ Method getMetas = ZipFile.class.getDeclaredMethod("getMetaInfEntryNames");
+ getMetas.setAccessible(true);
+ String[] names = (String[])getMetas.invoke(zf);
+ if (names == null) {
+ fail("Failed to get metanames from " + zf);
+ } else {
+ Arrays.sort(names);
+ check(Arrays.equals(names, metas));
+ }
+ }
+ }
+
+ private static class Zip {
+ String name;
+ Map<ZipEntry, byte[]> entries;
+ BasicFileAttributes attrs;
+ long lastModified;
+
+ Zip(String name, int num, int szMax, boolean prefix, boolean clean) {
+ this.name = name;
+ entries = new LinkedHashMap<>(num);
+ try {
+ Path p = Paths.get(name);
+ if (clean) {
+ Files.deleteIfExists(p);
+ }
+ paths.add(p);
+ } catch (Exception x) {
+ throw (RuntimeException)x;
+ }
+
+ try (FileOutputStream fos = new FileOutputStream(name);
+ BufferedOutputStream bos = new BufferedOutputStream(fos);
+ ZipOutputStream zos = new ZipOutputStream(bos))
+ {
+ if (prefix) {
+ byte[] bytes = new byte[r.nextInt(1000)];
+ r.nextBytes(bytes);
+ bos.write(bytes);
+ }
+ CRC32 crc = new CRC32();
+ for (int i = 0; i < num; i++) {
+ String ename = "entry-" + i + "-name-" + r.nextLong();
+ ZipEntry ze = new ZipEntry(ename);
+ int method = r.nextBoolean() ? ZipEntry.STORED : ZipEntry.DEFLATED;
+ writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
+ }
+ // add some manifest entries
+ for (int i = 0; i < r.nextInt(20); i++) {
+ String meta = "META-INF/" + "entry-" + i + "-metainf-" + r.nextLong();
+ ZipEntry ze = new ZipEntry(meta);
+ writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
+ }
+ } catch (Exception x) {
+ throw (RuntimeException)x;
+ }
+ try {
+ this.attrs = Files.readAttributes(Paths.get(name), BasicFileAttributes.class);
+ this.lastModified = new File(name).lastModified();
+ } catch (Exception x) {
+ throw (RuntimeException)x;
+ }
+ }
+
+ private void writeEntry(ZipOutputStream zos, CRC32 crc,
+ ZipEntry ze, int method, int szMax)
+ throws IOException
+ {
+ ze.setMethod(method);
+ byte[] data = new byte[r.nextInt(szMax + 1)];
+ r.nextBytes(data);
+ if (method == ZipEntry.STORED) { // must set size/csize/crc
+ ze.setSize(data.length);
+ ze.setCompressedSize(data.length);
+ crc.reset();
+ crc.update(data);
+ ze.setCrc(crc.getValue());
+ }
+ ze.setTime(System.currentTimeMillis());
+ ze.setComment(ze.getName());
+ zos.putNextEntry(ze);
+ zos.write(data);
+ zos.closeEntry();
+ entries.put(ze, data);
+ }
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static void pass() {passed++;}
+ static void pass(String msg) {System.out.println(msg); passed++;}
+ static void fail() {failed++; Thread.dumpStack();}
+ static void fail(String msg) {System.out.println(msg); fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static void unexpected(Throwable t, String msg) {
+ System.out.println(msg); failed++; t.printStackTrace();}
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- a/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java Wed Jul 05 21:09:54 2017 +0200
@@ -28,6 +28,7 @@
* @test
* @bug 8043758
* @summary Datagram Transport Layer Security (DTLS)
+ * @modules java.base/sun.security.util
* @run main/othervm DTLSOverDatagram
*/
@@ -40,7 +41,7 @@
import javax.net.ssl.*;
import java.util.concurrent.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/**
* An example to show the way to use SSLEngine in datagram connections.
--- a/jdk/test/javax/net/ssl/templates/SSLExplorer.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/javax/net/ssl/templates/SSLExplorer.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,8 +29,6 @@
import javax.net.ssl.*;
import java.util.*;
-import sun.misc.HexDumpEncoder;
-
/**
* Instances of this class acts as an explorer of the network data of an
* SSL/TLS connection.
--- a/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java Wed Jul 05 21:09:54 2017 +0200
@@ -107,14 +107,14 @@
System.err.println("printing content");
System.err.println(content);
}
- throw new RuntimeException("Expected <e4> to represent 'ä' but not found!");
+ throw new RuntimeException("Expected <e4> to represent '\u00e4' but not found!");
}
System.err.println("SUCCESS");
}
public int print(Graphics g, PageFormat pf, int pg) {
if (pg > 0) return NO_SUCH_PAGE;
- g.drawString("ä", 100, 100);
+ g.drawString("\u00e4", 100, 100);
return PAGE_EXISTS;
}
}
--- a/jdk/test/javax/security/auth/Subject/Subject.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/javax/security/auth/Subject/Subject.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,7 +29,6 @@
*/
package jjjjj.security.auth;
-import sun.misc.HexDumpEncoder;
import javax.management.remote.JMXPrincipal;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.x500.X500Principal;
@@ -107,7 +106,6 @@
public static byte[] enc(Object obj) {
try {
- HexDumpEncoder hex = new HexDumpEncoder();
ByteArrayOutputStream bout;
bout = new ByteArrayOutputStream();
new ObjectOutputStream(bout).writeObject(obj);
--- a/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
* 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,8 +33,6 @@
import java.net.*;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
-import java.security.Policy;
-import java.security.URIParameter;
import java.util.ArrayList;
import java.util.Collections;
import javax.xml.crypto.dsig.*;
@@ -115,10 +113,8 @@
// the policy only grants this test SocketPermission to accept, resolve
// and connect to localhost so that it can dereference 2nd reference
- URI policyURI =
- new File(System.getProperty("test.src", "."), "policy").toURI();
- Policy.setPolicy
- (Policy.getInstance("JavaPolicy", new URIParameter(policyURI)));
+ System.setProperty("java.security.policy",
+ System.getProperty("test.src", ".") + File.separator + "policy");
System.setSecurityManager(new SecurityManager());
try {
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java Wed Jul 05 21:09:54 2017 +0200
@@ -42,7 +42,11 @@
* multiple times, then the line number won't provide enough context to
* understand the failure.
* </pre>
+ *
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib}
*/
+@Deprecated
public class Asserts {
/**
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolFinder.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolFinder.java Wed Jul 05 21:09:54 2017 +0200
@@ -27,6 +27,11 @@
import java.nio.file.Path;
import java.nio.file.Paths;
+/**
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib}
+ */
+@Deprecated
public final class JDKToolFinder {
private JDKToolFinder() {
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java Wed Jul 05 21:09:54 2017 +0200
@@ -46,7 +46,10 @@
* Process p = pb.start();
* }
* </pre>
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib}
*/
+@Deprecated
public class JDKToolLauncher {
private final String executable;
private final List<String> vmArgs = new ArrayList<String>();
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java Wed Jul 05 21:09:54 2017 +0200
@@ -33,7 +33,12 @@
/**
* Utility class for verifying output and exit value from a {@code Process}.
+ *
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib/process}
+ *
*/
+@Deprecated
public final class OutputAnalyzer {
private final OutputBuffer output;
private final String stdout;
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java Wed Jul 05 21:09:54 2017 +0200
@@ -28,6 +28,11 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+/**
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib/process}
+ */
+@Deprecated
class OutputBuffer {
private static class OutputBufferException extends RuntimeException {
private static final long serialVersionUID = 8528687792643129571L;
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java Wed Jul 05 21:09:54 2017 +0200
@@ -27,6 +27,11 @@
import java.io.FileNotFoundException;
import java.io.IOException;
+/**
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib}
+ */
+@Deprecated
public class Platform {
private static final String osName = System.getProperty("os.name");
private static final String dataModel = System.getProperty("sun.arch.data.model");
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java Wed Jul 05 21:09:54 2017 +0200
@@ -27,8 +27,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -42,6 +40,12 @@
import java.util.function.Consumer;
import java.util.stream.Collectors;
+
+/**
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib/process}
+ */
+@Deprecated
public final class ProcessTools {
private static final class LineForwarder extends StreamPumper.LinePump {
private final PrintStream ps;
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java Wed Jul 05 21:09:54 2017 +0200
@@ -34,6 +34,11 @@
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicBoolean;
+/**
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib/process}
+ */
+@Deprecated
public final class StreamPumper implements Runnable {
private static final int BUF_SIZE = 256;
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java Wed Jul 05 21:09:54 2017 +0200
@@ -41,7 +41,11 @@
/**
* Common library for various test helper functions.
+ *
+ * @deprecated This class is deprecated. Use the one from
+ * {@code <root>/test/lib/share/classes/jdk/test/lib}
*/
+@Deprecated
public final class Utils {
/**
--- a/jdk/test/sun/misc/Encode/DecodeBuffer.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 4159554
- * @summary Problem with UUDecoder
- * @modules java.base/sun.misc
- */
-
-import sun.misc.*;
-import java.io.*;
-
-public class DecodeBuffer {
-
- public static void main(String[] args) throws Exception {
- String encoded;
- // text to encode and decode
- String originalText = "Hi There, please encode and decode me";
- UUDecoder uuD = new UUDecoder();
-
- encoded = "begin 644 encoder.buf\r\n" +
- "E2&D@5&AE<F4L('!L96%S92!E;F-O9&4@86YD(&1E8V]D92!M90$!\r\n"+
- " \r\nend\r\n";
- check (uuD, encoded, originalText);
-
- encoded = "begin 644 encoder.buf\n" +
- "E2&D@5&AE<F4L('!L96%S92!E;F-O9&4@86YD(&1E8V]D92!M90$!\n"+
- " \nend\n";
- check (uuD, encoded, originalText);
-
- encoded = "begin 644 encoder.buf\r" +
- "E2&D@5&AE<F4L('!L96%S92!E;F-O9&4@86YD(&1E8V]D92!M90$!\r"+
- " \rend\r";
- check (uuD, encoded, originalText);
-
- // Multi-line Unix text file
-
- String s1 = "begin 644 f\n"+
- "M3W)I9VYL(\"I(:2!4:&5R92P@<&QE87-E(&5N8V]D92!A;F0@9&5C;V1E(&UE\n"+
- "M*@IA;F0@;64@06YD($UE(&%N1\"!M92!!;F0@344@04Y$($U%(%I80U8@,3(S\n"+
- "-97)T\"E5)3U @45=%\"DUE\n"+
- " \nend\n";
-
- String s2 = "Orignl *Hi There, please encode and decode me*\n"+
- "and me And Me anD me And ME AND ME ZXCV 123ert\n"+
- "UIOP QWE\n";
- check (uuD, s1, s2);
-
- // Multi-line Windows text file
-
- s1 = "begin 644 f\n"+
- "M2&5L;&\\@22!A;2!A(&UU;'1I;&EN92!F:6QE#0IC<F5A=&5D(&]N(%=I;F1O\r\n"+
- "M=W,L('1O('1E<W0@=&AE(%5516YC;V1E<@T*86YD(%551&5C;V1E<B!C;&%S\r\n"+
- "$<V5S+G1O\r\n"+ " \r\nend\r\n";
- s2="Hello I am a multiline file\r\n"+
- "created on Windows, to test the UUEncoder\r\n"+
- "and UUDecoder classes.";
- check (uuD, s1, s2);
- }
-
- public static void check (UUDecoder uuD, String s, String original) throws Exception {
- String decoded;
- // do UU stuff
- decoded = new String(uuD.decodeBuffer(s));
- if (!decoded.equals (original)) {
- throw new Exception ("decoded text not same as original");
- }
- }
-}
--- a/jdk/test/sun/misc/Encode/Encode.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 4041231
- * @summary Test UUEncoder.java for proper masking in encodeAtom
- * @modules java.base/sun.misc
- */
-
-import sun.misc.*;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-public class Encode {
-
- public static void main(String[] args) throws Exception {
- UUEncoder encoder = new UUEncoder("encode.buf");
- byte[] buffer = new byte[3];
-
- buffer[0] = -1;
- buffer[1] = -1;
- buffer[2] = -1;
-
- ByteArrayInputStream in = new ByteArrayInputStream(buffer);
- ByteArrayOutputStream out = new ByteArrayOutputStream(10);
-
- encoder.encodeBuffer(in, out);
- byte[] result = out.toByteArray();
-
- if (result[22] == 31)
- throw new RuntimeException("UUEncoder generates incorrect byte sequences in encodeAtom.");
-
- }
-}
--- a/jdk/test/sun/misc/Encode/GetBytes.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 5031097
- * @summary sun.misc.CharacterEncoder(ByteBuffer) is dumping too
- * much information
- * @modules java.base/sun.misc
- * @author Brad Wetmore
- */
-
-import java.nio.*;
-import sun.misc.*;
-
-public class GetBytes {
-
- public static void main(String args[]) throws Exception {
-
- ByteBuffer bb = ByteBuffer.wrap(new byte [26 + 2]);
-
- for (int i = 'a'; i < 'a' + bb.capacity(); i++) {
- bb.put((byte)i);
- }
-
- /*
- * Slice a subbuffer out of the original buffer.
- */
- bb.position(1);
- bb.limit(bb.capacity() - 1);
-
- ByteBuffer src = bb.slice();
-
- CharacterEncoder e = new BASE64Encoder();
- CharacterDecoder d = new BASE64Decoder();
-
- String encoded = e.encodeBuffer(src);
- ByteBuffer dst = d.decodeBufferToByteBuffer(encoded);
-
- src.rewind();
- dst.rewind();
-
- if (src.compareTo(dst) != 0) {
- throw new Exception("Didn't encode/decode correctly");
- }
- }
-}
--- a/jdk/test/sun/security/krb5/auto/MSOID2.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/security/krb5/auto/MSOID2.java Wed Jul 05 21:09:54 2017 +0200
@@ -30,6 +30,7 @@
*/
import sun.security.jgss.GSSUtil;
+import sun.security.util.HexDumpEncoder;
// The basic krb5 test skeleton you can copy from
public class MSOID2 {
@@ -69,7 +70,7 @@
nt[pos] = (byte)newLen;
}
t = nt;
- new sun.misc.HexDumpEncoder().encodeBuffer(t, System.out);
+ new HexDumpEncoder().encodeBuffer(t, System.out);
}
if (t != null || !s.x().isEstablished()) t = s.take(t);
if (c.x().isEstablished() && s.x().isEstablished()) break;
--- a/jdk/test/sun/security/mscapi/PublicKeyInterop.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/security/mscapi/PublicKeyInterop.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,7 +29,7 @@
import java.util.*;
import javax.crypto.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
/*
* Confirm interoperability of RSA public keys between SunMSCAPI and SunJCE
--- a/jdk/test/sun/security/mscapi/PublicKeyInterop.sh Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/security/mscapi/PublicKeyInterop.sh Wed Jul 05 21:09:54 2017 +0200
@@ -25,6 +25,7 @@
# @test
# @bug 6888925
+# @modules java.base/sun.security.util
# @requires os.family == "windows"
# @run shell PublicKeyInterop.sh
# @summary SunMSCAPI's Cipher can't use RSA public keys obtained from other
--- a/jdk/test/sun/security/pkcs/pkcs7/SignerOrder.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/security/pkcs/pkcs7/SignerOrder.java Wed Jul 05 21:09:54 2017 +0200
@@ -40,7 +40,7 @@
import java.security.SignatureException;
import java.security.cert.X509Certificate;
import java.util.Date;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.pkcs.ContentInfo;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;
--- a/jdk/test/sun/security/pkcs/pkcs8/PKCS8Test.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/security/pkcs/pkcs8/PKCS8Test.java Wed Jul 05 21:09:54 2017 +0200
@@ -43,7 +43,7 @@
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.util.Arrays;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.pkcs.PKCS8Key;
import sun.security.provider.DSAPrivateKey;
import sun.security.util.DerOutputStream;
--- a/jdk/test/sun/security/pkcs/pkcs9/UnknownAttribute.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/security/pkcs/pkcs9/UnknownAttribute.java Wed Jul 05 21:09:54 2017 +0200
@@ -33,7 +33,7 @@
import java.io.*;
import java.util.Arrays;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
import sun.security.pkcs.PKCS9Attribute;
import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier;
--- a/jdk/test/sun/security/x509/X500Name/NullX500Name.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/security/x509/X500Name/NullX500Name.java Wed Jul 05 21:09:54 2017 +0200
@@ -32,7 +32,7 @@
import java.util.Arrays;
import sun.security.util.DerOutputStream;
import sun.security.x509.*;
-import sun.misc.HexDumpEncoder;
+import sun.security.util.HexDumpEncoder;
public class NullX500Name {
--- a/jdk/test/sun/text/resources/LocaleData.cldr Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/text/resources/LocaleData.cldr Wed Jul 05 21:09:54 2017 +0200
@@ -72,10 +72,10 @@
FormatData/en_GB/TimePatterns/1=HH:mm:ss z
FormatData/en_GB/TimePatterns/2=HH:mm:ss
FormatData/en_GB/TimePatterns/3=HH:mm
-FormatData/en_GB/DatePatterns/0=EEEE, MMMM d, y
-FormatData/en_GB/DatePatterns/1=MMMM d, y
-FormatData/en_GB/DatePatterns/2=MMM d, y
-FormatData/en_GB/DatePatterns/3=M/d/yy
+FormatData/en_GB/DatePatterns/0=EEEE, d MMMM y
+FormatData/en_GB/DatePatterns/1=d MMMM y
+FormatData/en_GB/DatePatterns/2=d MMM y
+FormatData/en_GB/DatePatterns/3=dd/MM/y
FormatData/en_GB/DateTimePatterns/0={1} 'at' {0}
# bug #4070795
@@ -398,10 +398,10 @@
FormatData/es_AR/NumberPatterns/0=#,##0.###
# FormatData/es_AR/NumberPatterns/1=$#,##0.00;($#,##0.00) # Changed; see bug 4122840
FormatData/es_AR/NumberPatterns/2=#,##0\u00a0%
-FormatData/es_AR/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_AR/TimePatterns/1=H:mm:ss z
-FormatData/es_AR/TimePatterns/2=H:mm:ss
-FormatData/es_AR/TimePatterns/3=H:mm
+FormatData/es_AR/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_AR/TimePatterns/1=h:mm:ss a z
+FormatData/es_AR/TimePatterns/2=h:mm:ss a
+FormatData/es_AR/TimePatterns/3=h:mm a
FormatData/es_AR/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_AR/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_AR/DatePatterns/2=d MMM y
@@ -414,10 +414,10 @@
# FormatData/es_BO/NumberPatterns/1=B$#,##0.00;(B$#,##0.00) # Changed; see bug 4122840
FormatData/es_BO/NumberPatterns/2=#,##0\u00a0%
CurrencyNames/es_BO/BOB=Bs
-FormatData/es_BO/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_BO/TimePatterns/1=H:mm:ss z
-FormatData/es_BO/TimePatterns/2=H:mm:ss
-FormatData/es_BO/TimePatterns/3=H:mm
+FormatData/es_BO/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_BO/TimePatterns/1=h:mm:ss a z
+FormatData/es_BO/TimePatterns/2=h:mm:ss a
+FormatData/es_BO/TimePatterns/3=h:mm a
FormatData/es_BO/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_BO/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_BO/DatePatterns/2=d MMM y
@@ -444,10 +444,10 @@
FormatData/es_CO/NumberPatterns/2=#,##0\u00a0%
# changed currency symbol during 5102005 bugfix
CurrencyNames/es_CO/COP=$
-FormatData/es_CO/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_CO/TimePatterns/1=H:mm:ss z
-FormatData/es_CO/TimePatterns/2=H:mm:ss
-FormatData/es_CO/TimePatterns/3=H:mm
+FormatData/es_CO/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_CO/TimePatterns/1=h:mm:ss a z
+FormatData/es_CO/TimePatterns/2=h:mm:ss a
+FormatData/es_CO/TimePatterns/3=h:mm a
FormatData/es_CO/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_CO/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_CO/DatePatterns/2=d/MM/y
@@ -461,10 +461,10 @@
# FormatData/es_CR/NumberPatterns/1=C#,##0.00;(C#,##0.00) # Changed; see bug 4122840
FormatData/es_CR/NumberPatterns/2=#,##0\u00a0%
CurrencyNames/es_CR/CRC=\u20a1
-FormatData/es_CR/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_CR/TimePatterns/1=H:mm:ss z
-FormatData/es_CR/TimePatterns/2=H:mm:ss
-FormatData/es_CR/TimePatterns/3=H:mm
+FormatData/es_CR/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_CR/TimePatterns/1=h:mm:ss a z
+FormatData/es_CR/TimePatterns/2=h:mm:ss a
+FormatData/es_CR/TimePatterns/3=h:mm a
FormatData/es_CR/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_CR/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_CR/DatePatterns/2=d MMM y
@@ -477,10 +477,10 @@
# FormatData/es_DO/NumberPatterns/1=RD$#,##0.00;(RD$#,##0.00) # Changed; see bug 4122840
FormatData/es_DO/NumberPatterns/2=#,##0\u00a0%
CurrencyNames/es_DO/DOP=$
-FormatData/es_DO/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_DO/TimePatterns/1=H:mm:ss z
-FormatData/es_DO/TimePatterns/2=H:mm:ss
-FormatData/es_DO/TimePatterns/3=H:mm
+FormatData/es_DO/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_DO/TimePatterns/1=h:mm:ss a z
+FormatData/es_DO/TimePatterns/2=h:mm:ss a
+FormatData/es_DO/TimePatterns/3=h:mm a
FormatData/es_DO/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_DO/DatePatterns/1=d 'de' MMMM 'de' y
# FormatData/es_DO/DatePatterns/2=MM/dd/yyyy # Changed: see bug 8037343
@@ -526,10 +526,10 @@
# FormatData/es_GT/NumberPatterns/1=Q#,##0.00;(Q#,##0.00) # Changed; see bug 4122840
FormatData/es_GT/NumberPatterns/2=#,##0\u00a0%
CurrencyNames/es_GT/GTQ=Q
-FormatData/es_GT/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_GT/TimePatterns/1=H:mm:ss z
-FormatData/es_GT/TimePatterns/2=H:mm:ss
-FormatData/es_GT/TimePatterns/3=H:mm
+FormatData/es_GT/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_GT/TimePatterns/1=h:mm:ss a z
+FormatData/es_GT/TimePatterns/2=h:mm:ss a
+FormatData/es_GT/TimePatterns/3=h:mm a
FormatData/es_GT/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_GT/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_GT/DatePatterns/2=d/MM/y
@@ -542,10 +542,10 @@
# FormatData/es_HN/NumberPatterns/1=L#,##0.00;(L#,##0.00) # Changed; see bug 4122840
FormatData/es_HN/NumberPatterns/2=#,##0\u00a0%
CurrencyNames/es_HN/HNL=L
-FormatData/es_HN/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_HN/TimePatterns/1=H:mm:ss z
-FormatData/es_HN/TimePatterns/2=H:mm:ss
-FormatData/es_HN/TimePatterns/3=H:mm
+FormatData/es_HN/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_HN/TimePatterns/1=h:mm:ss a z
+FormatData/es_HN/TimePatterns/2=h:mm:ss a
+FormatData/es_HN/TimePatterns/3=h:mm a
FormatData/es_HN/DatePatterns/0=EEEE dd 'de' MMMM 'de' y
FormatData/es_HN/DatePatterns/1=dd 'de' MMMM 'de' y
FormatData/es_HN/DatePatterns/2=d MMM y
@@ -558,10 +558,10 @@
# FormatData/es_MX/NumberPatterns/1=$#,##0.00;($#,##0.00) # Changed; see bug 4122840
FormatData/es_MX/NumberPatterns/2=#,##0%
CurrencyNames/es_MX/MXN=$
-FormatData/es_MX/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_MX/TimePatterns/1=H:mm:ss z
-FormatData/es_MX/TimePatterns/2=H:mm:ss
-FormatData/es_MX/TimePatterns/3=H:mm
+FormatData/es_MX/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_MX/TimePatterns/1=h:mm:ss a z
+FormatData/es_MX/TimePatterns/2=h:mm:ss a
+FormatData/es_MX/TimePatterns/3=h:mm a
FormatData/es_MX/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_MX/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_MX/DatePatterns/2=dd/MM/y
@@ -574,10 +574,10 @@
# FormatData/es_NI/NumberPatterns/1=$C#,##0.00;($C#,##0.00) # Changed; see bug 4122840
FormatData/es_NI/NumberPatterns/2=#,##0\u00a0%
CurrencyNames/es_NI/NIO=C$
-FormatData/es_NI/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_NI/TimePatterns/1=H:mm:ss z
-FormatData/es_NI/TimePatterns/2=H:mm:ss
-FormatData/es_NI/TimePatterns/3=H:mm
+FormatData/es_NI/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_NI/TimePatterns/1=h:mm:ss a z
+FormatData/es_NI/TimePatterns/2=h:mm:ss a
+FormatData/es_NI/TimePatterns/3=h:mm a
FormatData/es_NI/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_NI/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_NI/DatePatterns/2=d MMM y
@@ -590,10 +590,10 @@
# FormatData/es_PA/NumberPatterns/1=B#,##0.00;(B#,##0.00) # Changed; see bug 4122840
FormatData/es_PA/NumberPatterns/2=#,##0\u00a0%
CurrencyNames/es_PA/PAB=B/.
-FormatData/es_PA/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_PA/TimePatterns/1=H:mm:ss z
-FormatData/es_PA/TimePatterns/2=H:mm:ss
-FormatData/es_PA/TimePatterns/3=H:mm
+FormatData/es_PA/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_PA/TimePatterns/1=h:mm:ss a z
+FormatData/es_PA/TimePatterns/2=h:mm:ss a
+FormatData/es_PA/TimePatterns/3=h:mm a
FormatData/es_PA/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_PA/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_PA/DatePatterns/2=MM/dd/y
@@ -605,10 +605,10 @@
FormatData/es_PE/NumberPatterns/0=#,##0.###
# FormatData/es_PE/NumberPatterns/1=S/#,##0.00;S/-#,##0.00 # Changed; see bug 4122840
FormatData/es_PE/NumberPatterns/2=#,##0\u00a0%
-FormatData/es_PE/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_PE/TimePatterns/1=H:mm:ss z
-FormatData/es_PE/TimePatterns/2=H:mm:ss
-FormatData/es_PE/TimePatterns/3=H:mm
+FormatData/es_PE/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_PE/TimePatterns/1=h:mm:ss a z
+FormatData/es_PE/TimePatterns/2=h:mm:ss a
+FormatData/es_PE/TimePatterns/3=h:mm a
FormatData/es_PE/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_PE/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_PE/DatePatterns/2=d MMM y
@@ -621,10 +621,10 @@
# FormatData/es_PR/NumberPatterns/1=$#,##0.00;($#,##0.00) # Changed; see bug 4122840
FormatData/es_PR/NumberPatterns/2=#,##0\u00a0%
CurrencyNames/es_PR/USD=$
-FormatData/es_PR/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_PR/TimePatterns/1=H:mm:ss z
-FormatData/es_PR/TimePatterns/2=H:mm:ss
-FormatData/es_PR/TimePatterns/3=H:mm
+FormatData/es_PR/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_PR/TimePatterns/1=h:mm:ss a z
+FormatData/es_PR/TimePatterns/2=h:mm:ss a
+FormatData/es_PR/TimePatterns/3=h:mm a
FormatData/es_PR/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_PR/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_PR/DatePatterns/2=MM/dd/y
@@ -637,10 +637,10 @@
FormatData/es_PY/NumberPatterns/0=#,##0.###
# FormatData/es_PY/NumberPatterns/1=G#,##0.00;(G#,##0.00) # Changed; see bug 4122840
FormatData/es_PY/NumberPatterns/2=#,##0\u00a0%
-FormatData/es_PY/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_PY/TimePatterns/1=H:mm:ss z
-FormatData/es_PY/TimePatterns/2=H:mm:ss
-FormatData/es_PY/TimePatterns/3=H:mm
+FormatData/es_PY/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_PY/TimePatterns/1=h:mm:ss a z
+FormatData/es_PY/TimePatterns/2=h:mm:ss a
+FormatData/es_PY/TimePatterns/3=h:mm a
FormatData/es_PY/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_PY/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_PY/DatePatterns/2=d MMM y
@@ -653,10 +653,10 @@
# FormatData/es_SV/NumberPatterns/1=C#,##0.00;(C#,##0.00) # Changed; see bug 4122840
FormatData/es_SV/NumberPatterns/2=#,##0\u00a0%
#CurrencyNames/es_SV/SVC=<MISSING!>
-FormatData/es_SV/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_SV/TimePatterns/1=H:mm:ss z
-FormatData/es_SV/TimePatterns/2=H:mm:ss
-FormatData/es_SV/TimePatterns/3=H:mm
+FormatData/es_SV/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_SV/TimePatterns/1=h:mm:ss a z
+FormatData/es_SV/TimePatterns/2=h:mm:ss a
+FormatData/es_SV/TimePatterns/3=h:mm a
FormatData/es_SV/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_SV/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_SV/DatePatterns/2=d MMM y
@@ -669,10 +669,10 @@
FormatData/es_UY/NumberPatterns/0=#,##0.###
# FormatData/es_UY/NumberPatterns/1=NU$ #,##0.00;(NU$#,##0.00) # Changed; see bug 4122840
FormatData/es_UY/NumberPatterns/2=#,##0\u00a0%
-FormatData/es_UY/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_UY/TimePatterns/1=H:mm:ss z
-FormatData/es_UY/TimePatterns/2=H:mm:ss
-FormatData/es_UY/TimePatterns/3=H:mm
+FormatData/es_UY/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_UY/TimePatterns/1=h:mm:ss a z
+FormatData/es_UY/TimePatterns/2=h:mm:ss a
+FormatData/es_UY/TimePatterns/3=h:mm a
FormatData/es_UY/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_UY/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_UY/DatePatterns/2=d MMM y
@@ -686,10 +686,10 @@
FormatData/es_VE/NumberPatterns/0=#,##0.###
# FormatData/es_VE/NumberPatterns/1=Bs#,##0.00;Bs -#,##0.00 # Changed; see bug 4122840
FormatData/es_VE/NumberPatterns/2=#,##0\u00a0%
-FormatData/es_VE/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_VE/TimePatterns/1=H:mm:ss z
-FormatData/es_VE/TimePatterns/2=H:mm:ss
-FormatData/es_VE/TimePatterns/3=H:mm
+FormatData/es_VE/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_VE/TimePatterns/1=h:mm:ss a z
+FormatData/es_VE/TimePatterns/2=h:mm:ss a
+FormatData/es_VE/TimePatterns/3=h:mm a
FormatData/es_VE/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_VE/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_VE/DatePatterns/2=d MMM y
@@ -2372,22 +2372,22 @@
FormatData/en_AU/NumberPatterns/1=\u00a4#,##0.00
FormatData/en_NZ/NumberPatterns/1=\u00a4#,##0.00
FormatData/en_ZA/NumberPatterns/1=\u00a4#,##0.00
-FormatData/es_AR/NumberPatterns/1=#,##0.00\u00a0\u00a4
-FormatData/es_BO/NumberPatterns/1=#,##0.00\u00a0\u00a4
+FormatData/es_AR/NumberPatterns/1=\u00a4#,##0.00
+FormatData/es_BO/NumberPatterns/1=\u00a4#,##0.00
FormatData/es_CL/NumberPatterns/1=\u00a4#,##0.00;\u00a4-#,##0.00
-FormatData/es_CO/NumberPatterns/1=#,##0.00\u00a0\u00a4
-FormatData/es_CR/NumberPatterns/1=#,##0.00\u00a0\u00a4
-FormatData/es_DO/NumberPatterns/1=#,##0.00\u00a0\u00a4
+FormatData/es_CO/NumberPatterns/1=\u00a4#,##0.00
+FormatData/es_CR/NumberPatterns/1=\u00a4#,##0.00
+FormatData/es_DO/NumberPatterns/1=\u00a4#,##0.00
FormatData/es_EC/NumberPatterns/1=\u00a4#,##0.00;\u00a4-#,##0.00
-FormatData/es_GT/NumberPatterns/1=#,##0.00\u00a0\u00a4
-FormatData/es_HN/NumberPatterns/1=#,##0.00\u00a0\u00a4
+FormatData/es_GT/NumberPatterns/1=\u00a4#,##0.00
+FormatData/es_HN/NumberPatterns/1=\u00a4#,##0.00
FormatData/es_MX/NumberPatterns/1=\u00a4#,##0.00
-FormatData/es_NI/NumberPatterns/1=#,##0.00\u00a0\u00a4
-FormatData/es_PA/NumberPatterns/1=#,##0.00\u00a0\u00a4
-FormatData/es_PE/NumberPatterns/1=#,##0.00\u00a0\u00a4
-FormatData/es_PR/NumberPatterns/1=#,##0.00\u00a0\u00a4
+FormatData/es_NI/NumberPatterns/1=\u00a4#,##0.00
+FormatData/es_PA/NumberPatterns/1=\u00a4#,##0.00
+FormatData/es_PE/NumberPatterns/1=\u00a4#,##0.00
+FormatData/es_PR/NumberPatterns/1=\u00a4#,##0.00
FormatData/es_PY/NumberPatterns/1=\u00a4\u00a0#,##0.00;\u00a4\u00a0-#,##0.00
-FormatData/es_SV/NumberPatterns/1=#,##0.00\u00a0\u00a4
+FormatData/es_SV/NumberPatterns/1=\u00a4#,##0.00
FormatData/es_UY/NumberPatterns/1=\u00a4\u00a0#,##0.00
FormatData/es_VE/NumberPatterns/1=\u00a4#,##0.00;\u00a4-#,##0.00
FormatData/fr_FR/NumberPatterns/1=#,##0.00\u00a0\u00a4
@@ -2908,10 +2908,10 @@
FormatData/en_PH/TimePatterns/1=h:mm:ss a z
FormatData/en_PH/TimePatterns/2=h:mm:ss a
FormatData/en_PH/TimePatterns/3=h:mm a
-FormatData/en_PH/DatePatterns/0=EEEE, MMMM d, y
-FormatData/en_PH/DatePatterns/1=MMMM d, y
-FormatData/en_PH/DatePatterns/2=MMM d, y
-FormatData/en_PH/DatePatterns/3=M/d/yy
+FormatData/en_PH/DatePatterns/0=EEEE, d MMMM y
+FormatData/en_PH/DatePatterns/1=d MMMM y
+FormatData/en_PH/DatePatterns/2=d MMM y
+FormatData/en_PH/DatePatterns/3=dd/MM/y
FormatData/en_PH/DateTimePatterns/0={1} 'at' {0}
LocaleNames/en_PH/kj=Kuanyama
LocaleNames/en_PH/kl=Kalaallisut
@@ -3415,12 +3415,12 @@
FormatData/es_US/Eras/0=a. C.
FormatData/es_US/Eras/1=d. C.
FormatData/es_US/NumberPatterns/0=#,##0.###
-FormatData/es_US/NumberPatterns/1=#,##0.00\u00a0\u00a4
+FormatData/es_US/NumberPatterns/1=\u00a4#,##0.00
FormatData/es_US/NumberPatterns/2=#,##0\u00a0%
-FormatData/es_US/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_US/TimePatterns/1=H:mm:ss z
-FormatData/es_US/TimePatterns/2=H:mm:ss
-FormatData/es_US/TimePatterns/3=H:mm
+FormatData/es_US/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_US/TimePatterns/1=h:mm:ss a z
+FormatData/es_US/TimePatterns/2=h:mm:ss a
+FormatData/es_US/TimePatterns/3=h:mm a
FormatData/es_US/DatePatterns/0=EEEE, d 'de' MMMM 'de' y
FormatData/es_US/DatePatterns/1=d 'de' MMMM 'de' y
FormatData/es_US/DatePatterns/2=d MMM y
@@ -5605,7 +5605,7 @@
#CalendarData/sl/firstDayOfWeek=<MISSING!>
# bug 6573250
-CurrencyNames/en_CA/USD=$
+CurrencyNames/en_CA/USD=US$
# bug 6870908
FormatData/et/MonthNames/0=jaanuar
@@ -7684,14 +7684,14 @@
FormatData/sv_SE/NumberPatterns/2=#,##0\u00a0%
# bug 8017142
-FormatData/es_CL/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_CL/TimePatterns/1=H:mm:ss z
-FormatData/es_CL/TimePatterns/2=H:mm:ss
-FormatData/es_CL/TimePatterns/3=H:mm
-FormatData/es_EC/TimePatterns/0=H:mm:ss (zzzz)
-FormatData/es_EC/TimePatterns/1=H:mm:ss z
-FormatData/es_EC/TimePatterns/2=H:mm:ss
-FormatData/es_EC/TimePatterns/3=H:mm
+FormatData/es_CL/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_CL/TimePatterns/1=h:mm:ss a z
+FormatData/es_CL/TimePatterns/2=h:mm:ss a
+FormatData/es_CL/TimePatterns/3=h:mm a
+FormatData/es_EC/TimePatterns/0=h:mm:ss a zzzz
+FormatData/es_EC/TimePatterns/1=h:mm:ss a z
+FormatData/es_EC/TimePatterns/2=h:mm:ss a
+FormatData/es_EC/TimePatterns/3=h:mm a
# bug 8037343
FormatData/es_DO/DatePatterns/2=d MMM y
--- a/jdk/test/sun/text/resources/LocaleDataTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/text/resources/LocaleDataTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -36,7 +36,7 @@
* 6919624 6998391 7019267 7020960 7025837 7020583 7036905 7066203 7101495
* 7003124 7085757 7028073 7171028 7189611 8000983 7195759 8004489 8006509
* 7114053 7074882 7040556 8008577 8013836 8021121 6192407 6931564 8027695
- * 8017142 8037343 8055222 8042126 8074791 8075173 8080774 8129361
+ * 8017142 8037343 8055222 8042126 8074791 8075173 8080774 8129361 8134916
* @summary Verify locale data
* @run main LocaleDataTest
* @run main LocaleDataTest -cldr
@@ -149,6 +149,7 @@
import java.util.ResourceBundle;
import java.util.ResourceBundle.Control;
import java.util.MissingResourceException;
+import sun.util.resources.LocaleData;
public class LocaleDataTest
{
@@ -312,9 +313,7 @@
} else {
locale = new Locale(language, country, variant);
}
- ResourceBundle bundle = ResourceBundle.getBundle(fullName,
- locale,
- JRELocaleResourceBundleControl.INSTANCE);
+ ResourceBundle bundle = LocaleData.getBundle(fullName, locale);
resource = bundle.getObject(resTag);
}
catch (MissingResourceException e) {
@@ -368,51 +367,6 @@
}
return true;
}
-
- private static class JRELocaleResourceBundleControl extends ResourceBundle.Control {
- static final JRELocaleResourceBundleControl INSTANCE = new JRELocaleResourceBundleControl();
-
- private JRELocaleResourceBundleControl() {
- }
-
- @Override
- public Locale getFallbackLocale(String baseName, Locale locale) {
- if (baseName == null || locale == null) {
- throw new NullPointerException();
- }
- return null;
- }
-
- /**
- * Changes baseName to its per-language/country package name and
- * calls the super class implementation. For example,
- * if the baseName is "sun.text.resources.FormatData" and locale is ja_JP,
- * the baseName is changed to "sun.text.resources.ja.JP.FormatData". If
- * baseName contains "cldr", such as "sun.text.resources.cldr.FormatData",
- * the name is changed to "sun.text.resources.cldr.ja.JP.FormatData".
- */
- @Override
- public String toBundleName(String baseName, Locale locale) {
- String newBaseName = baseName;
- String lang = locale.getLanguage();
- String ctry = locale.getCountry();
- if (lang.length() > 0) {
- if (baseName.startsWith(UTIL_RESOURCES_PACKAGE + cldrSuffix)
- || baseName.startsWith(TEXT_RESOURCES_PACKAGE + cldrSuffix)) {
- // Assume the lengths are the same.
- if (UTIL_RESOURCES_PACKAGE.length()
- != TEXT_RESOURCES_PACKAGE.length()) {
- throw new InternalError("The resources package names have different lengths.");
- }
- int index = (TEXT_RESOURCES_PACKAGE + cldrSuffix).length();
- ctry = (ctry.length() == 2) ? ("." + ctry) : "";
- newBaseName = baseName.substring(0, index + 1) + lang + ctry
- + baseName.substring(index);
- }
- }
- return super.toBundleName(newBaseName, locale);
- }
- }
}
class EscapeReader extends FilterReader {
--- a/jdk/test/sun/tools/jinfo/JInfoSanityTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/tools/jinfo/JInfoSanityTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -71,7 +71,7 @@
String unknownHost = "Oja781nh2ev7vcvbajdg-Sda1-C";
OutputAnalyzer output = JInfoHelper.jinfoNoPid("med@" + unknownHost);
assertNotEquals(output.getExitValue(), 0, "A non-zero exit code should be returned for invalid operation");
- output.shouldContain("UnknownHostException: " + unknownHost);
+ output.shouldMatch(".*(Connection refused to host\\:|UnknownHostException\\:) " + unknownHost + ".*");
}
}
--- a/jdk/test/sun/tools/jps/TestJpsSanity.java Mon Dec 21 17:47:21 2015 +0100
+++ b/jdk/test/sun/tools/jps/TestJpsSanity.java Wed Jul 05 21:09:54 2017 +0200
@@ -62,7 +62,7 @@
OutputAnalyzer output = JpsHelper.jps(invalidHostName);
Asserts.assertNotEquals(output.getExitValue(), 0, "Exit code shouldn't be 0");
Asserts.assertFalse(output.getStderr().isEmpty(), "Error output should not be empty");
- output.shouldContain("Unknown host: " + invalidHostName);
+ output.shouldMatch(".*(RMI Registry not available at|Unknown host\\:) " + invalidHostName + ".*");
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/Hello.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This is a test program used in the test jjs-cpTest.sh.
+ */
+public class Hello {
+ public Hello() {}
+ public String getString() {
+ return "hello";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/args.js Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,21 @@
+/*
+ * This is the test JavaScript program used in jjs-argsTest.sh
+ */
+
+if (typeof(arguments) == 'undefined') {
+ throw new Error("arguments expected");
+}
+
+if (arguments.length != 2) {
+ throw new Error("2 arguments are expected here");
+}
+
+if (arguments[0] != 'hello') {
+ throw new Error("First arg should be 'hello'");
+}
+
+if (arguments[1] != 'world') {
+ throw new Error("Second arg should be 'world'");
+}
+
+print("Passed");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/classpath.js Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,8 @@
+/*
+ * This is the test JavaScript program used in jjs-cpTest.sh
+ */
+
+var v = new Packages.Hello();
+if (v.string != 'hello') {
+ throw new Error("Unexpected property value");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/common.sh Wed Jul 05 21:09:54 2017 +0200
@@ -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.
+#
+
+#
+
+setup() {
+ # Verify directory context variables are set
+ if [ "${TESTJAVA}" = "" ] ; then
+ echo "TESTJAVA not set. Test cannot execute. Failed."
+ exit 1
+ fi
+
+ if [ "${TESTCLASSES}" = "" ] ; then
+ TESTCLASSES="."
+ fi
+
+ if [ "${TESTSRC}" = "" ] ; then
+ TESTSRC="."
+ fi
+
+ OS=`uname -s`
+ case ${OS} in
+ Windows_*)
+ PS=";"
+ FS="\\"
+ # MKS diff deals with trailing CRs automatically
+ golden_diff="diff"
+ ;;
+ CYGWIN*)
+ PS=":"
+ FS="/"
+ # Cygwin diff needs to be told to ignore trailing CRs
+ golden_diff="diff --strip-trailing-cr"
+ ;;
+ *)
+ PS=":"
+ FS="/"
+ # Assume any other platform doesn't have the trailing CR stuff
+ golden_diff="diff"
+ ;;
+ esac
+
+ JJS="${TESTJAVA}/bin/jjs"
+ JAVAC="${TESTJAVA}/bin/javac"
+ JAVA="${TESTJAVA}/bin/java"
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/es6.js Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,13 @@
+/*
+ * This is the test JavaScript program used in jjs-es6Test.sh
+ */
+
+const X = 4;
+try {
+ X = 55;
+ throw new Error("should have thrown TypeError");
+} catch (e) {
+ if (! (e instanceof TypeError)) {
+ throw new Error("TypeError expected, got " + e);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/file.js Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * This is the test JavaScript program used in jjs-fileTest.sh
+ */
+
+// good old 'hello world'!
+print('hello');
+
+// basic number manipulation
+var v = 2 + 5;
+v *= 5;
+v.doubleValue();
+v = v + " is the value";
+if (v != 0) {
+ print('yes v != 0');
+}
+
+// basic java access
+java.lang.System.out.println('hello world from script');
+
+// basic stream manipulation
+var al = new java.util.ArrayList();
+al.add("hello");
+al.add("world");
+// script functions for lambas
+al.stream().map(function(s) s.toUpperCase()).forEach(print);
+
+// interface implementation
+new java.lang.Runnable() {
+ run: function() {
+ print('I am runnable');
+ }
+}.run();
+
+// java class extension
+var MyList = Java.extend(java.util.ArrayList);
+var m = new MyList() {
+ size: function() {
+ print("size called");
+ // call super.size()
+ return Java.super(m).size();
+ }
+};
+
+print("is m an ArrayList? " + (m instanceof java.util.ArrayList));
+m.add("hello");
+m.add("world");
+print(m.size());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/file.out Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,9 @@
+hello
+yes v != 0
+hello world from script
+HELLO
+WORLD
+I am runnable
+is m an ArrayList? true
+size called
+2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/jjs-DTest.sh Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+#
+# 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 8145750
+# @summary jjs fails to run simple scripts with security manager turned on
+# @run shell jjs-DTest.sh
+# Tests passing of Java system property by -D option
+
+. ${TESTSRC-.}/common.sh
+
+setup
+
+# test whether value specified by -D option is passed
+# to script as java.lang.System property.
+
+${JJS} -J-Djava.security.manager -J-Djava.security.policy=${TESTSRC}/sysprops.policy -Djjs.foo=bar ${TESTSRC}/sysprops.js
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/jjs-argsTest.sh Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+#
+# 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 8145750
+# @summary jjs fails to run simple scripts with security manager turned on
+# @run shell jjs-argsTest.sh
+# Tests passing of script arguments from the command line
+
+. ${TESTSRC-.}/common.sh
+
+setup
+
+# we check whether args after "--" are passed as script arguments
+
+${JJS} -J-Djava.security.manager ${TESTSRC}/args.js -- hello world
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/jjs-cpTest.sh Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+#
+# 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 8145750
+# @summary jjs fails to run simple scripts with security manager turned on
+# @run shell jjs-cpTest.sh
+# Tests -cp/-classpath option to set the classpath for jjs
+
+. ${TESTSRC-.}/common.sh
+
+setup
+
+rm -f Hello.class
+${JAVAC} ${TESTSRC}/Hello.java -d .
+
+# we check whether classpath setting for app classes
+# work with jjs. Script should be able to
+# access Java class "Hello".
+
+${JJS} -J-Djava.security.manager -cp . ${TESTSRC}/classpath.js
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+# -classpath and -cp are synonyms
+
+${JJS} -J-Djava.security.manager -classpath . ${TESTSRC}/classpath.js
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+rm -f Hello.class
+echo "Passed"
+exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/jjs-es6Test.sh Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+#
+# 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 8145750
+# @summary jjs fails to run simple scripts with security manager turned on
+# @run shell jjs-es6Test.sh
+# Tests ES6 language setting option '--language=es6'
+
+. ${TESTSRC-.}/common.sh
+
+setup
+
+${JJS} -J-Djava.security.manager --language=es6 ${TESTSRC}/es6.js
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/jjs-fileTest.sh Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+#
+# 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 8145750
+# @summary jjs fails to run simple scripts with security manager turned on
+# @run shell jjs-fileTest.sh
+# Tests basic script file execution. Execute file.js and check output
+# against file.out file
+
+. ${TESTSRC-.}/common.sh
+
+setup
+rm -f jjs-fileTest.out 2>/dev/null
+${JJS} -J-Djava.security.manager ${TESTSRC}/file.js > jjs-fileTest.out 2>&1
+
+$golden_diff jjs-fileTest.out ${TESTSRC}/file.out
+if [ $? != 0 ]
+then
+ echo "Output of jjs file.js differ from expected output. Failed."
+ rm -f jjs-fileTest.out 2>/dev/null
+ exit 1
+fi
+
+rm -f jjs-fTest.out
+echo "Passed"
+exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/jjs-helpTest.sh Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please 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 8145750
+# @summary jjs fails to run simple scripts with security manager turned on
+# @run shell jjs-helpTest.sh
+# Tests that the output of 'jjs -help' is not empty
+
+. ${TESTSRC-.}/common.sh
+
+setup
+
+rm -f jjs-helpTest.out 2>/dev/null
+${JJS} -J-Djava.security.manager -help > jjs-helpTest.out 2>&1
+
+if [ ! -s jjs-helpTest.out ]
+then
+ echo "Output of jjs -help is empty. Failed."
+ rm -f jjs-helpTest.out 2>/dev/null
+ exit 1
+fi
+
+rm -f jjs-helpTest.out 2>/dev/null
+
+echo "Passed"
+exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/jjs-scriptingTest.sh Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+#
+# 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 8145750
+# @summary jjs fails to run simple scripts with security manager turned on
+# @run shell jjs-scriptingTest.sh
+# Tests setting scripting mode via -scripting option
+
+. ${TESTSRC-.}/common.sh
+
+setup
+
+${JJS} -J-Djava.security.manager -scripting ${TESTSRC}/scripting.js
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/jjs-strictTest.sh Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+#
+# 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 8145750
+# @summary jjs fails to run simple scripts with security manager turned on
+# @run shell jjs-strictTest.sh
+# Tests basic ECMAScript strict mode setting via -strict option
+
+. ${TESTSRC-.}/common.sh
+
+setup
+
+${JJS} -J-Djava.security.manager -strict ${TESTSRC}/strict.js
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/scripting.js Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,18 @@
+/*
+ * This is the test JavaScript program used in jjs-scriptingTest.sh
+ */
+
+var str = <<END
+Multi line string
+works in scripting
+END
+
+var n = "Nashorn";
+var hello = "Hello, ${n}";
+if (hello != "Hello, Nashorn") {
+ throw new Error("string interpolation didn't work");
+}
+
+if (typeof readFully != "function") {
+ throw new Error("readFully is defined in -scripting");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/strict.js Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,12 @@
+/*
+ * This is the test JavaScript program used in jjs-strictTest.sh
+ */
+
+try {
+ v = "hello";
+ throw new Error("should have thrown ReferenceError");
+} catch (e) {
+ if (! (e instanceof ReferenceError)) {
+ throw new Error("ReferenceError expected, got " + e);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/sysprops.js Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,11 @@
+/*
+ * This is the test JavaScript program used in jjs-DTest.sh
+ */
+
+var Sys = java.lang.System;
+if (Sys.getProperty("jjs.foo") == "bar") {
+ print("Passed");
+} else {
+ // unexpected value
+ throw new Error("Unexpected System property value");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jjs/sysprops.policy Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,3 @@
+grant {
+ permission java.util.PropertyPermission "*", "read";
+};
--- a/make/Help.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/make/Help.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -83,6 +83,7 @@
$(info $(_) # To see executed command lines, use LOG=debug)
$(info $(_) JOBS=<n> # Run <n> parallel make jobs)
$(info $(_) # Note that -jN does not work as expected!)
+ $(info $(_) TEST_JOBS=<n> # Run <n> parallel test jobs)
$(info $(_) CONF_CHECK=<method> # What to do if spec file is out of date)
$(info $(_) # method is 'auto', 'ignore' or 'fail' (default))
$(info $(_) make test TEST=<test> # Only run the given test or tests, e.g.)
--- a/make/InitSupport.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/make/InitSupport.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -40,7 +40,8 @@
##############################################################################
# Make control variables, handled by Init.gmk
- INIT_CONTROL_VARIABLES := LOG CONF CONF_NAME SPEC JOBS CONF_CHECK COMPARE_BUILD
+ INIT_CONTROL_VARIABLES := LOG CONF CONF_NAME SPEC JOBS TEST_JOBS CONF_CHECK \
+ COMPARE_BUILD
# All known make control variables
MAKE_CONTROL_VARIABLES := $(INIT_CONTROL_VARIABLES) TEST JDK_FILTER
--- a/make/MainSupport.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/make/MainSupport.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -35,7 +35,8 @@
($(CD) $(SRC_ROOT)/test && $(MAKE) $(MAKE_ARGS) -j1 -k MAKEFLAGS= \
JT_HOME=$(JT_HOME) PRODUCT_HOME=$(JDK_IMAGE_DIR) \
TEST_IMAGE_DIR=$(TEST_IMAGE_DIR) \
- ALT_OUTPUTDIR=$(OUTPUT_ROOT) CONCURRENCY=$(JOBS) $1) || true
+ ALT_OUTPUTDIR=$(OUTPUT_ROOT) TEST_JOBS=$(TEST_JOBS) \
+ JOBS=$(JOBS) $1) || true
endef
# Cleans the dir given as $1
--- a/make/common/MakeBase.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/make/common/MakeBase.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -151,16 +151,16 @@
$(eval compress_paths = \
$(strip $(shell $(CAT) $(SRC_ROOT)/make/common/support/ListPathsSafely-pre-compress.incl)))
compress_paths += \
-$(subst $(SRC_ROOT),X97,\
-$(subst $(OUTPUT_ROOT),X98,\
-$(subst X,X00,\
+ $(subst $(SRC_ROOT),X97, \
+ $(subst $(OUTPUT_ROOT),X98, \
+ $(subst X,X00, \
$(subst $(SPACE),\n,$(strip $1)))))
$(eval compress_paths += \
$(strip $(shell $(CAT) $(SRC_ROOT)/make/common/support/ListPathsSafely-post-compress.incl)))
decompress_paths=$(SED) -f $(SRC_ROOT)/make/common/support/ListPathsSafely-uncompress.sed \
-e 's|X99|\\n|g' \
- -e 's|X98|$(OUTPUT_ROOT)|g' -e 's|X97|$(SRC_ROOT)|g' \
+ -e 's|X98|$(OUTPUT_ROOT)|g' -e 's|X97|$(SRC_ROOT)|g' \
-e 's|X00|X|g'
ListPathsSafely_IfPrintf = \
@@ -172,10 +172,10 @@
# Param 1 - Name of variable containing paths/arguments to output
# Param 2 - File to print to
# Param 3 - Set to true to append to file instead of overwriting
-define ListPathsSafely
- ifneq (,$$(word 10001,$$($1)))
- $$(error Cannot list safely more than 10000 paths. $1 has $$(words $$($1)) paths!)
- endif
+ define ListPathsSafely
+ ifneq (,$$(word 10001,$$($1)))
+ $$(error Cannot list safely more than 10000 paths. $1 has $$(words $$($1)) paths!)
+ endif
$$(call MakeDir, $$(dir $2))
ifneq ($$(strip $3), true)
$$(shell $(RM) $$(strip $2))
@@ -230,7 +230,7 @@
$$(call ListPathsSafely_IfPrintf,$1,$2,9251,9500)
$$(call ListPathsSafely_IfPrintf,$1,$2,9501,9750)
$$(call ListPathsSafely_IfPrintf,$1,$2,9751,10000)
-endef
+ endef
endif # HAS_FILE_FUNCTION
# The source tips can come from the Mercurial repository, or in the files
@@ -285,18 +285,24 @@
# Never remove warning messages; this is just for completeness
LOG_WARN :=
ifneq ($$(findstring $$(LOG_LEVEL), info debug trace),)
+ LogInfo = $$(info $$(strip $$1))
LOG_INFO :=
else
+ LogInfo =
LOG_INFO := > /dev/null
endif
ifneq ($$(findstring $$(LOG_LEVEL), debug trace),)
+ LogDebug = $$(info $$(strip $$1))
LOG_DEBUG :=
else
+ LogDebug =
LOG_DEBUG := > /dev/null
endif
ifneq ($$(findstring $$(LOG_LEVEL), trace),)
+ LogTrace = $$(info $$(strip $$1))
LOG_TRACE :=
else
+ LogTrace =
LOG_TRACE := > /dev/null
endif
endef
@@ -450,6 +456,23 @@
$(strip $(if $1,$(patsubst $(firstword $1)%,%,\
$(call remove-prefixes,$(filter-out $(firstword $1),$1),$2)),$2))
+# Convert the string given to upper case, without any $(shell)
+# Inspired by http://lists.gnu.org/archive/html/help-make/2013-09/msg00009.html
+uppercase_table := a,A b,B c,C d,D e,E f,F g,G h,H i,I j,J k,K l,L m,M n,N o,O \
+ p,P q,Q r,R s,S t,T u,U v,V w,W x,X y,Y z,Z
+
+uppercase_internal = \
+ $(if $(strip $1), $$(subst $(firstword $1), $(call uppercase_internal, \
+ $(wordlist 2, $(words $1), $1), $2)), $2)
+
+# Convert a string to upper case. Works only on a-z.
+# $1 - The string to convert
+uppercase = \
+ $(strip \
+ $(eval uppercase_result := $(call uppercase_internal, $(uppercase_table), $1)) \
+ $(uppercase_result) \
+ )
+
################################################################################
ifneq ($(DISABLE_CACHE_FIND), true)
@@ -560,8 +583,9 @@
$1_NAME_MACRO := identity
endif
- # Remove any trailing slash from SRC
+ # Remove any trailing slash from SRC and DEST
$1_SRC := $$(patsubst %/,%,$$($1_SRC))
+ $1_DEST := $$(patsubst %/,%,$$($1_DEST))
$$(foreach f, $$(patsubst $$($1_SRC)/%,%,$$($1_FILES)), \
$$(eval $$(call AddFileToCopy, $$($1_SRC)/$$f, \
@@ -592,9 +616,9 @@
WriteFile = \
$(file >$2,$(strip $1))
else
-# Use printf to get consistent behavior on all platforms.
-WriteFile = \
- $(shell $(PRINTF) "%s" $(call ShellQuote, $1) > $2)
+ # Use printf to get consistent behavior on all platforms.
+ WriteFile = \
+ $(shell $(PRINTF) "%s" $(call ShellQuote, $1) > $2)
endif
################################################################################
--- a/make/common/NativeCompilation.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/make/common/NativeCompilation.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -129,6 +129,12 @@
SYSROOT_LDFLAGS := $(BUILD_SYSROOT_LDFLAGS), \
))
+# BUILD toolchain with the C++ linker
+$(eval $(call DefineNativeToolchain, TOOLCHAIN_BUILD_LINK_CXX, \
+ EXTENDS := TOOLCHAIN_BUILD, \
+ LD := $(BUILD_LDCXX), \
+))
+
################################################################################
# Extensions of files handled by this macro.
@@ -209,8 +215,8 @@
$1_$2_OBJ := $3/$$(call replace_with_obj_extension, $$(notdir $2))
# Only continue if this object file hasn't been processed already. This lets the first found
# source file override any other with the same name.
- ifeq (,$$(findstring $$($1_$2_OBJ),$$($1_ALL_OBJS)))
- $1_ALL_OBJS+=$$($1_$2_OBJ)
+ ifeq (,$$(findstring $$($1_$2_OBJ),$$($1_OBJS_SO_FAR)))
+ $1_OBJS_SO_FAR+=$$($1_$2_OBJ)
ifeq (,$$(filter %.s,$2))
# And this is the dependency file for this obj file.
$1_$2_DEP:=$$(patsubst %$(OBJ_SUFFIX),%.d,$$($1_$2_OBJ))
@@ -223,13 +229,18 @@
-include $$($1_$2_DEP_TARGETS)
ifeq ($(TOOLCHAIN_TYPE), microsoft)
- $1_$2_DEBUG_OUT_FLAGS:=-Fd$$(patsubst %$(OBJ_SUFFIX),%.pdb,$$($1_$2_OBJ)) \
- -Fm$$(patsubst %$(OBJ_SUFFIX),%.map,$$($1_$2_OBJ))
+ $1_$2_DEBUG_OUT_FLAGS:=-Fd$$(patsubst %$(OBJ_SUFFIX),%.pdb,$$($1_$2_OBJ))
endif
endif
- $$($1_$2_OBJ) : $2 $$($1_COMPILE_VARDEPS_FILE) | $$($1_BUILD_INFO)
- $(ECHO) $(LOG_INFO) "Compiling $$(notdir $2) (for $$(notdir $$($1_TARGET)))"
+ ifneq ($$($1_$(notdir $2)_CFLAGS)$$($1_$(notdir $2)_CXXFLAGS), )
+ $1_$2_VARDEPS := $$($1_$(notdir $2)_CFLAGS) $$($1_$(notdir $2)_CXXFLAGS)
+ $1_$2_VARDEPS_FILE := $$(call DependOnVariable, $1_$2_VARDEPS, \
+ $$(patsubst %$(OBJ_SUFFIX),%.vardeps,$$($1_$2_OBJ)))
+ endif
+
+ $$($1_$2_OBJ) : $2 $$($1_COMPILE_VARDEPS_FILE) $$($1_$2_VARDEPS_FILE) | $$($1_BUILD_INFO)
+ $$(call LogInfo, Compiling $$(notdir $2) (for $$(notdir $$($1_TARGET))))
ifneq ($(TOOLCHAIN_TYPE), microsoft)
ifeq ($(TOOLCHAIN_TYPE)$$(filter %.s,$2), solstudio)
# The Solaris studio compiler doesn't output the full path to the object file in the
@@ -251,15 +262,17 @@
# setting -showIncludes, all included files are printed. These are filtered out and
# parsed into make dependences.
# Keep as much as possible on one execution line for best performance on Windows
+ $(RM) $$($1_$2_DEP).exitvalue ; \
($(call LogFailures, $$($1_$2_OBJ).log, $$($1_SAFE_NAME)_$$(notdir $2), \
$$($1_$2_COMP) $$($1_$2_FLAGS) -showIncludes $$($1_$2_DEBUG_OUT_FLAGS) \
- $(CC_OUT_OPTION)$$($1_$2_OBJ) $2) ; echo $$$$? > $$($1_$2_DEP).exitvalue) \
+ $(CC_OUT_OPTION)$$($1_$2_OBJ) $2) || echo $$$$? > $$($1_$2_DEP).exitvalue ) \
| $(TEE) $$($1_$2_DEP).raw | $(GREP) -v -e "^Note: including file:" \
-e "^$(notdir $2)$$$$" || test "$$$$?" = "1" ; \
- exit `cat $$($1_$2_DEP).exitvalue` ; \
- $(RM) $$($1_$2_DEP).exitvalue ; \\
+ ( test -s $$($1_$2_DEP).exitvalue \
+ && exit `$(CAT) $$($1_$2_DEP).exitvalue` || true ) ; \
($(ECHO) $$@: \\ ; \
- $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_$2_DEP).raw) | $(SORT) -u > $$($1_$2_DEP) ; \
+ $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_$2_DEP).raw) \
+ | $(SORT) -u > $$($1_$2_DEP) ; \
$(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_$2_DEP) > $$($1_$2_DEP_TARGETS)
endif
endif
@@ -286,7 +299,9 @@
# EXCLUDES do not pick source from these directories
# INCLUDE_FILES only compile exactly these files!
# EXCLUDE_FILES with these names
+# EXCLUDE_PATTERN exclude files matching any of these substrings
# EXTRA_FILES List of extra files not in any of the SRC dirs
+# EXTRA_OBJECT_FILES List of extra object files to include when linking
# VERSIONINFO_RESOURCE Input file for RC. Setting this implies that RC will be run
# RC_FLAGS flags for RC.
# MAPFILE mapfile
@@ -430,19 +445,29 @@
$$(error SRC specified to SetupNativeCompilation $1 contains missing directory $$d)))
# Find all files in the source trees. Sort to remove duplicates.
- $1_ALL_SRCS := $$(sort $$(call CacheFind,$$($1_SRC)))
+ $1_SRCS := $$(sort $$(call CacheFind,$$($1_SRC)))
+ $1_SRCS := $$(filter $$(NATIVE_SOURCE_EXTENSIONS), $$($1_SRCS))
# Extract the C/C++ files.
- $1_EXCLUDE_FILES:=$$(foreach i,$$($1_SRC),$$(addprefix $$i/,$$($1_EXCLUDE_FILES)))
- $1_INCLUDE_FILES:=$$(foreach i,$$($1_SRC),$$(addprefix $$i/,$$($1_INCLUDE_FILES)))
- ifneq ($$($1_EXCLUDE_FILES),)
- $1_EXCLUDE_FILES:=$$(addprefix %,$$($1_EXCLUDE_FILES))
+ ifneq ($$($1_EXCLUDE_PATTERNS), )
+ # We must not match the exclude pattern against the src root(s).
+ $1_SRCS_WITHOUT_ROOTS := $$($1_SRCS)
+ $$(foreach i,$$($1_SRC),$$(eval $1_SRCS_WITHOUT_ROOTS := $$(patsubst \
+ $$i/%,%, $$($1_SRCS_WITHOUT_ROOTS))))
+ $1_ALL_EXCLUDE_FILES := $$(call containing, $$($1_EXCLUDE_PATTERNS), \
+ $$($1_SRCS_WITHOUT_ROOTS))
endif
- $1_SRCS := $$(filter-out $$($1_EXCLUDE_FILES),$$(filter $$(NATIVE_SOURCE_EXTENSIONS),$$($1_ALL_SRCS)))
- ifneq (,$$(strip $$($1_INCLUDE_FILES)))
- $1_SRCS := $$(filter $$($1_INCLUDE_FILES),$$($1_SRCS))
+ ifneq ($$($1_EXCLUDE_FILES),)
+ $1_ALL_EXCLUDE_FILES += $$($1_EXCLUDE_FILES)
endif
- ifeq (,$$($1_SRCS))
- $$(error No sources found for $1 when looking inside the dirs $$($1_SRC))
+ ifneq ($$($1_ALL_EXCLUDE_FILES),)
+ $1_EXCLUDE_FILES_PAT := $$($1_ALL_EXCLUDE_FILES) \
+ $$(foreach i,$$($1_SRC),$$(addprefix $$i/,$$($1_ALL_EXCLUDE_FILES)))
+ $1_EXCLUDE_FILES_PAT := $$(addprefix %,$$($1_EXCLUDE_FILES_PAT))
+ $1_SRCS := $$(filter-out $$($1_EXCLUDE_FILES_PAT),$$($1_SRCS))
+ endif
+ ifneq ($$($1_INCLUDE_FILES), )
+ $1_INCLUDE_FILES_PAT := $$(foreach i,$$($1_SRC),$$(addprefix $$i/,$$($1_INCLUDE_FILES)))
+ $1_SRCS := $$(filter $$($1_INCLUDE_FILES_PAT),$$($1_SRCS))
endif
# There can be only a single bin dir root, no need to foreach over the roots.
$1_BINS := $$(wildcard $$($1_OBJECT_DIR)/*$(OBJ_SUFFIX))
@@ -466,16 +491,17 @@
$$(error No sources found for $1 when looking inside the dirs $$($1_SRC))
endif
- # Calculate the expected output from compiling the sources (sort to remove duplicates. Also provides
- # a reproducable order on the input files to the linker).
+ # Calculate the expected output from compiling the sources
$1_EXPECTED_OBJS_FILENAMES := $$(call replace_with_obj_extension, $$(notdir $$($1_SRCS)))
- $1_EXPECTED_OBJS:=$$(sort $$(addprefix $$($1_OBJECT_DIR)/,$$($1_EXPECTED_OBJS_FILENAMES)))
+ $1_EXPECTED_OBJS := $$(addprefix $$($1_OBJECT_DIR)/,$$($1_EXPECTED_OBJS_FILENAMES))
# Are there too many object files on disk? Perhaps because some source file was removed?
$1_SUPERFLOUS_OBJS:=$$(sort $$(filter-out $$($1_EXPECTED_OBJS),$$($1_BINS)))
# Clean out the superfluous object files.
ifneq ($$($1_SUPERFLUOUS_OBJS),)
$$(shell $(RM) -f $$($1_SUPERFLUOUS_OBJS))
endif
+ # Sort to remove dupliates and provide a reproducable order on the input files to the linker.
+ $1_ALL_OBJS := $$(sort $$($1_EXPECTED_OBJS) $$($1_EXTRA_OBJECT_FILES))
# Pickup extra OPENJDK_TARGET_OS_TYPE and/or OPENJDK_TARGET_OS dependent variables for CFLAGS.
$1_EXTRA_CFLAGS:=$$($1_CFLAGS_$(OPENJDK_TARGET_OS_TYPE)) $$($1_CFLAGS_$(OPENJDK_TARGET_OS))
@@ -593,9 +619,7 @@
# variables used in the call to add_native_source below.
$1_COMPILE_VARDEPS := $$($1_CFLAGS) $$($1_EXTRA_CFLAGS) $$($1_SYSROOT_CFLAGS) \
$$($1_CXXFLAGS) $$($1_EXTRA_CXXFLAGS) \
- $$($1_CC) $$($1_CXX) $$($1_AS) $$($1_ASFLAGS) \
- $$(foreach s, $$($1_SRCS), \
- $$($1_$$(notdir $$s)_CFLAGS) $$($1_$$(notdir $$s)_CXXFLAGS))
+ $$($1_CC) $$($1_CXX) $$($1_AS) $$($1_ASFLAGS)
$1_COMPILE_VARDEPS_FILE := $$(call DependOnVariable, $1_COMPILE_VARDEPS, \
$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).comp.vardeps)
@@ -675,55 +699,62 @@
ifeq ($$($1_STATIC_LIBRARY),)
ifeq ($$($1_DEBUG_SYMBOLS), true)
ifeq ($(ENABLE_DEBUG_SYMBOLS), true)
- ifneq ($(OPENJDK_TARGET_OS), macosx) # no MacOS X support yet
- ifneq ($$($1_OUTPUT_DIR),$$($1_OBJECT_DIR))
- # The dependency on TARGET is needed on windows for debuginfo files
- # to be rebuilt properly.
- $$($1_OUTPUT_DIR)/% : $$($1_OBJECT_DIR)/% $$($1_TARGET)
+ ifneq ($$($1_OUTPUT_DIR), $$($1_OBJECT_DIR))
+ # The dependency on TARGET is needed on windows for debuginfo files
+ # to be rebuilt properly.
+ $$($1_OUTPUT_DIR)/% : $$($1_OBJECT_DIR)/% $$($1_TARGET)
$(CP) $$< $$@
- endif
+ endif
- # Generate debuginfo files.
- ifeq ($(OPENJDK_TARGET_OS), windows)
- $1_EXTRA_LDFLAGS += "-pdb:$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).pdb" \
- "-map:$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).map"
- $1_DEBUGINFO_FILES := $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).pdb \
- $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).map
- # No separate command is needed for debuginfo on windows, instead
- # touch target to make sure it has a later time stamp than the debug
- # symbol files to avoid unnecessary relinking on rebuild.
- $1_CREATE_DEBUGINFO_CMDS := $(TOUCH) $$($1_TARGET)
+ # Generate debuginfo files.
+ ifeq ($(OPENJDK_TARGET_OS), windows)
+ $1_EXTRA_LDFLAGS += "-pdb:$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).pdb" \
+ "-map:$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).map"
+ $1_DEBUGINFO_FILES := $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).pdb \
+ $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).map
+ # No separate command is needed for debuginfo on windows, instead
+ # touch target to make sure it has a later time stamp than the debug
+ # symbol files to avoid unnecessary relinking on rebuild.
+ $1_CREATE_DEBUGINFO_CMDS := $(TOUCH) $$($1_TARGET)
- else ifneq ($(findstring $(OPENJDK_TARGET_OS), linux solaris), )
- $1_DEBUGINFO_FILES := $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).debuginfo
- # Setup the command line creating debuginfo files, to be run after linking.
- # It cannot be run separately since it updates the original target file
- $1_CREATE_DEBUGINFO_CMDS := \
- $(OBJCOPY) --only-keep-debug $$($1_TARGET) $$($1_DEBUGINFO_FILES) $$(NEWLINE) \
- $(CD) $$($1_OUTPUT_DIR) && \
- $(OBJCOPY) --add-gnu-debuglink=$$($1_DEBUGINFO_FILES) $$($1_TARGET)
- endif # No MacOS X support
+ else ifneq ($(findstring $(OPENJDK_TARGET_OS), linux solaris), )
+ $1_DEBUGINFO_FILES := $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).debuginfo
+ # Setup the command line creating debuginfo files, to be run after linking.
+ # It cannot be run separately since it updates the original target file
+ $1_CREATE_DEBUGINFO_CMDS := \
+ $(OBJCOPY) --only-keep-debug $$($1_TARGET) $$($1_DEBUGINFO_FILES) $$(NEWLINE) \
+ $(CD) $$($1_OUTPUT_DIR) && \
+ $(OBJCOPY) --add-gnu-debuglink=$$($1_DEBUGINFO_FILES) $$($1_TARGET)
- # This dependency dance ensures that debug info files get rebuilt
- # properly if deleted.
- $$($1_TARGET): $$($1_DEBUGINFO_FILES)
- $$($1_DEBUGINFO_FILES): $$($1_EXPECTED_OBJS)
+ else ifeq ($(OPENJDK_TARGET_OS), macosx)
+ $1_DEBUGINFO_FILES := $$($1_OBJECT_DIR)/$$($1_BASENAME).dSYM
+ # On Macosx, the debuginfo generation doesn't touch the linked binary, but
+ # to avoid always relinking, touch it anyway to force a later timestamp than
+ # the dSYM files.
+ $1_CREATE_DEBUGINFO_CMDS := \
+ $(DSYMUTIL) --out $$($1_DEBUGINFO_FILES) $$($1_TARGET) $$(NEWLINE) \
+ $(TOUCH) $$($1_TARGET)
+ endif # OPENJDK_TARGET_OS
- ifeq ($(ZIP_DEBUGINFO_FILES), true)
- $1_DEBUGINFO_ZIP := $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).diz
- $1 += $$(subst $$($1_OBJECT_DIR),$$($1_OUTPUT_DIR),$$($1_DEBUGINFO_ZIP))
+ # This dependency dance ensures that debug info files get rebuilt
+ # properly if deleted.
+ $$($1_TARGET): $$($1_DEBUGINFO_FILES)
+ $$($1_DEBUGINFO_FILES): $$($1_ALL_OBJS)
- # The dependency on TARGET is needed for debuginfo files
- # to be rebuilt properly.
- $$($1_DEBUGINFO_ZIP): $$($1_DEBUGINFO_FILES) $$($1_TARGET)
+ ifeq ($(ZIP_DEBUGINFO_FILES), true)
+ $1_DEBUGINFO_ZIP := $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).diz
+ $1 += $$(subst $$($1_OBJECT_DIR),$$($1_OUTPUT_DIR),$$($1_DEBUGINFO_ZIP))
+
+ # The dependency on TARGET is needed for debuginfo files
+ # to be rebuilt properly.
+ $$($1_DEBUGINFO_ZIP): $$($1_DEBUGINFO_FILES) $$($1_TARGET)
$(CD) $$($1_OBJECT_DIR) \
&& $(ZIP) -q $$@ $$(notdir $$($1_DEBUGINFO_FILES))
- else
- $1 += $$(subst $$($1_OBJECT_DIR),$$($1_OUTPUT_DIR),$$($1_DEBUGINFO_FILES))
- endif
+ else
+ $1 += $$(subst $$($1_OBJECT_DIR),$$($1_OUTPUT_DIR),$$($1_DEBUGINFO_FILES))
endif
- endif # !MacOS X
+ endif # $(ENABLE_DEBUG_SYMBOLS)
endif # $1_DEBUG_SYMBOLS
endif # !STATIC_LIBRARY
@@ -750,21 +781,34 @@
$1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \
$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).vardeps)
- $$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_REAL_MAPFILE) \
+ $1_LD_OBJ_ARG := $$($1_ALL_OBJS)
+
+ # If there are many object files, use an @-file.
+ ifneq ($$(word 17, $$($1_ALL_OBJS)), )
+ $1_OBJ_FILE_LIST := $$($1_OBJECT_DIR)/_$1_objectfilenames.txt
+ ifneq ($(TOOLCHAIN_TYPE),solstudio)
+ $1_LD_OBJ_ARG := $(COMPILER_COMMAND_FILE_FLAG)$$($1_OBJ_FILE_LIST)
+ else
+ # The solstudio linker does not support @-files.
+ $1_LD_OBJ_ARG := `cat $$($1_OBJ_FILE_LIST)`
+ endif
+ endif
+
+ $$($1_TARGET): $$($1_ALL_OBJS) $$($1_RES) $$($1_REAL_MAPFILE) \
$$($1_VARDEPS_FILE)
+ ifneq ($$($1_OBJ_FILE_LIST), )
+ $$(eval $$(call ListPathsSafely, $1_ALL_OBJS, $$($1_OBJ_FILE_LIST)))
+ endif
+ # Keep as much as possible on one execution line for best performance
+ # on Windows
$(ECHO) $(LOG_INFO) "Linking $$($1_BASENAME)" ; \
$(call LogFailures, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_link.log, $$($1_SAFE_NAME)_link, \
$$($1_LD) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $$($1_SYSROOT_LDFLAGS) \
$(LD_OUT_OPTION)$$@ \
- $$($1_EXPECTED_OBJS) $$($1_RES) \
+ $$($1_LD_OBJ_ARG) $$($1_RES) \
$$($1_LIBS) $$($1_EXTRA_LIBS)) ; \
$$($1_CREATE_DEBUGINFO_CMDS)
$$($1_STRIP_CMD)
- # Touch target to make sure it has a later time stamp than the debug
- # symbol files to avoid unnecessary relinking on rebuild.
- ifeq ($(OPENJDK_TARGET_OS), windows)
- $(TOUCH) $$@
- endif
endif
@@ -775,10 +819,10 @@
$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).vardeps)
# Generating a static library, ie object file archive.
- $$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_VARDEPS_FILE)
+ $$($1_TARGET): $$($1_ALL_OBJS) $$($1_RES) $$($1_VARDEPS_FILE)
$(ECHO) $(LOG_INFO) "Archiving $$($1_STATIC_LIBRARY)"
$(call LogFailures, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_link.log, $$($1_SAFE_NAME)_link, \
- $$($1_AR) $$($1_ARFLAGS) $(AR_OUT_OPTION)$$($1_TARGET) $$($1_EXPECTED_OBJS) \
+ $$($1_AR) $$($1_ARFLAGS) $(AR_OUT_OPTION)$$($1_TARGET) $$($1_ALL_OBJS) \
$$($1_RES))
ifeq ($(STATIC_BUILD), true)
$(GetSymbols)
@@ -796,13 +840,13 @@
$1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \
$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).vardeps)
- $$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_MANIFEST) \
+ $$($1_TARGET): $$($1_ALL_OBJS) $$($1_RES) $$($1_MANIFEST) \
$$($1_VARDEPS_FILE)
$(ECHO) $(LOG_INFO) "Linking executable $$($1_BASENAME)" ; \
$(call LogFailures, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_link.log, $$($1_SAFE_NAME)_link, \
$$($1_LD) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $$($1_SYSROOT_LDFLAGS) \
$(EXE_OUT_OPTION)$$($1_TARGET) \
- $$($1_EXPECTED_OBJS) $$($1_RES) \
+ $$($1_ALL_OBJS) $$($1_RES) \
$$($1_LIBS) $$($1_EXTRA_LIBS))
ifeq ($(OPENJDK_TARGET_OS), windows)
ifneq ($$($1_MANIFEST), )
@@ -818,11 +862,6 @@
endif
$$($1_CREATE_DEBUGINFO_CMDS)
$$($1_STRIP_CMD)
- # Touch target to make sure it has a later time stamp than the debug
- # symbol files to avoid unnecessary relinking on rebuild.
- ifeq ($(OPENJDK_TARGET_OS), windows)
- $(TOUCH) $$@
- endif
endif
endef
--- a/make/devkit/Tools.gmk Mon Dec 21 17:47:21 2015 +0100
+++ b/make/devkit/Tools.gmk Wed Jul 05 21:09:54 2017 +0200
@@ -82,7 +82,9 @@
libXi libXi-devel \
libXdmcp libXdmcp-devel \
libXau libXau-devel \
- libgcc
+ libgcc \
+ elfutils elfutils-devel \
+ elfutils-libelf elfutils-libelf-devel
ifeq ($(ARCH),x86_64)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/devkit/createSolarisDevkit.sh Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,148 @@
+#!/bin/bash
+#
+# 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 script creates a devkit for building OpenJDK on Solaris by copying
+# part of a Solaris Studio installation and cretaing a sysroot by installing
+# a limited set of system packages. It is assumed that a suitable pkg
+# publisher is configured for the system where the script is executed.
+#
+# The Solaris Studio installation must contain at least these packages:
+# developer/solarisstudio-124/backend 12.4-1.0.6.0 i--
+# developer/solarisstudio-124/c++ 12.4-1.0.10.0 i--
+# developer/solarisstudio-124/cc 12.4-1.0.4.0 i--
+# developer/solarisstudio-124/library/c++-libs 12.4-1.0.10.0 i--
+# developer/solarisstudio-124/library/math-libs 12.4-1.0.0.1 i--
+# developer/solarisstudio-124/library/studio-gccrt 12.4-1.0.0.1 i--
+# developer/solarisstudio-124/studio-common 12.4-1.0.0.1 i--
+# developer/solarisstudio-124/studio-ja 12.4-1.0.0.1 i--
+# developer/solarisstudio-124/studio-legal 12.4-1.0.0.1 i--
+# developer/solarisstudio-124/studio-zhCN 12.4-1.0.0.1 i--
+# In particular backend 12.4-1.0.6.0 contains a critical patch for the sparc
+# version.
+#
+# erik.joelsson@oracle.com
+
+USAGE="$0 <Solaris Studio installation> <Path to gnu make binary>"
+
+if [ "$1" = "" ] || [ "$2" = "" ]; then
+ echo $USAGE
+ exit 1
+fi
+
+SOLARIS_STUDIO_VERSION=12u4
+SOLARIS_VERSION=11u1
+case `uname -p` in
+ i*)
+ ARCH=x86
+ ;;
+ sparc*)
+ ARCH=sparc
+ ;;
+esac
+
+SOLARIS_STUDIO_SRC=$1
+GNU_MAKE=$2
+
+SCRIPT_DIR="$(cd "$(dirname $0)" > /dev/null && pwd)"
+BUILD_DIR="${SCRIPT_DIR}/../../build/devkit"
+
+DEVKIT_NAME=SS${SOLARIS_STUDIO_VERSION}-Solaris${SOLARIS_VERSION}
+DEVKIT_ROOT=${BUILD_DIR}/${DEVKIT_NAME}
+BUNDLE_NAME=${DEVKIT_NAME}.tar.gz
+BUNDLE=${BUILD_DIR}/${BUNDLE_NAME}
+INSTALL_ROOT=${BUILD_DIR}/install-root
+SYSROOT=${DEVKIT_ROOT}/sysroot
+SOLARIS_STUDIO_SUBDIR=SS${SOLARIS_STUDIO_VERSION}
+SOLARIS_STUDIO_DIR=${DEVKIT_ROOT}/${SOLARIS_STUDIO_SUBDIR}
+
+# Extract the publisher from the system
+if [ -z "${PUBLISHER_URI}" ]; then
+ PUBLISHER_URI="$(pkg publisher solaris | grep URI | awk '{ print $3 }')"
+fi
+
+if [ ! -d $INSTALL_ROOT ]; then
+ echo "Creating $INSTALL_ROOT and installing packages"
+ pkg image-create $INSTALL_ROOT
+ pkg -R $INSTALL_ROOT set-publisher -P -g ${PUBLISHER_URI} solaris
+ pkg -R $INSTALL_ROOT install --accept $(cat solaris11.1-package-list.txt)
+else
+ echo "Skipping installing packages"
+fi
+
+if [ ! -d $SYSROOT ]; then
+ echo "Copying from $INSTALL_ROOT to $SYSROOT"
+ mkdir -p $SYSROOT
+ cp -rH $INSTALL_ROOT/lib $SYSROOT/
+ mkdir $SYSROOT/usr $DEVKIT_ROOT/gnu
+ # Some of the tools in sysroot are needed in the OpenJDK build but cannot be
+ # run from their current location due to relative runtime paths in the
+ # binaries. Move the sysroot/usr/bin directory to the outer bin and have them
+ # be runnable from there to force them to link to the system libraries
+ cp -rH $INSTALL_ROOT/usr/bin $DEVKIT_ROOT
+ cp -rH $INSTALL_ROOT/usr/gnu/bin $DEVKIT_ROOT/gnu/
+ cp -rH $INSTALL_ROOT/usr/lib $SYSROOT/usr/
+ cp -rH $INSTALL_ROOT/usr/include $SYSROOT/usr/
+ pkg -R $INSTALL_ROOT list > $SYSROOT/pkg-list.txt
+else
+ echo "Skipping copying to $SYSROOT"
+fi
+
+if [ ! -d $SOLARIS_STUDIO_DIR ]; then
+ echo "Copying Solaris Studio from $SOLARIS_STUDIO_SRC"
+ cp -rH $SOLARIS_STUDIO_SRC ${SOLARIS_STUDIO_DIR%/*}
+ mv ${SOLARIS_STUDIO_DIR%/*}/${SOLARIS_STUDIO_SRC##*/} $SOLARIS_STUDIO_DIR
+ # Solaris Studio 12.4 requires /lib/libmmheap.so.1 to run, but this lib is not
+ # installed by default on all Solaris systems. Sneak it in from the sysroot to
+ # make it run OOTB on more systems.
+ cp $SYSROOT/lib/libmmheap.so.1 $SOLARIS_STUDIO_DIR/lib/compilers/sys/
+else
+ echo "Skipping copying of Solaris Studio"
+fi
+
+echo "Copying gnu make to $DEVKIT_ROOT/bin"
+mkdir -p $DEVKIT_ROOT/bin
+cp $GNU_MAKE $DEVKIT_ROOT/bin/
+if [ ! -e $DEVKIT_ROOT/bin/gmake ]; then
+ ln -s make $DEVKIT_ROOT/bin/gmake
+fi
+
+# Create the devkit.info file
+echo Creating devkit.info
+INFO_FILE=$DEVKIT_ROOT/devkit.info
+rm -f $INFO_FILE
+echo "# This file describes to configure how to interpret the contents of this devkit" >> $INFO_FILE
+echo "DEVKIT_NAME=\"Solaris Studio $SOLARIS_STUDIO_VERSION - Solaris $SOLARIS_VERSION - $ARCH\"" >> $INFO_FILE
+echo "DEVKIT_TOOLCHAIN_PATH=\"\$DEVKIT_ROOT/$SOLARIS_STUDIO_SUBDIR/bin:\$DEVKIT_ROOT/bin\"" >> $INFO_FILE
+echo "DEVKIT_EXTRA_PATH=\"\$DEVKIT_ROOT/bin\"" >> $INFO_FILE
+echo "DEVKIT_SYSROOT=\"\$DEVKIT_ROOT/sysroot\"" >> $INFO_FILE
+
+if [ ! -e $BUNDLE ]; then
+ echo "Creating $BUNDLE from $DEVKIT_ROOT"
+ cd $DEVKIT_ROOT/..
+ tar zcf $BUNDLE $DEVKIT_NAME
+else
+ echo "Skipping creation of $BUNDLE"
+fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/devkit/solaris11.1-package-list.txt Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,157 @@
+compress/bzip2@1.0.6-0.175.1.0.0.24.0
+consolidation/X/X-incorporation@0.5.11-0.175.1.21.0.3.1357
+consolidation/desktop/desktop-incorporation@0.5.11-0.175.1.21.0.4.0
+consolidation/install/install-incorporation@0.5.11-0.175.2.0.0.5.0
+consolidation/ips/ips-incorporation@0.5.11-0.175.1.20.0.3.0
+consolidation/l10n/l10n-incorporation@0.5.11-0.175.1.16.0.2.2
+consolidation/osnet/osnet-incorporation@0.5.11-0.175.1.21.0.4.2
+consolidation/sic_team/sic_team-incorporation@0.5.11-0.175.2.0.0.39.0
+consolidation/solaris_re/solaris_re-incorporation@0.5.11-0.175.2.4.0.4.0
+consolidation/sunpro/sunpro-incorporation@0.5.11-0.175.1.19.0.4.0
+crypto/ca-certificates@0.5.11-0.175.1.0.0.24.2
+database/berkeleydb-5@5.1.25-0.175.1.0.0.24.0
+database/mysql-51/library@5.1.37-0.175.1.10.0.5.0
+database/sqlite-3@3.7.14.1-0.175.1.10.0.4.0
+developer/base-developer-utilities@0.5.11-0.175.1.11.0.1.2
+developer/gnu-binutils@2.21.1-0.175.1.0.0.24.0
+developer/macro/cpp@0.5.11-0.175.1.19.0.4.0
+driver/management/bmc@0.5.11-0.175.1.0.0.24.2
+driver/management/ipmi@0.5.11-0.175.1.6.0.3.2
+driver/serial/usbser@0.5.11-0.175.1.0.0.24.2
+driver/storage/mpt@0.5.11-0.175.1.18.0.3.2
+image/library/libjpeg@6.0.2-0.175.0.0.0.0.0
+image/library/libpng@1.4.11-0.175.1.0.0.16.0
+image/library/libtiff@3.9.5-0.175.1.15.0.2.0
+library/apr-13@1.3.9-0.175.1.0.0.24.0
+library/apr-util-13@1.3.9-0.175.1.0.0.24.0
+library/apr-util-13/apr-ldap@1.3.9-0.175.1.0.0.24.0
+library/apr-util-13/dbd-mysql@1.3.9-0.175.1.0.0.24.0
+library/apr-util-13/dbd-sqlite@1.3.9-0.175.1.0.0.24.0
+library/database/gdbm@1.8.3-0.175.1.0.0.24.0
+library/expat@2.1.0-0.175.1.0.0.24.0
+library/libffi@3.0.9-0.175.0.0.0.0.0
+library/libidn@1.19-0.175.1.0.0.24.0
+library/libtecla@1.6.1-0.175.1.0.0.24.0
+library/libxml2@2.7.6-0.175.1.7.0.3.0
+library/libxslt@1.1.26-0.175.1.11.0.4.0
+library/ncurses@5.7-0.175.1.0.0.15.0
+library/nspr@4.9.5-0.175.2.0.0.39.0
+library/perl-5/sun-solaris-512@0.5.11-0.175.1.11.0.1.2
+library/print/cups-libs@1.4.5-0.175.1.8.0.3.0
+library/python-2/cherrypy@3.1.2-0.175.1.0.0.24.0
+library/python-2/cherrypy-26@3.1.2-0.175.1.0.0.24.0
+library/python-2/jsonrpclib@0.1.3-0.175.2.0.0.42.1
+library/python-2/jsonrpclib-26@0.1.3-0.175.2.0.0.42.1
+library/python-2/libxml2-26@2.7.6-0.175.1.7.0.3.0
+library/python-2/libxsl-26@1.1.26-0.175.1.11.0.4.0
+library/python-2/lxml@2.3.3-0.175.1.0.0.24.0
+library/python-2/lxml-26@2.3.3-0.175.1.0.0.24.0
+library/python-2/m2crypto@0.21.1-0.175.1.0.0.24.0
+library/python-2/m2crypto-26@0.21.1-0.175.1.0.0.24.0
+library/python-2/mako@0.4.1-0.175.1.0.0.24.0
+library/python-2/mako-26@0.4.1-0.175.1.0.0.24.0
+library/python-2/ply@3.1-0.175.1.0.0.24.0
+library/python-2/ply-26@3.1-0.175.1.0.0.24.0
+library/python-2/pybonjour@1.1.1-0.175.1.0.0.24.0
+library/python-2/pybonjour-26@1.1.1-0.175.1.0.0.24.0
+library/python-2/pycurl@7.19.0.1-0.175.1.0.0.24.0
+library/python-2/pycurl-26@7.19.0.1-0.175.1.0.0.24.0
+library/python-2/pyopenssl@0.11-0.175.1.0.0.24.0
+library/python-2/pyopenssl-26@0.11-0.175.1.0.0.24.0
+library/python-2/python-extra-26@2.6.4-0.175.1.0.0.15.0
+library/python-2/simplejson-26@2.1.2-0.175.1.7.0.4.0
+library/readline@5.2-0.175.1.0.0.24.0
+library/security/nss@4.14.3-0.175.2.0.0.39.0
+library/security/openssl@1.0.0.13-0.175.1.21.0.2.0
+library/security/trousers@0.3.6-0.175.1.0.0.24.0
+library/zlib@1.2.3-0.175.1.0.0.24.0
+media/cdrtools@3.0-0.175.1.21.0.4.0
+media/xorriso@0.6.0-0.175.1.0.0.24.0
+network/bridging@0.5.11-0.175.1.12.0.3.2
+package/pkg@0.5.11-0.175.1.20.0.3.0
+package/pkg/system-repository@0.5.11-0.175.1.9.0.1.0
+package/pkg/zones-proxy@0.5.11-0.175.1.0.0.24.0
+package/svr4@0.5.11-0.175.1.7.0.3.2
+print/cups@1.4.5-0.175.1.8.0.3.0
+release/name@0.5.11-0.175.2.4.0.4.0
+runtime/perl-512@5.12.5-0.175.1.8.0.4.0
+runtime/python-26@2.6.8-0.175.1.17.0.4.0
+service/network/dns/mdns@0.5.11-0.175.1.0.0.24.2
+service/network/slp@0.5.11-0.175.1.0.0.24.2
+service/security/gss@0.5.11-0.175.1.0.0.24.2
+service/security/kerberos-5@0.5.11-0.175.1.18.0.2.2
+shell/bash@4.1.9-0.175.1.13.0.1.0
+shell/ksh93@93.21.0.20110208-0.175.1.19.0.2.0
+system/boot-environment-utilities@0.5.11-0.175.1.9.0.1.2
+system/boot/grub@1.99-0.175.1.14.0.2.2
+system/boot/wanboot@0.5.11-0.175.1.0.0.24.2
+system/core-os@0.5.11-0.175.1.20.0.4.2
+system/data/keyboard/keytables@0.5.11-0.175.1.0.0.24.2
+system/data/terminfo/terminfo-core@0.5.11-0.175.1.14.0.3.2
+system/data/timezone@0.5.11-0.175.2.5.0.2.0
+system/device-administration@0.5.11-0.175.1.9.0.2.2
+system/dtrace@0.5.11-0.175.1.20.0.4.2
+system/dynamic-reconfiguration@0.5.11-0.175.1.13.0.2.2
+system/fault-management@0.5.11-0.175.1.18.0.4.2
+system/file-system/hsfs@0.5.11-0.175.1.0.0.24.2
+system/file-system/pcfs@0.5.11-0.175.1.0.0.24.2
+system/file-system/ufs@0.5.11-0.175.1.18.0.3.2
+system/file-system/zfs@0.5.11-0.175.1.21.0.3.2
+system/header@0.5.11-0.175.1.20.0.4.2
+system/install@0.5.11-0.175.1.0.0.24.1736
+system/install/auto-install/auto-install-common@0.5.11-0.175.1.18.0.3.1736
+system/install/configuration@0.5.11-0.175.1.10.0.3.1736
+system/install/locale@0.5.11-0.175.1.0.0.23.1134
+system/io/infiniband@0.5.11-0.175.1.20.0.4.2
+system/io/ultra-wideband@0.5.11-0.175.1.0.0.24.2
+system/io/usb@0.5.11-0.175.1.19.0.2.2
+system/kernel@0.5.11-0.175.1.21.0.4.2
+system/kernel/cpu-counters@0.5.11-0.175.1.17.0.1.2
+system/kernel/platform@0.5.11-0.175.1.21.0.4.2
+system/keyboard/keyboard-utilities@0.5.11-0.175.1.0.0.24.2
+system/library@0.5.11-0.175.1.20.0.3.2
+system/library/boot-management@0.5.11-0.175.1.19.0.1.2
+system/library/c++-runtime@0.5.11-0.175.1.19.0.4.0
+system/library/freetype-2@2.4.11-0.175.1.18.0.1.1350
+system/library/gcc-3-runtime@3.4.3-0.175.1.0.0.24.0
+system/library/iconv/utf-8@0.5.11-0.175.1.9.0.1.1150
+system/library/install@0.5.11-0.175.1.18.0.3.1736
+system/library/libdbus@1.2.28-0.175.1.16.0.2.0
+system/library/math@0.5.11-0.175.1.19.0.4.0
+system/library/mmheap@0.5.11-0.175.1.19.0.4.0
+system/library/security/gss@0.5.11-0.175.1.18.0.3.2
+system/library/security/gss/diffie-hellman@0.5.11-0.175.1.0.0.24.2
+system/library/security/gss/spnego@0.5.11-0.175.1.16.0.1.2
+system/library/security/libsasl@0.5.11-0.175.1.0.0.24.2
+system/library/storage/libdiskmgt@0.5.11-0.175.1.5.0.3.2
+system/library/storage/scsi-plugins@0.5.11-0.175.1.0.0.24.2
+system/library/storage/snia-ima@0.5.11-0.175.1.0.0.24.2
+system/library/storage/suri@0.5.11-0.175.1.0.0.24.2
+system/linker@0.5.11-0.175.1.20.0.1.2
+system/network@0.5.11-0.175.1.20.0.3.2
+system/picl@0.5.11-0.175.1.17.0.3.2
+system/resource-mgmt/resource-pools@0.5.11-0.175.1.0.0.24.2
+system/storage/iscsi/iscsi-initiator@0.5.11-0.175.1.19.0.3.2
+system/storage/iscsi/iscsi-iser@0.5.11-0.175.1.20.0.3.2
+system/system-events@0.5.11-0.175.1.0.0.24.2
+system/xopen/xcu4@0.5.11-0.175.1.13.0.4.2
+system/zones@0.5.11-0.175.1.17.0.4.2
+system/zones/brand/brand-solaris@0.5.11-0.175.1.17.0.4.2
+text/spelling-utilities@0.5.11-0.175.1.0.0.24.2
+web/curl@7.21.2-0.175.1.18.0.3.0
+web/server/apache-22@2.2.27-0.175.1.19.0.4.0
+web/server/apache-22/module/apache-wsgi-26@3.3-0.175.1.0.0.24.0
+x11/header/x11-protocols@7.7-0.175.1.0.0.24.1317
+x11/library/libice@1.0.8-0.175.1.0.0.24.1317
+x11/library/libpthread-stubs@0.3-0.175.1.0.0.24.1317
+x11/library/libsm@1.2.1-0.175.1.0.0.24.1317
+x11/library/libx11@1.5.0-0.175.1.8.0.4.1336
+x11/library/libxau@1.0.7-0.175.1.0.0.24.1317
+x11/library/libxcb@1.8.1-0.175.1.8.0.3.1332
+x11/library/libxdmcp@1.1.1-0.175.1.0.0.24.1317
+x11/library/libxevie@1.0.3-0.175.1.0.0.24.1317
+x11/library/libxext@1.3.1-0.175.1.8.0.3.1332
+x11/library/libxrender@0.9.7-0.175.1.8.0.3.1332
+x11/library/libxscrnsaver@1.2.2-0.175.1.0.0.24.1317
+x11/library/libxtst@1.2.1-0.175.1.8.0.3.1332
+x11/library/toolkit/libxt@1.1.3-0.175.1.8.0.3.1332
--- a/make/jprt.properties Mon Dec 21 17:47:21 2015 +0100
+++ b/make/jprt.properties Wed Jul 05 21:09:54 2017 +0200
@@ -69,9 +69,20 @@
jprt.productOpen.build.configure.args=${jprt.product.build.configure.args} --enable-openjdk-only
jprt.optimizedOpen.build.configure.args=${jprt.product.build.configure.args} --enable-openjdk-only
-# Select build flavors and build targets
-jprt.build.flavors=${my.is.hotspot.job ? ${my.build.flavors.hotspot} : ${my.build.flavors.default}}
-jprt.build.targets=${my.is.hotspot.job ? ${my.build.targets.hotspot} : ${my.build.targets.default}}
+
+# hotspot testset has custom build flavors and build targets
+my.jprt.testsetHasCustomBuildFlavors.hotspot=true
+my.jprt.testsetHasCustomBuildTargets.hotspot=true
+
+# determine if the specified testset has custom build flavors or build targets
+my.jprt.testsetHasCustomBuildFlavors=${my.jprt.testsetHasCustomBuildFlavors.${jprt.test.set}}
+my.jprt.testsetHasCustomBuildTargets=${my.jprt.testsetHasCustomBuildTargets.${jprt.test.set}}
+
+# Select build flavors and build targets based on the specified testset
+jprt.build.flavors=${my.jprt.testsetHasCustomBuildFlavors ? \
+ ${my.build.flavors.${jprt.test.set}} : ${my.build.flavors.default}}
+jprt.build.targets=${my.jprt.testsetHasCustomBuildTargets ? \
+ ${my.build.targets.${jprt.test.set}} : ${my.build.targets.default}}
# Select test targets - jprt default for jprt.test.set is "default"
jprt.test.targets=${my.test.targets.${jprt.test.set}}
@@ -131,6 +142,8 @@
--with-devkit=$GCC492_OEL64_HOME
jprt.macosx_x64.build.configure.args= \
--with-devkit=$XCODE63_MACOSX109_HOME
+jprt.solaris.build.configure.args= \
+ --with-devkit=$SS124_11u1_HOME
jprt.windows_i586.build.configure.args= \
--with-devkit=$VS2013SP4_HOME \
${jprt.i586.build.configure.args}
--- a/modules.xml Mon Dec 21 17:47:21 2015 +0100
+++ b/modules.xml Wed Jul 05 21:09:54 2017 +0200
@@ -428,6 +428,7 @@
<to>java.naming</to>
<to>java.rmi</to>
<to>java.security.jgss</to>
+ <to>java.security.sasl</to>
<to>java.smartcardio</to>
<to>jdk.crypto.ec</to>
<to>jdk.crypto.mscapi</to>
@@ -437,6 +438,7 @@
<to>jdk.jartool</to>
<to>jdk.policytool</to>
<to>jdk.security.auth</to>
+ <to>jdk.security.jgss</to>
</export>
<export>
<name>sun.security.x509</name>
--- a/nashorn/.hgtags Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/.hgtags Wed Jul 05 21:09:54 2017 +0200
@@ -331,3 +331,4 @@
9d52f9bb589c4caa3617fe1cf11c72512ab8e973 jdk-9+95
d52c09d5d98a81ee6102a25f662ec4b9ae614163 jdk-9+96
2beaef2b6a880c0bff8c9f57ffca33477d647f8b jdk-9+97
+68a36216f70c0de4c7e36f8978995934fc72ec03 jdk-9+98
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java Wed Jul 05 21:09:54 2017 +0200
@@ -59,6 +59,8 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_CREATEBUILTIN_SPECS_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT;
@@ -291,6 +293,13 @@
mi.push(memInfo.getArity());
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC);
}
+
+ String doc = memInfo.getDocumentation();
+ if (doc != null) {
+ mi.dup();
+ mi.loadLiteral(memInfo.getDocumentation());
+ mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATION, SCRIPTFUNCTION_SETDOCUMENTATION_DESC);
+ }
}
static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) {
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java Wed Jul 05 21:09:54 2017 +0200
@@ -42,6 +42,8 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_INIT_DESC4;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
@@ -159,6 +161,13 @@
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY,
SCRIPTFUNCTION_SETARITY_DESC);
}
+ final String doc = constructor.getDocumentation();
+ if (doc != null) {
+ mi.loadThis();
+ mi.loadLiteral(doc);
+ mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATION,
+ SCRIPTFUNCTION_SETDOCUMENTATION_DESC);
+ }
}
mi.returnVoid();
mi.computeMaxs();
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java Wed Jul 05 21:09:54 2017 +0200
@@ -85,6 +85,8 @@
private MemberInfo.Kind kind;
// script property name
private String name;
+ // documentation for this member
+ private String documentation;
// script property attributes
private int attributes;
// name of the java member
@@ -137,6 +139,20 @@
}
/**
+ * @return the documentation
+ */
+ public String getDocumentation() {
+ return documentation;
+ }
+
+ /**
+ * @param doc the documentation to set
+ */
+ public void setDocumentation(final String doc) {
+ this.documentation = doc;
+ }
+
+ /**
* Tag something as specialized constructor or not
* @param isSpecializedConstructor boolean, true if specialized constructor
*/
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java Wed Jul 05 21:09:54 2017 +0200
@@ -206,6 +206,7 @@
// These could be "null" if values are not supplied,
// in which case we have to use the default values.
private String name;
+ private String documentation;
private Integer attributes;
private Integer arity;
private Where where;
@@ -222,6 +223,13 @@
name = null;
}
break;
+ case "documentation":
+ this.documentation = (String)annotationValue;
+ if (documentation.isEmpty()) {
+ documentation = null;
+ }
+
+ break;
case "attributes":
this.attributes = (Integer)annotationValue;
break;
@@ -270,6 +278,8 @@
} else {
memInfo.setName(name == null ? methodName : name);
}
+
+ memInfo.setDocumentation(documentation);
memInfo.setAttributes(attributes == null ? MemberInfo.DEFAULT_ATTRIBUTES : attributes);
memInfo.setArity((arity == null)? MemberInfo.DEFAULT_ARITY : arity);
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Wed Jul 05 21:09:54 2017 +0200
@@ -118,6 +118,8 @@
static final String SCRIPTFUNCTION_TYPE = TYPE_SCRIPTFUNCTION.getInternalName();
static final String SCRIPTFUNCTION_SETARITY = "setArity";
static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
+ static final String SCRIPTFUNCTION_SETDOCUMENTATION = "setDocumentation";
+ static final String SCRIPTFUNCTION_SETDOCUMENTATION_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING);
static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype";
static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
static final String SCRIPTFUNCTION_CREATEBUILTIN = "createBuiltin";
--- a/nashorn/make/build-benchmark.xml Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/make/build-benchmark.xml Wed Jul 05 21:09:54 2017 +0200
@@ -314,7 +314,7 @@
classpath="${run.test.classpath}"
fork="true"
dir=".">
- <jvmarg line="${ext.class.path}"/>
+ <jvmarg line="${boot.class.path}"/>
<jvmarg line="${run.test.jvmargs.octane} -Xms${run.test.xms} -Xmx${run.test.xmx}"/>
<!-- pass on all properties prefixed with 'nashorn' to the runtime -->
<syspropertyset>
@@ -387,7 +387,7 @@
classpath="${run.test.classpath}"
fork="true"
dir=".">
- <jvmarg line="${ext.class.path}"/>
+ <jvmarg line="${boot.class.path}"/>
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx}"/>
<arg value="-timezone=PST"/>
<arg value="--class-cache-size=50"/>
--- a/nashorn/make/build.xml Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/make/build.xml Wed Jul 05 21:09:54 2017 +0200
@@ -48,12 +48,12 @@
<condition property="git.executable" value="/usr/local/bin/git" else="git">
<available file="/usr/local/bin/git"/>
</condition>
- <!-- check if testng.jar is avaiable, and download it if it isn't -->
+ <!-- check if testng.jar is available, and download it if it isn't -->
<available property="testng.already.present" file="${file.reference.testng.jar}"/>
<antcall target="get-testng"/>
<available property="testng.available" file="${file.reference.testng.jar}"/>
- <!-- check if asmtools-6.0.jar is avaiable, and download it if it isn't -->
+ <!-- check if asmtools-6.0.jar is available, and download it if it isn't -->
<!--
<available property="asmtools.already.present" file="${file.reference.asmtools.jar}"/>
<antcall target="get-asmtools"/>
@@ -84,6 +84,12 @@
<condition property="jfr.options" value="${run.test.jvmargs.jfr}" else="">
<istrue value="${jfr}"/>
</condition>
+
+ <condition property="test-sys-prop-no-security.os.not.windows">
+ <not>
+ <os family="windows"/>
+ </not>
+ </condition>
</target>
<!-- check minimum ant version required to be 1.8.4 -->
@@ -408,6 +414,13 @@
permission java.util.PropertyPermission "nashorn.test.*", "read";
};
+grant codeBase "file:/${basedir}/test/script/basic/apply_to_call/*" {
+ permission java.io.FilePermission "${basedir}/test/script/-", "read";
+ permission java.io.FilePermission "$${user.dir}", "read";
+ permission java.util.PropertyPermission "user.dir", "read";
+ permission java.util.PropertyPermission "nashorn.test.*", "read";
+};
+
grant codeBase "file:/${basedir}/test/script/basic/parser/*" {
permission java.io.FilePermission "${basedir}/test/script/-", "read";
permission java.io.FilePermission "$${user.dir}", "read";
--- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java Wed Jul 05 21:09:54 2017 +0200
@@ -25,6 +25,7 @@
package jdk.nashorn.tools.jjs;
+import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -34,21 +35,24 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.function.Function;
import jdk.internal.jline.NoInterruptUnixTerminal;
import jdk.internal.jline.Terminal;
import jdk.internal.jline.TerminalFactory;
import jdk.internal.jline.TerminalFactory.Flavor;
import jdk.internal.jline.WindowsTerminal;
import jdk.internal.jline.console.ConsoleReader;
+import jdk.internal.jline.console.KeyMap;
import jdk.internal.jline.console.completer.Completer;
import jdk.internal.jline.console.history.FileHistory;
class Console implements AutoCloseable {
+ private static final String DOCUMENTATION_SHORTCUT = "\033\133\132"; //Shift-TAB
private final ConsoleReader in;
private final FileHistory history;
Console(final InputStream cmdin, final PrintStream cmdout, final File historyFile,
- final Completer completer) throws IOException {
+ final Completer completer, final Function<String, String> docHelper) throws IOException {
TerminalFactory.registerFlavor(Flavor.WINDOWS, isCygwin()? JJSUnixTerminal::new : JJSWindowsTerminal::new);
TerminalFactory.registerFlavor(Flavor.UNIX, JJSUnixTerminal::new);
in = new ConsoleReader(cmdin, cmdout);
@@ -58,6 +62,7 @@
in.setHistory(history = new FileHistory(historyFile));
in.addCompleter(completer);
Runtime.getRuntime().addShutdownHook(new Thread((Runnable)this::saveHistory));
+ bind(DOCUMENTATION_SHORTCUT, (ActionListener)evt -> showDocumentation(docHelper));
}
String readLine(final String prompt) throws IOException {
@@ -138,4 +143,34 @@
private static boolean isCygwin() {
return System.getenv("SHELL") != null;
}
+
+ private void bind(String shortcut, Object action) {
+ KeyMap km = in.getKeys();
+ for (int i = 0; i < shortcut.length(); i++) {
+ final Object value = km.getBound(Character.toString(shortcut.charAt(i)));
+ if (value instanceof KeyMap) {
+ km = (KeyMap) value;
+ } else {
+ km.bind(shortcut.substring(i), action);
+ }
+ }
+ }
+
+ private void showDocumentation(final Function<String, String> docHelper) {
+ final String buffer = in.getCursorBuffer().buffer.toString();
+ final int cursor = in.getCursorBuffer().cursor;
+ final String doc = docHelper.apply(buffer.substring(0, cursor));
+ try {
+ if (doc != null) {
+ in.println();
+ in.println(doc);
+ in.redrawLine();
+ in.flush();
+ } else {
+ in.beep();
+ }
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java Wed Jul 05 21:09:54 2017 +0200
@@ -25,6 +25,9 @@
package jdk.nashorn.tools.jjs;
+import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
+import java.awt.Desktop;
import java.awt.GraphicsEnvironment;
import java.io.BufferedReader;
import java.io.File;
@@ -33,15 +36,21 @@
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
+import java.net.URI;
+import java.util.concurrent.Callable;
import java.util.function.Consumer;
+import java.util.function.Function;
import jdk.internal.jline.console.completer.Completer;
import jdk.internal.jline.console.UserInterruptException;
import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.objects.NativeJava;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.NativeJavaPackage;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
+import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.tools.Shell;
@@ -109,7 +118,32 @@
final PropertiesHelper propsHelper = new PropertiesHelper(env._classpath);
final NashornCompleter completer = new NashornCompleter(context, global, this, propsHelper);
- try (final Console in = new Console(System.in, System.out, HIST_FILE, completer)) {
+ try (final Console in = new Console(System.in, System.out, HIST_FILE, completer,
+ str -> {
+ try {
+ final Object res = context.eval(global, str, global, "<shell>");
+ if (res != null && res != UNDEFINED) {
+ // Special case Java types: show the javadoc for the class.
+ if (NativeJava.isType(UNDEFINED, res)) {
+ final String typeName = NativeJava.typeName(UNDEFINED, res).toString();
+ final String url = typeName.replace('.', '/').replace('$', '.') + ".html";
+ openBrowserForJavadoc(url);
+ } else if (res instanceof NativeJavaPackage) {
+ final String pkgName = ((NativeJavaPackage)res).getName();
+ final String url = pkgName.replace('.', '/') + "/package-summary.html";
+ openBrowserForJavadoc(url);
+ } else if (res instanceof ScriptFunction) {
+ return ((ScriptFunction)res).getDocumentation();
+ }
+
+ // FIXME: better than toString for other cases?
+ return JSType.toString(res);
+ }
+ } catch (Exception ignored) {
+ }
+ return null;
+ })) {
+
if (globalChanged) {
Context.setGlobal(global);
}
@@ -164,7 +198,7 @@
try {
final Object res = context.eval(global, source, global, "<shell>");
- if (res != ScriptRuntime.UNDEFINED) {
+ if (res != UNDEFINED) {
err.println(toString(res, global));
}
} catch (final Exception exp) {
@@ -218,7 +252,7 @@
final PrintWriter err, final boolean doe) {
try {
final Object res = context.eval(global, source, global, "<shell>");
- if (res != ScriptRuntime.UNDEFINED) {
+ if (res != UNDEFINED) {
err.println(JSType.toString(res));
}
} catch (final Exception e) {
@@ -228,4 +262,15 @@
}
}
}
+
+ // FIXME: needs to be changed to use javase 9 docs later
+ private static String JAVADOC_BASE = "http://download.java.net/jdk9/docs/api/";
+
+ private static void openBrowserForJavadoc(String relativeUrl) {
+ try {
+ final URI uri = new URI(JAVADOC_BASE + relativeUrl);
+ Desktop.getDesktop().browse(uri);
+ } catch (Exception ignored) {
+ }
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/PropertiesHelper.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/PropertiesHelper.java Wed Jul 05 21:09:54 2017 +0200
@@ -31,6 +31,7 @@
import java.util.Collections;
import java.util.List;
import java.util.WeakHashMap;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.NativeJavaPackage;
@@ -136,6 +137,42 @@
return props;
}
+ // This method creates a regex Pattern to use to do CamelCase
+ // matching. The pattern is derived from user supplied string
+ // containing one or more upper case characters in it.
+ private static Pattern makeCamelCasePattern(final String str) {
+ assert !str.isEmpty();
+
+ final char[] chars = str.toCharArray();
+ final StringBuilder buf = new StringBuilder();
+ boolean seenUpperCase = false;
+
+ // Skip first char for case check. Even if it is upper case,
+ // we do not want to put lower case matching pattern before
+ // the first letter!
+ buf.append(chars[0]);
+
+ for (int idx = 1; idx < chars.length; idx++) {
+ final char ch = chars[idx];
+ if (ch >= 'A' && ch <= 'Z') {
+ seenUpperCase = true;
+ buf.append("[^A-Z]*");
+ }
+ buf.append(ch);
+ }
+
+ if (seenUpperCase) {
+ // match anything at the end!
+ buf.append(".*");
+ try {
+ return Pattern.compile(buf.toString());
+ } catch (Exception exp) {
+ }
+ }
+
+ return null;
+ }
+
/**
* Returns the list of properties of the given object that start with the given prefix.
*
@@ -145,8 +182,21 @@
*/
List<String> getProperties(final Object obj, final String prefix) {
assert prefix != null && !prefix.isEmpty();
- return getProperties(obj).stream()
+ List<String> allProps = getProperties(obj);
+ List<String> props = allProps.stream()
.filter(s -> s.startsWith(prefix))
.collect(Collectors.toList());
+
+ // If no match, try CamelCase completion..
+ if (props.isEmpty()) {
+ final Pattern pat = makeCamelCasePattern(prefix);
+ if (pat != null) {
+ return allProps.stream()
+ .filter(s -> pat.matcher(s).matches())
+ .collect(Collectors.toList());
+ }
+ }
+
+ return props;
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Jul 05 21:09:54 2017 +0200
@@ -188,8 +188,6 @@
private static final Call ENSURE_INT = CompilerConstants.staticCallNoLookup(OptimisticReturnFilters.class,
"ensureInt", int.class, Object.class, int.class);
- private static final Call ENSURE_LONG = CompilerConstants.staticCallNoLookup(OptimisticReturnFilters.class,
- "ensureLong", long.class, Object.class, int.class);
private static final Call ENSURE_NUMBER = CompilerConstants.staticCallNoLookup(OptimisticReturnFilters.class,
"ensureNumber", double.class, Object.class, int.class);
@@ -1726,7 +1724,7 @@
enterStatement(expressionStatement);
loadAndDiscard(expressionStatement.getExpression());
- assert method.getStackSize() == 0;
+ assert method.getStackSize() == 0 : "stack not empty in " + expressionStatement;
return false;
}
@@ -2241,7 +2239,7 @@
* @param arrayType the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT
*/
private void loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
- assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
+ assert arrayType == Type.INT_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
final Expression[] nodes = arrayLiteralNode.getValue();
final Object presets = arrayLiteralNode.getPresets();
@@ -2389,20 +2387,9 @@
method.convert(Type.OBJECT);
} else if(!resultBounds.canBeNarrowerThan(Type.NUMBER)) {
method.load(((Integer)value).doubleValue());
- } else if(!resultBounds.canBeNarrowerThan(Type.LONG)) {
- method.load(((Integer)value).longValue());
} else {
method.load((Integer)value);
}
- } else if (value instanceof Long) {
- if(!resultBounds.canBeNarrowerThan(Type.OBJECT)) {
- method.load((Long)value);
- method.convert(Type.OBJECT);
- } else if(!resultBounds.canBeNarrowerThan(Type.NUMBER)) {
- method.load(((Long)value).doubleValue());
- } else {
- method.load((Long)value);
- }
} else if (value instanceof Double) {
if(!resultBounds.canBeNarrowerThan(Type.OBJECT)) {
method.load((Double)value);
@@ -3650,8 +3637,6 @@
private void loadMinusOne() {
if (type.isInteger()) {
method.load(isIncrement ? 1 : -1);
- } else if (type.isLong()) {
- method.load(isIncrement ? 1L : -1L);
} else {
method.load(isIncrement ? 1.0 : -1.0);
}
@@ -4033,23 +4018,66 @@
}
private void loadASSIGN_SHR(final BinaryNode binaryNode) {
- new BinarySelfAssignment(binaryNode) {
+ new SelfModifyingStore<BinaryNode>(binaryNode, binaryNode.lhs()) {
@Override
- protected void op() {
- doSHR();
- }
-
+ protected void evaluate() {
+ new OptimisticOperation(assignNode, new TypeBounds(Type.INT, Type.NUMBER)) {
+ @Override
+ void loadStack() {
+ assert assignNode.getWidestOperandType() == Type.INT;
+ if (isRhsZero(binaryNode)) {
+ loadExpressionAsType(binaryNode.lhs(), Type.INT);
+ } else {
+ loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), TypeBounds.INT, true, false);
+ method.shr();
+ }
+ }
+
+ @Override
+ void consumeStack() {
+ if (isOptimistic(binaryNode)) {
+ toUint32Optimistic(binaryNode.getProgramPoint());
+ } else {
+ toUint32Double();
+ }
+ }
+ }.emit(getOptimisticIgnoreCountForSelfModifyingExpression(binaryNode.lhs()));
+ method.convert(assignNode.getType());
+ }
}.store();
}
- private void doSHR() {
- // TODO: make SHR optimistic
- method.shr();
- toUint();
- }
-
- private void toUint() {
- JSType.TO_UINT32_I.invoke(method);
+ private void doSHR(final BinaryNode binaryNode) {
+ new OptimisticOperation(binaryNode, new TypeBounds(Type.INT, Type.NUMBER)) {
+ @Override
+ void loadStack() {
+ if (isRhsZero(binaryNode)) {
+ loadExpressionAsType(binaryNode.lhs(), Type.INT);
+ } else {
+ loadBinaryOperands(binaryNode);
+ method.shr();
+ }
+ }
+
+ @Override
+ void consumeStack() {
+ if (isOptimistic(binaryNode)) {
+ toUint32Optimistic(binaryNode.getProgramPoint());
+ } else {
+ toUint32Double();
+ }
+ }
+ }.emit();
+
+ }
+
+ private void toUint32Optimistic(final int programPoint) {
+ method.load(programPoint);
+ JSType.TO_UINT32_OPTIMISTIC.invoke(method);
+ }
+
+ private void toUint32Double() {
+ JSType.TO_UINT32_DOUBLE.invoke(method);
}
private void loadASSIGN_SUB(final BinaryNode binaryNode) {
@@ -4087,7 +4115,7 @@
// Non-optimistic, non-FP subtraction or multiplication. Allow them to overflow.
operandBounds = new TypeBounds(Type.narrowest(node.getWidestOperandType(),
numericBounds.widest), Type.NUMBER);
- forceConversionSeparation = node.getWidestOperationType().narrowerThan(numericBounds.widest);
+ forceConversionSeparation = true;
}
}
loadBinaryOperands(node.lhs(), node.rhs(), operandBounds, false, forceConversionSeparation);
@@ -4189,14 +4217,7 @@
}
private void loadSHR(final BinaryNode binaryNode) {
- // Optimize x >>> 0 to (uint)x
- if (isRhsZero(binaryNode)) {
- loadExpressionAsType(binaryNode.lhs(), Type.INT);
- toUint();
- } else {
- loadBinaryOperands(binaryNode);
- doSHR();
- }
+ doSHR(binaryNode);
}
private void loadSUB(final BinaryNode binaryNode, final TypeBounds resultBounds) {
@@ -4467,6 +4488,7 @@
}
} else {
final Type storeType = assignNode.getType();
+ assert storeType != Type.LONG;
if (symbol.hasSlotFor(storeType)) {
// Only emit a convert for a store known to be live; converts for dead stores can
// give us an unnecessary ClassCastException.
@@ -4851,8 +4873,6 @@
method.load(optimistic.getProgramPoint());
if(optimisticType.isInteger()) {
method.invoke(ENSURE_INT);
- } else if(optimisticType.isLong()) {
- method.invoke(ENSURE_LONG);
} else if(optimisticType.isNumber()) {
method.invoke(ENSURE_NUMBER);
} else {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java Wed Jul 05 21:09:54 2017 +0200
@@ -167,8 +167,7 @@
assert fieldName.equals(getFieldName(fieldIndex, PRIMITIVE_FIELD_TYPE)) || fieldType.isObject() : key + " object keys must store to L*-fields";
assert fieldName.equals(getFieldName(fieldIndex, Type.OBJECT)) || fieldType.isPrimitive() : key + " primitive keys must store to J*-fields";
- loadTuple(method, tuple);
-
+ loadTuple(method, tuple, true);
method.putField(fieldClass, fieldName, fieldDesc);
}
@@ -180,11 +179,7 @@
* @param tuple Tuple to store.
*/
private void putSlot(final MethodEmitter method, final long index, final MapTuple<T> tuple) {
- if (JSType.isRepresentableAsInt(index)) {
- method.load((int)index);
- } else {
- method.load(index);
- }
+ loadIndex(method, index);
loadTuple(method, tuple, false); //we don't pack array like objects
method.dynamicSetIndex(callSiteFlags);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FoldConstants.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FoldConstants.java Wed Jul 05 21:09:54 2017 +0200
@@ -307,9 +307,7 @@
final Type widest = Type.widest(lhs.getType(), rhs.getType());
boolean isInteger = widest.isInteger();
- boolean isLong = widest.isLong();
-
- double value;
+ final double value;
switch (parent.tokenType()) {
case DIV:
@@ -336,7 +334,8 @@
value = lhs.getNumber() - rhs.getNumber();
break;
case SHR:
- return LiteralNode.newInstance(token, finish, JSType.toUint32(lhs.getInt32() >>> rhs.getInt32()));
+ final long result = JSType.toUint32(lhs.getInt32() >>> rhs.getInt32());
+ return LiteralNode.newInstance(token, finish, JSType.isRepresentableAsInt(result) ? (int) result : (double) result);
case SAR:
return LiteralNode.newInstance(token, finish, lhs.getInt32() >> rhs.getInt32());
case SHL:
@@ -368,12 +367,9 @@
}
isInteger &= JSType.isStrictlyRepresentableAsInt(value);
- isLong &= JSType.isStrictlyRepresentableAsLong(value);
if (isInteger) {
return LiteralNode.newInstance(token, finish, (int)value);
- } else if (isLong) {
- return LiteralNode.newInstance(token, finish, (long)value);
}
return LiteralNode.newInstance(token, finish, value);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Wed Jul 05 21:09:54 2017 +0200
@@ -131,7 +131,6 @@
UNDEFINED(Type.UNDEFINED),
BOOLEAN(Type.BOOLEAN),
INT(Type.INT),
- LONG(Type.LONG),
DOUBLE(Type.NUMBER),
OBJECT(Type.OBJECT);
@@ -272,12 +271,9 @@
}
private static class SymbolConversions {
- private static final byte I2L = 1 << 0;
- private static final byte I2D = 1 << 1;
- private static final byte I2O = 1 << 2;
- private static final byte L2D = 1 << 3;
- private static final byte L2O = 1 << 4;
- private static final byte D2O = 1 << 5;
+ private static final byte I2D = 1 << 0;
+ private static final byte I2O = 1 << 1;
+ private static final byte D2O = 1 << 2;
private byte conversions;
@@ -288,9 +284,6 @@
case INT:
case BOOLEAN:
switch (to) {
- case LONG:
- recordConversion(I2L);
- return;
case DOUBLE:
recordConversion(I2D);
return;
@@ -301,18 +294,6 @@
illegalConversion(from, to);
return;
}
- case LONG:
- switch (to) {
- case DOUBLE:
- recordConversion(L2D);
- return;
- case OBJECT:
- recordConversion(L2O);
- return;
- default:
- illegalConversion(from, to);
- return;
- }
case DOUBLE:
if(to == LvarType.OBJECT) {
recordConversion(D2O);
@@ -340,26 +321,15 @@
if(hasConversion(D2O)) {
symbol.setHasSlotFor(Type.NUMBER);
}
- if(hasConversion(L2O)) {
- symbol.setHasSlotFor(Type.LONG);
- }
if(hasConversion(I2O)) {
symbol.setHasSlotFor(Type.INT);
}
}
if(symbol.hasSlotFor(Type.NUMBER)) {
- if(hasConversion(L2D)) {
- symbol.setHasSlotFor(Type.LONG);
- }
if(hasConversion(I2D)) {
symbol.setHasSlotFor(Type.INT);
}
}
- if(symbol.hasSlotFor(Type.LONG)) {
- if(hasConversion(I2L)) {
- symbol.setHasSlotFor(Type.INT);
- }
- }
}
}
@@ -378,7 +348,7 @@
if(lvarType != null) {
return lvarType;
}
- assert type.isObject();
+ assert type.isObject() : "Unsupported primitive type: " + type;
return LvarType.OBJECT;
}
private static LvarType widestLvarType(final LvarType t1, final LvarType t2) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Jul 05 21:09:54 2017 +0200
@@ -544,7 +544,6 @@
} else {
assert false : type + " cannot be packed!";
}
- //all others are nops, objects aren't packed
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Wed Jul 05 21:09:54 2017 +0200
@@ -41,7 +41,6 @@
import static jdk.nashorn.internal.runtime.JSType.GET_UNDEFINED;
import static jdk.nashorn.internal.runtime.JSType.TYPE_DOUBLE_INDEX;
import static jdk.nashorn.internal.runtime.JSType.TYPE_INT_INDEX;
-import static jdk.nashorn.internal.runtime.JSType.TYPE_LONG_INDEX;
import static jdk.nashorn.internal.runtime.JSType.TYPE_OBJECT_INDEX;
import static jdk.nashorn.internal.runtime.JSType.TYPE_UNDEFINED_INDEX;
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
@@ -535,8 +534,6 @@
switch (getAccessorTypeIndex(forType)) {
case TYPE_INT_INDEX:
return MH.explicitCastArguments(primitiveGetter, primitiveGetter.type().changeReturnType(int.class));
- case TYPE_LONG_INDEX:
- return primitiveGetter;
case TYPE_DOUBLE_INDEX:
return MH.filterReturnValue(primitiveGetter, UNPACK_DOUBLE);
case TYPE_OBJECT_INDEX:
@@ -623,7 +620,7 @@
}
assert !isOptimistic;
- //freely coerce the result to whatever you asked for, this is e.g. Object->int for a & b
+ // freely coerce the result to whatever you asked for, this is e.g. Object->int for a & b
final MethodHandle tgetter = getterForType(forType, primitiveGetter, objectGetter);
if (fti == TYPE_OBJECT_INDEX) {
if (fti != ti) {
@@ -638,22 +635,10 @@
case TYPE_INT_INDEX: {
return MH.asType(tgetter, tgetterType.changeReturnType(type));
}
- case TYPE_LONG_INDEX:
- switch (ti) {
- case TYPE_INT_INDEX:
- //get int while an int, truncating cast of long value
- return MH.filterReturnValue(tgetter, JSType.TO_INT32_L.methodHandle);
- case TYPE_LONG_INDEX:
- return primitiveGetter;
- default:
- return MH.asType(tgetter, tgetterType.changeReturnType(type));
- }
case TYPE_DOUBLE_INDEX:
switch (ti) {
case TYPE_INT_INDEX:
return MH.filterReturnValue(tgetter, JSType.TO_INT32_D.methodHandle);
- case TYPE_LONG_INDEX:
- return MH.explicitCastArguments(tgetter, tgetterType.changeReturnType(type));
case TYPE_DOUBLE_INDEX:
assert tgetterType.returnType() == double.class;
return tgetter;
@@ -734,12 +719,9 @@
switch (fti) {
case TYPE_INT_INDEX:
- case TYPE_LONG_INDEX:
switch (ti) {
case TYPE_INT_INDEX:
return MH.asType(primitiveSetter, pmt.changeParameterType(1, int.class));
- case TYPE_LONG_INDEX:
- return primitiveSetter;
case TYPE_DOUBLE_INDEX:
return MH.filterArguments(primitiveSetter, 1, PACK_DOUBLE);
default:
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectCreator.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectCreator.java Wed Jul 05 21:09:54 2017 +0200
@@ -29,6 +29,7 @@
import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -156,15 +157,15 @@
MethodEmitter loadTuple(final MethodEmitter method, final MapTuple<T> tuple, final boolean pack) {
loadValue(tuple.value, tuple.type);
- if (pack && codegen.useDualFields() && tuple.isPrimitive()) {
+ if (!codegen.useDualFields() || !tuple.isPrimitive()) {
+ method.convert(Type.OBJECT);
+ } else if (pack) {
method.pack();
- } else {
- method.convert(Type.OBJECT);
}
return method;
}
- MethodEmitter loadTuple(final MethodEmitter method, final MapTuple<T> tuple) {
- return loadTuple(method, tuple, true);
+ MethodEmitter loadIndex(final MethodEmitter method, final long index) {
+ return JSType.isRepresentableAsInt(index) ? method.load((int) index) : method.load((double) index);
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java Wed Jul 05 21:09:54 2017 +0200
@@ -109,8 +109,6 @@
//avoid blowing up the array if we can
if (constantValue instanceof Integer) {
arrayData = arrayData.set(index, ((Integer)constantValue).intValue(), false);
- } else if (constantValue instanceof Long) {
- arrayData = arrayData.set(index, ((Long)constantValue).longValue(), false);
} else if (constantValue instanceof Double) {
arrayData = arrayData.set(index, ((Double)constantValue).doubleValue(), false);
} else {
@@ -169,13 +167,13 @@
final int index = ArrayIndex.getArrayIndex(tuple.key);
assert ArrayIndex.isValidArrayIndex(index);
method.dup();
- method.load(ArrayIndex.toLongIndex(index));
- loadTuple(method, tuple);
+ loadIndex(method, ArrayIndex.toLongIndex(index));
+ loadTuple(method, tuple, false);
method.dynamicSetIndex(callSiteFlags);
} else {
assert property.getKey() instanceof String; // symbol keys not yet supported in object literals
method.dup();
- loadTuple(method, tuple);
+ loadTuple(method, tuple, false);
method.dynamicSet((String) property.getKey(), codegen.getCallSiteFlags(), false);
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java Wed Jul 05 21:09:54 2017 +0200
@@ -239,7 +239,7 @@
// currently deoptimize all the way to Object.
return Type.OBJECT;
}
- assert returnType == Type.INT || returnType == Type.LONG || returnType == Type.NUMBER || returnType == Type.OBJECT;
+ assert returnType == Type.INT || returnType == Type.NUMBER || returnType == Type.OBJECT;
return returnType;
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/IntType.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/IntType.java Wed Jul 05 21:09:54 2017 +0200
@@ -72,7 +72,7 @@
@Override
public Type nextWider() {
- return LONG;
+ return NUMBER;
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/LongType.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/LongType.java Wed Jul 05 21:09:54 2017 +0200
@@ -28,20 +28,11 @@
import static jdk.internal.org.objectweb.asm.Opcodes.L2D;
import static jdk.internal.org.objectweb.asm.Opcodes.L2I;
import static jdk.internal.org.objectweb.asm.Opcodes.LADD;
-import static jdk.internal.org.objectweb.asm.Opcodes.LAND;
-import static jdk.internal.org.objectweb.asm.Opcodes.LCMP;
import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0;
import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_1;
import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD;
-import static jdk.internal.org.objectweb.asm.Opcodes.LMUL;
-import static jdk.internal.org.objectweb.asm.Opcodes.LOR;
import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
-import static jdk.internal.org.objectweb.asm.Opcodes.LSHL;
-import static jdk.internal.org.objectweb.asm.Opcodes.LSHR;
import static jdk.internal.org.objectweb.asm.Opcodes.LSTORE;
-import static jdk.internal.org.objectweb.asm.Opcodes.LSUB;
-import static jdk.internal.org.objectweb.asm.Opcodes.LUSHR;
-import static jdk.internal.org.objectweb.asm.Opcodes.LXOR;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_LONG;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
@@ -53,7 +44,7 @@
/**
* Type class: LONG
*/
-class LongType extends BitwiseType {
+class LongType extends Type {
private static final long serialVersionUID = 1L;
private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Long.class, "valueOf", Long.class, long.class);
@@ -82,12 +73,6 @@
}
@Override
- public Type cmp(final MethodVisitor method) {
- method.visitInsn(LCMP);
- return INT;
- }
-
- @Override
public Type load(final MethodVisitor method, final int slot) {
assert slot != -1;
method.visitVarInsn(LLOAD, slot);
@@ -149,88 +134,6 @@
}
@Override
- public Type sub(final MethodVisitor method, final int programPoint) {
- if(programPoint == INVALID_PROGRAM_POINT) {
- method.visitInsn(LSUB);
- } else {
- method.visitInvokeDynamicInsn("lsub", "(JJ)J", MATHBOOTSTRAP, programPoint);
- }
- return LONG;
- }
-
- @Override
- public Type mul(final MethodVisitor method, final int programPoint) {
- if(programPoint == INVALID_PROGRAM_POINT) {
- method.visitInsn(LMUL);
- } else {
- method.visitInvokeDynamicInsn("lmul", "(JJ)J", MATHBOOTSTRAP, programPoint);
- }
- return LONG;
- }
-
- @Override
- public Type div(final MethodVisitor method, final int programPoint) {
- if (programPoint == INVALID_PROGRAM_POINT) {
- JSType.DIV_ZERO_LONG.invoke(method);
- } else {
- method.visitInvokeDynamicInsn("ldiv", "(JJ)J", MATHBOOTSTRAP, programPoint);
- }
- return LONG;
- }
-
- @Override
- public Type rem(final MethodVisitor method, final int programPoint) {
- if (programPoint == INVALID_PROGRAM_POINT) {
- JSType.REM_ZERO_LONG.invoke(method);
- } else {
- method.visitInvokeDynamicInsn("lrem", "(JJ)J", MATHBOOTSTRAP, programPoint);
- }
- return LONG;
- }
-
- @Override
- public Type shr(final MethodVisitor method) {
- method.visitInsn(LUSHR);
- return LONG;
- }
-
- @Override
- public Type sar(final MethodVisitor method) {
- method.visitInsn(LSHR);
- return LONG;
- }
-
- @Override
- public Type shl(final MethodVisitor method) {
- method.visitInsn(LSHL);
- return LONG;
- }
-
- @Override
- public Type and(final MethodVisitor method) {
- method.visitInsn(LAND);
- return LONG;
- }
-
- @Override
- public Type or(final MethodVisitor method) {
- method.visitInsn(LOR);
- return LONG;
- }
-
- @Override
- public Type xor(final MethodVisitor method) {
- method.visitInsn(LXOR);
- return LONG;
- }
-
- @Override
- public Type neg(final MethodVisitor method, final int programPoint) {
- method.visitInvokeDynamicInsn("lneg", "(J)J", MATHBOOTSTRAP, programPoint);
- return LONG;
- }
-
- @Override
public void _return(final MethodVisitor method) {
method.visitInsn(LRETURN);
}
@@ -246,9 +149,4 @@
method.visitInsn(LCONST_0);
return LONG;
}
-
- @Override
- public Type cmp(final MethodVisitor method, final boolean isCmpG) {
- return cmp(method);
- }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Wed Jul 05 21:09:54 2017 +0200
@@ -914,7 +914,7 @@
/**
* This is the long singleton, used for all long types
*/
- public static final BitwiseType LONG = putInCache(new LongType());
+ public static final Type LONG = putInCache(new LongType());
/**
* A string singleton
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BinaryNode.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BinaryNode.java Wed Jul 05 21:09:54 2017 +0200
@@ -70,7 +70,9 @@
TokenType.ASSIGN_DIV,
TokenType.ASSIGN_MOD,
TokenType.ASSIGN_MUL,
- TokenType.ASSIGN_SUB
+ TokenType.ASSIGN_SUB,
+ TokenType.SHR,
+ TokenType.ASSIGN_SHR
})));
/**
@@ -196,9 +198,7 @@
return Type.CHARSEQUENCE;
}
final Type widestOperandType = Type.widest(undefinedToNumber(booleanToInt(lhsType)), undefinedToNumber(booleanToInt(rhsType)));
- if(widestOperandType == Type.INT) {
- return Type.LONG;
- } else if (widestOperandType.isNumeric()) {
+ if (widestOperandType.isNumeric()) {
return Type.NUMBER;
}
// We pretty much can't know what it will be statically. Must presume OBJECT conservatively, as we can end
@@ -210,7 +210,7 @@
}
case SHR:
case ASSIGN_SHR:
- return Type.LONG;
+ return Type.NUMBER;
case ASSIGN_SAR:
case ASSIGN_SHL:
case BIT_AND:
@@ -239,10 +239,6 @@
if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
return Type.INT;
}
- final Type widestOperandType = Type.widest(booleanToInt(lhsType), booleanToInt(rhsType));
- if(widestOperandType == Type.INT) {
- return Type.LONG;
- }
return Type.NUMBER;
}
case VOID: {
@@ -565,6 +561,9 @@
if(type == null) {
return widest;
}
+ if (tokenType() == TokenType.ASSIGN_SHR || tokenType() == TokenType.SHR) {
+ return type;
+ }
return Type.narrowest(widest, Type.widest(type, Type.widest(lhs.getType(), rhs.getType())));
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Wed Jul 05 21:09:54 2017 +0200
@@ -386,8 +386,6 @@
private static Type numberGetType(final Number number) {
if (number instanceof Integer) {
return Type.INT;
- } else if (number instanceof Long) {
- return Type.LONG;
} else if (number instanceof Double) {
return Type.NUMBER;
} else {
@@ -418,6 +416,7 @@
* @return the new literal node
*/
public static LiteralNode<Number> newInstance(final long token, final int finish, final Number value) {
+ assert !(value instanceof Long);
return new NumberLiteralNode(token, finish, value);
}
@@ -776,8 +775,6 @@
assert !elementType.isUnknown();
if (elementType.isInteger()) {
return presetIntArray(value, postsets);
- } else if (elementType.isLong()) {
- return presetLongArray(value, postsets);
} else if (elementType.isNumeric()) {
return presetDoubleArray(value, postsets);
} else {
@@ -847,8 +844,6 @@
private static ArrayType getArrayType(final Type elementType) {
if (elementType.isInteger()) {
return Type.INT_ARRAY;
- } else if (elementType.isLong()) {
- return Type.LONG_ARRAY;
} else if (elementType.isNumeric()) {
return Type.NUMBER_ARRAY;
} else {
@@ -883,8 +878,6 @@
private boolean presetsMatchElementType() {
if (elementType == Type.INT) {
return presets instanceof int[];
- } else if (elementType == Type.LONG) {
- return presets instanceof long[];
} else if (elementType == Type.NUMBER) {
return presets instanceof double[];
} else {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java Wed Jul 05 21:09:54 2017 +0200
@@ -82,14 +82,12 @@
public static final int HAS_SLOT = 1 << 10;
/** Is this symbol known to store an int value ? */
public static final int HAS_INT_VALUE = 1 << 11;
- /** Is this symbol known to store a long value ? */
- public static final int HAS_LONG_VALUE = 1 << 12;
/** Is this symbol known to store a double value ? */
- public static final int HAS_DOUBLE_VALUE = 1 << 13;
+ public static final int HAS_DOUBLE_VALUE = 1 << 12;
/** Is this symbol known to store an object value ? */
- public static final int HAS_OBJECT_VALUE = 1 << 14;
+ public static final int HAS_OBJECT_VALUE = 1 << 13;
/** Is this symbol seen a declaration? Used for block scoped LET and CONST symbols only. */
- public static final int HAS_BEEN_DECLARED = 1 << 15;
+ public static final int HAS_BEEN_DECLARED = 1 << 14;
/** Null or name identifying symbol. */
private final String name;
@@ -256,7 +254,6 @@
*/
public int slotCount() {
return ((flags & HAS_INT_VALUE) == 0 ? 0 : 1) +
- ((flags & HAS_LONG_VALUE) == 0 ? 0 : 2) +
((flags & HAS_DOUBLE_VALUE) == 0 ? 0 : 2) +
((flags & HAS_OBJECT_VALUE) == 0 ? 0 : 1);
}
@@ -278,7 +275,6 @@
append("slot=").
append(firstSlot).append(' ');
if((flags & HAS_INT_VALUE) != 0) { sb.append('I'); }
- if((flags & HAS_LONG_VALUE) != 0) { sb.append('J'); }
if((flags & HAS_DOUBLE_VALUE) != 0) { sb.append('D'); }
if((flags & HAS_OBJECT_VALUE) != 0) { sb.append('O'); }
sb.append(')');
@@ -573,11 +569,6 @@
return typeSlot;
}
typeSlot += ((flags & HAS_INT_VALUE) == 0 ? 0 : 1);
- if(type.isLong()) {
- assert (flags & HAS_LONG_VALUE) != 0;
- return typeSlot;
- }
- typeSlot += ((flags & HAS_LONG_VALUE) == 0 ? 0 : 2);
if(type.isNumber()) {
assert (flags & HAS_DOUBLE_VALUE) != 0;
return typeSlot;
@@ -595,8 +586,6 @@
public boolean hasSlotFor(final Type type) {
if(type.isBoolean() || type.isInteger()) {
return (flags & HAS_INT_VALUE) != 0;
- } else if(type.isLong()) {
- return (flags & HAS_LONG_VALUE) != 0;
} else if(type.isNumber()) {
return (flags & HAS_DOUBLE_VALUE) != 0;
}
@@ -611,8 +600,6 @@
public void setHasSlotFor(final Type type) {
if(type.isBoolean() || type.isInteger()) {
setFlag(HAS_INT_VALUE);
- } else if(type.isLong()) {
- setFlag(HAS_LONG_VALUE);
} else if(type.isNumber()) {
setFlag(HAS_DOUBLE_VALUE);
} else {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java Wed Jul 05 21:09:54 2017 +0200
@@ -25,9 +25,6 @@
package jdk.nashorn.internal.ir.debug;
-import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
-import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.FLAGS_MASK;
-
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -502,6 +499,7 @@
appendOpcode(sb, Opcodes.INVOKEDYNAMIC).append(' ');
final boolean isNashornBootstrap = isNashornBootstrap(bsm);
+ final boolean isNashornMathBootstrap = isNashornMathBootstrap(bsm);
if (isNashornBootstrap) {
sb.append(NashornCallSiteDescriptor.getOperationName((Integer)bsmArgs[0]));
final String decodedName = NameCodec.decode(name);
@@ -529,12 +527,9 @@
} else if (cst instanceof Handle) {
appendHandle(sb, (Handle)cst);
} else if (cst instanceof Integer && isNashornBootstrap) {
- final int c = (Integer)cst;
- final int pp = c >> CALLSITE_PROGRAM_POINT_SHIFT;
- if (pp != 0) {
- sb.append(" pp=").append(pp);
- }
- sb.append(NashornCallSiteDescriptor.toString(c & FLAGS_MASK));
+ NashornCallSiteDescriptor.appendFlags((Integer) cst, sb);
+ } else if (cst instanceof Integer && isNashornMathBootstrap) {
+ sb.append(" pp=").append(cst);
} else {
sb.append(cst);
}
@@ -551,6 +546,10 @@
return "bootstrap".equals(bsm.getName()) && BOOTSTRAP_CLASS_NAME.equals(bsm.getOwner());
}
+ private static boolean isNashornMathBootstrap(final Handle bsm) {
+ return "mathBootstrap".equals(bsm.getName()) && BOOTSTRAP_CLASS_NAME.equals(bsm.getOwner());
+ }
+
private static boolean noFallThru(final int opcode) {
switch (opcode) {
case Opcodes.GOTO:
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Wed Jul 05 21:09:54 2017 +0200
@@ -1106,8 +1106,6 @@
return new NativeArray(ArrayData.allocate((Object[])obj), this);
} else if (obj instanceof double[]) { // extension
return new NativeArray(ArrayData.allocate((double[])obj), this);
- } else if (obj instanceof long[]) {
- return new NativeArray(ArrayData.allocate((long[])obj), this);
} else if (obj instanceof int[]) {
return new NativeArray(ArrayData.allocate((int[]) obj), this);
} else if (obj instanceof ArrayData) {
@@ -1994,16 +1992,6 @@
}
/**
- * Allocate a new long array.
- *
- * @param initial number values.
- * @return the new array
- */
- public static NativeArray allocate(final long[] initial) {
- return new NativeArray(ArrayData.allocate(initial));
- }
-
- /**
* Allocate a new integer array.
*
* @param initial number values.
@@ -2291,7 +2279,6 @@
new Specialization[] {
new Specialization(GlobalFunctions.PARSEINT_Z),
new Specialization(GlobalFunctions.PARSEINT_I),
- new Specialization(GlobalFunctions.PARSEINT_J),
new Specialization(GlobalFunctions.PARSEINT_OI),
new Specialization(GlobalFunctions.PARSEINT_O) });
this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArguments.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArguments.java Wed Jul 05 21:09:54 2017 +0200
@@ -128,12 +128,6 @@
}
@Override
- public boolean delete(final long key, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
- return isMapped(index) ? deleteMapped(index, strict) : super.delete(key, strict);
- }
-
- @Override
public boolean delete(final double key, final boolean strict) {
final int index = ArrayIndex.getArrayIndex(key);
return isMapped(index) ? deleteMapped(index, strict) : super.delete(key, strict);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Wed Jul 05 21:09:54 2017 +0200
@@ -100,20 +100,38 @@
}
NativeArray(final long length) {
- // TODO assert valid index in long before casting
- this(ArrayData.allocate((int)length));
+ this(ArrayData.allocate(length));
}
NativeArray(final int[] array) {
this(ArrayData.allocate(array));
}
- NativeArray(final long[] array) {
+ NativeArray(final double[] array) {
this(ArrayData.allocate(array));
}
- NativeArray(final double[] array) {
- this(ArrayData.allocate(array));
+ NativeArray(final long[] array) {
+ this(ArrayData.allocate(array.length));
+
+ ArrayData arrayData = this.getArray();
+ Class<?> widest = int.class;
+
+ for (int index = 0; index < array.length; index++) {
+ final long value = array[index];
+
+ if (widest == int.class && JSType.isRepresentableAsInt(value)) {
+ arrayData = arrayData.set(index, (int) value, false);
+ } else if (widest != Object.class && JSType.isRepresentableAsDouble(value)) {
+ arrayData = arrayData.set(index, (double) value, false);
+ widest = double.class;
+ } else {
+ arrayData = arrayData.set(index, (Object) value, false);
+ widest = Object.class;
+ }
+ }
+
+ this.setArray(arrayData);
}
NativeArray(final Object[] array) {
@@ -179,7 +197,7 @@
@Override
public MethodHandle call() {
return Bootstrap.createDynamicCallInvoker(rtype, Object.class, Object.class, Object.class,
- long.class, Object.class);
+ double.class, Object.class);
}
});
}
@@ -210,7 +228,7 @@
@Override
public MethodHandle call() {
return Bootstrap.createDynamicCallInvoker(Object.class, Object.class,
- Undefined.class, Object.class, Object.class, long.class, Object.class);
+ Undefined.class, Object.class, Object.class, double.class, Object.class);
}
});
}
@@ -246,8 +264,9 @@
@Override
public Object getLength() {
- final long length = JSType.toUint32(getArray().length());
- if (length < Integer.MAX_VALUE) {
+ final long length = getArray().length();
+ assert length >= 0L;
+ if (length <= Integer.MAX_VALUE) {
return (int)length;
}
return length;
@@ -445,7 +464,13 @@
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static Object length(final Object self) {
if (isArray(self)) {
- return JSType.toUint32(((ScriptObject) self).getArray().length());
+ final long length = ((ScriptObject) self).getArray().length();
+ assert length >= 0L;
+ // Cast to the narrowest supported numeric type to help optimistic type calculator
+ if (length <= Integer.MAX_VALUE) {
+ return (int) length;
+ }
+ return (double) length;
}
return 0;
@@ -1553,7 +1578,7 @@
private final MethodHandle everyInvoker = getEVERY_CALLBACK_INVOKER();
@Override
- protected boolean forEach(final Object val, final long i) throws Throwable {
+ protected boolean forEach(final Object val, final double i) throws Throwable {
return result = (boolean)everyInvoker.invokeExact(callbackfn, thisArg, val, i, self);
}
}.apply();
@@ -1573,7 +1598,7 @@
private final MethodHandle someInvoker = getSOME_CALLBACK_INVOKER();
@Override
- protected boolean forEach(final Object val, final long i) throws Throwable {
+ protected boolean forEach(final Object val, final double i) throws Throwable {
return !(result = (boolean)someInvoker.invokeExact(callbackfn, thisArg, val, i, self));
}
}.apply();
@@ -1593,7 +1618,7 @@
private final MethodHandle forEachInvoker = getFOREACH_CALLBACK_INVOKER();
@Override
- protected boolean forEach(final Object val, final long i) throws Throwable {
+ protected boolean forEach(final Object val, final double i) throws Throwable {
forEachInvoker.invokeExact(callbackfn, thisArg, val, i, self);
return true;
}
@@ -1614,7 +1639,7 @@
private final MethodHandle mapInvoker = getMAP_CALLBACK_INVOKER();
@Override
- protected boolean forEach(final Object val, final long i) throws Throwable {
+ protected boolean forEach(final Object val, final double i) throws Throwable {
final Object r = mapInvoker.invokeExact(callbackfn, thisArg, val, i, self);
result.defineOwnProperty(ArrayIndex.getArrayIndex(index), r);
return true;
@@ -1644,7 +1669,7 @@
private final MethodHandle filterInvoker = getFILTER_CALLBACK_INVOKER();
@Override
- protected boolean forEach(final Object val, final long i) throws Throwable {
+ protected boolean forEach(final Object val, final double i) throws Throwable {
if ((boolean)filterInvoker.invokeExact(callbackfn, thisArg, val, i, self)) {
result.defineOwnProperty(ArrayIndex.getArrayIndex(to++), val);
}
@@ -1676,7 +1701,7 @@
private final MethodHandle reduceInvoker = getREDUCE_CALLBACK_INVOKER();
@Override
- protected boolean forEach(final Object val, final long i) throws Throwable {
+ protected boolean forEach(final Object val, final double i) throws Throwable {
// TODO: why can't I declare the second arg as Undefined.class?
result = reduceInvoker.invokeExact(callbackfn, ScriptRuntime.UNDEFINED, result, val, i, self);
return true;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java Wed Jul 05 21:09:54 2017 +0200
@@ -124,7 +124,7 @@
@Override
public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
- if (returnType == int.class || returnType == long.class) {
+ if (returnType == int.class) {
return null;
}
return getContinuousElementGetter(getClass(), GET_ELEM, returnType, programPoint);
@@ -136,11 +136,6 @@
}
@Override
- public long getLong(final int index) {
- return (long)getDouble(index);
- }
-
- @Override
public double getDouble(final int index) {
return getElem(index);
}
@@ -166,11 +161,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- return set(index, (double)value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
setElem(index, value);
return this;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java Wed Jul 05 21:09:54 2017 +0200
@@ -124,7 +124,7 @@
@Override
public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
- if (returnType == int.class || returnType == long.class) {
+ if (returnType == int.class) {
return null;
}
return getContinuousElementGetter(getClass(), GET_ELEM, returnType, programPoint);
@@ -136,11 +136,6 @@
}
@Override
- public long getLong(final int index) {
- return (long)getDouble(index);
- }
-
- @Override
public double getDouble(final int index) {
return getElem(index);
}
@@ -166,11 +161,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- return set(index, (double)value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
setElem(index, value);
return this;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFunction.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFunction.java Wed Jul 05 21:09:54 2017 +0200
@@ -97,7 +97,6 @@
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object apply(final Object self, final Object thiz, final Object array) {
checkCallable(self);
-
final Object[] args = toApplyArgs(array);
if (self instanceof ScriptFunction) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java Wed Jul 05 21:09:54 2017 +0200
@@ -134,16 +134,6 @@
}
@Override
- public long getLong(final int index) {
- return getInt(index);
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- return getElem(index);
- }
-
- @Override
public double getDouble(final int index) {
return getInt(index);
}
@@ -170,11 +160,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- return set(index, (int)value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
return set(index, (int)value, strict);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java Wed Jul 05 21:09:54 2017 +0200
@@ -133,16 +133,6 @@
}
@Override
- public long getLong(final int index) {
- return getInt(index);
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- return getElem(index);
- }
-
- @Override
public double getDouble(final int index) {
return getInt(index);
}
@@ -169,11 +159,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- return set(index, (int)value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
return set(index, (int)value, strict);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java Wed Jul 05 21:09:54 2017 +0200
@@ -132,16 +132,6 @@
}
@Override
- public long getLong(final int index) {
- return getInt(index);
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- return getElem(index);
- }
-
- @Override
public double getDouble(final int index) {
return getInt(index);
}
@@ -168,11 +158,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- return set(index, (int)value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
return set(index, (int)value, strict);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Wed Jul 05 21:09:54 2017 +0200
@@ -185,36 +185,11 @@
}
@Override
- public int getInt(final long key, final int programPoint) {
- return (overrides && super.hasOwnProperty(key)) ? super.getInt(key, programPoint) : callAdapteeInt(programPoint, __get__, key);
- }
-
- @Override
public int getInt(final int key, final int programPoint) {
return (overrides && super.hasOwnProperty(key)) ? super.getInt(key, programPoint) : callAdapteeInt(programPoint, __get__, key);
}
@Override
- public long getLong(final Object key, final int programPoint) {
- return (overrides && super.hasOwnProperty(key)) ? super.getLong(key, programPoint) : callAdapteeLong(programPoint, __get__, key);
- }
-
- @Override
- public long getLong(final double key, final int programPoint) {
- return (overrides && super.hasOwnProperty(key)) ? super.getLong(key, programPoint) : callAdapteeLong(programPoint, __get__, key);
- }
-
- @Override
- public long getLong(final long key, final int programPoint) {
- return (overrides && super.hasOwnProperty(key)) ? super.getLong(key, programPoint) : callAdapteeLong(programPoint, __get__, key);
- }
-
- @Override
- public long getLong(final int key, final int programPoint) {
- return (overrides && super.hasOwnProperty(key)) ? super.getLong(key, programPoint) : callAdapteeLong(programPoint, __get__, key);
- }
-
- @Override
public double getDouble(final Object key, final int programPoint) {
return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key, programPoint) : callAdapteeDouble(programPoint, __get__, key);
}
@@ -225,11 +200,6 @@
}
@Override
- public double getDouble(final long key, final int programPoint) {
- return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key, programPoint) : callAdapteeDouble(programPoint, __get__, key);
- }
-
- @Override
public double getDouble(final int key, final int programPoint) {
return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key, programPoint) : callAdapteeDouble(programPoint, __get__, key);
}
@@ -245,11 +215,6 @@
}
@Override
- public Object get(final long key) {
- return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
- }
-
- @Override
public Object get(final int key) {
return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
}
@@ -264,15 +229,6 @@
}
@Override
- public void set(final Object key, final long value, final int flags) {
- if (overrides && super.hasOwnProperty(key)) {
- super.set(key, value, flags);
- } else {
- callAdaptee(__put__, key, value, flags);
- }
- }
-
- @Override
public void set(final Object key, final double value, final int flags) {
if (overrides && super.hasOwnProperty(key)) {
super.set(key, value, flags);
@@ -300,15 +256,6 @@
}
@Override
- public void set(final double key, final long value, final int flags) {
- if (overrides && super.hasOwnProperty(key)) {
- super.set(key, value, flags);
- } else {
- callAdaptee(__put__, key, value, flags);
- }
- }
-
- @Override
public void set(final double key, final double value, final int flags) {
if (overrides && super.hasOwnProperty(key)) {
super.set(key, value, flags);
@@ -327,42 +274,6 @@
}
@Override
- public void set(final long key, final int value, final int flags) {
- if (overrides && super.hasOwnProperty(key)) {
- super.set(key, value, flags);
- } else {
- callAdaptee(__put__, key, value, flags);
- }
- }
-
- @Override
- public void set(final long key, final long value, final int flags) {
- if (overrides && super.hasOwnProperty(key)) {
- super.set(key, value, flags);
- } else {
- callAdaptee(__put__, key, value, flags);
- }
- }
-
- @Override
- public void set(final long key, final double value, final int flags) {
- if (overrides && super.hasOwnProperty(key)) {
- super.set(key, value, flags);
- } else {
- callAdaptee(__put__, key, value, flags);
- }
- }
-
- @Override
- public void set(final long key, final Object value, final int flags) {
- if (overrides && super.hasOwnProperty(key)) {
- super.set(key, value, flags);
- } else {
- callAdaptee(__put__, key, value, flags);
- }
- }
-
- @Override
public void set(final int key, final int value, final int flags) {
if (overrides && super.hasOwnProperty(key)) {
super.set(key, value, flags);
@@ -372,15 +283,6 @@
}
@Override
- public void set(final int key, final long value, final int flags) {
- if (overrides && super.hasOwnProperty(key)) {
- super.set(key, value, flags);
- } else {
- callAdaptee(__put__, key, value, flags);
- }
- }
-
- @Override
public void set(final int key, final double value, final int flags) {
if (overrides && super.hasOwnProperty(key)) {
super.set(key, value, flags);
@@ -417,15 +319,6 @@
}
@Override
- public boolean has(final long key) {
- if (overrides && super.hasOwnProperty(key)) {
- return true;
- }
-
- return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
- }
-
- @Override
public boolean has(final double key) {
if (overrides && super.hasOwnProperty(key)) {
return true;
@@ -444,15 +337,6 @@
}
@Override
- public boolean delete(final long key, final boolean strict) {
- if (overrides && super.hasOwnProperty(key)) {
- return super.delete(key, strict);
- }
-
- return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
- }
-
- @Override
public boolean delete(final double key, final boolean strict) {
if (overrides && super.hasOwnProperty(key)) {
return super.delete(key, strict);
@@ -669,10 +553,6 @@
return JSType.toNumberMaybeOptimistic(callAdaptee(name, args), programPoint);
}
- private long callAdapteeLong(final int programPoint, final String name, final Object... args) {
- return JSType.toLongMaybeOptimistic(callAdaptee(name, args), programPoint);
- }
-
private int callAdapteeInt(final int programPoint, final String name, final Object... args) {
return JSType.toInt32MaybeOptimistic(callAdaptee(name, args), programPoint);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java Wed Jul 05 21:09:54 2017 +0200
@@ -33,8 +33,6 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
-import java.math.RoundingMode;
-import java.text.NumberFormat;
import java.util.Locale;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Wed Jul 05 21:09:54 2017 +0200
@@ -148,7 +148,8 @@
* @param buf external buffer - should be a nio ByteBuffer
* @return the 'obj' object
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "sets ByteBuffer to hold indexed data (nashorn extension)")
public static ScriptObject setIndexedPropertiesToExternalArrayData(final Object self, final Object obj, final Object buf) {
Global.checkObject(obj);
final ScriptObject sobj = (ScriptObject)obj;
@@ -168,7 +169,8 @@
* @param obj object to get prototype from
* @return the prototype of an object
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "returns the prototype of the specified object")
public static Object getPrototypeOf(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).getProto();
@@ -195,7 +197,8 @@
* @param proto prototype object to be used
* @return object whose prototype is set
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "sets the prototype of the given object (ES6)")
public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) {
if (obj instanceof ScriptObject) {
((ScriptObject)obj).setPrototypeOf(proto);
@@ -216,7 +219,8 @@
* @param prop property descriptor
* @return property descriptor
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "returns a property descriptor for an own property (not inherited property)")
public static Object getOwnPropertyDescriptor(final Object self, final Object obj, final Object prop) {
if (obj instanceof ScriptObject) {
final String key = JSType.toString(prop);
@@ -240,7 +244,8 @@
* @param obj object to query for property names
* @return array of property names
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "returns an array of all properties (enumerable or not) found directly on the given object")
public static ScriptObject getOwnPropertyNames(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return new NativeArray(((ScriptObject)obj).getOwnKeys(true));
@@ -258,7 +263,8 @@
* @param obj object to query for property names
* @return array of property names
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "returns an array of all symbol properties found directly on the given object (ES6)")
public static ScriptObject getOwnPropertySymbols(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return new NativeArray(((ScriptObject)obj).getOwnSymbols(true));
@@ -276,7 +282,8 @@
* @param props properties to define
* @return object created
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "creates a new object with the specified prototype object and properties")
public static ScriptObject create(final Object self, final Object proto, final Object props) {
if (proto != null) {
Global.checkObject(proto);
@@ -302,7 +309,8 @@
* @param attr attributes for property descriptor
* @return object
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "adds an own property and/or update the attributes of an existing own property of an object")
public static ScriptObject defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
final ScriptObject sobj = Global.checkObject(obj);
sobj.defineOwnProperty(JSType.toPropertyKey(prop), attr, true);
@@ -317,7 +325,8 @@
* @param props properties
* @return object
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "defines new or modifies existing properties directly on the given object")
public static ScriptObject defineProperties(final Object self, final Object obj, final Object props) {
final ScriptObject sobj = Global.checkObject(obj);
final Object propsObj = Global.toObject(props);
@@ -339,7 +348,8 @@
* @param obj object to seal
* @return sealed object
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "prevents new properties from being added to the given object and marks existing properties as non-configurable")
public static Object seal(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).seal();
@@ -358,7 +368,8 @@
* @param obj object to freeze
* @return frozen object
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "prevents new properties from being added to the given object and prevents existing properties from being removed or re-configured")
public static Object freeze(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).freeze();
@@ -376,7 +387,8 @@
* @param obj object, for which to set the internal extensible property to false
* @return object
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "prevents new properties from ever being added to the given object")
public static Object preventExtensions(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).preventExtensions();
@@ -394,7 +406,8 @@
* @param obj check whether an object is sealed
* @return true if sealed, false otherwise
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "tells if an object is sealed or not")
public static boolean isSealed(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).isSealed();
@@ -412,7 +425,8 @@
* @param obj check whether an object
* @return true if object is frozen, false otherwise
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "tells if an object is fronzen or not")
public static boolean isFrozen(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).isFrozen();
@@ -430,7 +444,8 @@
* @param obj check whether an object is extensible
* @return true if object is extensible, false otherwise
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "tells if an object is extensible or not")
public static boolean isExtensible(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).isExtensible();
@@ -448,7 +463,8 @@
* @param obj object from which to extract keys
* @return array of keys in object
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "returns an array of the given object's own enumerable properties")
public static ScriptObject keys(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
final ScriptObject sobj = (ScriptObject)obj;
@@ -471,7 +487,7 @@
* @param value value of object to be instantiated
* @return the new NativeObject
*/
- @Constructor
+ @Constructor(documentation = "creates a new script object or converts given value as a script object")
public static Object construct(final boolean newObj, final Object self, final Object value) {
final JSType type = JSType.ofNoFunction(value);
@@ -505,7 +521,8 @@
* @param self self reference
* @return ToString of object
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE)
+ @Function(attributes = Attribute.NOT_ENUMERABLE,
+ documentation = "returns a string representing of this object")
public static String toString(final Object self) {
return ScriptRuntime.builtinObjectToString(self);
}
@@ -558,7 +575,8 @@
* @param v property to check for
* @return true if property exists in object
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE)
+ @Function(attributes = Attribute.NOT_ENUMERABLE,
+ documentation = "tells whether this object has the specified property or not")
public static boolean hasOwnProperty(final Object self, final Object v) {
// Convert ScriptObjects to primitive with String.class hint
// but no need to convert other primitives to string.
@@ -575,7 +593,8 @@
* @param v v prototype object to check against
* @return true if object is prototype of v
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE)
+ @Function(attributes = Attribute.NOT_ENUMERABLE,
+ documentation = "tests for this object in another object's prototype chain")
public static boolean isPrototypeOf(final Object self, final Object v) {
if (!(v instanceof ScriptObject)) {
return false;
@@ -601,7 +620,8 @@
* @param v property to check if enumerable
* @return true if property is enumerable
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE)
+ @Function(attributes = Attribute.NOT_ENUMERABLE,
+ documentation = "tells whether the given property is enumerable or not")
public static boolean propertyIsEnumerable(final Object self, final Object v) {
final String str = JSType.toString(v);
final Object obj = Global.toObject(self);
@@ -676,7 +696,8 @@
* @param source the source object whose properties are bound to the target
* @return the target object after property binding
*/
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+ documentation = "binds the source object's properties to the target object (nashorn extension)")
public static Object bindProperties(final Object self, final Object target, final Object source) {
// target object has to be a ScriptObject
final ScriptObject targetObj = Global.checkObject(target);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Wed Jul 05 21:09:54 2017 +0200
@@ -210,14 +210,6 @@
}
@Override
- public Object get(final long key) {
- if (key >= 0 && key < value.length()) {
- return String.valueOf(value.charAt((int)key));
- }
- return super.get(key);
- }
-
- @Override
public Object get(final int key) {
if (key >= 0 && key < value.length()) {
return String.valueOf(value.charAt(key));
@@ -236,36 +228,11 @@
}
@Override
- public int getInt(final long key, final int programPoint) {
- return JSType.toInt32MaybeOptimistic(get(key), programPoint);
- }
-
- @Override
public int getInt(final int key, final int programPoint) {
return JSType.toInt32MaybeOptimistic(get(key), programPoint);
}
@Override
- public long getLong(final Object key, final int programPoint) {
- return JSType.toLongMaybeOptimistic(get(key), programPoint);
- }
-
- @Override
- public long getLong(final double key, final int programPoint) {
- return JSType.toLongMaybeOptimistic(get(key), programPoint);
- }
-
- @Override
- public long getLong(final long key, final int programPoint) {
- return JSType.toLongMaybeOptimistic(get(key), programPoint);
- }
-
- @Override
- public long getLong(final int key, final int programPoint) {
- return JSType.toLongMaybeOptimistic(get(key), programPoint);
- }
-
- @Override
public double getDouble(final Object key, final int programPoint) {
return JSType.toNumberMaybeOptimistic(get(key), programPoint);
}
@@ -276,11 +243,6 @@
}
@Override
- public double getDouble(final long key, final int programPoint) {
- return JSType.toNumberMaybeOptimistic(get(key), programPoint);
- }
-
- @Override
public double getDouble(final int key, final int programPoint) {
return JSType.toNumberMaybeOptimistic(get(key), programPoint);
}
@@ -298,12 +260,6 @@
}
@Override
- public boolean has(final long key) {
- final int index = ArrayIndex.getArrayIndex(key);
- return isValidStringIndex(index) || super.has(key);
- }
-
- @Override
public boolean has(final double key) {
final int index = ArrayIndex.getArrayIndex(key);
return isValidStringIndex(index) || super.has(key);
@@ -322,12 +278,6 @@
}
@Override
- public boolean hasOwnProperty(final long key) {
- final int index = ArrayIndex.getArrayIndex(key);
- return isValidStringIndex(index) || super.hasOwnProperty(key);
- }
-
- @Override
public boolean hasOwnProperty(final double key) {
final int index = ArrayIndex.getArrayIndex(key);
return isValidStringIndex(index) || super.hasOwnProperty(key);
@@ -339,12 +289,6 @@
}
@Override
- public boolean delete(final long key, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
- return checkDeleteIndex(index, strict)? false : super.delete(key, strict);
- }
-
- @Override
public boolean delete(final double key, final boolean strict) {
final int index = ArrayIndex.getArrayIndex(key);
return checkDeleteIndex(index, strict)? false : super.delete(key, strict);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java Wed Jul 05 21:09:54 2017 +0200
@@ -138,16 +138,6 @@
}
@Override
- public long getLong(final int index) {
- return getInt(index);
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- return getElem(index);
- }
-
- @Override
public double getDouble(final int index) {
return getInt(index);
}
@@ -174,11 +164,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- return set(index, (int)value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
return set(index, (int)value, strict);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java Wed Jul 05 21:09:54 2017 +0200
@@ -32,6 +32,7 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
+import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -41,6 +42,7 @@
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
@@ -78,7 +80,7 @@
private static final class Uint32ArrayData extends TypedArrayData<IntBuffer> {
- private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Uint32ArrayData.class, "getElem", long.class, int.class).methodHandle();
+ private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Uint32ArrayData.class, "getElem", double.class, int.class).methodHandle();
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint32ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
private Uint32ArrayData(final IntBuffer nb, final int start, final int end) {
@@ -103,14 +105,18 @@
return getContinuousElementGetter(getClass(), GET_ELEM, returnType, programPoint);
}
- private long getElem(final int index) {
+ private int getRawElem(final int index) {
try {
- return JSType.toUint32(nb.get(index));
+ return nb.get(index);
} catch (final IndexOutOfBoundsException e) {
throw new ClassCastException(); //force relink - this works for unoptimistic too
}
}
+ private double getElem(final int index) {
+ return JSType.toUint32(getRawElem(index));
+ }
+
private void setElem(final int index, final int elem) {
try {
if (index < nb.limit()) {
@@ -128,42 +134,37 @@
@Override
public Class<?> getElementType() {
- return long.class;
+ return double.class;
}
@Override
public Class<?> getBoxedElementType() {
- return Integer.class;
+ return Double.class;
}
@Override
public int getInt(final int index) {
- return (int)getLong(index);
+ return getRawElem(index);
}
@Override
- public long getLong(final int index) {
+ public int getIntOptimistic(final int index, final int programPoint) {
+ return JSType.toUint32Optimistic(getRawElem(index), programPoint);
+ }
+
+ @Override
+ public double getDouble(final int index) {
return getElem(index);
}
@Override
- public long getLongOptimistic(final int index, final int programPoint) {
+ public double getDoubleOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
- public double getDouble(final int index) {
- return getLong(index);
- }
-
- @Override
- public double getDoubleOptimistic(final int index, final int programPoint) {
- return getLong(index);
- }
-
- @Override
public Object getObject(final int index) {
- return getLong(index);
+ return getElem(index);
}
@Override
@@ -178,11 +179,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- return set(index, (int)value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
return set(index, (int)value, strict);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java Wed Jul 05 21:09:54 2017 +0200
@@ -138,16 +138,6 @@
}
@Override
- public long getLong(final int index) {
- return getInt(index);
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- return getElem(index);
- }
-
- @Override
public double getDouble(final int index) {
return getInt(index);
}
@@ -174,11 +164,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- return set(index, (int)value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
return set(index, (int)value, strict);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Wed Jul 05 21:09:54 2017 +0200
@@ -168,16 +168,6 @@
}
@Override
- public long getLong(final int index) {
- return getInt(index);
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- return getElem(index);
- }
-
- @Override
public double getDouble(final int index) {
return getInt(index);
}
@@ -204,11 +194,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- return set(index, (int)value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
return set(index, rint(value), strict);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Constructor.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Constructor.java Wed Jul 05 21:09:54 2017 +0200
@@ -48,4 +48,9 @@
* arity.
*/
public int arity() default -2;
+
+ /**
+ * @return the documentation string for this constructor.
+ */
+ public String documentation() default "";
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Function.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Function.java Wed Jul 05 21:09:54 2017 +0200
@@ -60,4 +60,9 @@
* @return where this function lives.
*/
public Where where() default Where.PROTOTYPE;
+
+ /**
+ * @return return the documentation string for this function.
+ */
+ public String documentation() default "";
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/JSONParser.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/JSONParser.java Wed Jul 05 21:09:54 2017 +0200
@@ -293,8 +293,6 @@
private static Class<?> getType(final Object value) {
if (value instanceof Integer) {
return int.class;
- } else if (value instanceof Long) {
- return long.class;
} else if (value instanceof Double) {
return double.class;
} else {
@@ -477,8 +475,6 @@
final double d = Double.parseDouble(source.substring(start, pos));
if (JSType.isRepresentableAsInt(d)) {
return (int) d;
- } else if (JSType.isRepresentableAsLong(d)) {
- return (long) d;
}
return d;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Wed Jul 05 21:09:54 2017 +0200
@@ -1131,11 +1131,7 @@
*/
private static Number valueOf(final String valueString, final int radix) throws NumberFormatException {
try {
- final long value = Long.parseLong(valueString, radix);
- if(value >= MIN_INT_L && value <= MAX_INT_L) {
- return (int)value;
- }
- return value;
+ return Integer.parseInt(valueString, radix);
} catch (final NumberFormatException e) {
if (radix == 10) {
return Double.valueOf(valueString);
@@ -1782,8 +1778,6 @@
//yet we don't want e.g. 1e6 to be a double unnecessarily
if (JSType.isStrictlyRepresentableAsInt(value)) {
return (int)value;
- } else if (JSType.isStrictlyRepresentableAsLong(value)) {
- return (long)value;
}
return value;
case STRING:
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Wed Jul 05 21:09:54 2017 +0200
@@ -221,7 +221,7 @@
assert setterType == null || setterType == getterType;
- if (getterType == int.class || getterType == long.class) {
+ if (getterType == int.class) {
primitiveGetter = MH.asType(getter, Lookup.GET_PRIMITIVE_TYPE);
primitiveSetter = setter == null ? null : MH.asType(setter, Lookup.SET_PRIMITIVE_TYPE);
} else if (getterType == double.class) {
@@ -400,17 +400,6 @@
}
}
- @Override
- public long getLongValue(final ScriptObject self, final ScriptObject owner) {
- try {
- return (long)getGetter(long.class).invokeExact((Object)self);
- } catch (final Error | RuntimeException e) {
- throw e;
- } catch (final Throwable e) {
- throw new RuntimeException(e);
- }
- }
-
@Override
public double getDoubleValue(final ScriptObject self, final ScriptObject owner) {
try {
@@ -453,21 +442,6 @@
* @param self owner
* @param value value
*/
- protected final void invokeSetter(final ScriptObject self, final long value) {
- try {
- getSetter(long.class, self.getMap()).invokeExact((Object)self, value);
- } catch (final Error | RuntimeException e) {
- throw e;
- } catch (final Throwable e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Invoke setter for this property with a value
- * @param self owner
- * @param value value
- */
protected final void invokeSetter(final ScriptObject self, final double value) {
try {
getSetter(double.class, self.getMap()).invokeExact((Object)self, value);
@@ -500,12 +474,6 @@
}
@Override
- public void setValue(final ScriptObject self, final ScriptObject owner, final long value, final boolean strict) {
- assert isConfigurable() || isWritable() : getKey() + " is not writable or configurable";
- invokeSetter(self, value);
- }
-
- @Override
public void setValue(final ScriptObject self, final ScriptObject owner, final double value, final boolean strict) {
assert isConfigurable() || isWritable() : getKey() + " is not writable or configurable";
invokeSetter(self, value);
@@ -533,7 +501,6 @@
final int i = getAccessorTypeIndex(type);
assert type == int.class ||
- type == long.class ||
type == double.class ||
type == Object.class :
"invalid getter type " + type + " for " + getKey();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/DebuggerSupport.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/DebuggerSupport.java Wed Jul 05 21:09:54 2017 +0200
@@ -239,7 +239,7 @@
if (ScriptObject.isArray(object)) {
sb.append('[');
- final long length = object.getLong("length", INVALID_PROGRAM_POINT);
+ final long length = (long) object.getDouble("length", INVALID_PROGRAM_POINT);
for (long i = 0; i < length; i++) {
if (object.has(i)) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/DefaultPropertyAccess.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/DefaultPropertyAccess.java Wed Jul 05 21:09:54 2017 +0200
@@ -44,36 +44,11 @@
}
@Override
- public int getInt(final long key, final int programPoint) {
- return getInt(JSType.toObject(key), programPoint);
- }
-
- @Override
public int getInt(final int key, final int programPoint) {
return getInt(JSType.toObject(key), programPoint);
}
@Override
- public long getLong(final Object key, final int programPoint) {
- return JSType.toLong(get(key));
- }
-
- @Override
- public long getLong(final double key, final int programPoint) {
- return getLong(JSType.toObject(key), programPoint);
- }
-
- @Override
- public long getLong(final long key, final int programPoint) {
- return getLong(JSType.toObject(key), programPoint);
- }
-
- @Override
- public long getLong(final int key, final int programPoint) {
- return getLong(JSType.toObject(key), programPoint);
- }
-
- @Override
public double getDouble(final Object key, final int programPoint) {
return JSType.toNumber(get(key));
}
@@ -84,11 +59,6 @@
}
@Override
- public double getDouble(final long key, final int programPoint) {
- return getDouble(JSType.toObject(key), programPoint);
- }
-
- @Override
public double getDouble(final int key, final int programPoint) {
return getDouble(JSType.toObject(key), programPoint);
}
@@ -102,11 +72,6 @@
}
@Override
- public Object get(final long key) {
- return get(JSType.toObject(key));
- }
-
- @Override
public Object get(final int key) {
return get(JSType.toObject(key));
}
@@ -117,11 +82,6 @@
}
@Override
- public void set(final double key, final long value, final int flags) {
- set(JSType.toObject(key), JSType.toObject(value), flags);
- }
-
- @Override
public void set(final double key, final double value, final int flags) {
set(JSType.toObject(key), JSType.toObject(value), flags);
}
@@ -132,36 +92,11 @@
}
@Override
- public void set(final long key, final int value, final int flags) {
- set(JSType.toObject(key), JSType.toObject(value), flags);
- }
-
- @Override
- public void set(final long key, final long value, final int flags) {
- set(JSType.toObject(key), JSType.toObject(value), flags);
- }
-
- @Override
- public void set(final long key, final double value, final int flags) {
- set(JSType.toObject(key), JSType.toObject(value), flags);
- }
-
- @Override
- public void set(final long key, final Object value, final int flags) {
- set(JSType.toObject(key), value, flags);
- }
-
- @Override
public void set(final int key, final int value, final int flags) {
set(JSType.toObject(key), JSType.toObject(value), flags);
}
@Override
- public void set(final int key, final long value, final int flags) {
- set(JSType.toObject(key), JSType.toObject(value), flags);
- }
-
- @Override
public void set(final int key, final double value, final int flags) {
set(JSType.toObject(key), JSType.toObject(value), flags);
}
@@ -177,11 +112,6 @@
}
@Override
- public void set(final Object key, final long value, final int flags) {
- set(key, JSType.toObject(value), flags);
- }
-
- @Override
public void set(final Object key, final double value, final int flags) {
set(key, JSType.toObject(value), flags);
}
@@ -198,11 +128,6 @@
}
@Override
- public boolean has(final long key) {
- return has(JSType.toObject(key));
- }
-
- @Override
public boolean has(final double key) {
return has(JSType.toObject(key));
}
@@ -213,11 +138,6 @@
}
@Override
- public boolean hasOwnProperty(final long key) {
- return hasOwnProperty(JSType.toObject(key));
- }
-
- @Override
public boolean hasOwnProperty(final double key) {
return hasOwnProperty(JSType.toObject(key));
}
@@ -231,11 +151,6 @@
}
@Override
- public boolean delete(final long key, final boolean strict) {
- return delete(JSType.toObject(key), strict);
- }
-
- @Override
public boolean delete(final double key, final boolean strict) {
return delete(JSType.toObject(key), strict);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Wed Jul 05 21:09:54 2017 +0200
@@ -89,11 +89,16 @@
}
@Override
- CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
+ CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden, boolean linkLogicOkay) {
assert isValidCallSite(callSiteType) : callSiteType;
CompiledFunction best = null;
for (final CompiledFunction candidate: code) {
+ if (!linkLogicOkay && candidate.hasLinkLogic()) {
+ // Skip! Version with no link logic is desired, but this one has link logic!
+ continue;
+ }
+
if (!forbidden.contains(candidate) && candidate.betterThanFinal(best, callSiteType)) {
best = candidate;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Wed Jul 05 21:09:54 2017 +0200
@@ -218,13 +218,6 @@
* Get the property value from self as object.
* @return the property value
*/
- public long getLongValue() {
- return property.getLongValue(getGetterReceiver(), getOwner());
- }
- /**
- * Get the property value from self as object.
- * @return the property value
- */
public double getDoubleValue() {
return property.getDoubleValue(getGetterReceiver(), getOwner());
}
@@ -252,16 +245,6 @@
* @param value the new value
* @param strict strict flag
*/
- public void setValue(final long value, final boolean strict) {
- property.setValue(getSetterReceiver(), getOwner(), value, strict);
- }
-
- /**
- * Set the property value in self.
- *
- * @param value the new value
- * @param strict strict flag
- */
public void setValue(final double value, final boolean strict) {
property.setValue(getSetterReceiver(), getOwner(), value, strict);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalFunctions.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalFunctions.java Wed Jul 05 21:09:54 2017 +0200
@@ -48,9 +48,6 @@
/** ParseInt - identity for ints */
public static final MethodHandle PARSEINT_I = MH.dropArguments(MH.identity(int.class), 0, Object.class);
- /** ParseInt - identity for longs */
- public static final MethodHandle PARSEINT_J = MH.dropArguments(MH.identity(long.class), 0, Object.class);
-
/** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
public static final MethodHandle PARSEINT_O = findOwnMH("parseInt", double.class, Object.class, Object.class);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Wed Jul 05 21:09:54 2017 +0200
@@ -119,14 +119,14 @@
public static final Call TO_INT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, double.class);
/** JavaScript compliant conversion function from int to uint32 */
- public static final Call TO_UINT32_I = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, int.class);
+ public static final Call TO_UINT32_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32Optimistic", int.class, int.class, int.class);
+
+ /** JavaScript compliant conversion function from int to uint32 */
+ public static final Call TO_UINT32_DOUBLE = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32Double", double.class, int.class);
/** JavaScript compliant conversion function from Object to uint32 */
public static final Call TO_UINT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, Object.class);
- /** JavaScript compliant conversion function from Object to long with type check */
- public static final Call TO_LONG_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toLongOptimistic", long.class, Object.class, int.class);
-
/** JavaScript compliant conversion function from number to uint32 */
public static final Call TO_UINT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, double.class);
@@ -172,36 +172,6 @@
/** Negate exact exact wrapper for potentially overflowing integer operations */
public static final Call NEGATE_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact", int.class, int.class, int.class);
- /** Add exact wrapper for potentially overflowing long operations */
- public static final Call ADD_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "addExact", long.class, long.class, long.class, int.class);
-
- /** Sub exact wrapper for potentially overflowing long operations */
- public static final Call SUB_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "subExact", long.class, long.class, long.class, int.class);
-
- /** Multiply exact wrapper for potentially overflowing long operations */
- public static final Call MUL_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "mulExact", long.class, long.class, long.class, int.class);
-
- /** Div exact wrapper for potentially integer division that turns into float point */
- public static final Call DIV_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class);
-
- /** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */
- public static final Call DIV_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", long.class, long.class, long.class);
-
- /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */
- public static final Call REM_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", long.class, long.class, long.class);
-
- /** Mod exact wrapper for potentially integer remainders that turns into float point */
- public static final Call REM_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", long.class, long.class, long.class, int.class);
-
- /** Decrement exact wrapper for potentially overflowing long operations */
- public static final Call DECREMENT_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "decrementExact", long.class, long.class, int.class);
-
- /** Increment exact wrapper for potentially overflowing long operations */
- public static final Call INCREMENT_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "incrementExact", long.class, long.class, int.class);
-
- /** Negate exact exact wrapper for potentially overflowing long operations */
- public static final Call NEGATE_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact", long.class, long.class, int.class);
-
/** Method handle to convert a JS Object to a Java array. */
public static final Call TO_JAVA_ARRAY = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaArray", Object.class, Object.class, Class.class);
@@ -215,7 +185,6 @@
private static final List<Type> ACCESSOR_TYPES = Collections.unmodifiableList(
Arrays.asList(
Type.INT,
- Type.LONG,
Type.NUMBER,
Type.OBJECT));
@@ -223,17 +192,14 @@
public static final int TYPE_UNDEFINED_INDEX = -1;
/** table index for integer type - hard coded so it can be used in switches at compile time */
public static final int TYPE_INT_INDEX = 0; //getAccessorTypeIndex(int.class);
- /** table index for long type - hard coded so it can be used in switches at compile time */
- public static final int TYPE_LONG_INDEX = 1; //getAccessorTypeIndex(long.class);
/** table index for double type - hard coded so it can be used in switches at compile time */
- public static final int TYPE_DOUBLE_INDEX = 2; //getAccessorTypeIndex(double.class);
+ public static final int TYPE_DOUBLE_INDEX = 1; //getAccessorTypeIndex(double.class);
/** table index for object type - hard coded so it can be used in switches at compile time */
- public static final int TYPE_OBJECT_INDEX = 3; //getAccessorTypeIndex(Object.class);
+ public static final int TYPE_OBJECT_INDEX = 2; //getAccessorTypeIndex(Object.class);
/** object conversion quickies with JS semantics - used for return value and parameter filter */
public static final List<MethodHandle> CONVERT_OBJECT = toUnmodifiableList(
JSType.TO_INT32.methodHandle(),
- JSType.TO_UINT32.methodHandle(),
JSType.TO_NUMBER.methodHandle(),
null
);
@@ -244,7 +210,6 @@
*/
public static final List<MethodHandle> CONVERT_OBJECT_OPTIMISTIC = toUnmodifiableList(
JSType.TO_INT32_OPTIMISTIC.methodHandle(),
- JSType.TO_LONG_OPTIMISTIC.methodHandle(),
JSType.TO_NUMBER_OPTIMISTIC.methodHandle(),
null
);
@@ -256,13 +221,16 @@
/** The value of Undefined cast to a double */
public static final double UNDEFINED_DOUBLE = Double.NaN;
+ // Minimum and maximum range between which every long value can be precisely represented as a double.
+ private static final long MAX_PRECISE_DOUBLE = 1L << 53;
+ private static final long MIN_PRECISE_DOUBLE = -MAX_PRECISE_DOUBLE;
+
/**
* Method handles for getters that return undefined coerced
* to the appropriate type
*/
public static final List<MethodHandle> GET_UNDEFINED = toUnmodifiableList(
MH.constant(int.class, UNDEFINED_INT),
- MH.constant(long.class, UNDEFINED_LONG),
MH.constant(double.class, UNDEFINED_DOUBLE),
MH.constant(Object.class, Undefined.getUndefined())
);
@@ -428,7 +396,7 @@
/**
* Returns true if double number can be represented as a long. Note that it returns true for negative
- * zero. If you need to exclude negative zero, use {@link #isStrictlyRepresentableAsLong(double)}.
+ * zero.
*
* @param number a double to inspect
* @return true for long representable doubles
@@ -438,29 +406,12 @@
}
/**
- * Returns true if double number can be represented as a long. Note that it returns false for negative
- * zero. If you don't need to distinguish negative zero, use {@link #isRepresentableAsLong(double)}.
- *
- * @param number a double to inspect
- *
- * @return true for long representable doubles
+ * Returns true if long number can be represented as double without loss of precision.
+ * @param number a long number
+ * @return true if the double representation does not lose precision
*/
- public static boolean isStrictlyRepresentableAsLong(final double number) {
- return isRepresentableAsLong(number) && isNotNegativeZero(number);
- }
-
- /**
- * Returns true if Object can be represented as a long
- *
- * @param obj an object to inspect
- *
- * @return true for long representable objects
- */
- public static boolean isRepresentableAsLong(final Object obj) {
- if (obj instanceof Number) {
- return isRepresentableAsLong(((Number)obj).doubleValue());
- }
- return false;
+ public static boolean isRepresentableAsDouble(final long number) {
+ return MAX_PRECISE_DOUBLE >= number && number >= MIN_PRECISE_DOUBLE;
}
/**
@@ -650,22 +601,6 @@
}
/**
- * Check whether a string is representable as a JavaScript number
- *
- * @param str a string
- *
- * @return true if string can be represented as a number
- */
- public static boolean isNumber(final String str) {
- try {
- Double.parseDouble(str);
- return true;
- } catch (final NumberFormatException e) {
- return false;
- }
- }
-
- /**
* Returns true if object represents a primitive JavaScript string value.
* @param obj the object
* @return true if the object represents a primitive JavaScript string value.
@@ -1033,35 +968,6 @@
}
/**
- * Optimistic long conversion - throws UnwarrantedOptimismException if double or Object
- *
- * @param obj object to convert
- * @param programPoint program point
- * @return long
- */
- public static long toLongOptimistic(final Object obj, final int programPoint) {
- if (obj != null) {
- final Class<?> clz = obj.getClass();
- if (clz == Long.class || clz == Integer.class) {
- return ((Number)obj).longValue();
- }
- }
- throw new UnwarrantedOptimismException(obj, programPoint);
- }
-
- /**
- * Object to int conversion that delegates to either {@link #toLong(Object)} or to
- * {@link #toLongOptimistic(Object, int)} depending on whether the program point is valid or not.
- * @param obj the object to convert
- * @param programPoint the program point; can be invalid.
- * @return the value converted to long
- * @throws UnwarrantedOptimismException if the value can't be represented as long and the program point is valid.
- */
- public static long toLongMaybeOptimistic(final Object obj, final int programPoint) {
- return UnwarrantedOptimismException.isValid(programPoint) ? toLongOptimistic(obj, programPoint) : toLong(obj);
- }
-
- /**
* JavaScript compliant Object to int32 conversion
* See ECMA 9.5 ToInt32
*
@@ -1098,10 +1004,6 @@
return UnwarrantedOptimismException.isValid(programPoint) ? toInt32Optimistic(obj, programPoint) : toInt32(obj);
}
- // Minimum and maximum range between which every long value can be precisely represented as a double.
- private static final long MAX_PRECISE_DOUBLE = 1L << 53;
- private static final long MIN_PRECISE_DOUBLE = -MAX_PRECISE_DOUBLE;
-
/**
* JavaScript compliant long to int32 conversion
*
@@ -1154,6 +1056,29 @@
}
/**
+ * Optimistic JavaScript compliant int to uint32 conversion
+ * @param num an int
+ * @param pp the program point
+ * @return the uint32 value if it can be represented by an int
+ * @throws UnwarrantedOptimismException if uint32 value cannot be represented by an int
+ */
+ public static int toUint32Optimistic(final int num, final int pp) {
+ if (num >= 0) {
+ return num;
+ }
+ throw new UnwarrantedOptimismException(toUint32Double(num), pp, Type.NUMBER);
+ }
+
+ /**
+ * JavaScript compliant int to uint32 conversion with double return type
+ * @param num an int
+ * @return the uint32 value as double
+ */
+ public static double toUint32Double(final int num) {
+ return (double) toUint32(num);
+ }
+
+ /**
* JavaScript compliant Object to uint16 conversion
* ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer)
*
@@ -1484,26 +1409,6 @@
try {
return Math.addExact(x, y);
} catch (final ArithmeticException e) {
- throw new UnwarrantedOptimismException((long)x + (long)y, programPoint);
- }
- }
-
- /**
- * Wrapper for addExact
- *
- * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
- * containing the result and the program point of the failure
- *
- * @param x first term
- * @param y second term
- * @param programPoint program point id
- * @return the result
- * @throws UnwarrantedOptimismException if overflow occurs
- */
- public static long addExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
- try {
- return Math.addExact(x, y);
- } catch (final ArithmeticException e) {
throw new UnwarrantedOptimismException((double)x + (double)y, programPoint);
}
}
@@ -1524,26 +1429,6 @@
try {
return Math.subtractExact(x, y);
} catch (final ArithmeticException e) {
- throw new UnwarrantedOptimismException((long)x - (long)y, programPoint);
- }
- }
-
- /**
- * Wrapper for subExact
- *
- * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
- * containing the result and the program point of the failure
- *
- * @param x first term
- * @param y second term
- * @param programPoint program point id
- * @return the result
- * @throws UnwarrantedOptimismException if overflow occurs
- */
- public static long subExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
- try {
- return Math.subtractExact(x, y);
- } catch (final ArithmeticException e) {
throw new UnwarrantedOptimismException((double)x - (double)y, programPoint);
}
}
@@ -1564,26 +1449,6 @@
try {
return Math.multiplyExact(x, y);
} catch (final ArithmeticException e) {
- throw new UnwarrantedOptimismException((long)x * (long)y, programPoint);
- }
- }
-
- /**
- * Wrapper for mulExact
- *
- * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
- * containing the result and the program point of the failure
- *
- * @param x first term
- * @param y second term
- * @param programPoint program point id
- * @return the result
- * @throws UnwarrantedOptimismException if overflow occurs
- */
- public static long mulExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
- try {
- return Math.multiplyExact(x, y);
- } catch (final ArithmeticException e) {
throw new UnwarrantedOptimismException((double)x * (double)y, programPoint);
}
}
@@ -1655,71 +1520,6 @@
}
/**
- * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as
- * long.
- *
- * @param x first term
- * @param y second term
- * @param programPoint program point id
- * @return the result
- * @throws UnwarrantedOptimismException if the result of the division can't be represented as long.
- */
- public static long divExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
- final long res;
- try {
- res = x / y;
- } catch (final ArithmeticException e) {
- assert y == 0L; // Only div by zero anticipated
- throw new UnwarrantedOptimismException(x > 0L ? Double.POSITIVE_INFINITY : x < 0L ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint);
- }
- final long rem = x % y;
- if (rem == 0L) {
- return res;
- }
- throw new UnwarrantedOptimismException((double)x / (double)y, programPoint);
- }
-
- /**
- * Implements long division but allows {@code x / 0} to be represented as 0. Useful when division of two longs
- * is coerced to long.
- * @param x the dividend
- * @param y the divisor
- * @return the result
- */
- public static long divZero(final long x, final long y) {
- return y == 0L ? 0L : x / y;
- }
-
- /**
- * Implements long remainder but allows {@code x % 0} to be represented as 0. Useful when remainder of two longs
- * is coerced to long.
- * @param x the dividend
- * @param y the divisor
- * @return the remainder
- */
- public static long remZero(final long x, final long y) {
- return y == 0L ? 0L : x % y;
- }
-
- /**
- * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int.
- *
- * @param x first term
- * @param y second term
- * @param programPoint program point id
- * @return the result
- * @throws UnwarrantedOptimismException if the modulo can't be represented as int.
- */
- public static long remExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
- try {
- return x % y;
- } catch (final ArithmeticException e) {
- assert y == 0L; // Only mod by zero anticipated
- throw new UnwarrantedOptimismException(Double.NaN, programPoint);
- }
- }
-
- /**
* Wrapper for decrementExact
*
* Catches ArithmeticException and rethrows as UnwarrantedOptimismException
@@ -1734,26 +1534,7 @@
try {
return Math.decrementExact(x);
} catch (final ArithmeticException e) {
- throw new UnwarrantedOptimismException((long)x - 1, programPoint);
- }
- }
-
- /**
- * Wrapper for decrementExact
- *
- * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
- * containing the result and the program point of the failure
- *
- * @param x number to negate
- * @param programPoint program point id
- * @return the result
- * @throws UnwarrantedOptimismException if overflow occurs
- */
- public static long decrementExact(final long x, final int programPoint) throws UnwarrantedOptimismException {
- try {
- return Math.decrementExact(x);
- } catch (final ArithmeticException e) {
- throw new UnwarrantedOptimismException((double)x - 1L, programPoint);
+ throw new UnwarrantedOptimismException((double)x - 1, programPoint);
}
}
@@ -1772,26 +1553,7 @@
try {
return Math.incrementExact(x);
} catch (final ArithmeticException e) {
- throw new UnwarrantedOptimismException((long)x + 1, programPoint);
- }
- }
-
- /**
- * Wrapper for incrementExact
- *
- * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
- * containing the result and the program point of the failure
- *
- * @param x the number to increment
- * @param programPoint program point id
- * @return the result
- * @throws UnwarrantedOptimismException if overflow occurs
- */
- public static long incrementExact(final long x, final int programPoint) throws UnwarrantedOptimismException {
- try {
- return Math.incrementExact(x);
- } catch (final ArithmeticException e) {
- throw new UnwarrantedOptimismException((double)x + 1L, programPoint);
+ throw new UnwarrantedOptimismException((double)x + 1, programPoint);
}
}
@@ -1813,28 +1575,6 @@
}
return Math.negateExact(x);
} catch (final ArithmeticException e) {
- throw new UnwarrantedOptimismException(-(long)x, programPoint);
- }
- }
-
- /**
- * Wrapper for negateExact
- *
- * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
- * containing the result and the program point of the failure
- *
- * @param x the number to negate
- * @param programPoint program point id
- * @return the result
- * @throws UnwarrantedOptimismException if overflow occurs
- */
- public static long negateExact(final long x, final int programPoint) throws UnwarrantedOptimismException {
- try {
- if (x == 0L) {
- throw new UnwarrantedOptimismException(-0.0, programPoint);
- }
- return Math.negateExact(x);
- } catch (final ArithmeticException e) {
throw new UnwarrantedOptimismException(-(double)x, programPoint);
}
}
@@ -1866,8 +1606,6 @@
return TYPE_UNDEFINED_INDEX;
} else if (type == int.class) {
return TYPE_INT_INDEX;
- } else if (type == long.class) {
- return TYPE_LONG_INDEX;
} else if (type == double.class) {
return TYPE_DOUBLE_INDEX;
} else if (!type.isPrimitive()) {
@@ -1972,8 +1710,6 @@
public static Class<?> getBoxedClass(final Class<?> clazz) {
if (clazz == int.class) {
return Integer.class;
- } else if (clazz == long.class) {
- return Long.class;
} else if (clazz == double.class) {
return Double.class;
}
@@ -1991,8 +1727,6 @@
if (o != null) {
if (o.getClass() == Integer.class) {
return MH.constant(int.class, ((Integer)o));
- } else if (o.getClass() == Long.class) {
- return MH.constant(long.class, ((Long)o));
} else if (o.getClass() == Double.class) {
return MH.constant(double.class, ((Double)o));
}
@@ -2010,8 +1744,6 @@
return Object.class;
} else if (o.getClass() == Integer.class) {
return int.class;
- } else if (o.getClass() == Long.class) {
- return long.class;
} else if (o.getClass() == Double.class) {
return double.class;
} else {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/OptimisticReturnFilters.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/OptimisticReturnFilters.java Wed Jul 05 21:09:54 2017 +0200
@@ -43,52 +43,42 @@
*/
public final class OptimisticReturnFilters {
private static final MethodHandle[] ENSURE_INT;
- private static final MethodHandle[] ENSURE_LONG;
private static final MethodHandle[] ENSURE_NUMBER;
+ // These extend the type index constants in JSType
+ private static final int VOID_TYPE_INDEX;
private static final int BOOLEAN_TYPE_INDEX;
private static final int CHAR_TYPE_INDEX;
+ private static final int LONG_TYPE_INDEX;
private static final int FLOAT_TYPE_INDEX;
- private static final int VOID_TYPE_INDEX;
static {
final MethodHandle INT_DOUBLE = findOwnMH("ensureInt", int.class, double.class, int.class);
ENSURE_INT = new MethodHandle[] {
null,
- findOwnMH("ensureInt", int.class, long.class, int.class),
INT_DOUBLE,
findOwnMH("ensureInt", int.class, Object.class, int.class),
findOwnMH("ensureInt", int.class, int.class),
findOwnMH("ensureInt", int.class, boolean.class, int.class),
findOwnMH("ensureInt", int.class, char.class, int.class),
+ findOwnMH("ensureInt", int.class, long.class, int.class),
INT_DOUBLE.asType(INT_DOUBLE.type().changeParameterType(0, float.class)),
};
- VOID_TYPE_INDEX = ENSURE_INT.length - 4;
- BOOLEAN_TYPE_INDEX = ENSURE_INT.length - 3;
- CHAR_TYPE_INDEX = ENSURE_INT.length - 2;
+ VOID_TYPE_INDEX = ENSURE_INT.length - 5;
+ BOOLEAN_TYPE_INDEX = ENSURE_INT.length - 4;
+ CHAR_TYPE_INDEX = ENSURE_INT.length - 3;
+ LONG_TYPE_INDEX = ENSURE_INT.length - 2;
FLOAT_TYPE_INDEX = ENSURE_INT.length - 1;
- final MethodHandle LONG_DOUBLE = findOwnMH("ensureLong", long.class, double.class, int.class);
- ENSURE_LONG = new MethodHandle[] {
- null,
- null,
- LONG_DOUBLE,
- findOwnMH("ensureLong", long.class, Object.class, int.class),
- ENSURE_INT[VOID_TYPE_INDEX].asType(ENSURE_INT[VOID_TYPE_INDEX].type().changeReturnType(long.class)),
- ENSURE_INT[BOOLEAN_TYPE_INDEX].asType(ENSURE_INT[BOOLEAN_TYPE_INDEX].type().changeReturnType(long.class)),
- ENSURE_INT[CHAR_TYPE_INDEX].asType(ENSURE_INT[CHAR_TYPE_INDEX].type().changeReturnType(long.class)),
- LONG_DOUBLE.asType(LONG_DOUBLE.type().changeParameterType(0, float.class)),
- };
-
ENSURE_NUMBER = new MethodHandle[] {
null,
null,
- null,
findOwnMH("ensureNumber", double.class, Object.class, int.class),
ENSURE_INT[VOID_TYPE_INDEX].asType(ENSURE_INT[VOID_TYPE_INDEX].type().changeReturnType(double.class)),
ENSURE_INT[BOOLEAN_TYPE_INDEX].asType(ENSURE_INT[BOOLEAN_TYPE_INDEX].type().changeReturnType(double.class)),
ENSURE_INT[CHAR_TYPE_INDEX].asType(ENSURE_INT[CHAR_TYPE_INDEX].type().changeReturnType(double.class)),
+ findOwnMH("ensureNumber", double.class, long.class, int.class),
null
};
}
@@ -136,8 +126,6 @@
final int provableTypeIndex = getProvableTypeIndex(provable);
if (actual == int.class) {
guard = ENSURE_INT[provableTypeIndex];
- } else if (actual == long.class) {
- guard = ENSURE_LONG[provableTypeIndex];
} else if (actual == double.class) {
guard = ENSURE_NUMBER[provableTypeIndex];
} else {
@@ -167,6 +155,8 @@
return 0; // never needs a guard, as it's assignable to int
} else if(provable == char.class) {
return CHAR_TYPE_INDEX;
+ } else if(provable == long.class) {
+ return LONG_TYPE_INDEX;
} else if(provable == float.class) {
return FLOAT_TYPE_INDEX;
}
@@ -179,7 +169,7 @@
if (JSType.isRepresentableAsInt(arg)) {
return (int)arg;
}
- throw new UnwarrantedOptimismException(arg, programPoint);
+ throw UnwarrantedOptimismException.createNarrowest(arg, programPoint);
}
@SuppressWarnings("unused")
@@ -187,7 +177,7 @@
if (JSType.isStrictlyRepresentableAsInt(arg)) {
return (int)arg;
}
- throw new UnwarrantedOptimismException(arg, programPoint);
+ throw new UnwarrantedOptimismException(arg, programPoint, Type.NUMBER);
}
/**
@@ -210,7 +200,7 @@
return (int)d;
}
}
- throw new UnwarrantedOptimismException(arg, programPoint);
+ throw UnwarrantedOptimismException.createNarrowest(arg, programPoint);
}
private static boolean isPrimitiveNumberWrapper(final Object obj) {
@@ -238,51 +228,30 @@
throw new UnwarrantedOptimismException(ScriptRuntime.UNDEFINED, programPoint, Type.OBJECT);
}
- private static long ensureLong(final double arg, final int programPoint) {
- if (JSType.isStrictlyRepresentableAsLong(arg)) {
- return (long)arg;
+
+ @SuppressWarnings("unused")
+ private static double ensureNumber(final long arg, final int programPoint) {
+ if (JSType.isRepresentableAsDouble(arg)) {
+ return (double) arg;
}
- throw new UnwarrantedOptimismException(arg, programPoint);
+ throw new UnwarrantedOptimismException(arg, programPoint, Type.OBJECT);
}
/**
- * Returns the argument value as a long. If the argument is not a wrapper for a primitive numeric type
- * with a value that can be exactly represented as a long, throw an {@link UnwarrantedOptimismException}.
- * This method is only public so that generated script code can use it. See {code CodeGenerator.ENSURE_LONG}.
- * @param arg the original argument.
- * @param programPoint the program point used in the exception
- * @return the value of the argument as a long.
- * @throws UnwarrantedOptimismException if the argument is not a wrapper for a primitive numeric type with
- * a value that can be exactly represented as a long
- */
- public static long ensureLong(final Object arg, final int programPoint) {
- if (arg != null) {
- final Class<?> c = arg.getClass();
- if (c == Long.class) {
- // Must check for Long separately, as Long.doubleValue() isn't precise.
- return ((Long)arg);
- } else if (c == Integer.class || c == Double.class || c == Float.class || c == Short.class ||
- c == Byte.class) {
- return ensureLong(((Number)arg).doubleValue(), programPoint);
- }
- }
- throw new UnwarrantedOptimismException(arg, programPoint);
- }
-
- /**
- * Returns the argument value as a double. If the argument is not a a wrapper for a primitive numeric type
- * throw an {@link UnwarrantedOptimismException}.This method is only public so that generated script code
- * can use it. See {code CodeGenerator.ENSURE_NUMBER}.
+ * Returns the argument value as a double. If the argument is not a wrapper for a primitive numeric type
+ * that can be represented as double throw an {@link UnwarrantedOptimismException}.
+ * This method is only public so that generated script code can use it. See {code CodeGenerator.ENSURE_NUMBER}.
* @param arg the original argument.
* @param programPoint the program point used in the exception
* @return the value of the argument as a double.
* @throws UnwarrantedOptimismException if the argument is not a wrapper for a primitive numeric type.
*/
public static double ensureNumber(final Object arg, final int programPoint) {
- if (isPrimitiveNumberWrapper(arg)) {
- return ((Number)arg).doubleValue();
+ if (isPrimitiveNumberWrapper(arg)
+ && (arg.getClass() != Long.class || JSType.isRepresentableAsDouble((Long) arg))) {
+ return ((Number) arg).doubleValue();
}
- throw new UnwarrantedOptimismException(arg, programPoint);
+ throw new UnwarrantedOptimismException(arg, programPoint, Type.OBJECT);
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Wed Jul 05 21:09:54 2017 +0200
@@ -450,16 +450,6 @@
* @param owner the owner of the property
* @return the property value
*/
- public abstract long getLongValue(final ScriptObject self, final ScriptObject owner);
-
- /**
- * get the Object value of this property from {@code owner}. This allows to bypass creation of the
- * getter MethodHandle for spill and user accessor properties.
- *
- * @param self the this object
- * @param owner the owner of the property
- * @return the property value
- */
public abstract double getDoubleValue(final ScriptObject self, final ScriptObject owner);
/**
@@ -492,17 +482,6 @@
* @param value the new property value
* @param strict is this a strict setter?
*/
- public abstract void setValue(final ScriptObject self, final ScriptObject owner, final long value, final boolean strict);
-
- /**
- * Set the value of this property in {@code owner}. This allows to bypass creation of the
- * setter MethodHandle for spill and user accessor properties.
- *
- * @param self the this object
- * @param owner the owner object
- * @param value the new property value
- * @param strict is this a strict setter?
- */
public abstract void setValue(final ScriptObject self, final ScriptObject owner, final double value, final boolean strict);
/**
@@ -593,8 +572,6 @@
return "undef";
} else if (type == int.class) {
return "i";
- } else if (type == long.class) {
- return "j";
} else if (type == double.class) {
return "d";
} else {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyAccess.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyAccess.java Wed Jul 05 21:09:54 2017 +0200
@@ -57,49 +57,9 @@
* @param programPoint or INVALID_PROGRAM_POINT if pessimistic
* @return the value
*/
- public int getInt(long key, int programPoint);
-
- /**
- * Get the value for a given key and return it as an int
- * @param key the key
- * @param programPoint or INVALID_PROGRAM_POINT if pessimistic
- * @return the value
- */
public int getInt(int key, int programPoint);
/**
- * Get the value for a given key and return it as a long
- * @param key the key
- * @param programPoint or INVALID_PROGRAM_POINT if pessimistic
- * @return the value
- */
- public long getLong(Object key, int programPoint);
-
- /**
- * Get the value for a given key and return it as a long
- * @param key the key
- * @param programPoint or INVALID_PROGRAM_POINT if pessimistic
- * @return the value
- */
- public long getLong(double key, int programPoint);
-
- /**
- * Get the value for a given key and return it as a long
- * @param key the key
- * @param programPoint or INVALID_PROGRAM_POINT if pessimistic
- * @return the value
- */
- public long getLong(long key, int programPoint);
-
- /**
- * Get the value for a given key and return it as a long
- * @param key the key
- * @param programPoint or INVALID_PROGRAM_POINT if pessimistic
- * @return the value
- */
- public long getLong(int key, int programPoint);
-
- /**
* Get the value for a given key and return it as a double
* @param key the key
* @param programPoint or INVALID_PROGRAM_POINT if pessimistic
@@ -121,14 +81,6 @@
* @param programPoint or INVALID_PROGRAM_POINT if pessimistic
* @return the value
*/
- public double getDouble(long key, int programPoint);
-
- /**
- * Get the value for a given key and return it as a double
- * @param key the key
- * @param programPoint or INVALID_PROGRAM_POINT if pessimistic
- * @return the value
- */
public double getDouble(int key, int programPoint);
/**
@@ -150,13 +102,6 @@
* @param key the key
* @return the value
*/
- public Object get(long key);
-
- /**
- * Get the value for a given key and return it as an Object
- * @param key the key
- * @return the value
- */
public Object get(int key);
/**
@@ -173,14 +118,6 @@
* @param value the value
* @param flags call site flags
*/
- public void set(Object key, long value, int flags);
-
- /**
- * Set the value of a given key
- * @param key the key
- * @param value the value
- * @param flags call site flags
- */
public void set(Object key, double value, int flags);
/**
@@ -205,14 +142,6 @@
* @param value the value
* @param flags call site flags
*/
- public void set(double key, long value, int flags);
-
- /**
- * Set the value of a given key
- * @param key the key
- * @param value the value
- * @param flags call site flags
- */
public void set(double key, double value, int flags);
/**
@@ -229,38 +158,6 @@
* @param value the value
* @param flags call site flags
*/
- public void set(long key, int value, int flags);
-
- /**
- * Set the value of a given key
- * @param key the key
- * @param value the value
- * @param flags call site flags
- */
- public void set(long key, long value, int flags);
-
- /**
- * Set the value of a given key
- * @param key the key
- * @param value the value
- * @param flags call site flags
- */
- public void set(long key, double value, int flags);
-
- /**
- * Set the value of a given key
- * @param key the key
- * @param value the value
- * @param flags call site flags
- */
- public void set(long key, Object value, int flags);
-
- /**
- * Set the value of a given key
- * @param key the key
- * @param value the value
- * @param flags call site flags
- */
public void set(int key, int value, int flags);
/**
@@ -269,14 +166,6 @@
* @param value the value
* @param flags call site flags
*/
- public void set(int key, long value, int flags);
-
- /**
- * Set the value of a given key
- * @param key the key
- * @param value the value
- * @param flags call site flags
- */
public void set(int key, double value, int flags);
/**
@@ -306,13 +195,6 @@
* @param key the key
* @return true if key exists
*/
- public boolean has(long key);
-
- /**
- * Check if the given key exists anywhere in the proto chain
- * @param key the key
- * @return true if key exists
- */
public boolean has(double key);
/**
@@ -334,13 +216,6 @@
* @param key the key
* @return true if key exists
*/
- public boolean hasOwnProperty(long key);
-
- /**
- * Check if the given key exists directly in the implementor
- * @param key the key
- * @return true if key exists
- */
public boolean hasOwnProperty(double key);
/**
@@ -357,14 +232,6 @@
* @param strict are we in strict mode
* @return true if deletion succeeded, false otherwise
*/
- public boolean delete(long key, boolean strict);
-
- /**
- * Delete a property with the given key from the implementor
- * @param key the key
- * @param strict are we in strict mode
- * @return true if deletion succeeded, false otherwise
- */
public boolean delete(double key, boolean strict);
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed Jul 05 21:09:54 2017 +0200
@@ -886,7 +886,7 @@
}
@Override
- synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
+ synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden, final boolean linkLogicOkay) {
assert isValidCallSite(callSiteType) : callSiteType;
CompiledFunction existingBest = pickFunction(callSiteType, false);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Wed Jul 05 21:09:54 2017 +0200
@@ -646,6 +646,24 @@
}
/**
+ * Get the documentation for this function
+ *
+ * @return the documentation
+ */
+ public final String getDocumentation() {
+ return data.getDocumentation();
+ }
+
+ /**
+ * Set the documentation for this function
+ *
+ * @param doc documentation String for this function
+ */
+ public final void setDocumentation(final String doc) {
+ data.setDocumentation(doc);
+ }
+
+ /**
* Get the name for this function
*
* @return the name
@@ -954,6 +972,13 @@
}
}
+ // Is this an unstable callsite which was earlier apply-to-call optimized?
+ // If so, earlier apply2call would have exploded arguments. We have to convert
+ // that as an array again!
+ if (isUnstable && NashornCallSiteDescriptor.isApplyToCall(desc)) {
+ boundHandle = MH.asCollector(boundHandle, Object[].class, type.parameterCount() - 2);
+ }
+
boundHandle = pairArguments(boundHandle, type);
if (bestInvoker.getSwitchPoints() != null) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed Jul 05 21:09:54 2017 +0200
@@ -70,6 +70,9 @@
// value, the function might still be capable of receiving variable number of arguments, see isVariableArity.
private int arity;
+ // this may be null, if not available
+ private String documentation;
+
/**
* A pair of method handles used for generic invoker and constructor. Field is volatile as it can be initialized by
* multiple threads concurrently, but we still tolerate a race condition in it as all values stored into it are
@@ -118,6 +121,10 @@
return arity;
}
+ final String getDocumentation() {
+ return documentation != null? documentation : toSource();
+ }
+
final boolean isVariableArity() {
return (flags & IS_VARIABLE_ARITY) != 0;
}
@@ -137,6 +144,15 @@
this.arity = arity;
}
+ /**
+ * Used from nasgen generated code.
+ *
+ * @param doc documentation for this function
+ */
+ void setDocumentation(final String doc) {
+ this.documentation = doc;
+ }
+
CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
final MethodHandle boundInvoker = bindInvokeHandle(originalInv.createComposableInvoker(), fn, self, args);
@@ -357,9 +373,23 @@
* @param runtimeScope the runtime scope. It can be used to evaluate types of scoped variables to guide the
* optimistic compilation, should the call to this method trigger code compilation. Can be null if current runtime
* scope is not known, but that might cause compilation of code that will need more deoptimization passes.
+ * @param linkLogicOkay is a CompiledFunction with a LinkLogic acceptable?
* @return the best function for the specified call site type.
*/
- abstract CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden);
+ abstract CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden, final boolean linkLogicOkay);
+
+ /**
+ * Returns the best function for the specified call site type.
+ * @param callSiteType The call site type. Call site types are expected to have the form
+ * {@code (callee, this[, args...])}.
+ * @param runtimeScope the runtime scope. It can be used to evaluate types of scoped variables to guide the
+ * optimistic compilation, should the call to this method trigger code compilation. Can be null if current runtime
+ * scope is not known, but that might cause compilation of code that will need more deoptimization passes.
+ * @return the best function for the specified call site type.
+ */
+ final CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
+ return getBest(callSiteType, runtimeScope, forbidden, true);
+ }
boolean isValidCallSite(final MethodType callSiteType) {
return callSiteType.parameterCount() >= 2 && // Must have at least (callee, this)
@@ -367,7 +397,7 @@
}
CompiledFunction getGeneric(final ScriptObject runtimeScope) {
- return getBest(getGenericType(), runtimeScope, CompiledFunction.NO_FUNCTIONS);
+ return getBest(getGenericType(), runtimeScope, CompiledFunction.NO_FUNCTIONS, false);
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Jul 05 21:09:54 2017 +0200
@@ -33,7 +33,6 @@
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_DOUBLE;
import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_INT;
-import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_LONG;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.GET;
@@ -188,7 +187,6 @@
static final MethodHandle[] SET_SLOW = new MethodHandle[] {
findOwnMH_V("set", void.class, Object.class, int.class, int.class),
- findOwnMH_V("set", void.class, Object.class, long.class, int.class),
findOwnMH_V("set", void.class, Object.class, double.class, int.class),
findOwnMH_V("set", void.class, Object.class, Object.class, int.class)
};
@@ -1087,21 +1085,6 @@
return UNDEFINED_INT;
}
- private static long getLongValue(final FindProperty find, final int programPoint) {
- final MethodHandle getter = find.getGetter(long.class, programPoint, null);
- if (getter != null) {
- try {
- return (long)getter.invokeExact((Object)find.getGetterReceiver());
- } catch (final Error|RuntimeException e) {
- throw e;
- } catch (final Throwable e) {
- throw new RuntimeException(e);
- }
- }
-
- return UNDEFINED_LONG;
- }
-
private static double getDoubleValue(final FindProperty find, final int programPoint) {
final MethodHandle getter = find.getGetter(double.class, programPoint, null);
if (getter != null) {
@@ -2804,18 +2787,6 @@
}
@Override
- public int getInt(final long key, final int programPoint) {
- final int index = getArrayIndex(key);
- final ArrayData array = getArray();
-
- if (array.has(index)) {
- return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
- }
-
- return getInt(index, JSType.toString(key), programPoint);
- }
-
- @Override
public int getInt(final int key, final int programPoint) {
final int index = getArrayIndex(key);
final ArrayData array = getArray();
@@ -2827,88 +2798,6 @@
return getInt(index, JSType.toString(key), programPoint);
}
- private long getLong(final int index, final Object key, final int programPoint) {
- if (isValidArrayIndex(index)) {
- for (ScriptObject object = this; ; ) {
- if (object.getMap().containsArrayKeys()) {
- final FindProperty find = object.findProperty(key, false, this);
- if (find != null) {
- return getLongValue(find, programPoint);
- }
- }
-
- if ((object = object.getProto()) == null) {
- break;
- }
-
- final ArrayData array = object.getArray();
-
- if (array.has(index)) {
- return isValid(programPoint) ?
- array.getLongOptimistic(index, programPoint) :
- array.getLong(index);
- }
- }
- } else {
- final FindProperty find = findProperty(key, true);
-
- if (find != null) {
- return getLongValue(find, programPoint);
- }
- }
-
- return JSType.toLong(invokeNoSuchProperty(key, false, programPoint));
- }
-
- @Override
- public long getLong(final Object key, final int programPoint) {
- final Object primitiveKey = JSType.toPrimitive(key, String.class);
- final int index = getArrayIndex(primitiveKey);
- final ArrayData array = getArray();
-
- if (array.has(index)) {
- return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
- }
-
- return getLong(index, JSType.toPropertyKey(primitiveKey), programPoint);
- }
-
- @Override
- public long getLong(final double key, final int programPoint) {
- final int index = getArrayIndex(key);
- final ArrayData array = getArray();
-
- if (array.has(index)) {
- return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
- }
-
- return getLong(index, JSType.toString(key), programPoint);
- }
-
- @Override
- public long getLong(final long key, final int programPoint) {
- final int index = getArrayIndex(key);
- final ArrayData array = getArray();
-
- if (array.has(index)) {
- return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
- }
-
- return getLong(index, JSType.toString(key), programPoint);
- }
-
- @Override
- public long getLong(final int key, final int programPoint) {
- final int index = getArrayIndex(key);
- final ArrayData array = getArray();
-
- if (array.has(index)) {
- return isValid(programPoint) ? array.getLongOptimistic(key, programPoint) : array.getLong(key);
- }
-
- return getLong(index, JSType.toString(key), programPoint);
- }
-
private double getDouble(final int index, final Object key, final int programPoint) {
if (isValidArrayIndex(index)) {
for (ScriptObject object = this; ; ) {
@@ -2968,18 +2857,6 @@
}
@Override
- public double getDouble(final long key, final int programPoint) {
- final int index = getArrayIndex(key);
- final ArrayData array = getArray();
-
- if (array.has(index)) {
- return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
- }
-
- return getDouble(index, JSType.toString(key), programPoint);
- }
-
- @Override
public double getDouble(final int key, final int programPoint) {
final int index = getArrayIndex(key);
final ArrayData array = getArray();
@@ -3049,18 +2926,6 @@
}
@Override
- public Object get(final long key) {
- final int index = getArrayIndex(key);
- final ArrayData array = getArray();
-
- if (array.has(index)) {
- return array.getObject(index);
- }
-
- return get(index, JSType.toString(key));
- }
-
- @Override
public Object get(final int key) {
final int index = getArrayIndex(key);
final ArrayData array = getArray();
@@ -3143,15 +3008,6 @@
}
}
- private void doesNotHave(final int index, final long value, final int callSiteFlags) {
- final long oldLength = getArray().length();
- final long longIndex = ArrayIndex.toLongIndex(index);
- if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
- final boolean strict = isStrictFlag(callSiteFlags);
- setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
- }
- }
-
private void doesNotHave(final int index, final double value, final int callSiteFlags) {
final long oldLength = getArray().length();
final long longIndex = ArrayIndex.toLongIndex(index);
@@ -3258,26 +3114,6 @@
}
@Override
- public void set(final Object key, final long value, final int callSiteFlags) {
- final Object primitiveKey = JSType.toPrimitive(key, String.class);
- final int index = getArrayIndex(primitiveKey);
-
- if (isValidArrayIndex(index)) {
- final ArrayData data = getArray();
- if (data.has(index)) {
- setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
- } else {
- doesNotHave(index, value, callSiteFlags);
- }
-
- return;
- }
-
- final Object propName = JSType.toPropertyKey(primitiveKey);
- setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
- }
-
- @Override
public void set(final Object key, final double value, final int callSiteFlags) {
final Object primitiveKey = JSType.toPrimitive(key, String.class);
final int index = getArrayIndex(primitiveKey);
@@ -3337,25 +3173,6 @@
}
@Override
- public void set(final double key, final long value, final int callSiteFlags) {
- final int index = getArrayIndex(key);
-
- if (isValidArrayIndex(index)) {
- final ArrayData data = getArray();
- if (data.has(index)) {
- setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
- } else {
- doesNotHave(index, value, callSiteFlags);
- }
-
- return;
- }
-
- final String propName = JSType.toString(key);
- setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
- }
-
- @Override
public void set(final double key, final double value, final int callSiteFlags) {
final int index = getArrayIndex(key);
@@ -3394,82 +3211,6 @@
}
@Override
- public void set(final long key, final int value, final int callSiteFlags) {
- final int index = getArrayIndex(key);
-
- if (isValidArrayIndex(index)) {
- final ArrayData data = getArray();
- if (data.has(index)) {
- setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
- } else {
- doesNotHave(index, value, callSiteFlags);
- }
-
- return;
- }
-
- final String propName = JSType.toString(key);
- setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
- }
-
- @Override
- public void set(final long key, final long value, final int callSiteFlags) {
- final int index = getArrayIndex(key);
-
- if (isValidArrayIndex(index)) {
- final ArrayData data = getArray();
- if (data.has(index)) {
- setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
- } else {
- doesNotHave(index, value, callSiteFlags);
- }
-
- return;
- }
-
- final String propName = JSType.toString(key);
- setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
- }
-
- @Override
- public void set(final long key, final double value, final int callSiteFlags) {
- final int index = getArrayIndex(key);
-
- if (isValidArrayIndex(index)) {
- final ArrayData data = getArray();
- if (data.has(index)) {
- setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
- } else {
- doesNotHave(index, value, callSiteFlags);
- }
-
- return;
- }
-
- final String propName = JSType.toString(key);
- setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
- }
-
- @Override
- public void set(final long key, final Object value, final int callSiteFlags) {
- final int index = getArrayIndex(key);
-
- if (isValidArrayIndex(index)) {
- final ArrayData data = getArray();
- if (data.has(index)) {
- setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
- } else {
- doesNotHave(index, value, callSiteFlags);
- }
-
- return;
- }
-
- final String propName = JSType.toString(key);
- setObject(findProperty(propName, true), callSiteFlags, propName, value);
- }
-
- @Override
public void set(final int key, final int value, final int callSiteFlags) {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
@@ -3487,25 +3228,6 @@
}
@Override
- public void set(final int key, final long value, final int callSiteFlags) {
- final int index = getArrayIndex(key);
-
- if (isValidArrayIndex(index)) {
- final ArrayData data = getArray();
- if (data.has(index)) {
- setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
- } else {
- doesNotHave(index, value, callSiteFlags);
- }
-
- return;
- }
-
- final String propName = JSType.toString(key);
- setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
- }
-
- @Override
public void set(final int key, final double value, final int callSiteFlags) {
final int index = getArrayIndex(key);
@@ -3557,12 +3279,6 @@
}
@Override
- public boolean has(final long key) {
- final int index = getArrayIndex(key);
- return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
- }
-
- @Override
public boolean has(final int key) {
final int index = getArrayIndex(key);
return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
@@ -3595,12 +3311,6 @@
}
@Override
- public boolean hasOwnProperty(final long key) {
- final int index = getArrayIndex(key);
- return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
- }
-
- @Override
public boolean hasOwnProperty(final double key) {
final int index = getArrayIndex(key);
return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
@@ -3626,22 +3336,6 @@
}
@Override
- public boolean delete(final long key, final boolean strict) {
- final int index = getArrayIndex(key);
- final ArrayData array = getArray();
-
- if (array.has(index)) {
- if (array.canDelete(index, strict)) {
- setArray(array.delete(index));
- return true;
- }
- return false;
- }
-
- return deleteObject(JSType.toObject(key), strict);
- }
-
- @Override
public boolean delete(final double key, final boolean strict) {
final int index = getArrayIndex(key);
final ArrayData array = getArray();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java Wed Jul 05 21:09:54 2017 +0200
@@ -278,9 +278,8 @@
* @param str a {@link String} to tokenize.
* @return a {@link List} of {@link String}s representing the tokens that
* constitute the string.
- * @throws IOException in case {@link StreamTokenizer#nextToken()} raises it.
*/
- public static List<String> tokenizeString(final String str) throws IOException {
+ public static List<String> tokenizeString(final String str) {
final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(str));
tokenizer.resetSyntax();
tokenizer.wordChars(0, 255);
@@ -290,7 +289,7 @@
tokenizer.quoteChar('\'');
final List<String> tokenList = new ArrayList<>();
final StringBuilder toAppend = new StringBuilder();
- while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
+ while (nextToken(tokenizer) != StreamTokenizer.TT_EOF) {
final String s = tokenizer.sval;
// The tokenizer understands about honoring quoted strings and recognizes
// them as one token that possibly contains multiple space-separated words.
@@ -309,4 +308,12 @@
}
return tokenList;
}
+
+ private static int nextToken(final StreamTokenizer tokenizer) {
+ try {
+ return tokenizer.nextToken();
+ } catch (final IOException ioe) {
+ return StreamTokenizer.TT_EOF;
+ }
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UnwarrantedOptimismException.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UnwarrantedOptimismException.java Wed Jul 05 21:09:54 2017 +0200
@@ -49,7 +49,10 @@
private final Type returnType;
/**
- * Constructor
+ * Constructor without explicit return type. The return type is determined statically from the class of
+ * the return value, and only canonical internal number representations are recognized. Use
+ * {@link #createNarrowest} if you want to handle float and long values as numbers instead of objects.
+ *
* @param returnValue actual return value from the too narrow operation
* @param programPoint program point where unwarranted optimism was detected
*/
@@ -58,7 +61,7 @@
}
/**
- * Check if a program point is valid
+ * Check if a program point is valid.
* @param programPoint the program point
* @return true if valid
*/
@@ -70,8 +73,6 @@
private static Type getReturnType(final Object v) {
if (v instanceof Double) {
return Type.NUMBER;
- } else if (v instanceof Long) {
- return Type.LONG;
}
assert !(v instanceof Integer) : v + " is an int"; // Can't have an unwarranted optimism exception with int
return Type.OBJECT;
@@ -97,6 +98,22 @@
}
/**
+ * Create an {@code UnwarrantedOptimismException} with the given return value and program point, narrowing
+ * the type to {@code number} if the value is a float or a long that can be represented as double.
+ *
+ * @param returnValue the return value
+ * @param programPoint the program point
+ * @return the exception
+ */
+ public static UnwarrantedOptimismException createNarrowest(final Object returnValue, final int programPoint) {
+ if (returnValue instanceof Float
+ || (returnValue instanceof Long && JSType.isRepresentableAsDouble((Long) returnValue))) {
+ return new UnwarrantedOptimismException(((Number) returnValue).doubleValue(), programPoint, Type.NUMBER);
+ }
+ return new UnwarrantedOptimismException(returnValue, programPoint);
+ }
+
+ /**
* Get the return value. This is a destructive readout, after the method is invoked the return value is null'd out.
* @return return value
*/
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java Wed Jul 05 21:09:54 2017 +0200
@@ -71,13 +71,11 @@
/** Getter method handle */
private final static MethodHandle INVOKE_OBJECT_GETTER = findOwnMH_S("invokeObjectGetter", Object.class, Accessors.class, MethodHandle.class, Object.class);
private final static MethodHandle INVOKE_INT_GETTER = findOwnMH_S("invokeIntGetter", int.class, Accessors.class, MethodHandle.class, int.class, Object.class);
- private final static MethodHandle INVOKE_LONG_GETTER = findOwnMH_S("invokeLongGetter", long.class, Accessors.class, MethodHandle.class, int.class, Object.class);
private final static MethodHandle INVOKE_NUMBER_GETTER = findOwnMH_S("invokeNumberGetter", double.class, Accessors.class, MethodHandle.class, int.class, Object.class);
/** Setter method handle */
private final static MethodHandle INVOKE_OBJECT_SETTER = findOwnMH_S("invokeObjectSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, Object.class);
private final static MethodHandle INVOKE_INT_SETTER = findOwnMH_S("invokeIntSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, int.class);
- private final static MethodHandle INVOKE_LONG_SETTER = findOwnMH_S("invokeLongSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, long.class);
private final static MethodHandle INVOKE_NUMBER_SETTER = findOwnMH_S("invokeNumberSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, double.class);
private static final Object OBJECT_GETTER_INVOKER_KEY = new Object();
@@ -188,11 +186,6 @@
}
@Override
- public long getLongValue(final ScriptObject self, final ScriptObject owner) {
- return (long)getObjectValue(self, owner);
- }
-
- @Override
public double getDoubleValue(final ScriptObject self, final ScriptObject owner) {
return (double)getObjectValue(self, owner);
}
@@ -214,11 +207,6 @@
}
@Override
- public void setValue(final ScriptObject self, final ScriptObject owner, final long value, final boolean strict) {
- setValue(self, owner, (Object) value, strict);
- }
-
- @Override
public void setValue(final ScriptObject self, final ScriptObject owner, final double value, final boolean strict) {
setValue(self, owner, (Object) value, strict);
}
@@ -244,8 +232,6 @@
public MethodHandle getOptimisticGetter(final Class<?> type, final int programPoint) {
if (type == int.class) {
return INVOKE_INT_GETTER;
- } else if (type == long.class) {
- return INVOKE_LONG_GETTER;
} else if (type == double.class) {
return INVOKE_NUMBER_GETTER;
} else {
@@ -269,8 +255,6 @@
public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
if (type == int.class) {
return INVOKE_INT_SETTER;
- } else if (type == long.class) {
- return INVOKE_LONG_SETTER;
} else if (type == double.class) {
return INVOKE_NUMBER_SETTER;
} else {
@@ -320,16 +304,6 @@
}
@SuppressWarnings("unused")
- private static long invokeLongGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable {
- final Object func = gs.getter;
- if (func instanceof ScriptFunction) {
- return (long) invoker.invokeExact(func, self);
- }
-
- throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
- }
-
- @SuppressWarnings("unused")
private static double invokeNumberGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable {
final Object func = gs.getter;
if (func instanceof ScriptFunction) {
@@ -360,16 +334,6 @@
}
@SuppressWarnings("unused")
- private static void invokeLongSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final long value) throws Throwable {
- final Object func = gs.setter;
- if (func instanceof ScriptFunction) {
- invoker.invokeExact(func, self, value);
- } else if (name != null) {
- throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
- }
- }
-
- @SuppressWarnings("unused")
private static void invokeNumberSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final double value) throws Throwable {
final Object func = gs.setter;
if (func instanceof ScriptFunction) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java Wed Jul 05 21:09:54 2017 +0200
@@ -52,9 +52,6 @@
/** Minimum chunk size for underlying arrays */
protected static final int CHUNK_SIZE = 32;
- /** Mask for getting a chunk */
- protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
-
/** Untouched data - still link callsites as IntArrayData, but expands to
* a proper ArrayData when we try to write to it */
public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData();
@@ -164,11 +161,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- return toRealArrayData(index).set(index, value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
return toRealArrayData(index).set(index, value, strict);
}
@@ -179,11 +171,6 @@
}
@Override
- public long getLong(final int index) {
- throw new ArrayIndexOutOfBoundsException(index); //empty
- }
-
- @Override
public double getDouble(final int index) {
throw new ArrayIndexOutOfBoundsException(index); //empty
}
@@ -288,13 +275,13 @@
* @param length the initial length
* @return ArrayData
*/
- public static ArrayData allocate(final int length) {
- if (length == 0) {
+ public static ArrayData allocate(final long length) {
+ if (length == 0L) {
return new IntArrayData();
} else if (length >= SparseArrayData.MAX_DENSE_LENGTH) {
return new SparseArrayData(EMPTY_ARRAY, length);
} else {
- return new DeletedRangeArrayFilter(new IntArrayData(length), 0, length - 1);
+ return new DeletedRangeArrayFilter(new IntArrayData((int) length), 0, length - 1);
}
}
@@ -309,8 +296,6 @@
if (clazz == int[].class) {
return new IntArrayData((int[])array, ((int[])array).length);
- } else if (clazz == long[].class) {
- return new LongArrayData((long[])array, ((long[])array).length);
} else if (clazz == double[].class) {
return new NumberArrayData((double[])array, ((double[])array).length);
} else {
@@ -334,16 +319,6 @@
* @param array the array to use for initial elements
* @return the ArrayData
*/
- public static ArrayData allocate(final long[] array) {
- return new LongArrayData(array, array.length);
- }
-
- /**
- * Allocate an ArrayData wrapping a given array
- *
- * @param array the array to use for initial elements
- * @return the ArrayData
- */
public static ArrayData allocate(final double[] array) {
return new NumberArrayData(array, array.length);
}
@@ -537,16 +512,6 @@
public abstract ArrayData set(final int index, final int value, final boolean strict);
/**
- * Set a long value at a given index
- *
- * @param index the index
- * @param value the value
- * @param strict are we in strict mode
- * @return new array data (or same)
- */
- public abstract ArrayData set(final int index, final long value, final boolean strict);
-
- /**
* Set an double value at a given index
*
* @param index the index
@@ -609,26 +574,6 @@
}
/**
- * Get a long value from a given index
- *
- * @param index the index
- * @return the value
- */
- public abstract long getLong(final int index);
-
- /**
- * Get optimistic long - default is that it's impossible. Overridden
- * by arrays that actually represents longs or narrower
- *
- * @param index the index
- * @param programPoint program point
- * @return the value
- */
- public long getLongOptimistic(final int index, final int programPoint) {
- throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType());
- }
-
- /**
* Get a double value from a given index
*
* @param index the index
@@ -821,12 +766,8 @@
return Object.class;
}
final Class<?> itemClass = item.getClass();
- if (itemClass == Long.class) {
+ if (itemClass == Double.class || itemClass == Float.class || itemClass == Long.class) {
if (widest == Integer.class) {
- widest = Long.class;
- }
- } else if (itemClass == Double.class || itemClass == Float.class) {
- if (widest == Integer.class || widest == Long.class) {
widest = Double.class;
}
} else if (itemClass != Integer.class && itemClass != Short.class && itemClass != Byte.class) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java Wed Jul 05 21:09:54 2017 +0200
@@ -109,13 +109,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- underlying = underlying.set(index, value, strict);
- setLength(underlying.length());
- return this;
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
underlying = underlying.set(index, value, strict);
setLength(underlying.length());
@@ -150,16 +143,6 @@
}
@Override
- public long getLong(final int index) {
- return underlying.getLong(index);
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- return underlying.getLongOptimistic(index, programPoint);
- }
-
- @Override
public double getDouble(final int index) {
return underlying.getDouble(index);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java Wed Jul 05 21:09:54 2017 +0200
@@ -122,12 +122,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- buf.put(index, (byte)value);
- return this;
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
buf.put(index, (byte)value);
return this;
@@ -139,11 +133,6 @@
}
@Override
- public long getLong(final int index) {
- return 0x0ff & buf.get(index);
- }
-
- @Override
public double getDouble(final int index) {
return 0x0ff & buf.get(index);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java Wed Jul 05 21:09:54 2017 +0200
@@ -120,12 +120,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- deleted.clear(ArrayIndex.toLongIndex(index));
- return super.set(index, value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
deleted.clear(ArrayIndex.toLongIndex(index));
return super.set(index, value, strict);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java Wed Jul 05 21:09:54 2017 +0200
@@ -163,24 +163,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- final long longIndex = ArrayIndex.toLongIndex(index);
- if (longIndex < lo || longIndex > hi) {
- return super.set(index, value, strict);
- } else if (longIndex > lo && longIndex < hi) {
- return getDeletedArrayFilter().set(index, value, strict);
- }
- if (longIndex == lo) {
- lo++;
- } else {
- assert longIndex == hi;
- hi--;
- }
-
- return isEmpty() ? getUnderlying().set(index, value, strict) : super.set(index, value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
final long longIndex = ArrayIndex.toLongIndex(index);
if (longIndex < lo || longIndex > hi) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java Wed Jul 05 21:09:54 2017 +0200
@@ -57,14 +57,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- if (strict) {
- throw typeError("cant.set.property", Integer.toString(index), "frozen array");
- }
- return this;
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
if (strict) {
throw typeError("cant.set.property", Integer.toString(index), "frozen array");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Wed Jul 05 21:09:54 2017 +0200
@@ -156,22 +156,6 @@
return darray;
}
- private long[] toLongArray() {
- assert length() <= array.length : "length exceeds internal array size";
- final int len = (int)length();
- final long[] larray = new long[array.length];
-
- for (int index = 0; index < len; index++) {
- larray[index] = array[index];
- }
-
- return larray;
- }
-
- private LongArrayData convertToLong() {
- return new LongArrayData(toLongArray(), (int)length());
- }
-
private NumberArrayData convertToDouble() {
return new NumberArrayData(toDoubleArray(), (int)length());
}
@@ -184,8 +168,6 @@
public ArrayData convert(final Class<?> type) {
if (type == Integer.class || type == Byte.class || type == Short.class) {
return this;
- } else if (type == Long.class) {
- return convertToLong();
} else if (type == Double.class || type == Float.class) {
return convertToDouble();
} else {
@@ -253,17 +235,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- if (JSType.isRepresentableAsInt(value)) {
- array[index] = JSType.toInt32(value);
- setLength(Math.max(index + 1, length()));
- return this;
- }
-
- return convert(Long.class).set(index, value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
if (JSType.isRepresentableAsInt(value)) {
array[index] = (int)(long)value;
@@ -285,16 +256,6 @@
}
@Override
- public long getLong(final int index) {
- return array[index];
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- return array[index];
- }
-
- @Override
public double getDouble(final int index) {
return array[index];
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IteratorAction.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IteratorAction.java Wed Jul 05 21:09:54 2017 +0200
@@ -130,6 +130,6 @@
*
* @throws Throwable if invocation throws an exception/error
*/
- protected abstract boolean forEach(final Object val, final long i) throws Throwable;
+ protected abstract boolean forEach(final Object val, final double i) throws Throwable;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LengthNotWritableFilter.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LengthNotWritableFilter.java Wed Jul 05 21:09:54 2017 +0200
@@ -91,22 +91,6 @@
}
@Override
- public long getLong(final int index) {
- if (index >= length()) {
- return JSType.toLong(get(index));
- }
- return underlying.getLong(index);
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- if (index >= length()) {
- return JSType.toLongOptimistic(get(index), programPoint);
- }
- return underlying.getLongOptimistic(index, programPoint);
- }
-
- @Override
public double getDouble(final int index) {
if (index >= length()) {
return JSType.toNumber(get(index));
@@ -149,15 +133,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- if (checkAdd(index, value)) {
- return this;
- }
- underlying = underlying.set(index, value, strict);
- return this;
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
if (checkAdd(index, value)) {
return this;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Mon Dec 21 17:47:21 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,406 +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.
- */
-
-package jdk.nashorn.internal.runtime.arrays;
-
-import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.util.Arrays;
-import jdk.nashorn.internal.runtime.JSType;
-import jdk.nashorn.internal.runtime.ScriptRuntime;
-
-/**
- * Implementation of {@link ArrayData} as soon as a long has been
- * written to the array
- */
-final class LongArrayData extends ContinuousArrayData implements IntOrLongElements {
- /**
- * The wrapped array
- */
- private long[] array;
-
- /**
- * Constructor
- * @param array an int array
- * @param length a length, not necessarily array.length
- */
- LongArrayData(final long array[], final int length) {
- super(length);
- assert array.length >= length;
- this.array = array;
- }
-
- @Override
- public final Class<?> getElementType() {
- return long.class;
- }
-
- @Override
- public final Class<?> getBoxedElementType() {
- return Long.class;
- }
-
- @Override
- public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
- return otherData instanceof IntElements ? this : otherData;
- }
-
- @Override
- public final int getElementWeight() {
- return 2;
- }
-
- @Override
- public LongArrayData copy() {
- return new LongArrayData(array.clone(), (int)length());
- }
-
- @Override
- public Object[] asObjectArray() {
- return toObjectArray(true);
- }
-
- private Object[] toObjectArray(final boolean trim) {
- assert length() <= array.length : "length exceeds internal array size";
- final int len = (int)length();
- final Object[] oarray = new Object[trim ? len : array.length];
-
- for (int index = 0; index < len; index++) {
- oarray[index] = array[index];
- }
-
- return oarray;
- }
-
- @Override
- public Object asArrayOfType(final Class<?> componentType) {
- if (componentType == long.class) {
- final int len = (int)length();
- return array.length == len ? array.clone() : Arrays.copyOf(array, len);
- }
- return super.asArrayOfType(componentType);
- }
-
- private double[] toDoubleArray() {
- assert length() <= array.length : "length exceeds internal array size";
- final int len = (int)length();
- final double[] darray = new double[array.length];
-
- for (int index = 0; index < len; index++) {
- darray[index] = array[index];
- }
-
- return darray;
- }
-
- @Override
- public ContinuousArrayData convert(final Class<?> type) {
- if (type == Integer.class || type == Long.class || type == Byte.class || type == Short.class) {
- return this;
- }
- final int len = (int)length();
- if (type == Double.class || type == Float.class) {
- return new NumberArrayData(toDoubleArray(), len);
- }
- return new ObjectArrayData(toObjectArray(false), len);
- }
-
- @Override
- public void shiftLeft(final int by) {
- System.arraycopy(array, by, array, 0, array.length - by);
- }
-
- @Override
- public ArrayData shiftRight(final int by) {
- final ArrayData newData = ensure(by + length() - 1);
- if (newData != this) {
- newData.shiftRight(by);
- return newData;
- }
- System.arraycopy(array, 0, array, by, array.length - by);
-
- return this;
- }
-
- @Override
- public ArrayData ensure(final long safeIndex) {
- if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
- return new SparseArrayData(this, safeIndex + 1);
- }
- final int alen = array.length;
- if (safeIndex >= alen) {
- final int newLength = ArrayData.nextSize((int)safeIndex);
- array = Arrays.copyOf(array, newLength);
- }
- if (safeIndex >= length()) {
- setLength(safeIndex + 1);
- }
- return this;
- }
-
- @Override
- public ArrayData shrink(final long newLength) {
- Arrays.fill(array, (int)newLength, array.length, 0L);
- return this;
- }
-
- @Override
- public ArrayData set(final int index, final Object value, final boolean strict) {
- if (value instanceof Long || value instanceof Integer ||
- value instanceof Byte || value instanceof Short) {
- return set(index, ((Number)value).longValue(), strict);
- } else if (value == ScriptRuntime.UNDEFINED) {
- return new UndefinedArrayFilter(this).set(index, value, strict);
- }
-
- final ArrayData newData = convert(value == null ? Object.class : value.getClass());
- return newData.set(index, value, strict);
- }
-
- @Override
- public ArrayData set(final int index, final int value, final boolean strict) {
- array[index] = value;
- setLength(Math.max(index + 1, length()));
- return this;
- }
-
- @Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- array[index] = value;
- setLength(Math.max(index + 1, length()));
- return this;
- }
-
- @Override
- public ArrayData set(final int index, final double value, final boolean strict) {
- if (JSType.isRepresentableAsLong(value)) {
- array[index] = (long)value;
- setLength(Math.max(index + 1, length()));
- return this;
- }
- return convert(Double.class).set(index, value, strict);
- }
-
- private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "getElem", long.class, int.class).methodHandle();
- private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "setElem", void.class, int.class, long.class).methodHandle();
-
- @SuppressWarnings("unused")
- private long getElem(final int index) {
- if (has(index)) {
- return array[index];
- }
- throw new ClassCastException();
- }
-
- @SuppressWarnings("unused")
- private void setElem(final int index, final long elem) {
- if (hasRoomFor(index)) {
- array[index] = elem;
- return;
- }
- throw new ClassCastException();
- }
-
- @Override
- public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
- if (returnType == int.class) {
- return null;
- }
- return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint);
- }
-
- @Override
- public MethodHandle getElementSetter(final Class<?> elementType) {
- return elementType == int.class || elementType == long.class ? getContinuousElementSetter(MH.asType(SET_ELEM, SET_ELEM.type().changeParameterType(2, elementType)), elementType) : null;
- }
-
- @Override
- public int getInt(final int index) {
- return JSType.toInt32(array[index]);
- }
-
- @Override
- public long getLong(final int index) {
- return array[index];
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- return array[index];
- }
-
- @Override
- public double getDouble(final int index) {
- return array[index];
- }
-
- @Override
- public double getDoubleOptimistic(final int index, final int programPoint) {
- return array[index];
- }
-
- @Override
- public Object getObject(final int index) {
- return array[index];
- }
-
- @Override
- public boolean has(final int index) {
- return 0 <= index && index < length();
- }
-
- @Override
- public ArrayData delete(final int index) {
- return new DeletedRangeArrayFilter(this, index, index);
- }
-
- @Override
- public ArrayData delete(final long fromIndex, final long toIndex) {
- return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
- }
-
- @Override
- public Object pop() {
- final int len = (int)length();
- if (len == 0) {
- return ScriptRuntime.UNDEFINED;
- }
-
- final int newLength = len - 1;
- final long elem = array[newLength];
- array[newLength] = 0;
- setLength(newLength);
-
- return elem;
- }
-
- @Override
- public ArrayData slice(final long from, final long to) {
- final long start = from < 0 ? from + length() : from;
- final long newLength = to - start;
- return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
- }
-
- @Override
- public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
- final long oldLength = length();
- final long newLength = oldLength - removed + added;
- if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
- throw new UnsupportedOperationException();
- }
- final ArrayData returnValue = removed == 0 ?
- EMPTY_ARRAY : new LongArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
-
- if (newLength != oldLength) {
- final long[] newArray;
-
- if (newLength > array.length) {
- newArray = new long[ArrayData.nextSize((int)newLength)];
- System.arraycopy(array, 0, newArray, 0, start);
- } else {
- newArray = array;
- }
-
- System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
- array = newArray;
- setLength(newLength);
- }
-
- return returnValue;
- }
-
- @Override
- public long fastPush(final int arg) {
- return fastPush((long)arg);
- }
-
- @Override
- public long fastPush(final long arg) {
- final int len = (int)length();
- if (len == array.length) {
- array = Arrays.copyOf(array, nextSize(len));
- }
- array[len] = arg;
- return increaseLength();
- }
-
- @Override
- public long fastPopLong() {
- if (length() == 0) {
- throw new ClassCastException(); //undefined result
- }
- final int newLength = (int)decreaseLength();
- final long elem = array[newLength];
- array[newLength] = 0;
- return elem;
- }
-
- @Override
- public double fastPopDouble() {
- return fastPopLong();
- }
-
- @Override
- public Object fastPopObject() {
- return fastPopLong();
- }
-
- @Override
- public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
- final int otherLength = (int)otherData.length();
- final int thisLength = (int)length();
- assert otherLength > 0 && thisLength > 0;
-
- final long[] otherArray = ((LongArrayData)otherData).array;
- final int newLength = otherLength + thisLength;
- final long[] newArray = new long[ArrayData.alignUp(newLength)];
-
- System.arraycopy(array, 0, newArray, 0, thisLength);
- System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
-
- return new LongArrayData(newArray, newLength);
- }
-
- @Override
- public String toString() {
- assert length() <= array.length : length() + " > " + array.length;
-
- final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).
- append(": [");
- final int len = (int)length();
- for (int i = 0; i < len; i++) {
- sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString()
- if (i + 1 < len) {
- sb.append(", ");
- }
- }
- sb.append(']');
-
- return sb.toString();
- }
-}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java Wed Jul 05 21:09:54 2017 +0200
@@ -51,14 +51,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- if (has(index)) {
- return underlying.set(index, value, strict);
- }
- return extensionCheck(strict, index);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
if (has(index)) {
return underlying.set(index, value, strict);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Wed Jul 05 21:09:54 2017 +0200
@@ -179,13 +179,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- array[index] = value;
- setLength(Math.max(index + 1, length()));
- return this;
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length()));
@@ -214,7 +207,7 @@
@Override
public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
- if (returnType == int.class || returnType == long.class) {
+ if (returnType == int.class) {
return null;
}
return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint);
@@ -231,11 +224,6 @@
}
@Override
- public long getLong(final int index) {
- return (long)array[index];
- }
-
- @Override
public double getDouble(final int index) {
return array[index];
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Wed Jul 05 21:09:54 2017 +0200
@@ -150,13 +150,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- array[index] = value;
- setLength(Math.max(index + 1, length()));
- return this;
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length()));
@@ -216,11 +209,6 @@
}
@Override
- public long getLong(final int index) {
- return JSType.toLong(array[index]);
- }
-
- @Override
public double getDouble(final int index) {
return JSType.toNumber(array[index]);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java Wed Jul 05 21:09:54 2017 +0200
@@ -195,21 +195,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- if (index >= 0 && index < maxDenseLength) {
- final long oldLength = underlying.length();
- ensure(index);
- underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
- setLength(Math.max(underlying.length(), length()));
- } else {
- final Long longIndex = indexToKey(index);
- sparseMap.put(longIndex, value);
- setLength(Math.max(longIndex + 1, length()));
- }
- return this;
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
if (index >= 0 && index < maxDenseLength) {
final long oldLength = underlying.length();
@@ -258,22 +243,6 @@
}
@Override
- public long getLong(final int index) {
- if (index >= 0 && index < maxDenseLength) {
- return underlying.getLong(index);
- }
- return JSType.toLong(sparseMap.get(indexToKey(index)));
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- if (index >= 0 && index < maxDenseLength) {
- return underlying.getLongOptimistic(index, programPoint);
- }
- return JSType.toLongOptimistic(sparseMap.get(indexToKey(index)), programPoint);
- }
-
- @Override
public double getDouble(final int index) {
if (index >= 0 && index < maxDenseLength) {
return underlying.getDouble(index);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java Wed Jul 05 21:09:54 2017 +0200
@@ -128,13 +128,6 @@
}
@Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- undefined.clear(index);
-
- return super.set(index, value, strict);
- }
-
- @Override
public ArrayData set(final int index, final double value, final boolean strict) {
undefined.clear(index);
@@ -160,24 +153,6 @@
}
@Override
- public long getLong(final int index) {
- if (undefined.isSet(index)) {
- return 0L;
- }
-
- return super.getLong(index);
- }
-
- @Override
- public long getLongOptimistic(final int index, final int programPoint) {
- if (undefined.isSet(index)) {
- throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
- }
-
- return super.getLongOptimistic(index, programPoint);
- }
-
- @Override
public double getDouble(final int index) {
if (undefined.isSet(index)) {
return Double.NaN;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java Wed Jul 05 21:09:54 2017 +0200
@@ -201,7 +201,7 @@
*
* @return callsite for a math intrinsic node
*/
- public static CallSite mathBootstrap(final MethodHandles.Lookup lookup, final String name, final MethodType type, final int programPoint) {
+ public static CallSite mathBootstrap(final Lookup lookup, final String name, final MethodType type, final int programPoint) {
final MethodHandle mh;
switch (name) {
case "iadd":
@@ -222,24 +222,6 @@
case "ineg":
mh = JSType.NEGATE_EXACT.methodHandle();
break;
- case "ladd":
- mh = JSType.ADD_EXACT_LONG.methodHandle();
- break;
- case "lsub":
- mh = JSType.SUB_EXACT_LONG.methodHandle();
- break;
- case "lmul":
- mh = JSType.MUL_EXACT_LONG.methodHandle();
- break;
- case "ldiv":
- mh = JSType.DIV_EXACT_LONG.methodHandle();
- break;
- case "lrem":
- mh = JSType.REM_EXACT_LONG.methodHandle();
- break;
- case "lneg":
- mh = JSType.NEGATE_EXACT_LONG.methodHandle();
- break;
default:
throw new AssertionError("unsupported math intrinsic");
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Wed Jul 05 21:09:54 2017 +0200
@@ -48,19 +48,8 @@
* A Dynalink linker to handle web browser built-in JS (DOM etc.) objects.
*/
final class BrowserJSObjectLinker implements TypeBasedGuardingDynamicLinker {
- private static ClassLoader extLoader;
- static {
- extLoader = BrowserJSObjectLinker.class.getClassLoader();
- // in case nashorn is loaded as bootstrap!
- if (extLoader == null) {
- extLoader = ClassLoader.getSystemClassLoader().getParent();
- }
- }
-
private static final String JSOBJECT_CLASS = "netscape.javascript.JSObject";
- // not final because this is lazily initialized
- // when we hit a subclass for the first time.
- private static volatile Class<?> jsObjectClass;
+ private static final Class<?> jsObjectClass = findBrowserJSObjectClass();
private final NashornBeansLinker nashornBeansLinker;
BrowserJSObjectLinker(final NashornBeansLinker nashornBeansLinker) {
@@ -73,22 +62,7 @@
}
static boolean canLinkTypeStatic(final Class<?> type) {
- if (jsObjectClass != null && jsObjectClass.isAssignableFrom(type)) {
- return true;
- }
-
- // check if this class is a subclass of JSObject
- Class<?> clazz = type;
- while (clazz != null) {
- if (clazz.getClassLoader() == extLoader &&
- clazz.getName().equals(JSOBJECT_CLASS)) {
- jsObjectClass = clazz;
- return true;
- }
- clazz = clazz.getSuperclass();
- }
-
- return false;
+ return jsObjectClass != null && jsObjectClass.isAssignableFrom(type);
}
private static void checkJSObjectClass() {
@@ -101,13 +75,10 @@
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
checkJSObjectClass();
- GuardedInvocation inv;
- if (jsObjectClass.isInstance(self)) {
- inv = lookup(desc, request, linkerServices);
- inv = inv.replaceMethods(linkerServices.filterInternalObjects(inv.getInvocation()), inv.getGuard());
- } else {
- throw new AssertionError(); // Should never reach here.
- }
+ assert jsObjectClass.isInstance(self);
+
+ GuardedInvocation inv = lookup(desc, request, linkerServices);
+ inv = inv.replaceMethods(linkerServices.filterInternalObjects(inv.getInvocation()), inv.getGuard());
return Bootstrap.asTypeSafeReturn(inv, linkerServices, desc);
}
@@ -122,7 +93,7 @@
final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
if (op == null) {
- return null;
+ return inv;
}
final String name = NashornCallSiteDescriptor.getOperand(desc);
switch (op) {
@@ -236,4 +207,18 @@
return MH.findVirtual(MethodHandles.publicLookup(), jsObjectClass, name, MH.type(rtype, types));
}
}
+
+ private static Class<?> findBrowserJSObjectClass() {
+ ClassLoader extLoader;
+ extLoader = BrowserJSObjectLinker.class.getClassLoader();
+ // in case nashorn is loaded as bootstrap!
+ if (extLoader == null) {
+ extLoader = ClassLoader.getSystemClassLoader().getParent();
+ }
+ try {
+ return Class.forName(JSOBJECT_CLASS, false, extLoader);
+ } catch (final ClassNotFoundException e) {
+ return null;
+ }
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Wed Jul 05 21:09:54 2017 +0200
@@ -141,8 +141,9 @@
}
/**
- * Main part of the implementation of {@link GuardingTypeConverterFactory#convertToType(Class, Class)} that doesn't
- * care about adapting the method signature; that's done by the invoking method. Returns conversion from Object to String/number/boolean (JS primitive types).
+ * Main part of the implementation of {@link GuardingTypeConverterFactory#convertToType} that doesn't
+ * care about adapting the method signature; that's done by the invoking method. Returns conversion
+ * from Object to String/number/boolean (JS primitive types).
* @param sourceType the source type
* @param targetType the target type
* @return a guarded invocation that converts from the source type to the target type.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Wed Jul 05 21:09:54 2017 +0200
@@ -174,28 +174,31 @@
* Function used by {@link NashornTextifier} to represent call site flags in
* human readable form
* @param flags call site flags
- * @return human readable form of this callsite descriptor
+ * @param sb the string builder
*/
- public static String toString(final int flags) {
- final StringBuilder sb = new StringBuilder();
+ public static void appendFlags(final int flags, final StringBuilder sb) {
+ final int pp = flags >> CALLSITE_PROGRAM_POINT_SHIFT;
+ if (pp != 0) {
+ sb.append(" pp=").append(pp);
+ }
if ((flags & CALLSITE_SCOPE) != 0) {
if ((flags & CALLSITE_FAST_SCOPE) != 0) {
- sb.append("fastscope ");
+ sb.append(" fastscope");
} else {
- assert (flags & CALLSITE_FAST_SCOPE) == 0 : "can't be fastscope without scope";
- sb.append("scope ");
+ sb.append(" scope");
}
if ((flags & CALLSITE_DECLARE) != 0) {
- sb.append("declare ");
+ sb.append(" declare");
}
+ } else {
+ assert (flags & CALLSITE_FAST_SCOPE) == 0 : "can't be fastscope without scope";
}
if ((flags & CALLSITE_APPLY_TO_CALL) != 0) {
- sb.append("apply2call ");
+ sb.append(" apply2call");
}
if ((flags & CALLSITE_STRICT) != 0) {
- sb.append("strict ");
+ sb.append(" strict");
}
- return sb.length() == 0 ? "" : " " + sb.toString().trim();
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java Wed Jul 05 21:09:54 2017 +0200
@@ -25,23 +25,6 @@
package jdk.nashorn.tools;
-import static jdk.nashorn.internal.runtime.Source.sourceFor;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.*;
-import java.util.stream.Collectors;
-
import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
@@ -60,10 +43,32 @@
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.ScriptingFunctions;
import jdk.nashorn.internal.runtime.Symbol;
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
import jdk.nashorn.internal.runtime.options.Options;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+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.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import static jdk.nashorn.internal.runtime.Source.sourceFor;
+
/**
* Command line Shell for processing JavaScript files.
*/
@@ -203,8 +208,7 @@
// parse options
if (args != null) {
try {
- // FIXME: preprocessArgs does not yet work fine
- final String[] prepArgs = args; // preprocessArgs(args);
+ final String[] prepArgs = preprocessArgs(args);
options.process(prepArgs);
} catch (final IllegalArgumentException e) {
werr.println(bundle.getString("shell.usage"));
@@ -236,35 +240,53 @@
}
/**
- * Preprocess the command line arguments passed in by the shell. This checks, for each of the arguments, whether it
- * can be a file name, and if so, whether the file exists. If the file exists and begins with a shebang line, and
- * the arguments on that line are a prefix of {@code args} with the file removed, it is assumed that a script file
- * being executed via shebang was found, and it is moved to the appropriate position in the argument list. The first
- * such match is used.
+ * Preprocess the command line arguments passed in by the shell. This method checks, for the first non-option
+ * argument, whether the file denoted by it begins with a shebang line. If so, it is assumed that execution in
+ * shebang mode is intended. The consequence of this is that the identified script file will be treated as the
+ * <em>only</em> script file, and all subsequent arguments will be regarded as arguments to the script.
* <p>
- * This method canonicalizes the command line arguments to the form {@code <options> <scripts> -- <arguments>},
- * where the last of the {@code scripts} is the one being run in shebang fashion.
+ * This method canonicalizes the command line arguments to the form {@code <options> <script> -- <arguments>} if a
+ * shebang script is identified. On platforms that pass shebang arguments as single strings, the shebang arguments
+ * will be broken down into single arguments; whitespace is used as separator.
+ * <p>
+ * Shebang mode is entered regardless of whether the script is actually run directly from the shell, or indirectly
+ * via the {@code jjs} executable. It is the user's / script author's responsibility to ensure that the arguments
+ * given on the shebang line do not lead to a malformed argument sequence. In particular, the shebang arguments
+ * should not contain any whitespace for purposes other than separating arguments, as the different platforms deal
+ * with whitespace in different and incompatible ways.
* <p>
* @implNote Example:<ul>
- * <li>Shebang line in {@code script.js}: {@code #!/path/to/jjs --language=es6 other.js -- arg1}</li>
+ * <li>Shebang line in {@code script.js}: {@code #!/path/to/jjs --language=es6}</li>
* <li>Command line: {@code ./script.js arg2}</li>
- * <li>{@code args} array passed to Nashorn: {@code --language=es6,other.js,--,arg1,./script.js,arg2}</li>
- * <li>Required canonicalized arguments array: {@code --language=es6,other.js,./script.js,--,arg1,arg2}</li>
+ * <li>{@code args} array passed to Nashorn: {@code --language=es6,./script.js,arg}</li>
+ * <li>Required canonicalized arguments array: {@code --language=es6,./script.js,--,arg2}</li>
* </ul>
*
* @param args the command line arguments as passed into Nashorn.
- * @return a properly ordered argument list
+ * @return the passed and possibly canonicalized argument list
*/
private static String[] preprocessArgs(final String[] args) {
- final List<String> largs = new ArrayList<>();
- Collections.addAll(largs, args);
- final List<String> pa = new ArrayList<>();
- String scriptFile = null;
- boolean found = false;
- for (int i = 0; i < args.length; ++i) {
- final String a = args[i];
- final Path p = Paths.get(a);
- if (!found && (!a.startsWith("-") || a.length() == 1) && Files.exists(p)) {
+ if (args.length == 0) {
+ return args;
+ }
+
+ final List<String> processedArgs = new ArrayList<>();
+ processedArgs.addAll(Arrays.asList(args));
+
+ // Nashorn supports passing multiple shebang arguments. On platforms that pass anything following the
+ // shebang interpreter notice as one argument, the first element of the argument array needs to be special-cased
+ // as it might actually contain several arguments. Mac OS X splits shebang arguments, other platforms don't.
+ // This special handling is also only necessary if the first argument actually starts with an option.
+ if (args[0].startsWith("-") && !System.getProperty("os.name", "generic").startsWith("Mac OS X")) {
+ processedArgs.addAll(0, ScriptingFunctions.tokenizeString(processedArgs.remove(0)));
+ }
+
+ int shebangFilePos = -1; // -1 signifies "none found"
+ // identify a shebang file and its position in the arguments array (if any)
+ for (int i = 0; i < processedArgs.size(); ++i) {
+ final String a = processedArgs.get(i);
+ if (!a.startsWith("-")) {
+ final Path p = Paths.get(a);
String l = "";
try (final BufferedReader r = Files.newBufferedReader(p)) {
l = r.readLine();
@@ -272,35 +294,18 @@
// ignore
}
if (l.startsWith("#!")) {
- List<String> shebangArgs = Arrays.asList(l.split(" "));
- shebangArgs = shebangArgs.subList(1, shebangArgs.size()); // remove #! part
- final int ssize = shebangArgs.size();
- final List<String> filteredArgs = largs.stream().filter(x -> !x.equals(a)).collect(Collectors.toList());
- if (filteredArgs.size() >= ssize && shebangArgs.equals(filteredArgs.subList(0, ssize))) {
- scriptFile = a;
- found = true;
- continue;
- }
+ shebangFilePos = i;
}
+ // We're only checking the first non-option argument. If it's not a shebang file, we're in normal
+ // execution mode.
+ break;
}
- pa.add(a);
}
- if (scriptFile != null) {
- // Insert the found script file name either before a -- argument, or at the end of the options list, before
- // any other arguments, with an extra --.
- int argidx = pa.indexOf("--");
- if (argidx == -1) {
- for (String s : pa) {
- ++argidx;
- if (s.charAt(0) != '-') {
- pa.add(argidx, "--");
- break;
- }
- }
- }
- pa.add(argidx, scriptFile);
+ if (shebangFilePos != -1) {
+ // Insert the argument separator after the shebang script file.
+ processedArgs.add(shebangFilePos + 1, "--");
}
- return pa.stream().toArray(String[]::new);
+ return processedArgs.stream().toArray(String[]::new);
}
/**
--- a/nashorn/test/script/basic/JDK-8062799.js Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/test/script/basic/JDK-8062799.js Wed Jul 05 21:09:54 2017 +0200
@@ -33,67 +33,46 @@
var b = true;
var i = 1;
- var l = 4294967296;
var d = 2.1;
var o = "foo";
print(inspect(b || b, "b || b"));
print(inspect(b || i, "b || i"));
- print(inspect(b || l, "b || l"));
print(inspect(b || d, "b || d"));
print(inspect(b || o, "b || o"));
print(inspect(i || b, "i || b"));
print(inspect(i || i, "i || i"));
- print(inspect(i || l, "i || l"));
print(inspect(i || d, "i || d"));
print(inspect(i || o, "i || o"));
- print(inspect(l || b, "l || b"));
- print(inspect(l || i, "l || i"));
- print(inspect(l || l, "l || l"));
- print(inspect(l || d, "l || d"));
- print(inspect(l || o, "l || o"));
-
print(inspect(d || b, "d || b"));
print(inspect(d || i, "d || i"));
- print(inspect(d || l, "d || l"));
print(inspect(d || d, "d || d"));
print(inspect(d || o, "d || o"));
print(inspect(o || b, "o || b"));
print(inspect(o || i, "o || i"));
- print(inspect(o || l, "o || l"));
print(inspect(o || d, "o || d"));
print(inspect(o || o, "o || o"));
print(inspect(b && b, "b && b"));
print(inspect(b && i, "b && i"));
- print(inspect(b && l, "b && l"));
print(inspect(b && d, "b && d"));
print(inspect(b && o, "b && o"));
print(inspect(i && b, "i && b"));
print(inspect(i && i, "i && i"));
- print(inspect(i && l, "i && l"));
print(inspect(i && d, "i && d"));
print(inspect(i && o, "i && o"));
- print(inspect(l && b, "l && b"));
- print(inspect(l && i, "l && i"));
- print(inspect(l && l, "l && l"));
- print(inspect(l && d, "l && d"));
- print(inspect(l && o, "l && o"));
-
print(inspect(d && b, "d && b"));
print(inspect(d && i, "d && i"));
- print(inspect(d && l, "d && l"));
print(inspect(d && d, "d && d"));
print(inspect(d && o, "d && o"));
print(inspect(o && b, "o && b"));
print(inspect(o && i, "o && i"));
- print(inspect(o && l, "o && l"));
print(inspect(o && d, "o && d"));
print(inspect(o && o, "o && o"));
})();
--- a/nashorn/test/script/basic/JDK-8062799.js.EXPECTED Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/test/script/basic/JDK-8062799.js.EXPECTED Wed Jul 05 21:09:54 2017 +0200
@@ -1,50 +1,32 @@
b || b: boolean
b || i: boolean
-b || l: boolean
b || d: boolean
b || o: boolean
i || b: int
i || i: int
-i || l: long
i || d: double
i || o: int
-l || b: long
-l || i: long
-l || l: long
-l || d: double
-l || o: long
d || b: double
d || i: double
-d || l: double
d || d: double
d || o: double
o || b: object
o || i: object
-o || l: object
o || d: object
o || o: object
b && b: boolean
b && i: int
-b && l: long
b && d: double
b && o: object
i && b: boolean
i && i: int
-i && l: long
i && d: double
i && o: object
-l && b: boolean
-l && i: long
-l && l: long
-l && d: double
-l && o: object
d && b: boolean
d && i: double
-d && l: double
d && d: double
d && o: object
o && b: boolean
o && i: int
-o && l: long
o && d: double
o && o: object
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8144020.js Wed Jul 05 21:09:54 2017 +0200
@@ -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.
+ */
+
+/**
+ * JDK-8144020: Remove long as an internal numeric type
+ *
+ * @test
+ * @run
+ */
+
+var LongProvider = Java.type("jdk.nashorn.test.models.LongProvider");
+var Long = Java.type("java.lang.Long");
+var LongClass = Long.class;
+var Integer = Java.type("java.lang.Integer");
+var Double = Java.type("java.lang.Double");
+
+var INT = "3";
+var DOUBLE = "5.5";
+var MAX_LONG = "9223372036854775807";
+var MIN_LONG = "-9223372036854775808";
+var BIG_LONG = "281474976710655"; // can be represented as double
+var NEG_LONG = "-281474976710656"; // can be represented as double
+var SMALL_LONG = "13";
+
+// Make sure we can pass longs from and to Java without losing precision
+LongProvider.checkLong(LongProvider.getLong(MAX_LONG), MAX_LONG);
+LongProvider.checkLong(LongProvider.getLong(MIN_LONG), MIN_LONG);
+LongProvider.checkLong(LongProvider.getLong(BIG_LONG), BIG_LONG);
+LongProvider.checkLong(LongProvider.getLong(NEG_LONG), NEG_LONG);
+LongProvider.checkLong(LongProvider.getLong(SMALL_LONG), SMALL_LONG);
+
+// a polymorphic function that can return various number types
+function getNumber(str) {
+ switch (str) {
+ case INT: return +INT;
+ case DOUBLE: return +DOUBLE;
+ default: return Long.parseLong(str);
+ }
+}
+
+function compareValue(n, str) {
+ switch (str) {
+ case INT: return Integer.compare(n, Integer.parseInt(str) == 0);
+ case DOUBLE: return Double.compare(n, Double.parseDouble(str) == 0);
+ default: return Long.compare(n, Long.parseLong(str) == 0);
+ }
+}
+
+// Call a a function with a sequence of values. The purpose of this is that we can handle
+// longs without losing precision in the presence of optimistic deoptimization, cached callsites, etc.
+function testSequence(fn, values) {
+ for (var i in values) {
+ fn(values[i]);
+ }
+}
+
+// We need to use "fresh" (unlinked and un-deoptimized) functions for each of the test runs.
+testSequence(function(str) {
+ var n = getNumber(str);
+ Assert.assertTrue(compareValue(n, str));
+}, [INT, BIG_LONG, MIN_LONG]);
+
+testSequence(function(str) {
+ var n = getNumber(str);
+ Assert.assertTrue(compareValue(n, str));
+}, [INT, MAX_LONG]);
+
+testSequence(function(str) {
+ var n = getNumber(str);
+ Assert.assertTrue(compareValue(n, str));
+}, [INT, DOUBLE, NEG_LONG]);
+
+testSequence(function(str) {
+ var n = getNumber(str);
+ Assert.assertTrue(compareValue(n, str));
+}, [DOUBLE, MAX_LONG]);
+
+testSequence(function(str) {
+ var n = getNumber(str);
+ Assert.assertTrue(compareValue(n, str));
+}, [DOUBLE, SMALL_LONG, MAX_LONG]);
+
+testSequence(function(str) {
+ var n = getNumber(str);
+ Assert.assertTrue(compareValue(n, str));
+}, [INT, DOUBLE, NEG_LONG, MAX_LONG]);
+
+testSequence(function(str) {
+ var n = getNumber(str);
+ Assert.assertTrue(compareValue(n, str));
+}, [DOUBLE, MAX_LONG, DOUBLE, INT]);
+
+// Make sure long arrays make it through Java.from and Java.to without losing precision
+var longArrayType = Java.type("long[]");
+for (var i = 0; i < 3; i++) {
+ LongProvider.checkLongArray(Java.to(Java.from(LongProvider.getLongArray(i)), longArrayType), i);
+}
+
+l = Long.parseLong(BIG_LONG);
+Assert.assertTrue(l >>> 8 === 0xffffff);
+Assert.assertTrue(l << 8 === -0x100);
+Assert.assertTrue(l + 1 === 0x1000000000000);
+Assert.assertTrue(l - 1 === 0xfffffffffffe);
+
+Assert.assertEquals(LongProvider.getLong(MAX_LONG).getClass(), LongClass);
+Assert.assertEquals(LongProvider.getLong(MIN_LONG).getClass(), LongClass);
--- a/nashorn/test/script/basic/JDK-8144131.js Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/test/script/basic/JDK-8144131.js Wed Jul 05 21:09:54 2017 +0200
@@ -30,12 +30,9 @@
var doubleArray = [97912312397.234, -182374983434.56];
var doubleArrayResults = [-871935411, -1986357002];
-var longArray = [0x7fffffff8c102ebc, -0x7fffffffe9dfec18];
-var longArrayResults = [-1945096192, 371201024];
-// Make sure arrays use double and long array data
+// Make sure array uses double array data
Assert.assertEquals(doubleArray[0].getClass(), java.lang.Double.class);
-Assert.assertEquals(longArray[0].getClass(), java.lang.Long.class);
function testBinaryOp(array, index, expected) {
Assert.assertEquals(array[index] & 0xffffffff, expected);
@@ -44,7 +41,4 @@
for (var i = 0; i < doubleArray.length; i++) {
testBinaryOp(doubleArray, i, doubleArrayResults[i]);
}
-for (var i = 0; i < longArray.length; i++) {
- testBinaryOp(longArray, i, longArrayResults[i]);
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8145550.js Wed Jul 05 21:09:54 2017 +0200
@@ -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.
+ */
+
+/**
+ * JDK-8141537: Megamorphic invoke should use CompiledFunction variants without any LinkLogic
+ *
+ * @test
+ * @option --unstable-relink-threshold=1
+ * @run
+ */
+
+load(__DIR__ + "NASHORN-421.js")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/apply_to_call/JDK-8145669.js Wed Jul 05 21:09:54 2017 +0200
@@ -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.
+ */
+
+/*
+ * JDK-8145669: apply2call optimized callsite fails after becoming megamorphic
+ *
+ * @test
+ * @option --unstable-relink-threshold=1
+ * @run
+ */
+
+load(__DIR__ + "apply_to_call2.js");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/apply_to_call/JDK-8145669.js.EXPECTED Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,8 @@
+start
+4711
+23
+17
+Overwriting call now
+1
+2
+3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/apply_to_call/JDK-8145669_2.js Wed Jul 05 21:09:54 2017 +0200
@@ -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.
+ */
+
+/**
+ * JDK-8145669: apply2call optimized callsite fails after becoming megamorphic
+ *
+ * @test
+ * @option --unstable-relink-threshold=1
+ * @run
+ */
+
+load(__DIR__ + "apply_to_call_varargs.js");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/apply_to_call/JDK-8145669_2.js.EXPECTED Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,66 @@
+[red=0, green=255, blue=255]
+undefined
+[red=1, green=255, blue=255]
+undefined
+[red=2, green=255, blue=255]
+undefined
+[red=3, green=255, blue=255]
+undefined
+[red=4, green=255, blue=255]
+undefined
+[red=5, green=255, blue=255]
+undefined
+[red=6, green=255, blue=255]
+undefined
+[red=7, green=255, blue=255]
+undefined
+[red=8, green=255, blue=255]
+undefined
+[red=9, green=255, blue=255]
+undefined
+[red=10, green=255, blue=255]
+undefined
+[red=11, green=255, blue=255]
+undefined
+[red=12, green=255, blue=255]
+undefined
+[red=13, green=255, blue=255]
+undefined
+[red=14, green=255, blue=255]
+undefined
+[red=15, green=255, blue=255]
+undefined
+Swapping out call
+[red=0, green=255, blue=255]
+undefined
+[red=1, green=255, blue=255]
+undefined
+[red=2, green=255, blue=255]
+undefined
+[red=3, green=255, blue=255]
+undefined
+[red=4, green=255, blue=255]
+undefined
+[red=5, green=255, blue=255]
+undefined
+[red=6, green=255, blue=255]
+undefined
+[red=7, green=255, blue=255]
+undefined
+[red=8, green=255, blue=255]
+undefined
+[red=9, green=255, blue=255]
+undefined
+[red=10, green=255, blue=255]
+undefined
+[red=11, green=255, blue=255]
+undefined
+[red=12, green=255, blue=255]
+undefined
+[red=13, green=255, blue=255]
+undefined
+[red=14, green=255, blue=255]
+undefined
+[red=15, green=255, blue=255]
+undefined
+All done!
--- a/nashorn/test/script/nosecurity/JDK-8067215.js Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/test/script/nosecurity/JDK-8067215.js Wed Jul 05 21:09:54 2017 +0200
@@ -32,7 +32,6 @@
var intType = Java.type("int");
var doubleType = Java.type("double");
-var longType = Java.type("long");
var objectType = Java.type("java.lang.Object");
var Context = Java.type("jdk.nashorn.internal.runtime.Context");
@@ -58,7 +57,6 @@
}
if (prop.getType() != getExpectedType(obj[key])) {
throw new Error("Wrong property type: " + prop.getType() + " // " + getExpectedType(obj[key]));
-
}
}
}
@@ -67,14 +65,8 @@
if (!dualFields) {
return objectType.class;
}
- if (JSType.isRepresentableAsInt(value)) {
- return intType.class;
- }
- if (JSType.isRepresentableAsLong(value)) {
- return longType.class;
- }
- if (JSType.isNumber(value)) {
- return doubleType.class;
+ if (typeof value === "number") {
+ return JSType.isRepresentableAsInt(value) ? intType.class : doubleType.class;
}
return objectType.class;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/JDK-8144221.js Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,155 @@
+/*
+ * 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 that shebang handling works properly.
+ *
+ * @test
+ * @runif os.not.windows
+ * @option -scripting
+ * @run
+ */
+
+// The test generates three different JavaScript source files. The first two
+// are generated at the beginning of the test and do not change.
+// * a.js
+// print("A: " + arguments)
+// * b.js
+// #!<path_to_jjs> -lalelu -- ignore
+// print("B: " + arguments)
+//
+// The third file, shebang.js, is generated differently for each particular
+// test case, containing different shebang lines and one statement:
+// * shebang.js
+// #!<path_to_jjs> <shebang_line>
+// print("S: " + arguments)
+//
+// The path_to_jjs is extracted from the environment based on JAVA_HOME, so the
+// latter must be set properly.
+//
+// Each shebang.js is run four times, in all possible combinations of values
+// from the following two axes:
+// * without passing any arguments, and passing the arguments 'a.js' and
+// '"hello world"' (the latter being a quoted string);
+// * run via jjs, and via direct shell execution (using shebang).
+
+var pseudosheb = "#!${jjs} -lalelu -- ignore",
+ System = Java.type('java.lang.System'),
+ Paths = Java.type('java.nio.file.Paths'),
+ Files = Java.type('java.nio.file.Files'),
+ Opt = Java.type('java.nio.file.StandardOpenOption'),
+ Arrays = Java.type('java.util.Arrays')
+
+var sep = Java.type('java.io.File').separator,
+ win = System.getProperty("os.name").startsWith("Windows"),
+ jjsName = "jjs" + (win ? ".exe" : ""),
+ javaHome = System.getProperty("java.home")
+
+var jjs = javaHome + "/../bin/".replace(/\//g, sep) + jjsName
+if (!Files.exists(Paths.get(jjs))) {
+ jjs = javaHome + "/bin/".replace(/\//g, sep) + jjsName
+}
+
+// Create and cwd to a temporary directory.
+
+var tmpdir = Files.createTempDirectory(null),
+ tmp = tmpdir.toAbsolutePath().toString(),
+ curpwd = $ENV.PWD
+
+$ENV.PWD = tmp
+
+// Test cases. Each case is documented with the expected output for the four
+// different executions.
+
+var shebs = [
+ // No arguments on the shebang line.
+ // noargs jjs/shebang -> no output but "S" prefix
+ // args jjs/shebang -> output the arguments with "S" prefix
+ "",
+ // One interpreter argument.
+ // noargs jjs/shebang -> no output but "S" prefix
+ // args jjs/shebang -> output the arguments with "S" prefix
+ "--language=es6",
+ // Two interpreter arguments.
+ // noargs jjs/shebang -> no output but "S" prefix
+ // args jjs/shebang -> output the arguments with "S" prefix
+ "--language=es6 -scripting",
+ // One interpreter argument and a JavaScript file without shebang.
+ // (For shebang execution, this is a pathological example, as the
+ // JavaScript file passed as a shebang argument will be analyzed and
+ // shebang mode will not be entered.)
+ // noargs jjs -> no output but "S" prefix
+ // args jjs -> output the arguments with "S" prefix
+ // noargs shebang -> no output but "A" and "S" prefixes
+ // args shebang -> output "A", "S", and "A" prefixes, then the error
+ // message:
+ // "java.io.IOException: hello world is not a file"
+ "-scripting a.js",
+ // One interpreter argument and a JavaScript file with shebang. (This
+ // is another pathological example, as it will force shebang mode,
+ // leading to all subsequent arguments, including shebang.js, being
+ // treated as arguments to the script b.js.)
+ // noargs jjs -> no output but the "S" prefix
+ // args jjs -> output the arguments with "S" prefix
+ // noargs shebang -> output shebang.js with "B" prefix
+ // args shebang -> output shebang.js and the arguments with "B"
+ // prefix
+ "-scripting b.js"
+ ]
+
+function write(file, lines) {
+ Files.write(Paths.get(tmp, file), Arrays.asList(lines), Opt.CREATE, Opt.WRITE)
+}
+
+function insn(name) {
+ return "print('${name}:' + arguments)"
+}
+
+function run(viajjs, name, arg1, arg2) {
+ var prefix = viajjs ? "${jjs} -scripting " : ''
+ $EXEC("${prefix}./shebang.js ${arg1} ${arg2}")
+ print("* ${name} via ${viajjs ? 'jjs' : 'shebang'}")
+ print($OUT.trim())
+ print($ERR.trim())
+}
+
+write('a.js', insn('A'))
+write('b.js', [pseudosheb, insn('B')])
+
+shebs.forEach(function(sheb) {
+ var shebang = "#!${jjs} ${sheb}"
+ print("<<< ${sheb} >>>")
+ write('shebang.js', [shebang, insn('S')])
+ $EXEC('chmod +x shebang.js')
+ run(false, 'noargs', '', '')
+ run(true, 'noargs', '', '')
+ run(false, 'withargs', 'a.js', '"hello world"')
+ run(true, 'withargs', 'a.js', '"hello world"')
+ $EXEC('rm shebang.js')
+})
+
+// Cleanup.
+
+$EXEC('rm a.js b.js')
+$ENV.PWD = curpwd
+Files.delete(tmpdir)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/JDK-8144221.js.EXPECTED Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,68 @@
+<<< >>>
+* noargs via shebang
+S:
+
+* noargs via jjs
+S:
+
+* withargs via shebang
+S:a.js,hello world
+
+* withargs via jjs
+S:a.js,hello world
+
+<<< --language=es6 >>>
+* noargs via shebang
+S:
+
+* noargs via jjs
+S:
+
+* withargs via shebang
+S:a.js,hello world
+
+* withargs via jjs
+S:a.js,hello world
+
+<<< --language=es6 -scripting >>>
+* noargs via shebang
+S:
+
+* noargs via jjs
+S:
+
+* withargs via shebang
+S:a.js,hello world
+
+* withargs via jjs
+S:a.js,hello world
+
+<<< -scripting a.js >>>
+* noargs via shebang
+A:
+S:
+
+* noargs via jjs
+S:
+
+* withargs via shebang
+A:
+S:
+A:
+java.io.IOException: hello world is not a file
+* withargs via jjs
+S:a.js,hello world
+
+<<< -scripting b.js >>>
+* noargs via shebang
+B:./shebang.js
+
+* noargs via jjs
+S:
+
+* withargs via shebang
+B:./shebang.js,a.js,hello world
+
+* withargs via jjs
+S:a.js,hello world
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/os-not-windows.js Wed Jul 05 21:09:54 2017 +0200
@@ -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 that we're not running on Windows. The test actually checks if the os.not.windows property is set and processed
+ * by runif correctly.
+ *
+ * @test
+ * @runif os.not.windows
+ * @run
+ */
+
+var os = java.lang.System.getProperty("os.name")
+
+if (os.startsWith("Windows")) {
+ throw "This test should not be run on Windows."
+}
--- a/nashorn/test/src/jdk/nashorn/api/javaaccess/test/NumberAccessTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/test/NumberAccessTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -143,7 +143,7 @@
@Test
public void accessStaticFinalFieldLong() throws ScriptException {
e.eval("var psf_long = SharedObject.publicStaticFinalLong;");
- assertEquals(SharedObject.publicStaticFinalLong, e.get("psf_long"));
+ assertEquals(SharedObject.publicStaticFinalLong, ((Number) e.get("psf_long")).longValue());
e.eval("SharedObject.publicStaticFinalLong = 120;");
assertEquals(8333333333333L, SharedObject.publicStaticFinalLong);
}
--- a/nashorn/test/src/jdk/nashorn/api/javaaccess/test/NumberBoxingTest.java Mon Dec 21 17:47:21 2015 +0100
+++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/test/NumberBoxingTest.java Wed Jul 05 21:09:54 2017 +0200
@@ -70,7 +70,7 @@
@Test
public void accessFieldLongBoxing() throws ScriptException {
e.eval("var p_long = o.publicLongBox;");
- assertEquals(o.publicLongBox, e.get("p_long"));
+ assertEquals(o.publicLongBox.longValue(), ((Number) e.get("p_long")).longValue());
e.eval("o.publicLongBox = 12;");
assertEquals(Long.valueOf(12), o.publicLongBox);
}
@@ -78,7 +78,7 @@
@Test
public void accessStaticFieldLongBoxing() throws ScriptException {
e.eval("var ps_long = SharedObject.publicStaticLongBox;");
- assertEquals(SharedObject.publicStaticLongBox, e.get("ps_long"));
+ assertEquals(SharedObject.publicStaticLongBox.longValue(), ((Number) e.get("ps_long")).longValue());
e.eval("SharedObject.publicStaticLongBox = 120;");
assertEquals(120L, SharedObject.publicStaticLongBox.longValue());
}
@@ -86,7 +86,7 @@
@Test
public void accessFinalFieldLongBoxing() throws ScriptException {
e.eval("var pf_long = o.publicFinalLongBox;");
- assertEquals(o.publicFinalLongBox, e.get("pf_long"));
+ assertEquals(o.publicFinalLongBox.longValue(), ((Number) e.get("pf_long")).longValue());
e.eval("o.publicFinalLongBox = 120;");
assertEquals(Long.valueOf(9377333334L), o.publicFinalLongBox);
}
@@ -94,7 +94,7 @@
@Test
public void accessStaticFinalFieldLongBoxing() throws ScriptException {
e.eval("var psf_long = SharedObject.publicStaticFinalLong;");
- assertEquals(SharedObject.publicStaticFinalLong, e.get("psf_long"));
+ assertEquals(SharedObject.publicStaticFinalLong, ((Number) e.get("psf_long")).longValue());
e.eval("SharedObject.publicStaticFinalLong = 120;");
assertEquals(8333333333333L, SharedObject.publicStaticFinalLong);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/test/models/LongProvider.java Wed Jul 05 21:09:54 2017 +0200
@@ -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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.test.models;
+
+import java.util.Arrays;
+
+/**
+ * A class that returns and receives longs.
+ */
+@SuppressWarnings("javadoc")
+public class LongProvider {
+
+ final static long[][] arrays = {
+ {1L, 2L, 3L},
+ {1L, 1L << 30, 1L << 50, 4L},
+ {1L, Long.MAX_VALUE, Long.MIN_VALUE, 4L}
+ };
+
+ public static long getLong(final String str) {
+ final long l = Long.parseLong(str);
+ checkLong(l, str);
+ return l;
+ }
+
+ public static long[] getLongArray(final int n) {
+ return arrays[n];
+ }
+
+ public static void checkLong(final long value, final String str) {
+ if (!Long.toString(value).equals(str)) {
+ throw new RuntimeException("Wrong value. Expected " + str + ", got " + value);
+ }
+ }
+
+ public static void checkLongArray(final long[] array, final int n) {
+ if (!Arrays.equals(array, arrays[n])) {
+ throw new RuntimeException("Arrays don't match: " + Arrays.toString(array) + ", " + Arrays.toString(arrays[n]));
+ }
+ }
+}
--- a/test/Makefile Mon Dec 21 17:47:21 2015 +0100
+++ b/test/Makefile Wed Jul 05 21:09:54 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2010, 2011, 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
@@ -60,18 +60,28 @@
# Bring in closed test targets if present
-include $(TOPDIR)/closed/test/Makefile
+ifeq ($(TEST_JOBS), 0)
+ JDK_TEST_JOBS=$(JOBS)
+else
+ JDK_TEST_JOBS=$(TEST_JOBS)
+endif
# Test targets
langtools_% :
- @$(NO_STOPPING)$(call SUBDIR_TEST, $(LANGTOOLS_DIR), JT_JAVA=$(PRODUCT_HOME) JTREG_HOME=$(JT_HOME) TEST="$(subst langtools_,,$@)" $(subst langtools_,,$@))
+ @$(NO_STOPPING)$(call SUBDIR_TEST, $(LANGTOOLS_DIR), CONCURRENCY=$(JDK_TEST_JOBS) JT_JAVA=$(PRODUCT_HOME) JTREG_HOME=$(JT_HOME) TEST="$(subst langtools_,,$@)" $(subst langtools_,,$@))
jdk_% core_%s svc_%:
- @$(NO_STOPPING)$(call SUBDIR_TEST, $(JDK_DIR), TEST="$@" $@)
+ @$(NO_STOPPING)$(call SUBDIR_TEST, $(JDK_DIR), CONCURRENCY=$(JDK_TEST_JOBS) TEST="$@" $@)
jaxp_%:
- @$(NO_STOPPING)$(call SUBDIR_TEST, $(JAXP_DIR), TEST="$@" $@)
+ @$(NO_STOPPING)$(call SUBDIR_TEST, $(JAXP_DIR), CONCURRENCY=$(JDK_TEST_JOBS) TEST="$@" $@)
+ifeq ($(TEST_JOBS), 0)
+ HOTSPOT_TEST_JOBS=1
+else
+ HOTSPOT_TEST_JOBS=$(TEST_JOBS)
+endif
hotspot_%:
- @$(NO_STOPPING)$(call SUBDIR_TEST, $(HOTSPOT_DIR), TEST="$@" $@)
+ @$(NO_STOPPING)$(call SUBDIR_TEST, $(HOTSPOT_DIR), CONCURRENCY=$(HOTSPOT_TEST_JOBS) TEST="$@" $@)
#
# jtreg_tests
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/Asserts.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,620 @@
+/*
+ * 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.test.lib;
+
+import java.util.Objects;
+
+/**
+ * Asserts that can be used for verifying assumptions in tests.
+ *
+ * An assertion will throw a {@link RuntimeException} if the assertion isn't true.
+ * All the asserts can be imported into a test by using a static import:
+ *
+ * <pre>
+ * {@code
+ * import static jdk.testlibrary.Asserts.*;
+ * }
+ *
+ * Always provide a message describing the assumption if the line number of the
+ * failing assertion isn't enough to understand why the assumption failed. For
+ * example, if the assertion is in a loop or in a method that is called
+ * multiple times, then the line number won't provide enough context to
+ * understand the failure.
+ * </pre>
+ */
+public class Asserts {
+
+ /**
+ * Shorthand for {@link #assertLessThan(Comparable, Comparable)}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertLessThan(Comparable, Comparable)
+ */
+ public static <T extends Comparable<T>> void assertLT(T lhs, T rhs) {
+ assertLessThan(lhs, rhs);
+ }
+
+ /**
+ * Shorthand for {@link #assertLessThan(Comparable, Comparable, String)}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @see #assertLessThan(Comparable, Comparable, String)
+ */
+ public static <T extends Comparable<T>> void assertLT(T lhs, T rhs, String msg) {
+ assertLessThan(lhs, rhs, msg);
+ }
+
+ /**
+ * Calls {@link #assertLessThan(Comparable, Comparable, String)} with a default message.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertLessThan(Comparable, Comparable, String)
+ */
+ public static <T extends Comparable<T>> void assertLessThan(T lhs, T rhs) {
+ assertLessThan(lhs, rhs, null);
+ }
+
+ /**
+ * Asserts that {@code lhs} is less than {@code rhs}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static <T extends Comparable<T>>void assertLessThan(T lhs, T rhs, String msg) {
+ if (!(compare(lhs, rhs, msg) < 0)) {
+ msg = Objects.toString(msg, "assertLessThan")
+ + ": expected that " + Objects.toString(lhs)
+ + " < " + Objects.toString(rhs);
+ fail(msg);
+ }
+ }
+
+ /**
+ * Shorthand for {@link #assertLessThanOrEqual(Comparable, Comparable)}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertLessThanOrEqual(Comparable, Comparable)
+ */
+ public static <T extends Comparable<T>> void assertLTE(T lhs, T rhs) {
+ assertLessThanOrEqual(lhs, rhs);
+ }
+
+ /**
+ * Shorthand for {@link #assertLessThanOrEqual(Comparable, Comparable, String)}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @see #assertLessThanOrEqual(Comparable, Comparable, String)
+ */
+ public static <T extends Comparable<T>> void assertLTE(T lhs, T rhs, String msg) {
+ assertLessThanOrEqual(lhs, rhs, msg);
+ }
+
+ /**
+ * Calls {@link #assertLessThanOrEqual(Comparable, Comparable, String)} with a default message.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertLessThanOrEqual(Comparable, Comparable, String)
+ */
+ public static <T extends Comparable<T>> void assertLessThanOrEqual(T lhs, T rhs) {
+ assertLessThanOrEqual(lhs, rhs, null);
+ }
+
+ /**
+ * Asserts that {@code lhs} is less than or equal to {@code rhs}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static <T extends Comparable<T>> void assertLessThanOrEqual(T lhs, T rhs, String msg) {
+ if (!(compare(lhs, rhs, msg) <= 0)) {
+ msg = Objects.toString(msg, "assertLessThanOrEqual")
+ + ": expected that " + Objects.toString(lhs)
+ + " <= " + Objects.toString(rhs);
+ fail(msg);
+ }
+ }
+
+ /**
+ * Shorthand for {@link #assertEquals(Object, Object)}.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertEquals(Object, Object)
+ */
+ public static void assertEQ(Object lhs, Object rhs) {
+ assertEquals(lhs, rhs);
+ }
+
+ /**
+ * Shorthand for {@link #assertEquals(Object, Object, String)}.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @see #assertEquals(Object, Object, String)
+ */
+ public static void assertEQ(Object lhs, Object rhs, String msg) {
+ assertEquals(lhs, rhs, msg);
+ }
+
+ /**
+ * Calls {@link #assertEquals(java.lang.Object, java.lang.Object, java.lang.String)} with a default message.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertEquals(Object, Object, String)
+ */
+ public static void assertEquals(Object lhs, Object rhs) {
+ assertEquals(lhs, rhs, null);
+ }
+
+ /**
+ * Asserts that {@code lhs} is equal to {@code rhs}.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static void assertEquals(Object lhs, Object rhs, String msg) {
+ if ((lhs != rhs) && ((lhs == null) || !(lhs.equals(rhs)))) {
+ msg = Objects.toString(msg, "assertEquals")
+ + ": expected " + Objects.toString(lhs)
+ + " to equal " + Objects.toString(rhs);
+ fail(msg);
+ }
+ }
+
+ /**
+ * Calls {@link #assertSame(java.lang.Object, java.lang.Object, java.lang.String)} with a default message.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertSame(Object, Object, String)
+ */
+ public static void assertSame(Object lhs, Object rhs) {
+ assertSame(lhs, rhs, null);
+ }
+
+ /**
+ * Asserts that {@code lhs} is the same as {@code rhs}.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static void assertSame(Object lhs, Object rhs, String msg) {
+ if (lhs != rhs) {
+ msg = Objects.toString(msg, "assertSame")
+ + ": expected " + Objects.toString(lhs)
+ + " to equal " + Objects.toString(rhs);
+ fail(msg);
+ }
+ }
+
+ /**
+ * Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable)}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertGreaterThanOrEqual(Comparable, Comparable)
+ */
+ public static <T extends Comparable<T>> void assertGTE(T lhs, T rhs) {
+ assertGreaterThanOrEqual(lhs, rhs);
+ }
+
+ /**
+ * Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable, String)}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @see #assertGreaterThanOrEqual(Comparable, Comparable, String)
+ */
+ public static <T extends Comparable<T>> void assertGTE(T lhs, T rhs, String msg) {
+ assertGreaterThanOrEqual(lhs, rhs, msg);
+ }
+
+ /**
+ * Calls {@link #assertGreaterThanOrEqual(Comparable, Comparable, String)} with a default message.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertGreaterThanOrEqual(Comparable, Comparable, String)
+ */
+ public static <T extends Comparable<T>> void assertGreaterThanOrEqual(T lhs, T rhs) {
+ assertGreaterThanOrEqual(lhs, rhs, null);
+ }
+
+ /**
+ * Asserts that {@code lhs} is greater than or equal to {@code rhs}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static <T extends Comparable<T>> void assertGreaterThanOrEqual(T lhs, T rhs, String msg) {
+ if (!(compare(lhs, rhs, msg) >= 0)) {
+ msg = Objects.toString(msg, "assertGreaterThanOrEqual")
+ + ": expected " + Objects.toString(lhs)
+ + " >= " + Objects.toString(rhs);
+ fail(msg);
+ }
+ }
+
+ /**
+ * Shorthand for {@link #assertGreaterThan(Comparable, Comparable)}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertGreaterThan(Comparable, Comparable)
+ */
+ public static <T extends Comparable<T>> void assertGT(T lhs, T rhs) {
+ assertGreaterThan(lhs, rhs);
+ }
+
+ /**
+ * Shorthand for {@link #assertGreaterThan(Comparable, Comparable, String)}.
+ *
+ * @param <T> a type
+ * @param lhs the left hand value
+ * @param rhs the right hand value
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @see #assertGreaterThan(Comparable, Comparable, String)
+ */
+ public static <T extends Comparable<T>> void assertGT(T lhs, T rhs, String msg) {
+ assertGreaterThan(lhs, rhs, msg);
+ }
+
+ /**
+ * Calls {@link #assertGreaterThan(Comparable, Comparable, String)} with a default message.
+ *
+ * @param <T> a type
+ * @param lhs the left hand value
+ * @param rhs the right hand value
+ * @see #assertGreaterThan(Comparable, Comparable, String)
+ */
+ public static <T extends Comparable<T>> void assertGreaterThan(T lhs, T rhs) {
+ assertGreaterThan(lhs, rhs, null);
+ }
+
+ /**
+ * Asserts that {@code lhs} is greater than {@code rhs}.
+ *
+ * @param <T> a type
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static <T extends Comparable<T>> void assertGreaterThan(T lhs, T rhs, String msg) {
+ if (!(compare(lhs, rhs, msg) > 0)) {
+ msg = Objects.toString(msg, "assertGreaterThan")
+ + ": expected " + Objects.toString(lhs)
+ + " > " + Objects.toString(rhs);
+ fail(msg);
+ }
+ }
+
+ /**
+ * Shorthand for {@link #assertNotEquals(Object, Object)}.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertNotEquals(Object, Object)
+ */
+ public static void assertNE(Object lhs, Object rhs) {
+ assertNotEquals(lhs, rhs);
+ }
+
+ /**
+ * Shorthand for {@link #assertNotEquals(Object, Object, String)}.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @see #assertNotEquals(Object, Object, String)
+ */
+ public static void assertNE(Object lhs, Object rhs, String msg) {
+ assertNotEquals(lhs, rhs, msg);
+ }
+
+ /**
+ * Calls {@link #assertNotEquals(Object, Object, String)} with a default message.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertNotEquals(Object, Object, String)
+ */
+ public static void assertNotEquals(Object lhs, Object rhs) {
+ assertNotEquals(lhs, rhs, null);
+ }
+
+ /**
+ * Asserts that {@code lhs} is not equal to {@code rhs}.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static void assertNotEquals(Object lhs, Object rhs, String msg) {
+ if ((lhs == rhs) || (lhs != null && lhs.equals(rhs))) {
+ msg = Objects.toString(msg, "assertNotEquals")
+ + ": expected " + Objects.toString(lhs)
+ + " to not equal " + Objects.toString(rhs);
+ fail(msg);
+ }
+ }
+
+ /**
+ * Calls {@link #assertNull(Object, String)} with a default message.
+ *
+ * @param o The reference assumed to be null.
+ * @see #assertNull(Object, String)
+ */
+ public static void assertNull(Object o) {
+ assertNull(o, null);
+ }
+
+ /**
+ * Asserts that {@code o} is null.
+ *
+ * @param o The reference assumed to be null.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static void assertNull(Object o, String msg) {
+ assertEquals(o, null, msg);
+ }
+
+ /**
+ * Calls {@link #assertNotNull(Object, String)} with a default message.
+ *
+ * @param o The reference assumed <i>not</i> to be null,
+ * @see #assertNotNull(Object, String)
+ */
+ public static void assertNotNull(Object o) {
+ assertNotNull(o, null);
+ }
+
+ /**
+ * Asserts that {@code o} is <i>not</i> null.
+ *
+ * @param o The reference assumed <i>not</i> to be null,
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static void assertNotNull(Object o, String msg) {
+ assertNotEquals(o, null, msg);
+ }
+
+ /**
+ * Calls {@link #assertFalse(boolean, String)} with a default message.
+ *
+ * @param value The value assumed to be false.
+ * @see #assertFalse(boolean, String)
+ */
+ public static void assertFalse(boolean value) {
+ assertFalse(value, null);
+ }
+
+ /**
+ * Asserts that {@code value} is {@code false}.
+ *
+ * @param value The value assumed to be false.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static void assertFalse(boolean value, String msg) {
+ if (value) {
+ msg = Objects.toString(msg, "assertFalse")
+ + ": expected false, was true";
+ fail(msg);
+ }
+ }
+
+ /**
+ * Calls {@link #assertTrue(boolean, String)} with a default message.
+ *
+ * @param value The value assumed to be true.
+ * @see #assertTrue(boolean, String)
+ */
+ public static void assertTrue(boolean value) {
+ assertTrue(value, null);
+ }
+
+ /**
+ * Asserts that {@code value} is {@code true}.
+ *
+ * @param value The value assumed to be true.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static void assertTrue(boolean value, String msg) {
+ if (!value) {
+ msg = Objects.toString(msg, "assertTrue")
+ + ": expected true, was false";
+ fail(msg);
+ }
+ }
+
+ private static <T extends Comparable<T>> int compare(T lhs, T rhs, String msg) {
+ if (lhs == null || rhs == null) {
+ fail(lhs, rhs, msg + ": values must be non-null:", ",");
+ }
+ return lhs.compareTo(rhs);
+ }
+
+/**
+ * Asserts that two strings are equal.
+ *
+ * If strings are not equals, then exception message
+ * will contain {@code msg} followed by list of mismatched lines.
+ *
+ * @param str1 First string to compare.
+ * @param str2 Second string to compare.
+ * @param msg A description of the assumption.
+ * @throws RuntimeException if strings are not equal.
+ */
+ public static void assertStringsEqual(String str1, String str2,
+ String msg) {
+ String lineSeparator = System.getProperty("line.separator");
+ String str1Lines[] = str1.split(lineSeparator);
+ String str2Lines[] = str2.split(lineSeparator);
+
+ int minLength = Math.min(str1Lines.length, str2Lines.length);
+ String longestStringLines[] = ((str1Lines.length == minLength) ?
+ str2Lines : str1Lines);
+
+ boolean stringsAreDifferent = false;
+
+ StringBuilder messageBuilder = new StringBuilder(msg);
+
+ messageBuilder.append("\n");
+
+ for (int line = 0; line < minLength; line++) {
+ if (!str1Lines[line].equals(str2Lines[line])) {
+ messageBuilder.append(String.
+ format("[line %d] '%s' differs " +
+ "from '%s'\n",
+ line,
+ str1Lines[line],
+ str2Lines[line]));
+ stringsAreDifferent = true;
+ }
+ }
+
+ if (minLength < longestStringLines.length) {
+ String stringName = ((longestStringLines == str1Lines) ?
+ "first" : "second");
+ messageBuilder.append(String.format("Only %s string contains " +
+ "following lines:\n",
+ stringName));
+ stringsAreDifferent = true;
+ for(int line = minLength; line < longestStringLines.length; line++) {
+ messageBuilder.append(String.
+ format("[line %d] '%s'", line,
+ longestStringLines[line]));
+ }
+ }
+
+ if (stringsAreDifferent) {
+ fail(messageBuilder.toString());
+ }
+ }
+
+ /**
+ * Returns a string formatted with a message and expected and actual values.
+ * @param lhs the actual value
+ * @param rhs the expected value
+ * @param message the actual value
+ * @param relation the asserted relationship between lhs and rhs
+ * @return a formatted string
+ */
+ public static String format(Object lhs, Object rhs, String message, String relation) {
+ StringBuilder sb = new StringBuilder(80);
+ if (message != null) {
+ sb.append(message);
+ sb.append(' ');
+ }
+ sb.append("<");
+ sb.append(Objects.toString(lhs));
+ sb.append("> ");
+ sb.append(Objects.toString(relation, ","));
+ sb.append(" <");
+ sb.append(Objects.toString(rhs));
+ sb.append(">");
+ return sb.toString();
+ }
+
+ /**
+ * Fail reports a failure with message fail.
+ *
+ * @throws RuntimeException always
+ */
+ public static void fail() {
+ fail("fail");
+ }
+
+ /**
+ * Fail reports a failure with a message.
+ * @param message for the failure
+ * @throws RuntimeException always
+ */
+ public static void fail(String message) {
+ throw new RuntimeException(message);
+ }
+
+ /**
+ * Fail reports a failure with a formatted message.
+ *
+ * @param lhs the actual value
+ * @param rhs the expected value
+ * @param message to be format before the expected and actual values
+ * @param relation the asserted relationship between lhs and rhs
+ * @throws RuntimeException always
+ */
+ public static void fail(Object lhs, Object rhs, String message, String relation) {
+ throw new RuntimeException(format(lhs, rhs, message, relation));
+ }
+
+ /**
+ * Fail reports a failure with a message and a cause.
+ * @param message to be format before the expected and actual values
+ * @param cause the exception that caused this failure
+ * @throws RuntimeException always
+ */
+ public static void fail(String message, Throwable cause) {
+ throw new RuntimeException(message, cause);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/JDKToolFinder.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,106 @@
+/*
+ * 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.test.lib;
+
+import java.io.FileNotFoundException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public final class JDKToolFinder {
+
+ private JDKToolFinder() {
+ }
+
+ /**
+ * Returns the full path to an executable in jdk/bin based on System
+ * property {@code test.jdk} or {@code compile.jdk} (both are set by the jtreg test suite)
+ *
+ * @return Full path to an executable in jdk/bin
+ */
+ public static String getJDKTool(String tool) {
+
+ // First try to find the executable in test.jdk
+ try {
+ return getTool(tool, "test.jdk");
+ } catch (FileNotFoundException e) {
+
+ }
+
+ // Now see if it's available in compile.jdk
+ try {
+ return getTool(tool, "compile.jdk");
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException("Failed to find " + tool +
+ ", looked in test.jdk (" + System.getProperty("test.jdk") +
+ ") and compile.jdk (" + System.getProperty("compile.jdk") + ")");
+ }
+ }
+
+ /**
+ * Returns the full path to an executable in jdk/bin based on System
+ * property {@code compile.jdk}
+ *
+ * @return Full path to an executable in jdk/bin
+ */
+ public static String getCompileJDKTool(String tool) {
+ try {
+ return getTool(tool, "compile.jdk");
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Returns the full path to an executable in jdk/bin based on System
+ * property {@code test.jdk}
+ *
+ * @return Full path to an executable in jdk/bin
+ */
+ public static String getTestJDKTool(String tool) {
+ try {
+ return getTool(tool, "test.jdk");
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static String getTool(String tool, String property) throws FileNotFoundException {
+ String jdkPath = System.getProperty(property);
+
+ if (jdkPath == null) {
+ throw new RuntimeException(
+ "System property '" + property + "' not set. This property is normally set by jtreg. "
+ + "When running test separately, set this property using '-D" + property + "=/path/to/jdk'.");
+ }
+
+ Path toolName = Paths.get("bin", tool + (Platform.isWindows() ? ".exe" : ""));
+
+ Path jdkTool = Paths.get(jdkPath, toolName.toString());
+ if (!jdkTool.toFile().exists()) {
+ throw new FileNotFoundException("Could not find file " + jdkTool.toAbsolutePath());
+ }
+
+ return jdkTool.toAbsolutePath().toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/JDKToolLauncher.java Wed Jul 05 21:09:54 2017 +0200
@@ -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.
+ */
+
+package jdk.test.lib;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import jdk.test.lib.process.*;
+
+/**
+ * A utility for constructing command lines for starting JDK tool processes.
+ *
+ * The JDKToolLauncher can in particular be combined with a
+ * java.lang.ProcessBuilder to easily run a JDK tool. For example, the following
+ * code run {@code jmap -heap} against a process with GC logging turned on for
+ * the {@code jmap} process:
+ *
+ * <pre>
+ * {@code
+ * JDKToolLauncher jmap = JDKToolLauncher.create("jmap")
+ * .addVMArg("-XX:+PrintGC");
+ * .addVMArg("-XX:+PrintGCDetails")
+ * .addToolArg("-heap")
+ * .addToolArg(pid);
+ * ProcessBuilder pb = new ProcessBuilder(jmap.getCommand());
+ * Process p = pb.start();
+ * }
+ * </pre>
+ */
+public class JDKToolLauncher {
+ private final String executable;
+ private final List<String> vmArgs = new ArrayList<String>();
+ private final List<String> toolArgs = new ArrayList<String>();
+
+ private JDKToolLauncher(String tool, boolean useCompilerJDK) {
+ if (useCompilerJDK) {
+ executable = JDKToolFinder.getJDKTool(tool);
+ } else {
+ executable = JDKToolFinder.getTestJDKTool(tool);
+ }
+ vmArgs.addAll(Arrays.asList(ProcessTools.getPlatformSpecificVMArgs()));
+ }
+
+ /**
+ * Creates a new JDKToolLauncher for the specified tool. Using tools path
+ * from the compiler JDK.
+ *
+ * @param tool
+ * The name of the tool
+ * @return A new JDKToolLauncher
+ */
+ public static JDKToolLauncher create(String tool) {
+ return new JDKToolLauncher(tool, true);
+ }
+
+ /**
+ * Creates a new JDKToolLauncher for the specified tool in the Tested JDK.
+ *
+ * @param tool
+ * The name of the tool
+ *
+ * @return A new JDKToolLauncher
+ */
+ public static JDKToolLauncher createUsingTestJDK(String tool) {
+ return new JDKToolLauncher(tool, false);
+ }
+
+ /**
+ * Adds an argument to the JVM running the tool.
+ *
+ * The JVM arguments are passed to the underlying JVM running the tool.
+ * Arguments will automatically be prepended with "-J".
+ *
+ * Any platform specific arguments required for running the tool are
+ * automatically added.
+ *
+ *
+ * @param arg
+ * The argument to VM running the tool
+ * @return The JDKToolLauncher instance
+ */
+ public JDKToolLauncher addVMArg(String arg) {
+ vmArgs.add(arg);
+ return this;
+ }
+
+ /**
+ * Adds an argument to the tool.
+ *
+ * @param arg
+ * The argument to the tool
+ * @return The JDKToolLauncher instance
+ */
+ public JDKToolLauncher addToolArg(String arg) {
+ toolArgs.add(arg);
+ return this;
+ }
+
+ /**
+ * Returns the command that can be used for running the tool.
+ *
+ * @return An array whose elements are the arguments of the command.
+ */
+ public String[] getCommand() {
+ List<String> command = new ArrayList<String>();
+ command.add(executable);
+ // Add -J in front of all vmArgs
+ for (String arg : vmArgs) {
+ command.add("-J" + arg);
+ }
+ command.addAll(toolArgs);
+ return command.toArray(new String[command.size()]);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/Platform.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,206 @@
+/*
+ * 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.test.lib;
+
+import java.util.regex.Pattern;
+
+public class Platform {
+ private static final String osName = System.getProperty("os.name");
+ private static final String dataModel = System.getProperty("sun.arch.data.model");
+ private static final String vmVersion = System.getProperty("java.vm.version");
+ private static final String javaVersion = System.getProperty("java.version");
+ private static final String osArch = System.getProperty("os.arch");
+ private static final String vmName = System.getProperty("java.vm.name");
+ private static final String userName = System.getProperty("user.name");
+ private static final String compiler = System.getProperty("sun.management.compiler");
+
+ public static boolean isClient() {
+ return vmName.endsWith(" Client VM");
+ }
+
+ public static boolean isServer() {
+ return vmName.endsWith(" Server VM");
+ }
+
+ public static boolean isGraal() {
+ return vmName.endsWith(" Graal VM");
+ }
+
+ public static boolean isZero() {
+ return vmName.endsWith(" Zero VM");
+ }
+
+ public static boolean isMinimal() {
+ return vmName.endsWith(" Minimal VM");
+ }
+
+ public static boolean isEmbedded() {
+ return vmName.contains("Embedded");
+ }
+
+ public static boolean isTieredSupported() {
+ return compiler.contains("Tiered Compilers");
+ }
+
+ public static boolean is32bit() {
+ return dataModel.equals("32");
+ }
+
+ public static boolean is64bit() {
+ return dataModel.equals("64");
+ }
+
+ public static boolean isAix() {
+ return isOs("aix");
+ }
+
+ public static boolean isLinux() {
+ return isOs("linux");
+ }
+
+ public static boolean isOSX() {
+ return isOs("mac");
+ }
+
+ public static boolean isSolaris() {
+ return isOs("sunos");
+ }
+
+ public static boolean isWindows() {
+ return isOs("win");
+ }
+
+ private static boolean isOs(String osname) {
+ return osName.toLowerCase().startsWith(osname.toLowerCase());
+ }
+
+ public static String getOsName() {
+ return osName;
+ }
+
+ public static boolean isDebugBuild() {
+ return (vmVersion.toLowerCase().contains("debug") ||
+ javaVersion.toLowerCase().contains("debug"));
+ }
+
+ public static String getVMVersion() {
+ return vmVersion;
+ }
+
+ // Returns true for sparc and sparcv9.
+ public static boolean isSparc() {
+ return isArch("sparc.*");
+ }
+
+ public static boolean isARM() {
+ return isArch("arm.*");
+ }
+
+ public static boolean isPPC() {
+ return isArch("ppc.*");
+ }
+
+ public static boolean isX86() {
+ // On Linux it's 'i386', Windows 'x86' without '_64' suffix.
+ return isArch("(i386)|(x86(?!_64))");
+ }
+
+ public static boolean isX64() {
+ // On OSX it's 'x86_64' and on other (Linux, Windows and Solaris) platforms it's 'amd64'
+ return isArch("(amd64)|(x86_64)");
+ }
+
+ public static boolean isAArch64() {
+ return isArch("aarch64");
+ }
+
+ private static boolean isArch(String archnameRE) {
+ return Pattern.compile(archnameRE, Pattern.CASE_INSENSITIVE)
+ .matcher(osArch)
+ .matches();
+ }
+
+ public static String getOsArch() {
+ return osArch;
+ }
+
+ /**
+ * Return a boolean for whether we expect to be able to attach
+ * the SA to our own processes on this system.
+ */
+ public static boolean shouldSAAttach() throws Exception {
+
+ if (isAix()) {
+ return false; // SA not implemented.
+ } else if (isLinux()) {
+ return canPtraceAttachLinux();
+ } else if (isOSX()) {
+ return canAttachOSX();
+ } else {
+ // Other platforms expected to work:
+ return true;
+ }
+ }
+
+ /**
+ * On Linux, first check the SELinux boolean "deny_ptrace" and return false
+ * as we expect to be denied if that is "1". Then expect permission to attach
+ * if we are root, so return true. Then return false for an expected denial
+ * if "ptrace_scope" is 1, and true otherwise.
+ */
+ public static boolean canPtraceAttachLinux() throws Exception {
+
+ // SELinux deny_ptrace:
+ String deny_ptrace = Utils.fileAsString("/sys/fs/selinux/booleans/deny_ptrace");
+ if (deny_ptrace != null && deny_ptrace.contains("1")) {
+ // ptrace will be denied:
+ return false;
+ }
+
+ // YAMA enhanced security ptrace_scope:
+ // 0 - a process can PTRACE_ATTACH to any other process running under the same uid
+ // 1 - restricted ptrace: a process must be a children of the inferior or user is root
+ // 2 - only processes with CAP_SYS_PTRACE may use ptrace or user is root
+ // 3 - no attach: no processes may use ptrace with PTRACE_ATTACH
+ String ptrace_scope = Utils.fileAsString("/proc/sys/kernel/yama/ptrace_scope");
+ if (ptrace_scope != null) {
+ if (ptrace_scope.startsWith("3")) {
+ return false;
+ }
+ if (!userName.equals("root") && !ptrace_scope.startsWith("0")) {
+ // ptrace will be denied:
+ return false;
+ }
+ }
+ // Otherwise expect to be permitted:
+ return true;
+ }
+
+ /**
+ * On OSX, expect permission to attach only if we are root.
+ */
+ public static boolean canAttachOSX() throws Exception {
+ return userName.equals("root");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/Utils.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,640 @@
+/*
+ * 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.test.lib;
+
+import java.io.File;
+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.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import sun.misc.Unsafe;
+
+import jdk.test.lib.process.*;
+import static jdk.test.lib.Asserts.assertTrue;
+
+/**
+ * Common library for various test helper functions.
+ */
+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.
+ */
+ public static final String NEW_LINE = System.getProperty("line.separator");
+
+ /**
+ * Returns the value of 'test.vm.opts' system property.
+ */
+ public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim();
+
+ /**
+ * Returns the value of 'test.java.opts' system property.
+ */
+ 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;
+
+ /**
+ * Defines property name for seed value.
+ */
+ public static final String SEED_PROPERTY_NAME = "jdk.test.lib.random.seed";
+
+ /* (non-javadoc)
+ * Random generator with (or without) predefined seed. Depends on
+ * "jdk.test.lib.random.seed" property value.
+ */
+ private static volatile Random RANDOM_GENERATOR;
+
+ /**
+ * Contains the seed value used for {@link java.util.Random} creation.
+ */
+ public static final long SEED = Long.getLong(SEED_PROPERTY_NAME, new Random().nextLong());
+ /**
+ * Returns the value of 'test.timeout.factor' system property
+ * converted to {@code double}.
+ */
+ public static final double TIMEOUT_FACTOR;
+ static {
+ String toFactor = System.getProperty("test.timeout.factor", "1.0");
+ TIMEOUT_FACTOR = Double.parseDouble(toFactor);
+ }
+
+ /**
+ * Returns the value of JTREG default test timeout in milliseconds
+ * converted to {@code long}.
+ */
+ public static final long DEFAULT_TEST_TIMEOUT = TimeUnit.SECONDS.toMillis(120);
+
+ private Utils() {
+ // Private constructor to prevent class instantiation
+ }
+
+ /**
+ * Returns the list of VM options.
+ *
+ * @return List of VM options
+ */
+ public static List<String> getVmOptions() {
+ return Arrays.asList(safeSplitString(VM_OPTIONS));
+ }
+
+ /**
+ * Returns the list of VM options with -J prefix.
+ *
+ * @return The list of VM options with -J prefix
+ */
+ public static List<String> getForwardVmOptions() {
+ String[] opts = safeSplitString(VM_OPTIONS);
+ for (int i = 0; i < opts.length; i++) {
+ opts[i] = "-J" + opts[i];
+ }
+ return Arrays.asList(opts);
+ }
+
+ /**
+ * Returns the default JTReg arguments for a jvm running a test.
+ * This is the combination of JTReg arguments test.vm.opts and test.java.opts.
+ * @return An array of options, or an empty array if no options.
+ */
+ public static String[] getTestJavaOpts() {
+ List<String> opts = new ArrayList<String>();
+ Collections.addAll(opts, safeSplitString(VM_OPTIONS));
+ Collections.addAll(opts, safeSplitString(JAVA_OPTIONS));
+ return opts.toArray(new String[0]);
+ }
+
+ /**
+ * Combines given arguments with default JTReg arguments for a jvm running a test.
+ * This is the combination of JTReg arguments test.vm.opts and test.java.opts
+ * @return The combination of JTReg test java options and user args.
+ */
+ public static String[] addTestJavaOpts(String... userArgs) {
+ List<String> opts = new ArrayList<String>();
+ Collections.addAll(opts, getTestJavaOpts());
+ Collections.addAll(opts, userArgs);
+ return opts.toArray(new String[0]);
+ }
+
+ /**
+ * Removes any options specifying which GC to use, for example "-XX:+UseG1GC".
+ * Removes any options matching: -XX:(+/-)Use*GC
+ * Used when a test need to set its own GC version. Then any
+ * GC specified by the framework must first be removed.
+ * @return A copy of given opts with all GC options removed.
+ */
+ private static final Pattern useGcPattern = Pattern.compile(
+ "(?:\\-XX\\:[\\+\\-]Use.+GC)"
+ + "|(?:\\-Xconcgc)");
+ public static List<String> removeGcOpts(List<String> opts) {
+ List<String> optsWithoutGC = new ArrayList<String>();
+ for (String opt : opts) {
+ if (useGcPattern.matcher(opt).matches()) {
+ System.out.println("removeGcOpts: removed " + opt);
+ } else {
+ optsWithoutGC.add(opt);
+ }
+ }
+ return optsWithoutGC;
+ }
+
+ /**
+ * Returns the default JTReg arguments for a jvm running a test without
+ * options that matches regular expressions in {@code filters}.
+ * This is the combination of JTReg arguments test.vm.opts and test.java.opts.
+ * @param filters Regular expressions used to filter out options.
+ * @return An array of options, or an empty array if no options.
+ */
+ public static String[] getFilteredTestJavaOpts(String... filters) {
+ String options[] = getTestJavaOpts();
+
+ if (filters.length == 0) {
+ return options;
+ }
+
+ List<String> filteredOptions = new ArrayList<String>(options.length);
+ Pattern patterns[] = new Pattern[filters.length];
+ for (int i = 0; i < filters.length; i++) {
+ patterns[i] = Pattern.compile(filters[i]);
+ }
+
+ for (String option : options) {
+ boolean matched = false;
+ for (int i = 0; i < patterns.length && !matched; i++) {
+ Matcher matcher = patterns[i].matcher(option);
+ matched = matcher.find();
+ }
+ if (!matched) {
+ filteredOptions.add(option);
+ }
+ }
+
+ return filteredOptions.toArray(new String[filteredOptions.size()]);
+ }
+
+ /**
+ * Splits a string by white space.
+ * Works like String.split(), but returns an empty array
+ * if the string is null or empty.
+ */
+ private static String[] safeSplitString(String s) {
+ if (s == null || s.trim().isEmpty()) {
+ return new String[] {};
+ }
+ return s.trim().split("\\s+");
+ }
+
+ /**
+ * @return The full command line for the ProcessBuilder.
+ */
+ public static String getCommandLine(ProcessBuilder pb) {
+ StringBuilder cmd = new StringBuilder();
+ for (String s : pb.command()) {
+ cmd.append(s).append(" ");
+ }
+ return cmd.toString();
+ }
+
+ /**
+ * Returns the free port on the local host.
+ * The function will spin until a valid port number is found.
+ *
+ * @return The port number
+ * @throws InterruptedException if any thread has interrupted the current thread
+ * @throws IOException if an I/O error occurs when opening the socket
+ */
+ public static int getFreePort() throws InterruptedException, IOException {
+ int port = -1;
+
+ while (port <= 0) {
+ Thread.sleep(100);
+
+ ServerSocket serverSocket = null;
+ try {
+ serverSocket = new ServerSocket(0);
+ port = serverSocket.getLocalPort();
+ } finally {
+ serverSocket.close();
+ }
+ }
+
+ return port;
+ }
+
+ /**
+ * Returns the name of the local host.
+ *
+ * @return The host name
+ * @throws UnknownHostException if IP address of a host could not be determined
+ */
+ public static String getHostname() throws UnknownHostException {
+ InetAddress inetAddress = InetAddress.getLocalHost();
+ String hostName = inetAddress.getHostName();
+
+ assertTrue((hostName != null && !hostName.isEmpty()),
+ "Cannot get hostname");
+
+ return hostName;
+ }
+
+ /**
+ * Uses "jcmd -l" to search for a jvm pid. This function will wait
+ * forever (until jtreg timeout) for the pid to be found.
+ * @param key Regular expression to search for
+ * @return The found pid.
+ */
+ public static int waitForJvmPid(String key) throws Throwable {
+ final long iterationSleepMillis = 250;
+ System.out.println("waitForJvmPid: Waiting for key '" + key + "'");
+ System.out.flush();
+ while (true) {
+ int pid = tryFindJvmPid(key);
+ if (pid >= 0) {
+ return pid;
+ }
+ Thread.sleep(iterationSleepMillis);
+ }
+ }
+
+ /**
+ * Searches for a jvm pid in the output from "jcmd -l".
+ *
+ * Example output from jcmd is:
+ * 12498 sun.tools.jcmd.JCmd -l
+ * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar
+ *
+ * @param key A regular expression to search for.
+ * @return The found pid, or -1 if not found.
+ * @throws Exception If multiple matching jvms are found.
+ */
+ public static int tryFindJvmPid(String key) throws Throwable {
+ OutputAnalyzer output = null;
+ try {
+ JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd");
+ jcmdLauncher.addToolArg("-l");
+ output = ProcessTools.executeProcess(jcmdLauncher.getCommand());
+ output.shouldHaveExitValue(0);
+
+ // Search for a line starting with numbers (pid), follwed by the key.
+ Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n");
+ Matcher matcher = pattern.matcher(output.getStdout());
+
+ int pid = -1;
+ if (matcher.find()) {
+ pid = Integer.parseInt(matcher.group(1));
+ System.out.println("findJvmPid.pid: " + pid);
+ if (matcher.find()) {
+ throw new Exception("Found multiple JVM pids for key: " + key);
+ }
+ }
+ return pid;
+ } catch (Throwable t) {
+ System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t));
+ throw t;
+ }
+ }
+
+ /**
+ * Adjusts the provided timeout value for the TIMEOUT_FACTOR
+ * @param tOut the timeout value to be adjusted
+ * @return The timeout value adjusted for the value of "test.timeout.factor"
+ * system property
+ */
+ public static long adjustTimeout(long tOut) {
+ return Math.round(tOut * Utils.TIMEOUT_FACTOR);
+ }
+
+ /**
+ * Return the contents of the named file as a single String,
+ * or null if not found.
+ * @param filename name of the file to read
+ * @return String contents of file, or null if file not found.
+ * @throws IOException
+ * if an I/O error occurs reading from the file or a malformed or
+ * unmappable byte sequence is read
+ */
+ public static String fileAsString(String filename) throws IOException {
+ Path filePath = Paths.get(filename);
+ if (!Files.exists(filePath)) return null;
+ return new String(Files.readAllBytes(filePath));
+ }
+
+ /**
+ * @return Unsafe instance.
+ */
+ public static synchronized Unsafe getUnsafe() {
+ if (unsafe == null) {
+ try {
+ Field f = Unsafe.class.getDeclaredField("theUnsafe");
+ f.setAccessible(true);
+ unsafe = (Unsafe) f.get(null);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ throw new RuntimeException("Unable to get Unsafe instance.", e);
+ }
+ }
+ return unsafe;
+ }
+ private static final char[] hexArray = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ /**
+ * Returns hex view of byte array
+ *
+ * @param bytes byte array to process
+ * @return Space separated hexadecimal string representation of bytes
+ */
+
+ public static String toHexString(byte[] bytes) {
+ char[] hexView = new char[bytes.length * 3];
+ int i = 0;
+ for (byte b : bytes) {
+ hexView[i++] = hexArray[(b >> 4) & 0x0F];
+ hexView[i++] = hexArray[b & 0x0F];
+ hexView[i++] = ' ';
+ }
+ return new String(hexView);
+ }
+
+ /**
+ * Returns {@link java.util.Random} generator initialized with particular seed.
+ * The seed could be provided via system property {@link Utils#SEED_PROPERTY_NAME}
+ * In case no seed is provided, the method uses a random number.
+ * The used seed printed to stdout.
+ * @return {@link java.util.Random} generator with particular seed.
+ */
+ public static Random getRandomInstance() {
+ if (RANDOM_GENERATOR == null) {
+ synchronized (Utils.class) {
+ if (RANDOM_GENERATOR == null) {
+ RANDOM_GENERATOR = new Random(SEED);
+ System.out.printf("For random generator using seed: %d%n", SEED);
+ System.out.printf("To re-run test with same seed value please add \"-D%s=%d\" to command line.%n", SEED_PROPERTY_NAME, SEED);
+ }
+ }
+ }
+ return RANDOM_GENERATOR;
+ }
+
+ /**
+ * Returns random element of non empty collection
+ *
+ * @param <T> a type of collection element
+ * @param collection collection of elements
+ * @return random element of collection
+ * @throws IllegalArgumentException if collection is empty
+ */
+ public static <T> T getRandomElement(Collection<T> collection)
+ throws IllegalArgumentException {
+ if (collection.isEmpty()) {
+ throw new IllegalArgumentException("Empty collection");
+ }
+ Random random = getRandomInstance();
+ int elementIndex = 1 + random.nextInt(collection.size() - 1);
+ Iterator<T> iterator = collection.iterator();
+ while (--elementIndex != 0) {
+ iterator.next();
+ }
+ return iterator.next();
+ }
+
+ /**
+ * Wait for condition to be true
+ *
+ * @param condition, a condition to wait for
+ */
+ public static final void waitForCondition(BooleanSupplier condition) {
+ waitForCondition(condition, -1L, 100L);
+ }
+
+ /**
+ * Wait until timeout for condition to be true
+ *
+ * @param condition, a condition to wait for
+ * @param timeout a time in milliseconds to wait for condition to be true
+ * specifying -1 will wait forever
+ * @return condition value, to determine if wait was successful
+ */
+ public static final boolean waitForCondition(BooleanSupplier condition,
+ long timeout) {
+ return waitForCondition(condition, timeout, 100L);
+ }
+
+ /**
+ * Wait until timeout for condition to be true for specified time
+ *
+ * @param condition, a condition to wait for
+ * @param timeout a time in milliseconds to wait for condition to be true,
+ * specifying -1 will wait forever
+ * @param sleepTime a time to sleep value in milliseconds
+ * @return condition value, to determine if wait was successful
+ */
+ public static final boolean waitForCondition(BooleanSupplier condition,
+ long timeout, long sleepTime) {
+ long startTime = System.currentTimeMillis();
+ while (!(condition.getAsBoolean() || (timeout != -1L
+ && ((System.currentTimeMillis() - startTime) > timeout)))) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new Error(e);
+ }
+ }
+ return condition.getAsBoolean();
+ }
+
+ /**
+ * Interface same as java.lang.Runnable but with
+ * method {@code run()} able to throw any Throwable.
+ */
+ public static interface ThrowingRunnable {
+ void run() throws Throwable;
+ }
+
+ /**
+ * Filters out an exception that may be thrown by the given
+ * test according to the given filter.
+ *
+ * @param test - method that is invoked and checked for exception.
+ * @param filter - function that checks if the thrown exception matches
+ * criteria given in the filter's implementation.
+ * @return - exception that matches the filter if it has been thrown or
+ * {@code null} otherwise.
+ * @throws Throwable - if test has thrown an exception that does not
+ * match the filter.
+ */
+ public static Throwable filterException(ThrowingRunnable test,
+ Function<Throwable, Boolean> filter) throws Throwable {
+ try {
+ test.run();
+ } catch (Throwable t) {
+ if (filter.apply(t)) {
+ return t;
+ } else {
+ throw t;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 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.
+ * @param runnable what we run
+ * @param expectedException expected exception
+ */
+ public static void runAndCheckException(Runnable runnable, Class<? extends Throwable> 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<Throwable> checkException) {
+ try {
+ runnable.run();
+ checkException.accept(null);
+ } catch (Throwable 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;
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/process/OutputAnalyzer.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,436 @@
+/*
+ * 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.test.lib.process;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class OutputAnalyzer {
+
+ private final String stdout;
+ private final String stderr;
+ private final int exitValue;
+
+ /**
+ * Create an OutputAnalyzer, a utility class for verifying output and exit
+ * value from a Process
+ *
+ * @param process Process to analyze
+ * @throws IOException If an I/O error occurs.
+ */
+ public OutputAnalyzer(Process process) throws IOException {
+ OutputBuffer output = ProcessTools.getOutput(process);
+ exitValue = process.exitValue();
+ this.stdout = output.getStdout();
+ this.stderr = output.getStderr();
+ }
+
+ /**
+ * Create an OutputAnalyzer, a utility class for verifying output
+ *
+ * @param buf String buffer to analyze
+ */
+ public OutputAnalyzer(String buf) {
+ this(buf, buf);
+ }
+
+ /**
+ * Create an OutputAnalyzer, a utility class for verifying output
+ *
+ * @param stdout stdout buffer to analyze
+ * @param stderr stderr buffer to analyze
+ */
+ public OutputAnalyzer(String stdout, String stderr) {
+ this.stdout = stdout;
+ this.stderr = stderr;
+ exitValue = -1;
+ }
+
+ /**
+ * Verify that the stdout contents of output buffer is empty
+ *
+ * @throws RuntimeException
+ * If stdout was not empty
+ */
+ public void stdoutShouldBeEmpty() {
+ if (!getStdout().isEmpty()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("stdout was not empty");
+ }
+ }
+
+ /**
+ * Verify that the stderr contents of output buffer is empty
+ *
+ * @throws RuntimeException
+ * If stderr was not empty
+ */
+ public void stderrShouldBeEmpty() {
+ if (!getStderr().isEmpty()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("stderr was not empty");
+ }
+ }
+
+ /**
+ * Verify that the stdout contents of output buffer is not empty
+ *
+ * @throws RuntimeException
+ * If stdout was empty
+ */
+ public void stdoutShouldNotBeEmpty() {
+ if (getStdout().isEmpty()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("stdout was empty");
+ }
+ }
+
+ /**
+ * Verify that the stderr contents of output buffer is not empty
+ *
+ * @throws RuntimeException
+ * If stderr was empty
+ */
+ public void stderrShouldNotBeEmpty() {
+ if (getStderr().isEmpty()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("stderr was empty");
+ }
+ }
+
+ /**
+ * Verify that the stdout and stderr contents of output buffer contains the string
+ *
+ * @param expectedString String that buffer should contain
+ * @throws RuntimeException If the string was not found
+ */
+ public OutputAnalyzer shouldContain(String expectedString) {
+ if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stdout contents of output buffer contains the string
+ *
+ * @param expectedString String that buffer should contain
+ * @throws RuntimeException If the string was not found
+ */
+ public OutputAnalyzer stdoutShouldContain(String expectedString) {
+ if (!stdout.contains(expectedString)) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + expectedString + "' missing from stdout \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stderr contents of output buffer contains the string
+ *
+ * @param expectedString String that buffer should contain
+ * @throws RuntimeException If the string was not found
+ */
+ public OutputAnalyzer stderrShouldContain(String expectedString) {
+ if (!stderr.contains(expectedString)) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + expectedString + "' missing from stderr \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stdout and stderr contents of output buffer does not contain the string
+ *
+ * @param expectedString String that the buffer should not contain
+ * @throws RuntimeException If the string was found
+ */
+ public OutputAnalyzer shouldNotContain(String notExpectedString) {
+ if (stdout.contains(notExpectedString)) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + notExpectedString + "' found in stdout \n");
+ }
+ if (stderr.contains(notExpectedString)) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + notExpectedString + "' found in stderr \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stdout contents of output buffer does not contain the string
+ *
+ * @param expectedString String that the buffer should not contain
+ * @throws RuntimeException If the string was found
+ */
+ public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) {
+ if (stdout.contains(notExpectedString)) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + notExpectedString + "' found in stdout \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stderr contents of output buffer does not contain the string
+ *
+ * @param expectedString String that the buffer should not contain
+ * @throws RuntimeException If the string was found
+ */
+ public OutputAnalyzer stderrShouldNotContain(String notExpectedString) {
+ if (stderr.contains(notExpectedString)) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + notExpectedString + "' found in stderr \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stdout and stderr contents of output buffer matches
+ * the pattern
+ *
+ * @param pattern
+ * @throws RuntimeException If the pattern was not found
+ */
+ public OutputAnalyzer shouldMatch(String pattern) {
+ Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
+ Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
+ if (!stdoutMatcher.find() && !stderrMatcher.find()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + pattern
+ + "' missing from stdout/stderr \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stdout contents of output buffer matches the
+ * pattern
+ *
+ * @param pattern
+ * @throws RuntimeException If the pattern was not found
+ */
+ public OutputAnalyzer stdoutShouldMatch(String pattern) {
+ Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
+ if (!matcher.find()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + pattern
+ + "' missing from stdout \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stderr contents of output buffer matches the
+ * pattern
+ *
+ * @param pattern
+ * @throws RuntimeException If the pattern was not found
+ */
+ public OutputAnalyzer stderrShouldMatch(String pattern) {
+ Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
+ if (!matcher.find()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + pattern
+ + "' missing from stderr \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stdout and stderr contents of output buffer does not
+ * match the pattern
+ *
+ * @param pattern
+ * @throws RuntimeException If the pattern was found
+ */
+ public OutputAnalyzer shouldNotMatch(String pattern) {
+ Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
+ if (matcher.find()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + pattern
+ + "' found in stdout: '" + matcher.group() + "' \n");
+ }
+ matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
+ if (matcher.find()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + pattern
+ + "' found in stderr: '" + matcher.group() + "' \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stdout contents of output buffer does not match the
+ * pattern
+ *
+ * @param pattern
+ * @throws RuntimeException If the pattern was found
+ */
+ public OutputAnalyzer stdoutShouldNotMatch(String pattern) {
+ Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
+ if (matcher.find()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + pattern
+ + "' found in stdout \n");
+ }
+ return this;
+ }
+
+ /**
+ * Verify that the stderr contents of output buffer does not match the
+ * pattern
+ *
+ * @param pattern
+ * @throws RuntimeException If the pattern was found
+ */
+ public OutputAnalyzer stderrShouldNotMatch(String pattern) {
+ Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
+ if (matcher.find()) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("'" + pattern
+ + "' found in stderr \n");
+ }
+ return this;
+ }
+
+ /**
+ * Get the captured group of the first string matching the pattern.
+ * stderr is searched before stdout.
+ *
+ * @param pattern The multi-line pattern to match
+ * @param group The group to capture
+ * @return The matched string or null if no match was found
+ */
+ public String firstMatch(String pattern, int group) {
+ Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
+ Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
+ if (stderrMatcher.find()) {
+ return stderrMatcher.group(group);
+ }
+ if (stdoutMatcher.find()) {
+ return stdoutMatcher.group(group);
+ }
+ return null;
+ }
+
+ /**
+ * Get the first string matching the pattern.
+ * stderr is searched before stdout.
+ *
+ * @param pattern The multi-line pattern to match
+ * @return The matched string or null if no match was found
+ */
+ public String firstMatch(String pattern) {
+ return firstMatch(pattern, 0);
+ }
+
+ /**
+ * Verify the exit value of the process
+ *
+ * @param expectedExitValue Expected exit value from process
+ * @throws RuntimeException If the exit value from the process did not match the expected value
+ */
+ public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) {
+ if (getExitValue() != expectedExitValue) {
+ reportDiagnosticSummary();
+ throw new RuntimeException("Expected to get exit value of ["
+ + expectedExitValue + "]\n");
+ }
+ return this;
+ }
+
+
+ /**
+ * Report summary that will help to diagnose the problem
+ * Currently includes:
+ * - standard input produced by the process under test
+ * - standard output
+ * - exit code
+ * Note: the command line is printed by the ProcessTools
+ */
+ private void reportDiagnosticSummary() {
+ String msg =
+ " stdout: [" + stdout + "];\n" +
+ " stderr: [" + stderr + "]\n" +
+ " exitValue = " + getExitValue() + "\n";
+
+ System.err.println(msg);
+ }
+
+
+ /**
+ * Get the contents of the output buffer (stdout and stderr)
+ *
+ * @return Content of the output buffer
+ */
+ public String getOutput() {
+ return stdout + stderr;
+ }
+
+ /**
+ * Get the contents of the stdout buffer
+ *
+ * @return Content of the stdout buffer
+ */
+ public String getStdout() {
+ return stdout;
+ }
+
+ /**
+ * Get the contents of the stderr buffer
+ *
+ * @return Content of the stderr buffer
+ */
+ public String getStderr() {
+ return stderr;
+ }
+
+ /**
+ * Get the process exit value
+ *
+ * @return Process exit value
+ */
+ public int getExitValue() {
+ return exitValue;
+ }
+
+ /**
+ * Get the contents of the output buffer (stdout and stderr) as list of strings.
+ * Output will be split by newlines.
+ *
+ * @return Contents of the output buffer as list of strings
+ */
+ public List<String> asLines() {
+ return asLines(getOutput());
+ }
+
+ private List<String> asLines(String buffer) {
+ return Arrays.asList(buffer.split("(\\r\\n|\\n|\\r)"));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/process/OutputBuffer.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.test.lib.process;
+
+public class OutputBuffer {
+ private final String stdout;
+ private final String stderr;
+
+ /**
+ * Create an OutputBuffer, a class for storing and managing stdout and stderr
+ * results separately
+ *
+ * @param stdout stdout result
+ * @param stderr stderr result
+ */
+ public OutputBuffer(String stdout, String stderr) {
+ this.stdout = stdout;
+ this.stderr = stderr;
+ }
+
+ /**
+ * Returns the stdout result
+ *
+ * @return stdout result
+ */
+ public String getStdout() {
+ return stdout;
+ }
+
+ /**
+ * Returns the stderr result
+ *
+ * @return stderr result
+ */
+ public String getStderr() {
+ return stderr;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/process/ProcessTools.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,590 @@
+/*
+ * 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.test.lib.process;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.concurrent.CountDownLatch;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Predicate;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.Platform;
+import jdk.test.lib.Utils;
+
+public final class ProcessTools {
+ private static final class LineForwarder extends StreamPumper.LinePump {
+ private final PrintStream ps;
+ private final String prefix;
+ LineForwarder(String prefix, PrintStream os) {
+ this.ps = os;
+ this.prefix = prefix;
+ }
+ @Override
+ protected void processLine(String line) {
+ ps.println("[" + prefix + "] " + line);
+ }
+ }
+
+ private ProcessTools() {
+ }
+
+ /**
+ * Pumps stdout and stderr from running the process into a String.
+ *
+ * @param processHandler ProcessHandler to run.
+ * @return Output from process.
+ * @throws IOException If an I/O error occurs.
+ */
+ public static OutputBuffer getOutput(ProcessBuilder processBuilder) throws IOException {
+ return getOutput(processBuilder.start());
+ }
+
+ /**
+ * Pumps stdout and stderr the running process into a String.
+ *
+ * @param process Process to pump.
+ * @return Output from process.
+ * @throws IOException If an I/O error occurs.
+ */
+ public static OutputBuffer getOutput(Process process) throws IOException {
+ ByteArrayOutputStream stderrBuffer = new ByteArrayOutputStream();
+ ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream();
+ StreamPumper outPumper = new StreamPumper(process.getInputStream(), stdoutBuffer);
+ StreamPumper errPumper = new StreamPumper(process.getErrorStream(), stderrBuffer);
+ Thread outPumperThread = new Thread(outPumper);
+ Thread errPumperThread = new Thread(errPumper);
+
+ outPumperThread.setDaemon(true);
+ errPumperThread.setDaemon(true);
+
+ outPumperThread.start();
+ errPumperThread.start();
+
+ try {
+ process.waitFor();
+ outPumperThread.join();
+ errPumperThread.join();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return null;
+ }
+
+ return new OutputBuffer(stdoutBuffer.toString(), stderrBuffer.toString());
+ }
+
+ /**
+ * <p>Starts a process from its builder.</p>
+ * <span>The default redirects of STDOUT and STDERR are started</span>
+ * @param name The process name
+ * @param processBuilder The process builder
+ * @return Returns the initialized process
+ * @throws IOException
+ */
+ public static Process startProcess(String name,
+ ProcessBuilder processBuilder)
+ throws IOException {
+ return startProcess(name, processBuilder, (Consumer<String>)null);
+ }
+
+ /**
+ * <p>Starts a process from its builder.</p>
+ * <span>The default redirects of STDOUT and STDERR are started</span>
+ * <p>It is possible to monitor the in-streams via the provided {@code consumer}
+ * @param name The process name
+ * @param consumer {@linkplain Consumer} instance to process the in-streams
+ * @param processBuilder The process builder
+ * @return Returns the initialized process
+ * @throws IOException
+ */
+ @SuppressWarnings("overloads")
+ public static Process startProcess(String name,
+ ProcessBuilder processBuilder,
+ Consumer<String> consumer)
+ throws IOException {
+ try {
+ return startProcess(name, processBuilder, consumer, null, -1, TimeUnit.NANOSECONDS);
+ } catch (InterruptedException | TimeoutException e) {
+ // will never happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * <p>Starts a process from its builder.</p>
+ * <span>The default redirects of STDOUT and STDERR are started</span>
+ * <p>
+ * It is possible to wait for the process to get to a warmed-up state
+ * via {@linkplain Predicate} condition on the STDOUT
+ * </p>
+ * @param name The process name
+ * @param processBuilder The process builder
+ * @param linePredicate The {@linkplain Predicate} to use on the STDOUT
+ * Used to determine the moment the target app is
+ * properly warmed-up.
+ * It can be null - in that case the warmup is skipped.
+ * @param timeout The timeout for the warmup waiting; -1 = no wait; 0 = wait forever
+ * @param unit The timeout {@linkplain TimeUnit}
+ * @return Returns the initialized {@linkplain Process}
+ * @throws IOException
+ * @throws InterruptedException
+ * @throws TimeoutException
+ */
+ public static Process startProcess(String name,
+ ProcessBuilder processBuilder,
+ final Predicate<String> linePredicate,
+ long timeout,
+ TimeUnit unit)
+ throws IOException, InterruptedException, TimeoutException {
+ return startProcess(name, processBuilder, null, linePredicate, timeout, unit);
+ }
+
+ /**
+ * <p>Starts a process from its builder.</p>
+ * <span>The default redirects of STDOUT and STDERR are started</span>
+ * <p>
+ * It is possible to wait for the process to get to a warmed-up state
+ * via {@linkplain Predicate} condition on the STDOUT and monitor the
+ * in-streams via the provided {@linkplain Consumer}
+ * </p>
+ * @param name The process name
+ * @param processBuilder The process builder
+ * @param lineConsumer The {@linkplain Consumer} the lines will be forwarded to
+ * @param linePredicate The {@linkplain Predicate} to use on the STDOUT
+ * Used to determine the moment the target app is
+ * properly warmed-up.
+ * It can be null - in that case the warmup is skipped.
+ * @param timeout The timeout for the warmup waiting; -1 = no wait; 0 = wait forever
+ * @param unit The timeout {@linkplain TimeUnit}
+ * @return Returns the initialized {@linkplain Process}
+ * @throws IOException
+ * @throws InterruptedException
+ * @throws TimeoutException
+ */
+ public static Process startProcess(String name,
+ ProcessBuilder processBuilder,
+ final Consumer<String> lineConsumer,
+ final Predicate<String> linePredicate,
+ long timeout,
+ TimeUnit unit)
+ throws IOException, InterruptedException, TimeoutException {
+ System.out.println("["+name+"]:" + processBuilder.command().stream().collect(Collectors.joining(" ")));
+ Process p = processBuilder.start();
+ StreamPumper stdout = new StreamPumper(p.getInputStream());
+ StreamPumper stderr = new StreamPumper(p.getErrorStream());
+
+ stdout.addPump(new LineForwarder(name, System.out));
+ stderr.addPump(new LineForwarder(name, System.err));
+ if (lineConsumer != null) {
+ StreamPumper.LinePump pump = new StreamPumper.LinePump() {
+ @Override
+ protected void processLine(String line) {
+ lineConsumer.accept(line);
+ }
+ };
+ stdout.addPump(pump);
+ stderr.addPump(pump);
+ }
+
+
+ CountDownLatch latch = new CountDownLatch(1);
+ if (linePredicate != null) {
+ StreamPumper.LinePump pump = new StreamPumper.LinePump() {
+ @Override
+ protected void processLine(String line) {
+ if (latch.getCount() > 0 && linePredicate.test(line)) {
+ latch.countDown();
+ }
+ }
+ };
+ stdout.addPump(pump);
+ stderr.addPump(pump);
+ } else {
+ latch.countDown();
+ }
+ final Future<Void> stdoutTask = stdout.process();
+ final Future<Void> stderrTask = stderr.process();
+
+ try {
+ if (timeout > -1) {
+ if (timeout == 0) {
+ latch.await();
+ } else {
+ if (!latch.await(Utils.adjustTimeout(timeout), unit)) {
+ throw new TimeoutException();
+ }
+ }
+ }
+ } catch (TimeoutException | InterruptedException e) {
+ System.err.println("Failed to start a process (thread dump follows)");
+ for(Map.Entry<Thread, StackTraceElement[]> s : Thread.getAllStackTraces().entrySet()) {
+ printStack(s.getKey(), s.getValue());
+ }
+
+ if (p.isAlive()) {
+ p.destroyForcibly();
+ }
+
+ stdoutTask.cancel(true);
+ stderrTask.cancel(true);
+ throw e;
+ }
+
+ return new ProcessImpl(p, stdoutTask, stderrTask);
+ }
+
+ /**
+ * <p>Starts a process from its builder.</p>
+ * <span>The default redirects of STDOUT and STDERR are started</span>
+ * <p>
+ * It is possible to wait for the process to get to a warmed-up state
+ * via {@linkplain Predicate} condition on the STDOUT. The warm-up will
+ * wait indefinitely.
+ * </p>
+ * @param name The process name
+ * @param processBuilder The process builder
+ * @param linePredicate The {@linkplain Predicate} to use on the STDOUT
+ * Used to determine the moment the target app is
+ * properly warmed-up.
+ * It can be null - in that case the warmup is skipped.
+ * @return Returns the initialized {@linkplain Process}
+ * @throws IOException
+ * @throws InterruptedException
+ * @throws TimeoutException
+ */
+ @SuppressWarnings("overloads")
+ public static Process startProcess(String name,
+ ProcessBuilder processBuilder,
+ final Predicate<String> linePredicate)
+ throws IOException, InterruptedException, TimeoutException {
+ return startProcess(name, processBuilder, linePredicate, 0, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Get the process id of the current running Java process
+ *
+ * @return Process id
+ */
+ public static long getProcessId() throws Exception {
+ return ProcessHandle.current().getPid();
+ }
+
+ /**
+ * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris)
+ *
+ * @return String[] with platform specific arguments, empty if there are
+ * none
+ */
+ public static String[] getPlatformSpecificVMArgs() {
+
+ if (Platform.is64bit() && Platform.isSolaris()) {
+ return new String[] { "-d64" };
+ }
+
+ return new String[] {};
+ }
+
+
+ /**
+ * Create ProcessBuilder using the java launcher from the jdk to be tested and
+ * with any platform specific arguments prepended
+ */
+ public static ProcessBuilder createJavaProcessBuilder(String... command) throws Exception {
+ return createJavaProcessBuilder(false, command);
+ }
+
+ /**
+ * Create ProcessBuilder using the java launcher from the jdk to be tested,
+ * and with any platform specific arguments prepended.
+ *
+ * @param addTestVmAndJavaOptions If true, adds test.vm.opts and test.java.opts
+ * to the java arguments.
+ * @param command Arguments to pass to the java command.
+ * @return The ProcessBuilder instance representing the java command.
+ */
+ public static ProcessBuilder createJavaProcessBuilder(boolean addTestVmAndJavaOptions, String... command) throws Exception {
+ String javapath = JDKToolFinder.getJDKTool("java");
+
+ ArrayList<String> args = new ArrayList<>();
+ args.add(javapath);
+ Collections.addAll(args, getPlatformSpecificVMArgs());
+
+ if (addTestVmAndJavaOptions) {
+ // -cp is needed to make sure the same classpath is used whether the test is
+ // run in AgentVM mode or OtherVM mode. It was added to the hotspot version
+ // of this API as part of 8077608. However, for the jdk version it is only
+ // added when addTestVmAndJavaOptions is true in order to minimize
+ // disruption to existing JDK tests, which have yet to be tested with -cp
+ // being added. At some point -cp should always be added to be consistent
+ // with what the hotspot version does.
+ args.add("-cp");
+ args.add(System.getProperty("java.class.path"));
+ Collections.addAll(args, Utils.getTestJavaOpts());
+ }
+
+ Collections.addAll(args, command);
+
+ // Reporting
+ StringBuilder cmdLine = new StringBuilder();
+ for (String cmd : args)
+ cmdLine.append(cmd).append(' ');
+ System.out.println("Command line: [" + cmdLine.toString() + "]");
+
+ return new ProcessBuilder(args.toArray(new String[args.size()]));
+ }
+
+ private static void printStack(Thread t, StackTraceElement[] stack) {
+ System.out.println("\t" + t +
+ " stack: (length = " + stack.length + ")");
+ if (t != null) {
+ for (StackTraceElement stack1 : stack) {
+ System.out.println("\t" + stack1);
+ }
+ System.out.println();
+ }
+ }
+
+ /**
+ * Executes a test jvm process, waits for it to finish and returns the process output.
+ * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added.
+ * The java from the test.jdk is used to execute the command.
+ *
+ * The command line will be like:
+ * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds
+ *
+ * The jvm process will have exited before this method returns.
+ *
+ * @param cmds User specifed arguments.
+ * @return The output from the process.
+ */
+ public static OutputAnalyzer executeTestJvm(String... cmds) throws Exception {
+ ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds));
+ return executeProcess(pb);
+ }
+
+ /**
+ * Executes a process, waits for it to finish and returns the process output.
+ * The process will have exited before this method returns.
+ * @param pb The ProcessBuilder to execute.
+ * @return The {@linkplain OutputAnalyzer} instance wrapping the process.
+ */
+ public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Exception {
+ OutputAnalyzer output = null;
+ Process p = null;
+ boolean failed = false;
+ try {
+ p = pb.start();
+ output = new OutputAnalyzer(p);
+ p.waitFor();
+
+ return output;
+ } catch (Throwable t) {
+ if (p != null) {
+ p.destroyForcibly().waitFor();
+ }
+
+ failed = true;
+ System.out.println("executeProcess() failed: " + t);
+ throw t;
+ } finally {
+ if (failed) {
+ System.err.println(getProcessLog(pb, output));
+ }
+ }
+ }
+
+ /**
+ * Executes a process, waits for it to finish and returns the process output.
+ *
+ * The process will have exited before this method returns.
+ *
+ * @param cmds The command line to execute.
+ * @return The output from the process.
+ */
+ public static OutputAnalyzer executeProcess(String... cmds) throws Throwable {
+ return executeProcess(new ProcessBuilder(cmds));
+ }
+
+ /**
+ * Used to log command line, stdout, stderr and exit code from an executed process.
+ * @param pb The executed process.
+ * @param output The output from the process.
+ */
+ public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) {
+ String stderr = output == null ? "null" : output.getStderr();
+ String stdout = output == null ? "null" : output.getStdout();
+ String exitValue = output == null ? "null": Integer.toString(output.getExitValue());
+ StringBuilder logMsg = new StringBuilder();
+ final String nl = System.getProperty("line.separator");
+ logMsg.append("--- ProcessLog ---" + nl);
+ logMsg.append("cmd: " + getCommandLine(pb) + nl);
+ logMsg.append("exitvalue: " + exitValue + nl);
+ logMsg.append("stderr: " + stderr + nl);
+ logMsg.append("stdout: " + stdout + nl);
+
+ return logMsg.toString();
+ }
+
+ /**
+ * @return The full command line for the ProcessBuilder.
+ */
+ public static String getCommandLine(ProcessBuilder pb) {
+ if (pb == null) {
+ return "null";
+ }
+ StringBuilder cmd = new StringBuilder();
+ for (String s : pb.command()) {
+ cmd.append(s).append(" ");
+ }
+ return cmd.toString().trim();
+ }
+
+ /**
+ * Executes a process, waits for it to finish, prints the process output
+ * to stdout, and returns the process output.
+ *
+ * The process will have exited before this method returns.
+ *
+ * @param cmds The command line to execute.
+ * @return The {@linkplain OutputAnalyzer} instance wrapping the process.
+ */
+ public static OutputAnalyzer executeCommand(String... cmds)
+ throws Throwable {
+ String cmdLine = Arrays.stream(cmds).collect(Collectors.joining(" "));
+ System.out.println("Command line: [" + cmdLine + "]");
+ OutputAnalyzer analyzer = ProcessTools.executeProcess(cmds);
+ System.out.println(analyzer.getOutput());
+ return analyzer;
+ }
+
+ /**
+ * Executes a process, waits for it to finish, prints the process output
+ * to stdout and returns the process output.
+ *
+ * The process will have exited before this method returns.
+ *
+ * @param pb The ProcessBuilder to execute.
+ * @return The {@linkplain OutputAnalyzer} instance wrapping the process.
+ */
+ public static OutputAnalyzer executeCommand(ProcessBuilder pb)
+ throws Throwable {
+ String cmdLine = pb.command().stream().collect(Collectors.joining(" "));
+ System.out.println("Command line: [" + cmdLine + "]");
+ OutputAnalyzer analyzer = ProcessTools.executeProcess(pb);
+ System.out.println(analyzer.getOutput());
+ return analyzer;
+ }
+
+ private static class ProcessImpl extends Process {
+
+ private final Process p;
+ private final Future<Void> stdoutTask;
+ private final Future<Void> stderrTask;
+
+ public ProcessImpl(Process p, Future<Void> stdoutTask, Future<Void> stderrTask) {
+ this.p = p;
+ this.stdoutTask = stdoutTask;
+ this.stderrTask = stderrTask;
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ return p.getOutputStream();
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ return p.getInputStream();
+ }
+
+ @Override
+ public InputStream getErrorStream() {
+ return p.getErrorStream();
+ }
+
+ @Override
+ public int waitFor() throws InterruptedException {
+ int rslt = p.waitFor();
+ waitForStreams();
+ return rslt;
+ }
+
+ @Override
+ public int exitValue() {
+ return p.exitValue();
+ }
+
+ @Override
+ public void destroy() {
+ p.destroy();
+ }
+
+ @Override
+ public long getPid() {
+ return p.getPid();
+ }
+
+ @Override
+ public boolean isAlive() {
+ return p.isAlive();
+ }
+
+ @Override
+ public Process destroyForcibly() {
+ return p.destroyForcibly();
+ }
+
+ @Override
+ public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException {
+ boolean rslt = p.waitFor(timeout, unit);
+ if (rslt) {
+ waitForStreams();
+ }
+ return rslt;
+ }
+
+ private void waitForStreams() throws InterruptedException {
+ try {
+ stdoutTask.get();
+ } catch (ExecutionException e) {
+ }
+ try {
+ stderrTask.get();
+ } catch (ExecutionException e) {
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/process/StreamPumper.java Wed Jul 05 21:09:54 2017 +0200
@@ -0,0 +1,197 @@
+/*
+ * 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.test.lib.process;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public final class StreamPumper implements Runnable {
+
+ private static final int BUF_SIZE = 256;
+
+ /**
+ * Pump will be called by the StreamPumper to process the incoming data
+ */
+ abstract public static class Pump {
+ abstract void register(StreamPumper d);
+ }
+
+ /**
+ * OutputStream -> Pump adapter
+ */
+ final public static class StreamPump extends Pump {
+ private final OutputStream out;
+ public StreamPump(OutputStream out) {
+ this.out = out;
+ }
+
+ @Override
+ void register(StreamPumper sp) {
+ sp.addOutputStream(out);
+ }
+ }
+
+ /**
+ * Used to process the incoming data line-by-line
+ */
+ abstract public static class LinePump extends Pump {
+ @Override
+ final void register(StreamPumper sp) {
+ sp.addLineProcessor(this);
+ }
+
+ abstract protected void processLine(String line);
+ }
+
+ private final InputStream in;
+ private final Set<OutputStream> outStreams = new HashSet<>();
+ private final Set<LinePump> linePumps = new HashSet<>();
+
+ private final AtomicBoolean processing = new AtomicBoolean(false);
+ private final FutureTask<Void> processingTask = new FutureTask<>(this, null);
+
+ public StreamPumper(InputStream in) {
+ this.in = in;
+ }
+
+ /**
+ * Create a StreamPumper that reads from in and writes to out.
+ *
+ * @param in The stream to read from.
+ * @param out The stream to write to.
+ */
+ public StreamPumper(InputStream in, OutputStream out) {
+ this(in);
+ this.addOutputStream(out);
+ }
+
+ /**
+ * Implements Thread.run(). Continuously read from {@code in} and write to
+ * {@code out} until {@code in} has reached end of stream. Abort on
+ * interruption. Abort on IOExceptions.
+ */
+ @Override
+ public void run() {
+ try (BufferedInputStream is = new BufferedInputStream(in)) {
+ ByteArrayOutputStream lineBos = new ByteArrayOutputStream();
+ byte[] buf = new byte[BUF_SIZE];
+ int len = 0;
+ int linelen = 0;
+
+ while ((len = is.read(buf)) > 0 && !Thread.interrupted()) {
+ for(OutputStream out : outStreams) {
+ out.write(buf, 0, len);
+ }
+ if (!linePumps.isEmpty()) {
+ int i = 0;
+ int lastcrlf = -1;
+ while (i < len) {
+ if (buf[i] == '\n' || buf[i] == '\r') {
+ int bufLinelen = i - lastcrlf - 1;
+ if (bufLinelen > 0) {
+ lineBos.write(buf, lastcrlf + 1, bufLinelen);
+ }
+ linelen += bufLinelen;
+
+ if (linelen > 0) {
+ lineBos.flush();
+ final String line = lineBos.toString();
+ linePumps.stream().forEach((lp) -> {
+ lp.processLine(line);
+ });
+ lineBos.reset();
+ linelen = 0;
+ }
+ lastcrlf = i;
+ }
+
+ i++;
+ }
+ if (lastcrlf == -1) {
+ lineBos.write(buf, 0, len);
+ linelen += len;
+ } else if (lastcrlf < len - 1) {
+ lineBos.write(buf, lastcrlf + 1, len - lastcrlf - 1);
+ linelen += len - lastcrlf - 1;
+ }
+ }
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ for(OutputStream out : outStreams) {
+ try {
+ out.flush();
+ } catch (IOException e) {}
+ }
+ try {
+ in.close();
+ } catch (IOException e) {}
+ }
+ }
+
+ final void addOutputStream(OutputStream out) {
+ outStreams.add(out);
+ }
+
+ final void addLineProcessor(LinePump lp) {
+ linePumps.add(lp);
+ }
+
+ final public StreamPumper addPump(Pump ... pump) {
+ if (processing.get()) {
+ throw new IllegalStateException("Can not modify pumper while " +
+ "processing is in progress");
+ }
+ for(Pump p : pump) {
+ p.register(this);
+ }
+ return this;
+ }
+
+ final public Future<Void> process() {
+ if (!processing.compareAndSet(false, true)) {
+ throw new IllegalStateException("Can not re-run the processing");
+ }
+ Thread t = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ processingTask.run();
+ }
+ });
+ t.setDaemon(true);
+ t.start();
+
+ return processingTask;
+ }
+}