diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index 43b90b329b2..32f36110423 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -340,3 +340,4 @@ cf1dc4c035fb84693d4ae5ad818785cb4d1465d1 jdk9-b90
12a6fb4f070f8ca8fbca219ab9abf5da8908b317 jdk-9+95
5582a79892596169ebddb3e2c2aa44939e4e3f40 jdk-9+96
75c3897541ecb52ee16d001ea605b12971df7303 jdk-9+97
+48987460c7d49a29013963ee44d090194396bb61 jdk-9+98
diff --git a/README b/README
index e1fdec5d4ab..477b38887fc 100644
--- a/README
+++ b/README
@@ -6,7 +6,7 @@ README:
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 @@ README:
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 @@ Simple Build Instructions:
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".
diff --git a/README-builds.html b/README-builds.html
index d81549d5ce4..42cc0f11b7c 100644
--- a/README-builds.html
+++ b/README-builds.html
@@ -250,9 +250,7 @@ Compilers, freetype, cups, and
Mac OS X
-Install XCode 4.5.2 and also
-install the "Command line tools" found under the preferences pane
-"Downloads"
+Install XCode 6.3
@@ -279,39 +277,67 @@ OpenJDK.
Studio Compilers
At a minimum, the Studio 12 Update 1 Compilers (containing
-version 5.10 of the C and C++ compilers) is required, including specific
+technetwork/server-storage/solarisstudio/downloads/index.htm">Studio 12 Update 4 Compilers (containing
+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
-
+
+
+
+
+ Package |
+ Version |
+
+
+
+
+ developer/solarisstudio-124/backend |
+ 12.4-1.0.6.0 |
+
+
+ developer/solarisstudio-124/c++ |
+ 12.4-1.0.10.0 |
+
+
+ developer/solarisstudio-124/cc |
+ 12.4-1.0.4.0 |
+
+
+ developer/solarisstudio-124/library/c++-libs |
+ 12.4-1.0.10.0 |
+
+
+ developer/solarisstudio-124/library/math-libs |
+ 12.4-1.0.0.1 |
+
+
+ developer/solarisstudio-124/library/studio-gccrt |
+ 12.4-1.0.0.1 |
+
+
+ developer/solarisstudio-124/studio-common |
+ 12.4-1.0.0.1 |
+
+
+ developer/solarisstudio-124/studio-ja |
+ 12.4-1.0.0.1 |
+
+
+ developer/solarisstudio-124/studio-legal |
+ 12.4-1.0.0.1 |
+
+
+ developer/solarisstudio-124/studio-zhCN |
+ 12.4-1.0.0.1 |
+
+
+
+
-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
.
@@ -1144,10 +1170,6 @@ where the resulting bits can be used.
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
@@ -1176,7 +1198,7 @@ so that they can be dealt with accordingly.
Linux X86 (32-bit) and X64 (64-bit) |
Oracle Enterprise Linux 6.4 |
- gcc 4.8.2 |
+ gcc 4.9.2 |
JDK 8 |
2 or more |
1 GB |
@@ -1184,8 +1206,8 @@ so that they can be dealt with accordingly.
Solaris SPARCV9 (64-bit) |
- Solaris 10 Update 10 |
- Studio 12 Update 3 + patches |
+ Solaris 11 Update 1 |
+ Studio 12 Update 4 + patches |
JDK 8 |
4 or more |
4 GB |
@@ -1193,8 +1215,8 @@ so that they can be dealt with accordingly.
Solaris X64 (64-bit) |
- Solaris 10 Update 10 |
- Studio 12 Update 3 + patches |
+ Solaris 11 Update 1 |
+ Studio 12 Update 4 + patches |
JDK 8 |
4 or more |
4 GB |
@@ -1221,7 +1243,7 @@ so that they can be dealt with accordingly.
Mac OS X X64 (64-bit) |
Mac OS X 10.9 "Mavericks" |
- XCode 5.1.1 or newer |
+ Xcode 6.3 or newer |
JDK 8 |
2 or more |
4 GB |
diff --git a/README-builds.md b/README-builds.md
index 21367477890..bddb467612e 100644
--- a/README-builds.md
+++ b/README-builds.md
@@ -215,9 +215,7 @@ And for specific systems:
* **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/)
#### Linux
@@ -239,36 +237,66 @@ OpenJDK.
##### 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
+>
+
+
+ **Package** |
+ **Version** |
+
+
+
+
+ developer/solarisstudio-124/backend |
+ 12.4-1.0.6.0 |
+
+
+ developer/solarisstudio-124/c++ |
+ 12.4-1.0.10.0 |
+
+
+ developer/solarisstudio-124/cc |
+ 12.4-1.0.4.0 |
+
+
+ developer/solarisstudio-124/library/c++-libs |
+ 12.4-1.0.10.0 |
+
+
+ developer/solarisstudio-124/library/math-libs |
+ 12.4-1.0.0.1 |
+
+
+ developer/solarisstudio-124/library/studio-gccrt |
+ 12.4-1.0.0.1 |
+
+
+ developer/solarisstudio-124/studio-common |
+ 12.4-1.0.0.1 |
+
+
+ developer/solarisstudio-124/studio-ja |
+ 12.4-1.0.0.1 |
+
+
+ developer/solarisstudio-124/studio-legal |
+ 12.4-1.0.0.1 |
+
+
+ developer/solarisstudio-124/studio-zhCN |
+ 12.4-1.0.0.1 |
+
+
+
-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 @@ where the resulting bits can be used.
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 @@ so that they can be dealt with accordingly.
Linux X86 (32-bit) and X64 (64-bit) |
Oracle Enterprise Linux 6.4 |
- gcc 4.8.2 |
+ gcc 4.9.2 |
JDK 8 |
2 or more |
1 GB |
@@ -1083,8 +1107,8 @@ so that they can be dealt with accordingly.
Solaris SPARCV9 (64-bit) |
- Solaris 10 Update 10 |
- Studio 12 Update 3 + patches |
+ Solaris 11 Update 1 |
+ Studio 12 Update 4 + patches |
JDK 8 |
4 or more |
4 GB |
@@ -1092,8 +1116,8 @@ so that they can be dealt with accordingly.
Solaris X64 (64-bit) |
- Solaris 10 Update 10 |
- Studio 12 Update 3 + patches |
+ Solaris 11 Update 1 |
+ Studio 12 Update 4 + patches |
JDK 8 |
4 or more |
4 GB |
@@ -1120,7 +1144,7 @@ so that they can be dealt with accordingly.
Mac OS X X64 (64-bit) |
Mac OS X 10.9 "Mavericks" |
- XCode 5.1.1 or newer |
+ Xcode 6.3 or newer |
JDK 8 |
2 or more |
4 GB |
diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4
index 74f0ae6af9c..5c2f1b62642 100644
--- a/common/autoconf/build-performance.m4
+++ b/common/autoconf/build-performance.m4
@@ -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_DEFUN_ONCE([BPERF_SETUP_BUILD_JOBS],
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],
diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac
index cafecd5a993..8e2823ba0c9 100644
--- a/common/autoconf/configure.ac
+++ b/common/autoconf/configure.ac
@@ -44,6 +44,7 @@ m4_include([boot-jdk.m4])
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 @@ JDKOPT_SETUP_OPEN_OR_CUSTOM
# 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 @@ BASIC_SETUP_DEFAULT_MAKE_TARGET
# We need build & target for this.
JDKOPT_SETUP_JDK_OPTIONS
+HOTSPOT_SETUP_HOTSPOT_OPTIONS
JDKVER_SETUP_JDK_VERSION_NUMBERS
###############################################################################
@@ -220,7 +223,7 @@ LIB_SETUP_LIBRARIES
#
###############################################################################
-JDKOPT_SETUP_BUILD_TWEAKS
+HOTSPOT_SETUP_BUILD_TWEAKS
JDKOPT_DETECT_INTREE_EC
###############################################################################
@@ -233,6 +236,7 @@ JDKOPT_DETECT_INTREE_EC
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
diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4
index 88f2e89dd6f..af375d28432 100644
--- a/common/autoconf/flags.m4
+++ b/common/autoconf/flags.m4
@@ -120,13 +120,17 @@ AC_DEFUN([FLAGS_SETUP_SYSROOT_FLAGS],
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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS],
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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS],
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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS],
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_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS],
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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK],
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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK],
# 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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK],
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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK],
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.
diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh
index a322c533c01..f5e0859115c 100644
--- a/common/autoconf/generated-configure.sh
+++ b/common/autoconf/generated-configure.sh
@@ -646,11 +646,11 @@ JAVA_FLAGS_SMALL
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 @@ CXXFLAGS_DEBUG_SYMBOLS
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 @@ EXE_OUT_OPTION
CC_OUT_OPTION
STRIPFLAGS
ARFLAGS
+COMPILER_COMMAND_FILE_FLAG
COMPILER_TARGET_BITS_FLAG
JT_HOME
JTREGEXE
@@ -753,6 +755,7 @@ HOTSPOT_CXX
HOTSPOT_RC
HOTSPOT_MT
BUILD_AS
+BUILD_LDCXX
BUILD_LD
BUILD_AR
BUILD_NM
@@ -799,6 +802,7 @@ ac_ct_PROPER_COMPILER_CC
PROPER_COMPILER_CC
TOOLCHAIN_PATH_CC
POTENTIAL_CC
+TOOLCHAIN_VERSION
VS_LIB
VS_INCLUDE
VS_PATH
@@ -857,11 +861,11 @@ JDK_RC_PLATFORM_NAME
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 @@ INCLUDE_SA
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_conf_name
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_dxsdk_include
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 @@ Optional Features:
--with-debug-level=fastdebug) [disabled]
--disable-headful disable building headful support (graphical UI
support) [enabled]
- --enable-hotspot-test-in-build
- run the Queens test after Hotspot build [disabled]
--enable-unlimited-crypto
Enable unlimited crypto policy [disabled]
+ --enable-hotspot-test-in-build
+ run the Queens test after Hotspot build [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 @@ Optional Packages:
--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 @@ Optional Packages:
--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 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
#
-# 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 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
################################################################################
#
# Optionally enable distributed compilation of native code using icecc/icecream
@@ -3939,7 +3946,11 @@ Then run configure with '--with-freetype-src='. This will
automatically build the freetype library into '/lib64' for 64-bit
builds or into '/lib32' for 32-bit builds.
Afterwards you can always use '--with-freetype-include=/include'
-and '--with-freetype-lib=/lib32|64' for other builds."
+and '--with-freetype-lib=/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 @@ pkgadd_help() {
# 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 @@ pkgadd_help() {
-
-
###############################################################################
#
# Enable or disable the elliptic curve crypto implementation
@@ -4064,7 +4140,6 @@ pkgadd_help() {
-
################################################################################
#
# Gcov coverage data for hotspot
@@ -4078,8 +4153,6 @@ pkgadd_help() {
#
-
-
#
# 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 @@ VS_SDK_PLATFORM_NAME_2013=
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1449850507
+DATE_WHEN_GENERATED=1450277321
###############################################################################
#
@@ -15607,17 +15680,6 @@ fi
# 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 @@ fi
$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 @@ if test "${with_jvm_interpreter+set}" = set; then :
fi
-if test "x$with_jvm_interpreter" = x; then
- with_jvm_interpreter="template"
-fi
+ { $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; }
-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
+ 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 variants of the JVM to build" >&5
$as_echo_n "checking which variants of the JVM to build... " >&6; }
@@ -15697,10 +15739,10 @@ fi
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 @@ $as_echo "$with_jvm_variants" >&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_echo "$with_jvm_variants" >&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 @@ $as_echo "$with_jvm_variants" >&6; }
# 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 @@ $as_echo "$with_jvm_variants" >&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 @@ $as_echo "$DEBUG_LEVEL" >&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 @@ $as_echo "$DEBUG_LEVEL" >&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 @@ fi
# 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 @@ $as_echo "$headful_msg" >&6; }
- # 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
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
fi
- ###############################################################################
- #
# Compress jars
- #
COMPRESS_JARS=false
@@ -23232,6 +23226,22 @@ fi
+ # 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,8 +31442,12 @@ $as_echo "$as_me: or run \"bash.exe -l\" from a VS command prompt and then run c
# 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
+
# For solaris we really need solaris tools, and not the GNU equivalent.
# The build tools on Solaris reside in /usr/ccs (C Compilation System),
# so add that to path before starting to probe.
@@ -45214,6 +45228,7 @@ $as_echo "$as_me: Rewriting BUILD_AR to \"$new_complete\"" >&6;}
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 @@ $as_echo "$as_me: Rewriting BUILD_AR to \"$new_complete\"" >&6;}
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 @@ $as_echo "$as_me: Rewriting BUILD_AR to \"$new_complete\"" >&6;}
+
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 @@ $as_echo "$supports" >&6; }
# "-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 @@ $as_echo "$supports" >&6; }
# "-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 "$supports" >&6; }
$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,14 +45922,18 @@ $as_echo "$tool_specified" >&6; }
- # 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
+
# FIXME: figure out if we should select AR flags depending on OS or toolchain.
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
ARFLAGS="-r"
@@ -46646,37 +46667,38 @@ $as_echo "$ac_cv_c_bigendian" >&6; }
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 @@ $as_echo "$ac_cv_c_bigendian" >&6; }
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 @@ $as_echo "$ac_cv_c_bigendian" >&6; }
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 @@ $as_echo "$ac_cv_c_bigendian" >&6; }
+
if test "x$OPENJDK_TARGET_OS" = xsolaris; then
CFLAGS_JDK="${CFLAGS_JDK} -D__solaris__"
CXXFLAGS_JDK="${CXXFLAGS_JDK} -D__solaris__"
@@ -47022,6 +47045,25 @@ $as_echo "$supports" >&6; }
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 @@ $as_echo "$supports" >&6; }
# 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 @@ $as_echo "$supports" >&6; }
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 @@ $as_echo "$supports" >&6; }
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 @@ $as_echo_n "checking what type of native debug symbols to use... " >&6; }
# Check whether --with-native-debug-symbols was given.
if test "${with_native_debug_symbols+set}" = set; then :
withval=$with_native_debug_symbols;
+ 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
- with_native_debug_symbols="zipped"
+
+ 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 @@ $as_echo "$FREETYPE_LIB_PATH" >&6; }
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 @@ fi
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 @@ $as_echo "$JOBS" >&6; }
+ # 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)
##############################################################################
diff --git a/common/autoconf/help.m4 b/common/autoconf/help.m4
index cf977f0598f..df5d0c87554 100644
--- a/common/autoconf/help.m4
+++ b/common/autoconf/help.m4
@@ -86,7 +86,11 @@ Then run configure with '--with-freetype-src='. This will
automatically build the freetype library into '/lib64' for 64-bit
builds or into '/lib32' for 32-bit builds.
Afterwards you can always use '--with-freetype-include=/include'
-and '--with-freetype-lib=/lib[32|64]' for other builds."
+and '--with-freetype-lib=/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
}
diff --git a/common/autoconf/hotspot.m4 b/common/autoconf/hotspot.m4
new file mode 100644
index 00000000000..ec357f99572
--- /dev/null
+++ b/common/autoconf/hotspot.m4
@@ -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)
+])
diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4
index 3f7a29e0abb..5f9ffb2e006 100644
--- a/common/autoconf/jdk-options.m4
+++ b/common/autoconf/jdk-options.m4
@@ -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_DEFUN_ONCE([JDKOPT_SETUP_JDK_VARIANT],
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 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL],
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_OPEN_OR_CUSTOM],
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_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS],
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 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS],
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 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS],
fi
AC_SUBST(UNLIMITED_CRYPTO)
- ###############################################################################
- #
# Compress jars
- #
COMPRESS_JARS=false
AC_SUBST(COMPRESS_JARS)
@@ -455,19 +194,6 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS],
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_DEFUN_ONCE([JDKOPT_DETECT_INTREE_EC],
AC_SUBST(ENABLE_INTREE_EC)
])
-
AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
[
#
@@ -498,8 +223,21 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
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_DEFUN_ONCE([JDKOPT_SETUP_STATIC_BUILD],
AC_SUBST(STATIC_BUILD)
])
-
-
diff --git a/common/autoconf/lib-freetype.m4 b/common/autoconf/lib-freetype.m4
index 06753706bd2..2683fe23b6f 100644
--- a/common/autoconf/lib-freetype.m4
+++ b/common/autoconf/lib-freetype.m4
@@ -321,6 +321,25 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE],
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])
diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in
index 10b65f2592d..86b4761709a 100644
--- a/common/autoconf/spec.gmk.in
+++ b/common/autoconf/spec.gmk.in
@@ -204,13 +204,12 @@ SUPPORT_HEADLESS:=@SUPPORT_HEADLESS@
# 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 @@ SJAVAC_SERVER_DIR=$(MAKESUPPORT_OUTPUTDIR)/javacservers
# 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 @@ FREETYPE_BUNDLE_LIB_PATH=@FREETYPE_BUNDLE_LIB_PATH@
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 @@ MACOSX_VERSION_MIN=@MACOSX_VERSION_MIN@
# 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 @@ LDFLAGS_TESTEXE:=@LDFLAGS_TESTEXE@
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 @@ COMPRESS_JARS=@COMPRESS_JARS@
# (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 @@ PNG_CFLAGS:=@PNG_CFLAGS@
# Misc
#
-# Name of Service Agent library
-SALIB_NAME=@SALIB_NAME@
-
INCLUDE_SA=@INCLUDE_SA@
OS_VERSION_MAJOR:=@OS_VERSION_MAJOR@
diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4
index 0d9fb7cbedd..3f5750dcc89 100644
--- a/common/autoconf/toolchain.m4
+++ b/common/autoconf/toolchain.m4
@@ -216,7 +216,11 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION],
# 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 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS],
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 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS],
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_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS],
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 @@ AC_DEFUN_ONCE([TOOLCHAIN_MISC_CHECKS],
[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_DEFUN_ONCE([TOOLCHAIN_MISC_CHECKS],
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
diff --git a/common/bin/compare.sh b/common/bin/compare.sh
index 0c63bdcbeca..9e680f08b0a 100644
--- a/common/bin/compare.sh
+++ b/common/bin/compare.sh
@@ -37,13 +37,18 @@ fi
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 @@ compare_bin_file() {
# 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 @@ compare_bin_file() {
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 \
diff --git a/common/bin/compare_exceptions.sh.incl b/common/bin/compare_exceptions.sh.incl
index 79ef2f2c6d9..1ee38e29021 100644
--- a/common/bin/compare_exceptions.sh.incl
+++ b/common/bin/compare_exceptions.sh.incl
@@ -57,14 +57,18 @@ ACCEPTED_BIN_DIFF="
./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 @@ ACCEPTED_BIN_DIFF="
./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/g' \
+ -e 's/0x[0-9a-z]\{2,9\}//g'"
fi
if [ "$OPENJDK_TARGET_OS" = "linux" ] && [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; then
@@ -135,6 +150,7 @@ ACCEPTED_BIN_DIFF="
./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 @@ ACCEPTED_BIN_DIFF="
./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 @@ SKIP_FULLDUMP_DIFF="true"
# 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\}//g' \
- -e 's/\([0-9a-f][0-9a-f].\)\{2,8\}[0-9a-f][0-9a-f]//g' \
- -e 's/\(0x\)[0-9a-f]*\([,(>]\)/\1\2/g' \
- -e 's/\(0x\)[0-9a-f]*$/\1/g' \
- -e 's/\(\#.\)[0-9a-f]*\(.<\)/\1\2/g' \
- -e 's/[\.A-Za-z0-9%]\{16,16\}$//g'"
+ -e 's/\.[a-zA-Z0-9_\$]\{15\}//g' \
+ -e 's/\(\# \)[0-9a-f]*\( <\)/\1\2/g' \
+ -e 's/0x[0-9a-f]*$//g' \
+ -e 's/0x[0-9a-f]*\([,(>]\)/\1/g' \
+ -e 's/: [0-9a-f][0-9a-f]\( [0-9a-f][0-9a-f]\)\{2,10\}/: /g' \
+ -e 's/ [\.A-Za-z0-9%@]\{16\}$/ /g'"
fi
@@ -425,18 +446,23 @@ ACCEPTED_SMALL_SIZE_DIFF="
./bin/xjc
"
-# Filter random C++ symbol strings.
# Some numbers differ randomly.
DIS_DIFF_FILTER="$SED \
- -e 's/\$[a-zA-Z0-9_\$]\{15,15\}//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]//g' \
- -e 's/\(%g1,.0x\)[0-9a-f]*\(,.%g1\)/\1\2/g' \
- -e 's/\(!.\)[0-9a-f]*\(.\2/g' \
- -e 's/\!.[0-9a-f]\{1,4\} <_DYNAMIC+0x[0-9a-f]\{1,4\}>//g'"
+ -e 's/\$[a-zA-Z0-9_\$]\{15\}//g' \
+ -e 's/: [0-9a-f][0-9a-f]\( [0-9a-f][0-9a-f]\)\{2,10\}/: /g' \
+ -e 's/, [0-9a-fx\-]\{1,8\}/, /g' \
+ -e 's/call [0-9a-f]\{7\}/call /g' \
+ -e 's/0x[0-9a-f]\{1,8\}//g' \
+ -e 's/\! [0-9a-f]\{1,8\} /! /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 @@ ACCEPTED_BIN_DIFF="
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\}//g'"
+DIS_DIFF_FILTER="LANG=C $SED \
+ -e 's/0x[0-9a-f]\{3,16\}//g' -e 's/^[0-9a-f]\{12,20\}//'"
fi
diff --git a/common/conf/jib-profiles.js b/common/conf/jib-profiles.js
index b9c09fcd018..90d9621c6af 100644
--- a/common/conf/jib-profiles.js
+++ b/common/conf/jib-profiles.js
@@ -357,8 +357,8 @@ var getJibProfilesDependencies = function (input, common) {
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"
};
diff --git a/corba/.hgtags b/corba/.hgtags
index 05a0a1e4423..9a465cddc83 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -340,3 +340,4 @@ f7d70caad89ad0c43bb057bca0aad6f17ce05a6a jdk9-b92
fd038e8a16eec80d0d6b337d74a582790ed4b3ee jdk-9+95
feb1bd85d7990dcf5584ca9e53104269c01db006 jdk-9+96
10a482b863582376d4ca229090334b23b05159fc jdk-9+97
+ea285530245cf4e0edf0479121a41347d3030eba jdk-9+98
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index 68035c56bdd..bd53ef2dfeb 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -500,3 +500,4 @@ a22b7c80529f5f05c847e932e017456e83c46233 jdk9-b94
0c79cf3cdf0904fc4a630b91b32904491e1ae430 jdk-9+95
a94bb7203596dd632486f1e3655fa5f70541dc08 jdk-9+96
de592ea5f7ba0f8a8c5afc03bd169f7690c72b6f jdk-9+97
+e5b1a23be1e105417ba1c4c576ab373eb3fa2c2b jdk-9+98
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
index e200826e467..9c70c9734b9 100644
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
@@ -1446,7 +1446,7 @@ public class CommandProcessor {
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 @@ public class CommandProcessor {
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 @@ public class CommandProcessor {
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 @@ public class CommandProcessor {
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
thread.printThreadIDOn(out);
out.println(" " + thread.getThreadName());
+ thread.printInfoOn(out);
+ out.println("\n...");
}
}
}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
index a6f04042184..406b6d775b9 100644
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
@@ -416,7 +416,7 @@ public class JavaThread extends Thread {
} 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());
diff --git a/hotspot/make/aix/makefiles/xlc.make b/hotspot/make/aix/makefiles/xlc.make
index cf8d085c39a..676ba5c6a6d 100644
--- a/hotspot/make/aix/makefiles/xlc.make
+++ b/hotspot/make/aix/makefiles/xlc.make
@@ -74,6 +74,9 @@ CFLAGS += $(VM_PICFLAG)
CFLAGS += -qnortti
CFLAGS += -qnoeh
+# for compiler-level tls
+CFLAGS += -qtls=default
+
CFLAGS += -D_REENTRANT
# no xlc counterpart for -fcheck-new
# CFLAGS += -fcheck-new
diff --git a/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk b/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk
index a3febc1c302..2c8a2f7f88e 100644
--- a/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk
+++ b/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk
@@ -71,7 +71,7 @@ else ifeq ($(OPENJDK_TARGET_OS), solaris)
-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
diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make
index 7920596193f..835ad2fda3a 100644
--- a/hotspot/make/linux/makefiles/gcc.make
+++ b/hotspot/make/linux/makefiles/gcc.make
@@ -260,6 +260,13 @@ endif
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)
diff --git a/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp
index 96a967fb961..a9cd044a1d8 100644
--- a/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp
@@ -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 @@ address InterpreterGenerator::generate_abstract_entry(void) {
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");
-}
diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
index c9608bc7492..eae6417b08b 100644
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
@@ -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 @@ void MacroAssembler::encode_iso_array(Register src, Register dst,
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);
+}
diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
index 2eb119125f2..369a484c6ec 100644
--- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
@@ -1973,7 +1973,7 @@ class StubGenerator: public StubCodeGenerator {
// 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 @@ class StubGenerator: public StubCodeGenerator {
__ 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);
diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp
new file mode 100644
index 00000000000..b9501b948f1
--- /dev/null
+++ b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp
@@ -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
+
+#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
+#include
+
+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
diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
index fb339033869..314af0b87ab 100644
--- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
@@ -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/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
-
-#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;
-}
+#include "utilities/macros.hpp"
int AbstractInterpreter::BasicType_as_index(BasicType type) {
@@ -279,1195 +53,6 @@ int AbstractInterpreter::BasicType_as_index(BasicType type) {
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 @@ void AbstractInterpreter::layout_activation(Method* method,
*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
-#include
-
-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
diff --git a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp
index 0fbf97085ca..280ebd5148b 100644
--- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp
@@ -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 @@ address InterpreterGenerator::generate_Reference_get_entry(void) {
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");
-}
diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp
new file mode 100644
index 00000000000..1d99393562f
--- /dev/null
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp
@@ -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
diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp
index 361e637d253..5179d817853 100644
--- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp
@@ -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);
+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();
}
-
- // 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();
- }
-
- // 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 @@ void AbstractInterpreter::layout_activation(Method* method,
}
}
-// =============================================================================
-// Exceptions
+// Support abs and sqrt like in compiler.
+// For others we can use a normal (native) entry.
-void TemplateInterpreterGenerator::generate_throw_exception() {
- Register Rexception = R17_tos,
- Rcontinuation = R3_RET;
+bool TemplateInterpreter::math_entry_available(AbstractInterpreter::MethodKind kind) {
+ if (!InlineIntrinsics) return false;
- // --------------------------------------------------------------------------
- // 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();
- }
+ 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
diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp
index 4450dd71897..b9003dd3c4b 100644
--- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp
@@ -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
diff --git a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp
index c5fc75d049f..4e9199fa9d8 100644
--- a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp
@@ -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 @@ address InterpreterGenerator::generate_abstract_entry(void) {
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
diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp
index 59b5b41a0d8..0d069a48ea5 100644
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp
@@ -360,10 +360,10 @@ void MacroAssembler::leave() {
#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 @@ void MacroAssembler::get_thread() {
}
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;
}
diff --git a/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp b/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp
index aa4e4c16bb7..adacfda4ae6 100644
--- a/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp
@@ -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 @@ inline void fill_subword(void* start, void* end, int value) {
" 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 @@ inline void fill_subword(void* start, void* end, int value) {
void memset_with_concurrent_readers(void* to, int value, size_t size) {
Prefetch::write(to, 0);
void* end = static_cast(to) + size;
- if (size >= BytesPerWord) {
+ if (size >= (size_t)BytesPerWord) {
// Fill any partial word prefix.
uintx* aligned_to = static_cast(align_ptr_up(to, BytesPerWord));
fill_subword(to, aligned_to, value);
@@ -144,10 +144,10 @@ void memset_with_concurrent_readers(void* to, int value, size_t size) {
" 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
diff --git a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp
index 3342f51388e..024049ca5b2 100644
--- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp
@@ -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::verify() {
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());
}
diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad
index 15526706f78..3b3a848cdb5 100644
--- a/hotspot/src/cpu/sparc/vm/sparc.ad
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad
@@ -1651,6 +1651,7 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf,
#endif // !_LP64
Unimplemented();
+ return 0;
}
#ifndef PRODUCT
diff --git a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.cpp b/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.cpp
index 3a9ca6fffc9..f8083c0f273 100644
--- a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.cpp
@@ -36,7 +36,7 @@ extern "C" {
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.");
diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp
new file mode 100644
index 00000000000..31545256045
--- /dev/null
+++ b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp
@@ -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
diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
index a76004f786d..04d15c42693 100644
--- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
@@ -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();
+int AbstractInterpreter::BasicType_as_index(BasicType type) {
+ int i = 0;
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;
+ 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();
}
- __ ret(); // return from interpreter activation
- __ delayed()->restore(I5_savedSP, G0, SP); // remove interpreter frame
- NOT_PRODUCT(__ emit_int32(0);) // marker for disassembly
- return entry;
+ assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds");
+ return i;
}
-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;
+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 @@ void AbstractInterpreter::layout_activation(Method* method,
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
diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp
index 08a293f99a2..de467071b1b 100644
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp
@@ -175,6 +175,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
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
diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp
index 47ae7aeb26c..a0e3f0685b6 100644
--- a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp
+++ b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp
@@ -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 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin
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");
-}
diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp
index cf3e45849bc..42d7fecb8b1 100644
--- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp
@@ -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 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin
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");
-}
diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
index 21646e1bc0d..50f85fbfa84 100644
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
@@ -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(
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
diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp
similarity index 79%
rename from hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
rename to hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp
index cea18ba83a7..e011552dfcb 100644
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp
@@ -51,6 +51,10 @@
#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;
@@ -95,12 +99,13 @@ address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(
__ empty_expression_stack();
// setup parameters
// ??? convention: expect aberrant index in register ebx
- __ lea(c_rarg1, ExternalAddress((address)name));
+ 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),
- c_rarg1, rbx);
+ rarg, rbx);
return entry;
}
@@ -108,7 +113,8 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
address entry = __ pc();
// object is at TOS
- __ pop(c_rarg1);
+ Register rarg = NOT_LP64(rax) LP64_ONLY(c_rarg1);
+ __ pop(rarg);
// expression stack must be empty before entering the VM if an
// exception happened
@@ -118,7 +124,7 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
CAST_FROM_FN_PTR(address,
InterpreterRuntime::
throw_ClassCastException),
- c_rarg1);
+ rarg);
return entry;
}
@@ -126,31 +132,35 @@ 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(c_rarg2);
+ __ pop(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));
+ __ lea(rarg, ExternalAddress((address)name));
if (pass_oop) {
__ call_VM(rax, CAST_FROM_FN_PTR(address,
InterpreterRuntime::
create_klass_exception),
- c_rarg1, c_rarg2);
+ rarg, 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));
+ __ lea(rarg2, ExternalAddress((address)message));
} else {
- __ movptr(c_rarg2, NULL_WORD);
+ __ movptr(rarg2, NULL_WORD);
}
__ call_VM(rax,
CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception),
- c_rarg1, c_rarg2);
+ rarg, rarg2);
}
// throw exception
__ jump(ExternalAddress(Interpreter::throw_exception_entry()));
@@ -170,6 +180,30 @@ address TemplateInterpreterGenerator::generate_continuation_for(TosState state)
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
@@ -200,18 +234,29 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
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(r15_thread, JavaThread::pending_monitorenter_offset()), 0);
+ __ cmpb(Address(thread, JavaThread::pending_monitorenter_offset()), 0);
__ jcc(Assembler::zero, L);
// Clear flag.
- __ movb(Address(r15_thread, JavaThread::pending_monitorenter_offset()), 0);
+ __ movb(Address(thread, JavaThread::pending_monitorenter_offset()), 0);
// Satisfy calling convention for lock_method().
__ get_method(rbx);
// Take lock.
@@ -222,7 +267,7 @@ address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, i
// handle exceptions
{
Label L;
- __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
+ __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
__ jcc(Assembler::zero, L);
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
@@ -234,41 +279,52 @@ address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, i
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;
+#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));
@@ -303,7 +359,7 @@ address TemplateInterpreterGenerator::generate_safept_entry_for(
// so we have a 'sticky' overflow test
//
// rbx: method
-// ecx: invocation counter
+// rcx: invocation counter
//
void InterpreterGenerator::generate_counter_incr(
Label* overflow,
@@ -383,10 +439,10 @@ void InterpreterGenerator::generate_counter_incr(
void InterpreterGenerator::generate_counter_overflow(Label* do_continue) {
// Asm interpreter on entry
- // r14 - locals
- // r13 - bcp
+ // r14/rdi - locals
+ // r13/rsi - bcp
// rbx - method
- // edx - cpool --- DOES NOT APPEAR TO BE TRUE
+ // rdx - cpool --- DOES NOT APPEAR TO BE TRUE
// rbp - interpreter frame
// On return (i.e. jump to entry_point) [ back to invocation of interpreter ]
@@ -400,11 +456,12 @@ void InterpreterGenerator::generate_counter_overflow(Label* do_continue) {
// 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);
+ Register rarg = NOT_LP64(rax) LP64_ONLY(c_rarg1);
+ __ movl(rarg, 0);
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::frequency_counter_overflow),
- c_rarg1);
+ rarg);
__ movptr(rbx, Address(rbp, method_offset)); // restore Method*
// Preserve invariant that r13/r14 contain bcp/locals of sender frame
@@ -450,8 +507,15 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
// 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());
+ 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);
@@ -485,20 +549,25 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
// check against the current stack bottom
__ cmpptr(rsp, rax);
- __ jcc(Assembler::above, after_frame_check);
+
+ __ 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, r13);
+ __ 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);
@@ -508,7 +577,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
//
// Args:
// rbx: Method*
-// r14: locals
+// r14/rdi: locals
//
// Kills:
// rax
@@ -540,7 +609,7 @@ void TemplateInterpreterGenerator::lock_method() {
__ 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)));
+ __ 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()));
@@ -566,8 +635,9 @@ void TemplateInterpreterGenerator::lock_method() {
__ 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);
+ 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
@@ -576,17 +646,17 @@ void TemplateInterpreterGenerator::lock_method() {
// Args:
// rax: return address
// rbx: Method*
-// r14: pointer to locals
-// r13: sender sp
+// 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(r13); // set sender sp
+ __ push(rbcp); // 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
+ __ 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;
@@ -604,11 +674,11 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
__ 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
+ __ push(rlocals); // set locals pointer
if (native_call) {
__ push(0); // no bcp
} else {
- __ push(r13); // set bcp
+ __ push(rbcp); // set bcp
}
__ push(0); // reserve word for pointer to expression stack bottom
__ movptr(Address(rsp, 0), rsp); // set expression stack bottom
@@ -667,6 +737,10 @@ address InterpreterGenerator::generate_Reference_get_entry(void) {
// 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.
@@ -674,18 +748,23 @@ address InterpreterGenerator::generate_Reference_get_entry(void) {
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 */,
- r15_thread /* thread */,
+ 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, r13); // set sp to sender sp
+ __ mov(rsp, sender_sp); // set sp to sender sp
__ jmp(rdi);
__ ret(0);
@@ -701,169 +780,6 @@ address InterpreterGenerator::generate_Reference_get_entry(void) {
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.
@@ -872,7 +788,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// rbx: Method*
- // r13: sender sp
+ // rbcp: sender sp
address entry_point = __ pc();
@@ -892,13 +808,13 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// rbx: Method*
// rcx: size of parameters
- // r13: sender sp
+ // rbcp: 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));
+ // compute beginning of parameters
+ __ lea(rlocals, Address(rsp, rcx, Interpreter::stackElementScale(), -wordSize));
// add 2 zero-initialized slots for native calls
// initialize result_handler slot
@@ -935,7 +851,9 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// _do_not_unlock_if_synchronized to true. The remove_activation will
// check this flag.
- const Address do_not_unlock_if_synchronized(r15_thread,
+ 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);
@@ -951,6 +869,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
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
@@ -991,17 +910,26 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// work registers
const Register method = rbx;
- const Register t = r11;
+ 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
{
@@ -1019,12 +947,12 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
}
// call signature handler
- assert(InterpreterRuntime::SignatureHandlerGenerator::from() == r14,
+ assert(InterpreterRuntime::SignatureHandlerGenerator::from() == rlocals,
"adjust this code");
assert(InterpreterRuntime::SignatureHandlerGenerator::to() == rsp,
"adjust this code");
- assert(InterpreterRuntime::SignatureHandlerGenerator::temp() == rscratch1,
- "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
@@ -1056,8 +984,13 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
__ 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);
}
@@ -1066,8 +999,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
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);
+ __ cmpptr(rax, unsatisfied.addr());
__ jcc(Assembler::notEqual, L);
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
@@ -1079,17 +1011,28 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
}
// pass JNIEnv
- __ lea(c_rarg0, Address(r15_thread, JavaThread::jni_environment_offset()));
+#ifndef _LP64
+ __ get_thread(thread);
+ __ lea(t, Address(thread, JavaThread::jni_environment_offset()));
+ __ movptr(Address(rsp, 0), t);
- // 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());
+ // 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(r15_thread, JavaThread::thread_state_offset()));
+ __ movl(t, Address(thread, JavaThread::thread_state_offset()));
__ cmpl(t, _thread_in_Java);
__ jcc(Assembler::equal, L);
__ stop("Wrong thread state in native stub");
@@ -1099,12 +1042,13 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// Change state to native
- __ movl(Address(r15_thread, JavaThread::thread_state_offset()),
+ __ movl(Address(thread, JavaThread::thread_state_offset()),
_thread_in_native);
// Call the native method.
__ call(rax);
- // result potentially in rax or xmm0
+ // 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();
@@ -1114,11 +1058,40 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// 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
- __ movl(Address(r15_thread, JavaThread::thread_state_offset()),
+ NOT_LP64(__ get_thread(thread));
+ __ movl(Address(thread, JavaThread::thread_state_offset()),
_thread_in_native_trans);
if (os::is_MP()) {
@@ -1132,10 +1105,17 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// 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);
+ __ 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;
@@ -1144,7 +1124,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
Label L;
__ jcc(Assembler::notEqual, L);
- __ cmpl(Address(r15_thread, JavaThread::suspend_flags_offset()), 0);
+ __ cmpl(Address(thread, JavaThread::suspend_flags_offset()), 0);
__ jcc(Assembler::equal, Continue);
__ bind(L);
@@ -1155,6 +1135,13 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// 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
@@ -1162,17 +1149,18 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
__ 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(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java);
+ __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_Java);
// reset_last_Java_frame
- __ reset_last_Java_frame(true, true);
+ __ reset_last_Java_frame(thread, true, true);
// reset handle block
- __ movptr(t, Address(r15_thread, JavaThread::active_handles_offset()));
+ __ 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
@@ -1190,7 +1178,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
__ 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
+ // keep stack depth as expected by pushing oop which will eventually be discarded
__ push(ltos);
__ bind(no_oop);
}
@@ -1198,11 +1186,15 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
{
Label no_reguard;
- __ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()),
+ __ 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
@@ -1210,6 +1202,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
__ mov(rsp, r12); // restore sp
__ popa(); // XXX only restore smashed registers
__ reinit_heapbase();
+#endif // _LP64
__ bind(no_reguard);
}
@@ -1220,14 +1213,14 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// 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
+ // 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(r15_thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
+ __ 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
@@ -1255,12 +1248,14 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// has not been unlocked by an explicit monitorexit bytecode.
const Address monitor(rbp,
(intptr_t)(frame::interpreter_frame_initial_sp_offset *
- wordSize - sizeof(BasicObjectLock)));
+ wordSize - (int)sizeof(BasicObjectLock)));
+
+ const Register regmon = NOT_LP64(rdx) LP64_ONLY(c_rarg1);
// monitor expect in c_rarg1 for slow unlock path
- __ lea(c_rarg1, monitor); // address of first monitor
+ __ lea(regmon, monitor); // address of first monitor
- __ movptr(t, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()));
+ __ movptr(t, Address(regmon, BasicObjectLock::obj_offset_in_bytes()));
__ testptr(t, t);
__ jcc(Assembler::notZero, unlock);
@@ -1271,7 +1266,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
__ should_not_reach_here();
__ bind(unlock);
- __ unlock_object(c_rarg1);
+ __ unlock_object(regmon);
}
__ bind(L);
}
@@ -1287,7 +1282,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// restore potential result in ST0 & handle result
__ pop(ltos);
- __ pop(dtos);
+ LP64_ONLY( __ pop(dtos));
__ movptr(t, Address(rbp,
(frame::interpreter_frame_result_handler_offset) * wordSize));
@@ -1319,7 +1314,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// ebx: Method*
- // r13: sender sp
+ // rbcp: sender sp
address entry_point = __ pc();
const Address constMethod(rbx, Method::const_offset());
@@ -1335,7 +1330,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
// rbx: Method*
// rcx: size of parameters
- // r13: sender_sp (could differ from sp+wordSize if we were called via c2i )
+ // 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
@@ -1350,8 +1345,8 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
// get return address
__ pop(rax);
- // compute beginning of parameters (r14)
- __ lea(r14, Address(rsp, rcx, Address::times_8, -wordSize));
+ // compute beginning of parameters
+ __ lea(rlocals, Address(rsp, rcx, Interpreter::stackElementScale(), -wordSize));
// rdx - # of additional locals
// allocate space for locals
@@ -1395,7 +1390,9 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
// _do_not_unlock_if_synchronized to true. The remove_activation
// will check this flag.
- const Address do_not_unlock_if_synchronized(r15_thread,
+ 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);
@@ -1420,6 +1417,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
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
@@ -1479,42 +1477,6 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
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
@@ -1527,16 +1489,17 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
__ 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_bcp(); // r13/rsi points to call/send
__ restore_locals();
- __ reinit_heapbase(); // restore r12 as heapbase.
+ 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: exception bcp
+ // r13/rsi: exception bcp
__ verify_oop(rax);
- __ mov(c_rarg1, 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
@@ -1545,10 +1508,10 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
__ call_VM(rdx,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::exception_handler_for_exception),
- c_rarg1);
+ rarg);
// rax: exception handler entry point
// rdx: preserved exception oop
- // r13: bcp for exception handler
+ // 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!)
@@ -1575,9 +1538,11 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
// 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()));
+ 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(r15_thread, JavaThread::popframe_condition_offset()), rdx);
+ __ movl(Address(thread, JavaThread::popframe_condition_offset()), rdx);
{
// Check to see whether we are returning to a deoptimized frame.
@@ -1591,9 +1556,10 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
// 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));
+ 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), c_rarg1);
+ InterpreterRuntime::interpreter_contains), rarg);
__ testl(rax, rax);
__ jcc(Assembler::notZero, caller_not_deoptimized);
@@ -1604,14 +1570,15 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
__ 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);
+ __ 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),
- r15_thread, rax, r14);
+ thread, rax, rlocals);
__ remove_activation(vtos, rdx,
/* throw_monitor_exception */ false,
@@ -1620,7 +1587,8 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
// Inform deoptimization that it is responsible for restoring
// these arguments
- __ movl(Address(r15_thread, JavaThread::popframe_condition_offset()),
+ NOT_LP64(__ get_thread(thread));
+ __ movl(Address(thread, JavaThread::popframe_condition_offset()),
JavaThread::popframe_force_deopt_reexecution_bit);
// Continue in deoptimization handler
@@ -1645,18 +1613,29 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
// 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);
- __ reset_last_Java_frame(true, true);
+#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(); // XXX do we need this?
- __ restore_locals(); // XXX do we need this?
+ __ 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) {
@@ -1664,15 +1643,16 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
}
// Clear the popframe condition flag
- __ movl(Address(r15_thread, JavaThread::popframe_condition_offset()),
+ NOT_LP64(__ get_thread(thread));
+ __ movl(Address(thread, JavaThread::popframe_condition_offset()),
JavaThread::popframe_inactive);
#if INCLUDE_JVMTI
{
Label L_done;
- const Register local0 = r14;
+ const Register local0 = rlocals;
- __ cmpb(Address(r13, 0), Bytecodes::_invokestatic);
+ __ 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.
@@ -1680,7 +1660,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
__ 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);
+ __ 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);
@@ -1697,11 +1677,13 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
// preserve exception over this code sequence
__ pop_ptr(rax);
- __ movptr(Address(r15_thread, JavaThread::vm_result_offset()), 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
- __ get_vm_result(rax, r15_thread);
+ 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
@@ -1715,7 +1697,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
__ push(rdx); // save return address
__ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
SharedRuntime::exception_handler_for_return_address),
- r15_thread, rdx);
+ thread, rdx);
__ mov(rbx, rax); // save exception handler
__ pop(rdx); // restore return address
__ pop(rax); // restore exception
@@ -1734,10 +1716,12 @@ address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state
__ restore_bcp();
__ restore_locals();
__ empty_expression_stack();
- __ load_earlyret_value(state);
+ __ load_earlyret_value(state); // 32 bits returns value in rdx, so don't reuse
- __ movptr(rdx, Address(r15_thread, JavaThread::jvmti_thread_state_offset()));
- Address cond_addr(rdx, JvmtiThreadState::earlyret_state_offset());
+ 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);
@@ -1768,8 +1752,13 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
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();
@@ -1794,9 +1783,23 @@ InterpreterGenerator::InterpreterGenerator(StubQueue* code)
// 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);
@@ -1815,6 +1818,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
__ pop(c_rarg0);
__ pop(state);
__ ret(0); // return from result handler
+#endif // _LP64
return entry;
}
@@ -1846,11 +1850,15 @@ void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
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
}
diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp
new file mode 100644
index 00000000000..d43d2606829
--- /dev/null
+++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp
@@ -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
diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp
new file mode 100644
index 00000000000..b77270b02ca
--- /dev/null
+++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp
@@ -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
diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp
index 7a12d82e9af..9b84f71bc3c 100644
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp
@@ -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 @@ void AbstractInterpreter::layout_activation(Method* method,
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
diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
deleted file mode 100644
index 6e27d776142..00000000000
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp
index 2ca11c6a1d7..b589e0100ce 100644
--- a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp
@@ -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() {
diff --git a/hotspot/src/cpu/zero/vm/interpreter_zero.cpp b/hotspot/src/cpu/zero/vm/interpreter_zero.cpp
index 7172443db8f..c99e9391b62 100644
--- a/hotspot/src/cpu/zero/vm/interpreter_zero.cpp
+++ b/hotspot/src/cpu/zero/vm/interpreter_zero.cpp
@@ -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 @@ address InterpreterGenerator::generate_abstract_entry() {
bool AbstractInterpreter::can_be_compiled(methodHandle m) {
return true;
}
-
-void Deoptimization::unwind_callee_save_values(frame* f,
- vframeArray* vframe_array) {
-}
diff --git a/hotspot/src/os/aix/vm/globals_aix.hpp b/hotspot/src/os/aix/vm/globals_aix.hpp
index ef12d703159..51612fae7a6 100644
--- a/hotspot/src/os/aix/vm/globals_aix.hpp
+++ b/hotspot/src/os/aix/vm/globals_aix.hpp
@@ -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);
diff --git a/hotspot/src/os/aix/vm/jvm_aix.cpp b/hotspot/src/os/aix/vm/jvm_aix.cpp
index 4e95697a241..7a9fb8969b8 100644
--- a/hotspot/src/os/aix/vm/jvm_aix.cpp
+++ b/hotspot/src/os/aix/vm/jvm_aix.cpp
@@ -109,92 +109,3 @@ JVM_ENTRY_NO_ENV(jboolean, JVM_RaiseSignal(jint sig))
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
+#include
+#include
-// 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 @@ bool libperfstat::init() {
#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 @@ void libperfstat::cleanup() {
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);
}
-void libperfstat::perfstat_reset() {
- assert(g_initialized, "libperfstat not initialized");
- assert(g_fun_perfstat_reset, "");
- g_fun_perfstat_reset();
+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() {
+ 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;
}
diff --git a/hotspot/src/os/aix/vm/libperfstat_aix.hpp b/hotspot/src/os/aix/vm/libperfstat_aix.hpp
index 8d7b45da12f..c0da6709061 100644
--- a/hotspot/src/os/aix/vm/libperfstat_aix.hpp
+++ b/hotspot/src/os/aix/vm/libperfstat_aix.hpp
@@ -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
+#include
+#include
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// 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
+//
+// 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<. */
+ 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<. */
+ 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<. */
+ 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 @@ public:
// 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<.
+ 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
diff --git a/hotspot/src/os/aix/vm/loadlib_aix.cpp b/hotspot/src/os/aix/vm/loadlib_aix.cpp
index 183e2395b21..53e4891442b 100644
--- a/hotspot/src/os/aix/vm/loadlib_aix.cpp
+++ b/hotspot/src/os/aix/vm/loadlib_aix.cpp
@@ -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"
diff --git a/hotspot/src/os/aix/vm/misc_aix.cpp b/hotspot/src/os/aix/vm/misc_aix.cpp
index daad0e19c36..52a26c0f592 100644
--- a/hotspot/src/os/aix/vm/misc_aix.cpp
+++ b/hotspot/src/os/aix/vm/misc_aix.cpp
@@ -26,6 +26,8 @@
#include "runtime/stubRoutines.hpp"
#include
+#include
+#include
void MiscUtils::init_critsect(MiscUtils::critsect_t* cs) {
const int rc = pthread_mutex_init(cs, NULL);
diff --git a/hotspot/src/os/aix/vm/misc_aix.hpp b/hotspot/src/os/aix/vm/misc_aix.hpp
index 8b66d2e040b..ba38bda137b 100644
--- a/hotspot/src/os/aix/vm/misc_aix.hpp
+++ b/hotspot/src/os/aix/vm/misc_aix.hpp
@@ -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
@@ -40,7 +42,6 @@
} \
}
#define ERRBYE(s) { trcVerbose(s); return -1; }
-#define trc(fmt, ...)
#define assert0(b) assert((b), "")
#define guarantee0(b) guarantee((b), "")
diff --git a/hotspot/src/os/aix/vm/osThread_aix.cpp b/hotspot/src/os/aix/vm/osThread_aix.cpp
index c5566147f99..c2b1f69b291 100644
--- a/hotspot/src/os/aix/vm/osThread_aix.cpp
+++ b/hotspot/src/os/aix/vm/osThread_aix.cpp
@@ -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;
diff --git a/hotspot/src/os/aix/vm/osThread_aix.hpp b/hotspot/src/os/aix/vm/osThread_aix.hpp
index a18943cd67d..f27934dd852 100644
--- a/hotspot/src/os/aix/vm/osThread_aix.hpp
+++ b/hotspot/src/os/aix/vm/osThread_aix.hpp
@@ -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;
}
// ***************************************************************
diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp
index 65f005e6977..a0a1e38239a 100644
--- a/hotspot/src/os/aix/vm/os_aix.cpp
+++ b/hotspot/src/os/aix/vm/os_aix.cpp
@@ -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
#include
-// 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
+// Missing prototypes for various system APIs.
+extern "C"
+int mread_real_time(timebasestruct_t *t, size_t size_of_timebasestruct_t);
-// 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).
#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 int* codeptr_t;
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 @@ inline bool is_valid_codepointer(codeptr_t p) {
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 @@ inline bool is_valid_codepointer(codeptr_t p) {
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 @@ static struct {
// 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::available_memory() {
}
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 @@ static bool my_disclaim64(char* addr, size_t size) {
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 @@ static bool my_disclaim64(char* addr, size_t size) {
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 @@ static char cpu_arch[] = "ppc64";
#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) {
- vm_page_info pi;
- pi.addr = (uint64_t)addr;
- if (::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");
+ if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) {
+ // AS/400 older than V6R1: no vmgetinfo here, default to 4K
return SIZE_4K;
}
-}
-
-// Returns the kernel thread id of the currently running thread.
-pid_t os::Aix::gettid() {
- return (pid_t) thread_self();
+ vm_page_info pi;
+ pi.addr = (uint64_t)addr;
+ if (checked_vmgetinfo(&pi, VM_PAGE_INFO, sizeof(pi)) == 0) {
+ return pi.pagesize;
+ } else {
+ assert(false, "vmgetinfo failed to retrieve page size");
+ return SIZE_4K;
+ }
}
void os::Aix::initialize_system_info() {
@@ -387,7 +391,6 @@ void os::Aix::initialize_system_info() {
// 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 @@ static const char* describe_pagesize(size_t pagesize) {
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 @@ static void query_multipage_support() {
}
// 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 @@ static void query_multipage_support() {
// 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 @@ static void query_multipage_support() {
{
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 @@ static void query_multipage_support() {
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 @@ static void query_multipage_support() {
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 @@ void os::init_system_properties_values() {
// Found the full path to libjvm.so.
// Now cut the path to /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 @@ bool os::Aix::get_meminfo(meminfo_t* pmi) {
memset(pmi, 0, sizeof(meminfo_t));
if (os::Aix::on_pase()) {
+ // On PASE, use the libo4 porting library.
- Unimplemented();
+ 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 @@ bool os::Aix::get_meminfo(meminfo_t* pmi) {
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 @@ bool os::Aix::get_meminfo(meminfo_t* pmi) {
}
} // 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 @@ static void *java_start(Thread *thread) {
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 @@ static void *java_start(Thread *thread) {
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());
+ // Thread_id is pthread id.
+ osthread->set_thread_id(pthread_id);
- // initialize signal mask for this thread
+ // .. 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 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
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 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
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 @@ bool os::create_attached_thread(JavaThread* thread) {
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 @@ void os::free_thread(OSThread* osthread) {
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 @@ void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) {
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 @@ size_t os::lasterror(char *buf, size_t len) {
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 @@ bool os::dll_build_name(char* buffer, size_t buflen,
} 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 @@ void os::print_os_info(outputStream* st) {
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 : "");
+ // Print out EXTSHM because it is an unsupported setting.
const char* const extshm = ::getenv("EXTSHM");
st->print_cr(" EXTSHM=%s.", extshm ? extshm : "");
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 : "");
+
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::get_summary_cpu_info(char* buf, size_t buflen) {
}
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 @@ int os::sigexitnum_pd() {
// 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 @@ static int check_pending_signals(bool wait) {
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 @@ static int check_pending_signals(bool wait) {
// 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 @@ struct vmembk_t {
// 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 @@ static char* reserve_shmated_memory (
// 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 @@ static char* reserve_shmated_memory (
// (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 @@ static bool uncommit_shmated_memory(char* addr, size_t size) {
return true;
}
+//////////////////////////////// mmap-based routines /////////////////////////////////
+
// Reserve memory via mmap.
// If is given, an attempt is made to attach at the given address.
// Failing that, memory is allocated at any address.
@@ -2227,9 +2276,6 @@ static bool uncommit_mmaped_memory(char* addr, size_t size) {
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 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec,
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 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size,
}
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 @@ bool os::pd_release_memory(char* addr, size_t size) {
// 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 @@ static bool checked_mprotect(char* addr, size_t size, int prot) {
} 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 @@ void os::large_page_init() {
}
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 @@ void javaSignalHandler(int sig, siginfo_t* info, void* uc) {
// 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 os::Aix::set_signal_handler(int sig, bool set_installed) {
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 @@ void os::Aix::set_signal_handler(int sig, bool set_installed) {
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 @@ void os::Aix::check_signal_handler(int sig) {
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 @@ void os::Aix::check_signal_handler(int sig) {
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 @@ void os::Aix::check_signal_handler(int sig) {
}
} 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 @@ void os::Aix::check_signal_handler(int sig) {
}
}
-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 @@ void os::init(void) {
// (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 @@ void os::init(void) {
// 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 @@ void os::init(void) {
}
} 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 @@ void os::init(void) {
_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 @@ void os::init(void) {
// 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 @@ void os::init(void) {
// 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 @@ jint os::init_2(void) {
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 @@ jint os::init_2(void) {
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 @@ jint os::init_2(void) {
// 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 @@ jint os::init_2(void) {
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 @@ ExtendedPC os::get_thread_pc(Thread* thread) {
////////////////////////////////////////////////////////////////////////////////
// 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 @@ bool os::is_thread_cpu_time_supported() {
// 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;
- } 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)) {
+ // 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
+ 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 os::pause() {
(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 @@ void os::Aix::initialize_os_info() {
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 @@ void os::Aix::initialize_os_info() {
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 @@ void os::Aix::scan_environment() {
// 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 : "");
- }
+ trcVerbose("EXTSHM=%s.", p ? p : "");
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 @@ void os::Aix::scan_environment() {
trcVerbose("XPG_SUS_ENV=%s.", p ? p : "");
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 @@ void os::Aix::scan_environment() {
_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 : "");
+ }
+
+ p = ::getenv("LDR_CNTRL");
+ trcVerbose("LDR_CNTRL=%s.", p ? p : "");
+ 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 : "");
- 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();
+ 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 (we load this dynamically
-// because it is only available on AIX.
+// 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");
- }
+ trcVerbose("libperfstat initialized.");
}
-} // end: os::Aix::initialize_libperfstat
+}
/////////////////////////////////////////////////////////////////////////////
// thread stack
@@ -4313,7 +4411,7 @@ static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size)
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 @@ static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size)
}
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:
+ // Note: we get three values from pthread_getthrds_np:
+ // __pi_stackaddr, __pi_stacksize, __pi_stackend
//
- // --------------------- real base ? at page border ?
+ // high addr ---------------------
//
- // 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
+ // | 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
//
- // --------------------- __pi_stackend - not page aligned, (xxxxF890)
- //
- // stack
- // ....
- //
- // stack
- //
- // --------------------- __pi_stackend - __pi_stacksize
- //
- // 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;
diff --git a/hotspot/src/os/aix/vm/os_aix.hpp b/hotspot/src/os/aix/vm/os_aix.hpp
index 7381da500e2..11942fc9fb1 100644
--- a/hotspot/src/os/aix/vm/os_aix.hpp
+++ b/hotspot/src/os/aix/vm/os_aix.hpp
@@ -34,9 +34,6 @@ static bool zero_page_read_protected() { return false; }
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 @@ class Aix {
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 @@ class Aix {
// 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 @@ class Aix {
// 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 @@ class Aix {
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 @@ class Aix {
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 @@ class Aix {
};
- // 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<.
- 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 {
diff --git a/hotspot/src/os/aix/vm/os_aix.inline.hpp b/hotspot/src/os/aix/vm/os_aix.inline.hpp
index 7de0626dae6..e28f2d325bc 100644
--- a/hotspot/src/os/aix/vm/os_aix.inline.hpp
+++ b/hotspot/src/os/aix/vm/os_aix.inline.hpp
@@ -36,10 +36,6 @@
#include
#include
-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 @@ inline bool os::allocate_stack_guard_pages() {
// 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.
diff --git a/hotspot/src/os/aix/vm/thread_aix.inline.hpp b/hotspot/src/os/aix/vm/thread_aix.inline.hpp
deleted file mode 100644
index 04623516049..00000000000
--- a/hotspot/src/os/aix/vm/thread_aix.inline.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os/bsd/vm/jvm_bsd.cpp b/hotspot/src/os/bsd/vm/jvm_bsd.cpp
index e2e140e2055..f891f7c1b91 100644
--- a/hotspot/src/os/bsd/vm/jvm_bsd.cpp
+++ b/hotspot/src/os/bsd/vm/jvm_bsd.cpp
@@ -108,84 +108,3 @@ JVM_ENTRY_NO_ENV(jboolean, JVM_RaiseSignal(jint sig))
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; iinitialize_thread_current();
OSThread* osthread = thread->osthread();
Monitor* sync = osthread->startThread_lock();
@@ -882,44 +882,6 @@ void os::free_thread(OSThread* osthread) {
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 @@ void os::Bsd::check_signal_handler(int sig) {
}
} 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 @@ void os::Bsd::check_signal_handler(int sig) {
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
diff --git a/hotspot/src/os/bsd/vm/os_bsd.inline.hpp b/hotspot/src/os/bsd/vm/os_bsd.inline.hpp
index 3afb5c21a83..4a654614c2b 100644
--- a/hotspot/src/os/bsd/vm/os_bsd.inline.hpp
+++ b/hotspot/src/os/bsd/vm/os_bsd.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,10 +34,6 @@
#include
#include
-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);
diff --git a/hotspot/src/os/bsd/vm/thread_bsd.inline.hpp b/hotspot/src/os/bsd/vm/thread_bsd.inline.hpp
deleted file mode 100644
index 86f125dc5b4..00000000000
--- a/hotspot/src/os/bsd/vm/thread_bsd.inline.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os/linux/vm/jvm_linux.cpp b/hotspot/src/os/linux/vm/jvm_linux.cpp
index 35404b8217a..25e58c01ef4 100644
--- a/hotspot/src/os/linux/vm/jvm_linux.cpp
+++ b/hotspot/src/os/linux/vm/jvm_linux.cpp
@@ -108,91 +108,3 @@ JVM_ENTRY_NO_ENV(jboolean, JVM_RaiseSignal(jint sig))
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; iinitialize_thread_current();
OSThread* osthread = thread->osthread();
Monitor* sync = osthread->startThread_lock();
@@ -873,43 +873,6 @@ void os::free_thread(OSThread* osthread) {
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();
-}
-
//////////////////////////////////////////////////////////////////////////////
// initial thread
@@ -4570,8 +4533,12 @@ void os::Linux::check_signal_handler(int sig) {
}
} 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 @@ void os::Linux::check_signal_handler(int sig) {
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
diff --git a/hotspot/src/os/linux/vm/os_linux.inline.hpp b/hotspot/src/os/linux/vm/os_linux.inline.hpp
index ba4b777d520..7559cde3d00 100644
--- a/hotspot/src/os/linux/vm/os_linux.inline.hpp
+++ b/hotspot/src/os/linux/vm/os_linux.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,10 +34,6 @@
#include
#include
-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);
diff --git a/hotspot/src/os/linux/vm/thread_linux.inline.hpp b/hotspot/src/os/linux/vm/thread_linux.inline.hpp
deleted file mode 100644
index b58dc078948..00000000000
--- a/hotspot/src/os/linux/vm/thread_linux.inline.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp
index 93c4cbb6b09..55de3ebc259 100644
--- a/hotspot/src/os/posix/vm/os_posix.cpp
+++ b/hotspot/src/os/posix/vm/os_posix.cpp
@@ -493,166 +493,171 @@ bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
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
- { SIGSTOP, "SIGSTOP" },
- { SIGSYS, "SIGSYS" },
+#ifdef SIGSTKFLT
+ { SIGSTKFLT, "SIGSTKFLT" },
+#endif
+ { 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 @@ const char* os::Posix::get_signal_name(int sig, char* out, size_t outlen) {
#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 @@ const char* os::Posix::get_signal_name(int sig, char* out, size_t outlen) {
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 @@ bool os::Posix::is_valid_signal(int sig) {
#endif
}
+// Returns:
+// "invalid ()" for an invalid signal number
+// "SIG" 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) {
diff --git a/hotspot/src/os/posix/vm/os_posix.hpp b/hotspot/src/os/posix/vm/os_posix.hpp
index 84a1a6eda43..27b0554881e 100644
--- a/hotspot/src/os/posix/vm/os_posix.hpp
+++ b/hotspot/src/os/posix/vm/os_posix.hpp
@@ -51,6 +51,12 @@ public:
// 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);
diff --git a/hotspot/src/os/posix/vm/threadLocalStorage_posix.cpp b/hotspot/src/os/posix/vm/threadLocalStorage_posix.cpp
new file mode 100644
index 00000000000..cc703ef811f
--- /dev/null
+++ b/hotspot/src/os/posix/vm/threadLocalStorage_posix.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "runtime/threadLocalStorage.hpp"
+#include
+
+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");
+}
diff --git a/hotspot/src/os/solaris/vm/jvm_solaris.cpp b/hotspot/src/os/solaris/vm/jvm_solaris.cpp
index ae2eb037dc8..3dfa84e0f9e 100644
--- a/hotspot/src/os/solaris/vm/jvm_solaris.cpp
+++ b/hotspot/src/os/solaris/vm/jvm_solaris.cpp
@@ -106,40 +106,3 @@ JVM_ENTRY_NO_ENV(jboolean, JVM_RaiseSignal(jint sig))
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
diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp
index 84b5f73e60b..6604a3b148a 100644
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp
@@ -728,6 +728,9 @@ extern "C" void* java_start(void* thread_addr) {
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 @@ void os::Solaris::check_signal_handler(int sig) {
}
} 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 os::Solaris::install_signal_handlers() {
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 @@ int os::fork_and_exec(char* cmd) {
// 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 {
diff --git a/hotspot/src/os/solaris/vm/thread_solaris.inline.hpp b/hotspot/src/os/solaris/vm/thread_solaris.inline.hpp
deleted file mode 100644
index fdbc553cd22..00000000000
--- a/hotspot/src/os/solaris/vm/thread_solaris.inline.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os/windows/vm/jvm_windows.cpp b/hotspot/src/os/windows/vm/jvm_windows.cpp
index d6a299a239c..1e9a3fe5c49 100644
--- a/hotspot/src/os/windows/vm/jvm_windows.cpp
+++ b/hotspot/src/os/windows/vm/jvm_windows.cpp
@@ -89,39 +89,3 @@ JVM_ENTRY_NO_ENV(jboolean, JVM_RaiseSignal(jint sig))
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;iinitialize_thread_current();
+
OSThread* osthr = thread->osthread();
assert(osthr->get_state() == RUNNABLE, "invalid os thread state");
@@ -1799,24 +1801,32 @@ void os::print_memory_info(outputStream* st) {
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 @@ int os::signal_wait() {
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 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
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 @@ bool os::message_box(const char* title, const char* message) {
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 @@ void os::init(void) {
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 @@ void Parker::park(bool isAbsolute, jlong time) {
}
}
- 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 @@ void Parker::park(bool isAbsolute, jlong time) {
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 @@ LONG WINAPI os::win32::serialize_fault_filter(struct _EXCEPTION_POINTERS* e) {
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 @@ void TestReserveMemorySpecial_test() {
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
+
+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());
+}
diff --git a/hotspot/src/os/windows/vm/thread_windows.inline.hpp b/hotspot/src/os/windows/vm/thread_windows.inline.hpp
deleted file mode 100644
index 95dd17cecc7..00000000000
--- a/hotspot/src/os/windows/vm/thread_windows.inline.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp
index f0b867e88da..3029342e364 100644
--- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp
+++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp
@@ -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 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
ucontext_t* uc = (ucontext_t*) ucVoid;
- Thread* t = ThreadLocalStorage::get_thread_slow(); // slow & steady
+ Thread* t = Thread::current_or_null_safe();
SignalHandlerMark shm(t);
diff --git a/hotspot/src/os_cpu/aix_ppc/vm/vmStructs_aix_ppc.hpp b/hotspot/src/os_cpu/aix_ppc/vm/vmStructs_aix_ppc.hpp
index a892c92126b..7a29d8351b0 100644
--- a/hotspot/src/os_cpu/aix_ppc/vm/vmStructs_aix_ppc.hpp
+++ b/hotspot/src/os_cpu/aix_ppc/vm/vmStructs_aix_ppc.hpp
@@ -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)
diff --git a/hotspot/src/os_cpu/bsd_x86/vm/assembler_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/assembler_bsd_x86.cpp
index 18bed6b0a6c..dd20ea833c8 100644
--- a/hotspot/src/os_cpu/bsd_x86/vm/assembler_bsd_x86.cpp
+++ b/hotspot/src/os_cpu/bsd_x86/vm/assembler_bsd_x86.cpp
@@ -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
diff --git a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp
index ba2c97185a6..413cfc69560 100644
--- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp
+++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp
@@ -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 @@ JVM_handle_bsd_signal(int sig,
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)
diff --git a/hotspot/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp
deleted file mode 100644
index 0515fbc3fd0..00000000000
--- a/hotspot/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp
+++ /dev/null
@@ -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
-}
diff --git a/hotspot/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.hpp b/hotspot/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.hpp
deleted file mode 100644
index 7fedb95f6e5..00000000000
--- a/hotspot/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os_cpu/bsd_zero/vm/assembler_bsd_zero.cpp b/hotspot/src/os_cpu/bsd_zero/vm/assembler_bsd_zero.cpp
index ec56a35cd6b..cb6fbce1579 100644
--- a/hotspot/src/os_cpu/bsd_zero/vm/assembler_bsd_zero.cpp
+++ b/hotspot/src/os_cpu/bsd_zero/vm/assembler_bsd_zero.cpp
@@ -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
diff --git a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp
index 40a455688f5..ff580acb164 100644
--- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp
+++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp
@@ -134,7 +134,7 @@ JVM_handle_bsd_signal(int sig,
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);
diff --git a/hotspot/src/os_cpu/bsd_zero/vm/threadLS_bsd_zero.cpp b/hotspot/src/os_cpu/bsd_zero/vm/threadLS_bsd_zero.cpp
deleted file mode 100644
index 73e5e829f46..00000000000
--- a/hotspot/src/os_cpu/bsd_zero/vm/threadLS_bsd_zero.cpp
+++ /dev/null
@@ -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);
-}
diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/assembler_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/assembler_linux_aarch64.cpp
index 96dcfcf2992..920d94da7f1 100644
--- a/hotspot/src/os_cpu/linux_aarch64/vm/assembler_linux_aarch64.cpp
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/assembler_linux_aarch64.cpp
@@ -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);
-}
-
diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp
index 7ae7e616052..d2cac0810f6 100644
--- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp
@@ -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 @@ JVM_handle_linux_signal(int sig,
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)
diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.cpp
deleted file mode 100644
index e7b0d4dfa1b..00000000000
--- a/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.cpp
+++ /dev/null
@@ -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;
-}
diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.hpp b/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.hpp
deleted file mode 100644
index 73c6afc5ea8..00000000000
--- a/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.s b/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.s
new file mode 100644
index 00000000000..f541844b9d6
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/threadLS_linux_aarch64.s
@@ -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
diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.hpp b/hotspot/src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.hpp
index 96053ec31bd..70e37cecaeb 100644
--- a/hotspot/src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.hpp
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.hpp
@@ -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 @@ private:
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; }
diff --git a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp
index 1c42912c4a7..56b9b390e3c 100644
--- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp
+++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp
@@ -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 @@ JVM_handle_linux_signal(int sig,
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);
diff --git a/hotspot/src/os_cpu/linux_ppc/vm/threadLS_linux_ppc.cpp b/hotspot/src/os_cpu/linux_ppc/vm/threadLS_linux_ppc.cpp
deleted file mode 100644
index 8b6aa99f89d..00000000000
--- a/hotspot/src/os_cpu/linux_ppc/vm/threadLS_linux_ppc.cpp
+++ /dev/null
@@ -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);
-}
diff --git a/hotspot/src/os_cpu/linux_ppc/vm/threadLS_linux_ppc.hpp b/hotspot/src/os_cpu/linux_ppc/vm/threadLS_linux_ppc.hpp
deleted file mode 100644
index ac9beffcc85..00000000000
--- a/hotspot/src/os_cpu/linux_ppc/vm/threadLS_linux_ppc.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp
index 16457399fca..727380a6b8c 100644
--- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp
+++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp
@@ -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 @@ address os::Linux::ucontext_get_pc(ucontext_t* uc) {
}
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 @@ JVM_handle_linux_signal(int sig,
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 @@ JVM_handle_linux_signal(int sig,
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
+ return false;
}
void os::Linux::init_thread_fpu_state(void) {
diff --git a/hotspot/src/os_cpu/linux_sparc/vm/threadLS_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/threadLS_linux_sparc.cpp
deleted file mode 100644
index 3f291a06aa6..00000000000
--- a/hotspot/src/os_cpu/linux_sparc/vm/threadLS_linux_sparc.cpp
+++ /dev/null
@@ -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);
-}
diff --git a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86.cpp
index 5c0c07a0c91..dd20ea833c8 100644
--- a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86.cpp
+++ b/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86.cpp
@@ -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
diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp
index fe1c4c59068..438b2673e66 100644
--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp
+++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp
@@ -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 @@ JVM_handle_linux_signal(int sig,
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)
diff --git a/hotspot/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp
deleted file mode 100644
index addb46d6059..00000000000
--- a/hotspot/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os_cpu/linux_x86/vm/threadLS_linux_x86.hpp b/hotspot/src/os_cpu/linux_x86/vm/threadLS_linux_x86.hpp
deleted file mode 100644
index f3f2f26f88a..00000000000
--- a/hotspot/src/os_cpu/linux_x86/vm/threadLS_linux_x86.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os_cpu/linux_zero/vm/assembler_linux_zero.cpp b/hotspot/src/os_cpu/linux_zero/vm/assembler_linux_zero.cpp
index ec56a35cd6b..cb6fbce1579 100644
--- a/hotspot/src/os_cpu/linux_zero/vm/assembler_linux_zero.cpp
+++ b/hotspot/src/os_cpu/linux_zero/vm/assembler_linux_zero.cpp
@@ -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
diff --git a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp
index b17d58e60b0..2b4ea0bd7b8 100644
--- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp
+++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp
@@ -125,7 +125,7 @@ JVM_handle_linux_signal(int sig,
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);
diff --git a/hotspot/src/os_cpu/linux_zero/vm/threadLS_linux_zero.cpp b/hotspot/src/os_cpu/linux_zero/vm/threadLS_linux_zero.cpp
deleted file mode 100644
index 73e5e829f46..00000000000
--- a/hotspot/src/os_cpu/linux_zero/vm/threadLS_linux_zero.cpp
+++ /dev/null
@@ -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);
-}
diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp
index d139566c72d..faa33919e98 100644
--- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp
@@ -290,7 +290,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
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 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
+ return false;
}
void os::print_context(outputStream *st, void *context) {
diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp
deleted file mode 100644
index 30210a453cc..00000000000
--- a/hotspot/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp
+++ /dev/null
@@ -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();
-}
diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.hpp
deleted file mode 100644
index e3d96c87ae7..00000000000
--- a/hotspot/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp
index d4c0feccaa3..8d43f0378f4 100644
--- a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp
+++ b/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp
@@ -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 @@ void MacroAssembler::int3() {
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);
- }
-}
diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
index 28845c326b8..a28440fc9ff 100644
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
@@ -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 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
}
#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)
diff --git a/hotspot/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp
deleted file mode 100644
index 30210a453cc..00000000000
--- a/hotspot/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp
+++ /dev/null
@@ -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();
-}
diff --git a/hotspot/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.hpp b/hotspot/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.hpp
deleted file mode 100644
index 4f8da7bcb65..00000000000
--- a/hotspot/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.hpp
+++ /dev/null
@@ -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
diff --git a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp
index ce48421c6d4..71e1e8b6aad 100644
--- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp
+++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp
@@ -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 @@ void MacroAssembler::get_thread(Register thread) {
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
diff --git a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp
index f17330ace65..66933305a0c 100644
--- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp
+++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp
@@ -85,14 +85,14 @@ void os::os_exception_wrapper(java_call_t f, JavaValue* value, const methodHandl
//
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 @@ void os::os_exception_wrapper(java_call_t f, JavaValue* value, const methodHandl
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
diff --git a/hotspot/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp
deleted file mode 100644
index f363816d973..00000000000
--- a/hotspot/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp
+++ /dev/null
@@ -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);
-}
diff --git a/hotspot/src/share/vm/classfile/classFileError.cpp b/hotspot/src/share/vm/classfile/classFileError.cpp
index 82165e703f2..c3cde1a5436 100644
--- a/hotspot/src/share/vm/classfile/classFileError.cpp
+++ b/hotspot/src/share/vm/classfile/classFileError.cpp
@@ -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) {
- 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) 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, 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,
+ 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, 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
diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp
index aa788362bc7..14d6efdba08 100644
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp
@@ -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 @@ void ClassFileParser::parse_constant_pool_entries(int length, TRAPS) {
// 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 @@ void ClassFileParser::parse_constant_pool_entries(int length, TRAPS) {
}
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);
}
- 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);
+ 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_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_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_Long :
+ }
+ 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: {
+ // 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
+ 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: {
// 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->long_at_put(index, 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_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++; // Skip entry following eigth-byte constant, see JVM book p. 98
+ }
+ 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_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_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); }
+static inline bool 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 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 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
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 "".
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 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
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(ConstantPool* cp,
+ int index,
+ Handle patch,
+ TRAPS) {
+ assert(cp != NULL, "invariant");
-void ClassFileParser::patch_constant_pool(const constantPoolHandle& cp, int index, Handle patch, TRAPS) {
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 @@ void ClassFileParser::patch_constant_pool(const constantPoolHandle& cp, int inde
"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
};
+static const int HASH_ROW_SIZE = 256;
-#define HASH_ROW_SIZE 256
-
-unsigned int hash(Symbol* name, Symbol* sig) {
+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 @@ unsigned int hash(Symbol* name, Symbol* sig) {
}
-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 @@ bool put_after_lookup(Symbol* name, Symbol* sig, NameSigHash** table) {
return true;
}
+// 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");
-Array* ClassFileParser::parse_interfaces(int length,
- Handle protection_domain,
- Symbol* class_name,
- bool* has_default_methods,
- TRAPS) {
- if (length == 0) {
+ 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(_loader_data, length, NULL, CHECK_NULL);
+ assert(itfs_len > 0, "only called for len>0");
+ _local_interfaces = MetadataFactory::new_array(_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 @@ Array* ClassFileParser::parse_interfaces(int length,
}
}
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);
+ }
+ case T_FLOAT: {
+ guarantee_property(value_type.is_float(),
+ "Inconsistent constant value type in class file %s",
+ CHECK);
break;
- case T_DOUBLE:
- guarantee_property(value_type.is_double(), "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);
+ }
+ 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;")
+ }
+ 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);
+ "Bad string initial value in class file %s",
+ CHECK);
+ break;
+ }
+ 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 'e':
+ index += 4; // skip e_class, e_name
+ break;
+ 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 @@ void ClassFileParser::parse_field_attributes(u2 attributes_count,
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 @@ void ClassFileParser::parse_field_attributes(u2 attributes_count,
"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 @@ void ClassFileParser::parse_field_attributes(u2 attributes_count,
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 @@ static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) {
return result;
}
-class FieldAllocationCount: public ResourceObj {
+class ClassFileParser::FieldAllocationCount : public ResourceObj {
public:
u2 count[MAX_FIELD_ALLOCATION_TYPE];
@@ -1100,18 +1401,33 @@ class FieldAllocationCount: public ResourceObj {
}
};
-Array* 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 @@ Array* ClassFileParser::parse_fields(Symbol* class_name,
// 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);
+ name_index, CHECK);
+ const Symbol* const name = cp->symbol_at(name_index);
+ verify_legal_field_name(name, CHECK);
- u2 signature_index = cfs->get_u2_fast();
+ 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(
_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(
- _loader_data, length, NULL,
- CHECK_NULL);
+ _fields_type_annotations =
+ MetadataFactory::new_array(_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 @@ Array* ClassFileParser::parse_fields(Symbol* class_name,
}
}
- 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 @@ Array* ClassFileParser::parse_fields(Symbol* class_name,
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 @@ Array* ClassFileParser::parse_fields(Symbol* class_name,
}
// 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(_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* fields = MetadataFactory::new_array(
- _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 @@ Array* ClassFileParser::parse_fields(Symbol* class_name,
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 @@ Array* ClassFileParser::parse_fields(Symbol* class_name,
}
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++));
}
}
+const u2* ClassFileParser::parse_exception_table(const ClassFileStream* const cfs,
+ u4 code_length,
+ u4 exception_table_length,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
-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* 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 @@ u2* ClassFileParser::parse_exception_table(u4 code_length,
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 @@ void ClassFileParser::parse_linenumber_table(
(*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 @@ class Classfile_LVT_Element VALUE_OBJ_CLASS_SPEC {
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 @@ void copy_lvt_element(Classfile_LVT_Element *src, LocalVariableTableElement *lvt
}
// 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 @@ u2* ClassFileParser::parse_localvariable_table(u4 code_length,
"Invalid length %u in %s in class file %s",
length, tbl_name, CHECK_NULL);
}
- int cp_size = _cp->length();
+ 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 @@ u2* ClassFileParser::parse_localvariable_table(u4 code_length,
"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 @@ u2* ClassFileParser::parse_localvariable_table(u4 code_length,
}
-void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index,
- u1* u1_array, u2* u2_array, 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 @@ void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_i
*u2_index = i2;
}
-u1* ClassFileParser::parse_stackmap_table(
- u4 code_attribute_length, TRAPS) {
- if (code_attribute_length == 0)
- return NULL;
+static const u1* parse_stackmap_table(const ClassFileStream* const cfs,
+ u4 code_attribute_length,
+ bool need_verify,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
- ClassFileStream* cfs = stream();
- u1* stackmap_table_start = cfs->get_u1_buffer();
+ if (0 == code_attribute_length) {
+ return NULL;
+ }
+
+ 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);
+ cfs->skip_u1(code_attribute_length, CHECK_NULL);
- if (!_need_verify && !DumpSharedSpaces) {
+ 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 @@ u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length,
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 @@ void ClassFileParser::throwIllegalSignature(
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 @@ ClassFileParser::FieldAnnotationCollector::~FieldAnnotationCollector() {
MetadataFactory::free_array(_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 @@ void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) {
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 @@ void ClassFileParser::ClassAnnotationCollector::apply_to(instanceKlassHandle k)
* 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 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm,
typedef ResourceHashtable 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 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm,
}
// 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_localvariable_table(ConstMethod* cm,
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 @@ void ClassFileParser::copy_method_annotations(ConstMethod* cm,
// 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));
+ name_index, CHECK_NULL);
+ const Symbol* const name = cp->symbol_at(name_index);
+ verify_legal_method_name(name, CHECK_NULL);
- u2 signature_index = cfs->get_u2_fast();
+ 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);
+ signature_index, CHECK_NULL);
+ const Symbol* const signature = cp->symbol_at(signature_index);
- AccessFlags access_flags;
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
} else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) {
flags &= JVM_ACC_STATIC | JVM_ACC_STRICT;
} else {
- classfile_parse_error("Method is not static in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Method 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 , class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Interface cannot have a method named , 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* 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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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));
+ method_attribute_name_index, CHECK_NULL);
- Symbol* method_attribute_name = _cp->symbol_at(method_attribute_name_index);
+ 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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
// 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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
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 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
// 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.
+// 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");
-Array* 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();
+ 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(_loader_data, length, NULL, CHECK_NULL);
+ _methods = MetadataFactory::new_array(_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 @@ Array* ClassFileParser::parse_methods(bool is_interface,
&& !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 @@ Array* ClassFileParser::parse_methods(bool is_interface,
{
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 @@ Array* ClassFileParser::parse_methods(bool is_interface,
}
if (dup) {
classfile_parse_error("Duplicate method name&signature in class file %s",
- CHECK_NULL);
+ CHECK);
}
}
}
- return _methods;
}
-
-intArray* ClassFileParser::sort_methods(Array* methods) {
- int length = methods->length();
+static const intArray* sort_methods(Array* 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 @@ intArray* ClassFileParser::sort_methods(Array* methods) {
// 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 @@ intArray* ClassFileParser::sort_methods(Array* methods) {
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 @@ intArray* ClassFileParser::sort_methods(Array* methods) {
}
// 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 @@ u2 ClassFileParser::parse_generic_signature_attribute(TRAPS) {
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 @@ void ClassFileParser::parse_classfile_sourcefile_attribute(TRAPS) {
set_class_sourcefile_index(sourcefile_index);
}
+void ClassFileParser::parse_classfile_source_debug_extension_attribute(const ClassFileStream* const cfs,
+ int length,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
-
-void ClassFileParser::parse_classfile_source_debug_extension_attribute(int length, TRAPS) {
- ClassFileStream* cfs = stream();
- u1* sde_buffer = cfs->get_u1_buffer();
+ 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 @@ void ClassFileParser::parse_classfile_source_debug_extension_attribute(int lengt
// 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 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_at
// ...
// enclosing_method_class_index,
// enclosing_method_method_index]
- int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0);
- Array* inner_classes = MetadataFactory::new_array(_loader_data, size, CHECK_0);
+ const int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0);
+ Array* const inner_classes = MetadataFactory::new_array(_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 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_at
"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 @@ void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) {
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 @@ void ClassFileParser::parse_classfile_signature_attribute(TRAPS) {
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 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_b
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 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_b
// 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);
+ const int index_size = (attribute_array_length * 2);
- Array* operands = MetadataFactory::new_array(_loader_data, index_size + operand_count, CHECK);
+ Array* const operands =
+ MetadataFactory::new_array(_loader_data, index_size + operand_count, CHECK);
// Eagerly assign operands so they will be deallocated with the constant
// pool if there is an error.
- _cp->set_operands(operands);
+ 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 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_b
// 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 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_b
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 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio
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 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio
} 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 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio
"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 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio
"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 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio
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 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio
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 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio
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 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio
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::parse_classfile_attributes(ClassFileParser::ClassAnnotatio
}
}
-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 @@ void ClassFileParser::create_combined_annotations(TRAPS) {
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 @@ void ClassFileParser::create_combined_annotations(TRAPS) {
// 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 @@ void ClassFileParser::apply_parsed_class_metadata(
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 @@ AnnotationArray* ClassFileParser::assemble_annotations(u1* runtime_visible_annot
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 @@ instanceKlassHandle ClassFileParser::parse_super_class(int super_class_index,
// 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 @@ instanceKlassHandle ClassFileParser::parse_super_class(int super_class_index,
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* 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 @@ class FieldLayoutInfo : public StackObj {
};
// 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 @@ void ClassFileParser::layout_fields(Handle class_loader,
// 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 @@ void ClassFileParser::layout_fields(Handle class_loader,
// 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;
+ int next_nonstatic_field_offset = nonstatic_fields_start;
- bool is_contended_class = parsed_annotations->is_contended();
+ 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 @@ void ClassFileParser::layout_fields(Handle class_loader,
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 @@ void ClassFileParser::layout_fields(Handle class_loader,
//
// 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 @@ void ClassFileParser::layout_fields(Handle class_loader,
// 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 @@ void ClassFileParser::layout_fields(Handle class_loader,
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 @@ void ClassFileParser::layout_fields(Handle class_loader,
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 @@ void ClassFileParser::layout_fields(Handle class_loader,
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 @@ void ClassFileParser::layout_fields(Handle class_loader,
}
}
- 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 @@ void ClassFileParser::layout_fields(Handle class_loader,
// 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 @@ void ClassFileParser::layout_fields(Handle class_loader,
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 @@ void ClassFileParser::layout_fields(Handle class_loader,
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 @@ void ClassFileParser::layout_fields(Handle class_loader,
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 @@ void ClassFileParser::layout_fields(Handle class_loader,
if (PrintFieldLayout) {
print_field_layout(_class_name,
_fields,
- _cp,
+ cp,
instance_size,
nonstatic_fields_start,
nonstatic_fields_end,
@@ -3733,751 +4121,13 @@ void ClassFileParser::layout_fields(Handle class_loader,
info->has_nonstatic_fields = has_nonstatic_fields;
}
+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) {
-instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
- ClassLoaderData* loader_data,
- Handle protection_domain,
- KlassHandle host_klass,
- GrowableArray* cp_patches,
- TempNewSymbol& parsed_name,
- bool verify,
- TRAPS) {
+ assert(k != NULL, "invariant");
- // 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* local_interfaces =
- parse_interfaces(itfs_len, protection_domain, _class_name,
- &has_default_methods, CHECK_(nullHandle));
-
- u2 java_fields_count = 0;
- // Fields (offsets are filled in later)
- FieldAllocationCount fac;
- Array* fields = parse_fields(class_name,
- access_flags.is_interface(),
- &fac, &java_fields_count,
- CHECK_(nullHandle));
- // Methods
- bool has_final_method = false;
- AccessFlags promoted_flags;
- promoted_flags.set_flags(0);
- Array* methods = parse_methods(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 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* 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(_loader_data, _fields);
-
- // Free methods
- InstanceKlass::deallocate_methods(_loader_data, _methods);
-
- // beware of the Universe::empty_blah_array!!
- if (_inner_classes != Universe::the_empty_short_array()) {
- MetadataFactory::free_array(_loader_data, _inner_classes);
- }
-
- // Free interfaces
- InstanceKlass::deallocate_interfaces(_loader_data, _super_klass(),
- _local_interfaces, _transitive_interfaces);
-
- 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(_loader_data, _annotations);
- MetadataFactory::free_array(_loader_data, _type_annotations);
- Annotations::free_contents(_loader_data, _fields_annotations);
- Annotations::free_contents(_loader_data, _fields_type_annotations);
- }
-
- clear_class_metadata();
-
- // deallocate the klass if already created. 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* 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) {
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::fill_oop_maps(instanceKlassHandle k,
}
-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 @@ void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) {
// 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* local_interfaces = defined_klass->local_interfaces();
+ const Array* 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 @@ void ClassFileParser::record_defined_class_dependencies(instanceKlassHandle defi
// utility methods for appending an array with check for duplicates
-void append_interfaces(GrowableArray* result, Array* ifs) {
+static void append_interfaces(GrowableArray* result,
+ const Array* 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* ClassFileParser::compute_transitive_interfaces(
- instanceKlassHandle super,
- Array* local_ifs, TRAPS) {
+static Array* compute_transitive_interfaces(const InstanceKlass* super,
+ Array* 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 @@ Array* ClassFileParser::compute_transitive_interfaces(
return local_ifs;
} else {
ResourceMark rm;
- GrowableArray* result = new GrowableArray(max_transitive_size);
+ GrowableArray* const result = new GrowableArray(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* new_result = MetadataFactory::new_array(_loader_data, length, CHECK_NULL);
+ Array* const new_result =
+ MetadataFactory::new_array(loader_data, length, CHECK_NULL);
for (int i = 0; i < length; i++) {
- Klass* e = result->at(i);
- assert(e != NULL, "just checking");
+ 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_class_access(instanceKlassHandle this_klass, T
}
-void ClassFileParser::check_super_interface_access(instanceKlassHandle this_klass, TRAPS) {
- Array* 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* 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_super_interface_access(instanceKlassHandle this_klas
}
-void ClassFileParser::check_final_method_override(instanceKlassHandle this_klass, TRAPS) {
- Array* 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* 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 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 @@ void ClassFileParser::check_final_method_override(instanceKlassHandle this_klass
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 @@ void ClassFileParser::check_final_method_override(instanceKlassHandle this_klass
// 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* methods = this_klass->methods();
- int num_methods = methods->length();
+ const Array* 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 @@ void ClassFileParser::check_illegal_static_method(instanceKlassHandle this_klass
// 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 @@ void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) {
}
}
-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 @@ bool ClassFileParser::has_illegal_visibility(jint flags) {
(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_field_modifiers(
}
}
-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_method_modifiers(
}
}
-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= 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 @@ void ClassFileParser::verify_legal_utf8(const unsigned char* buffer, int length,
} // end of for
}
+// Unqualified names may not contain the characters '.', ';', '[', or '/'.
+// Method names also may not contain the characters '<' or '>', unless
+// or . Note that method names may not be or 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 @@ void ClassFileParser::verify_legal_class_name(Symbol* name, TRAPS) {
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 @@ void ClassFileParser::verify_legal_class_name(Symbol* name, TRAPS) {
}
if (!legal) {
ResourceMark rm(THREAD);
+ assert(_class_name != NULL, "invariant");
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -5065,7 +4922,7 @@ void ClassFileParser::verify_legal_class_name(Symbol* name, TRAPS) {
}
// 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 @@ void ClassFileParser::verify_legal_field_name(Symbol* name, TRAPS) {
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 @@ void ClassFileParser::verify_legal_field_name(Symbol* name, TRAPS) {
if (!legal) {
ResourceMark rm(THREAD);
+ assert(_class_name != NULL, "invariant");
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -5098,7 +4956,7 @@ void ClassFileParser::verify_legal_field_name(Symbol* name, TRAPS) {
}
// 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 @@ void ClassFileParser::verify_legal_method_name(Symbol* name, TRAPS) {
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 @@ void ClassFileParser::verify_legal_method_name(Symbol* name, TRAPS) {
if (!legal) {
ResourceMark rm(THREAD);
+ assert(_class_name != NULL, "invariant");
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -5136,13 +4995,15 @@ void ClassFileParser::verify_legal_method_name(Symbol* name, TRAPS) {
// 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 @@ void ClassFileParser::verify_legal_field_signature(Symbol* name, Symbol* signatu
// 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 @@ int ClassFileParser::verify_legal_method_signature(Symbol* name, Symbol* signatu
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 @@ int ClassFileParser::verify_legal_method_signature(Symbol* name, Symbol* signatu
return 0;
}
-
-// Unqualified names may not contain the characters '.', ';', '[', or '/'.
-// Method names also may not contain the characters '<' or '>', unless
-// or . Note that method names may not be or 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 '['
- }
- 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;
+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;
+}
-// 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;
+jint ClassFileParser::layout_size() const {
+ assert(_field_info != NULL, "invariant");
+ return _field_info->instance_size;
+}
- 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
+static void check_methods_for_intrinsics(const InstanceKlass* ik,
+ const Array* 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));
}
- 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;
- 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 (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;
+ // 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));
}
+ }
+ } // end for
- if (result.get_jboolean()) {
+#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;
}
- }
- }
- 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.
-char* ClassFileParser::skip_over_field_signature(char* signature,
- bool void_ok,
- unsigned int length,
- 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);
+ 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;
}
- 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);
+ 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));
+ }
}
- // The rest of what's there better be a legal signature
- signature++;
- length--;
- void_ok = false;
- break;
+ } // end for
+ } // CheckIntrinsics
+#endif // ASSERT
+ }
+}
- default:
- return NULL;
+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* 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(_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 NULL;
+
+ // 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());
+ }
+ } else {
+ tty->print("[Loaded %s from %s]\n", ik->external_name(),
+ _loader_data->class_loader()->klass()->external_name());
+ }
+ }
+
+ 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());
+ }
+ // print out each of the interface classes referred to by this class.
+ const Array* 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);
+ }
+ }
+ }
+ }
+
+ 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* 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(_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(_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(_loader_data, _annotations);
+ MetadataFactory::free_array(_loader_data, _type_annotations);
+ Annotations::free_contents(_loader_data, _fields_annotations);
+ Annotations::free_contents(_loader_data, _fields_type_annotations);
+ }
+
+ clear_class_metadata();
+
+ // deallocate the klass if already created. 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);
+ }
+}
+
+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) {
+ 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);
+ }
+ _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");
+ }
+ }
+
+ // 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(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();
}
diff --git a/hotspot/src/share/vm/classfile/classFileParser.hpp b/hotspot/src/share/vm/classfile/classFileParser.hpp
index ec7ea19cba2..d6fd836d61c 100644
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp
@@ -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
+class Array;
+class ClassFileStream;
+class ClassLoaderData;
class CompressedLineNumberWriteStream;
-class FieldAllocationCount;
+class ConstMethod;
class FieldInfo;
-class FieldLayoutInfo;
-
+template
+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* _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* _fields;
+ Array* _methods;
+ Array* _inner_classes;
+ Array* _local_interfaces;
+ Array* _transitive_interfaces;
+ Annotations* _combined_annotations;
+ AnnotationArray* _annotations;
+ AnnotationArray* _type_annotations;
+ Array* _fields_annotations;
+ Array* _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* _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* _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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
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* _fields;
- Array* _methods;
- Array* _inner_classes;
- Array* _local_interfaces;
- Array* _transitive_interfaces;
- Annotations* _combined_annotations;
- AnnotationArray* _annotations;
- AnnotationArray* _type_annotations;
- Array* _fields_annotations;
- Array* _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* 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);
+
+ const InstanceKlass* parse_super_class(ConstantPool* const cp,
+ const int super_class_index,
+ const bool need_verify,
+ TRAPS);
- instanceKlassHandle parse_super_class(int super_class_index, 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* parse_fields(Symbol* class_name,
- bool is_interface,
- FieldAllocationCount *fac,
- u2* java_fields_count_ptr, TRAPS);
- void print_field_layout(Symbol* name,
- Array* 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* parse_methods(bool is_interface,
- AccessFlags* promoted_flags,
- bool* has_final_method,
- bool* declares_default_methods,
- TRAPS);
- intArray* sort_methods(Array* methods);
+ Method* parse_method(const ClassFileStream* const cfs,
+ bool is_interface,
+ const ConstantPool* cp,
+ AccessFlags* const promoted_flags,
+ 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_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);
+
+ 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* compute_transitive_interfaces(instanceKlassHandle super,
- Array* 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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
#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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
#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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
}
}
- 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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
}
}
- 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_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_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;
- bool is_anonymous() {
- return _host_klass.not_null();
- }
- bool has_cp_patch_at(int index) {
+ 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;
+
+ 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* 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* 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; }
+
+ 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* 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; }
- // 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);
};
#endif // SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
diff --git a/hotspot/src/share/vm/classfile/classFileStream.cpp b/hotspot/src/share/vm/classfile/classFileStream.cpp
index 4cd811f88b3..cbe37f195db 100644
--- a/hotspot/src/share/vm/classfile/classFileStream.cpp
+++ b/hotspot/src/share/vm/classfile/classFileStream.cpp
@@ -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 @@ u1 ClassFileStream::get_u1(TRAPS) {
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);
}
diff --git a/hotspot/src/share/vm/classfile/classFileStream.hpp b/hotspot/src/share/vm/classfile/classFileStream.hpp
index df44070252e..2d69de74b3a 100644
--- a/hotspot/src/share/vm/classfile/classFileStream.hpp
+++ b/hotspot/src/share/vm/classfile/classFileStream.hpp
@@ -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 ;
+
+ protected:
+ const u1* clone_buffer() const;
+ const char* const clone_source() const;
- void truncated_file_error(TRAPS);
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 @@ class ClassFileStream: public ResourceObj {
// 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
diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp
index 8ef74775f4c..8a2597f515e 100644
--- a/hotspot/src/share/vm/classfile/classLoader.cpp
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp
@@ -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 @@ bool string_ends_with(const char* str, const char* str_to_find) {
}
-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 @@ ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
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 @@ u1* ClassPathZipEntry::open_entry(const char* name, jint* filesize, bool nul_ter
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 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
}
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,73 +1003,93 @@ objArrayOop ClassLoader::get_system_packages(TRAPS) {
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");
+
+ 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();
-instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
- ResourceMark rm(THREAD);
- const char* class_name = h_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 *t, int length,
int number_of_entries) {
diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp
index 63034372251..92ee90f2675 100644
--- a/hotspot/src/share/vm/classfile/classLoader.hpp
+++ b/hotspot/src/share/vm/classfile/classLoader.hpp
@@ -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 {
- private:
+class ClassPathEntry : public CHeapObj {
+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 @@ class ClassPathZipEntry: public ClassPathEntry {
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 @@ private:
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 @@ class ClassLoader: AllStatic {
// 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 @@ class ClassLoader: AllStatic {
}
// 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.
diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp
index 734b4acb225..7415ab64ba6 100644
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp
@@ -166,7 +166,9 @@ void ClassLoaderData::classes_do(void f(InstanceKlass*)) {
}
}
-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 ClassLoaderDataGraph::clear_claimed_marks() {
}
}
-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",
diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp
index ce323c799f8..4d4b9d48e41 100644
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp
@@ -275,7 +275,7 @@ class ClassLoaderData : public CHeapObj {
// 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 @@ class ClassLoaderData : public CHeapObj {
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 @@ class ClassLoaderData : public CHeapObj {
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) {
diff --git a/hotspot/src/share/vm/classfile/classLoaderExt.hpp b/hotspot/src/share/vm/classfile/classLoaderExt.hpp
index c455a25bd5c..990a8b61f04 100644
--- a/hotspot/src/share/vm/classfile/classLoaderExt.hpp
+++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp
@@ -41,7 +41,7 @@ public:
_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 @@ public:
}
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);
diff --git a/hotspot/src/share/vm/classfile/compactHashtable.cpp b/hotspot/src/share/vm/classfile/compactHashtable.cpp
index c951c512558..68781c1e14d 100644
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/compactHashtable.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "memory/metaspaceShared.hpp"
#include "prims/jvm.h"
diff --git a/hotspot/src/share/vm/classfile/compactHashtable.hpp b/hotspot/src/share/vm/classfile/compactHashtable.hpp
index 5df875fd8ec..1c9e336729a 100644
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp
@@ -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 @@ public:
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 @@ private:
juint* _buckets;
inline Symbol* lookup_entry(CompactHashtable* 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* 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 @@ public:
}
// 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);
diff --git a/hotspot/src/share/vm/classfile/compactHashtable.inline.hpp b/hotspot/src/share/vm/classfile/compactHashtable.inline.hpp
new file mode 100644
index 00000000000..96aeb551ccd
--- /dev/null
+++ b/hotspot/src/share/vm/classfile/compactHashtable.inline.hpp
@@ -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
+inline Symbol* CompactHashtable::lookup_entry(CompactHashtable* 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
+inline oop CompactHashtable::lookup_entry(CompactHashtable* 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
+inline T CompactHashtable::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
diff --git a/hotspot/src/share/vm/classfile/defaultMethods.cpp b/hotspot/src/share/vm/classfile/defaultMethods.cpp
index 7c5038fd391..c1173aff04c 100644
--- a/hotspot/src/share/vm/classfile/defaultMethods.cpp
+++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp
@@ -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 bool already_in_vtable_slots(GrowableArray* slots, Meth
}
static GrowableArray* find_empty_vtable_slots(
- InstanceKlass* klass, GrowableArray* mirandas, TRAPS) {
+ InstanceKlass* klass, const GrowableArray* mirandas, TRAPS) {
assert(klass != NULL, "Must be valid class");
@@ -777,7 +778,8 @@ static void create_default_methods( InstanceKlass* klass,
// 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* mirandas, TRAPS) {
+ InstanceKlass* klass, const GrowableArray* 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 @@ void DefaultMethods::generate_default_methods(
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);
diff --git a/hotspot/src/share/vm/classfile/defaultMethods.hpp b/hotspot/src/share/vm/classfile/defaultMethods.hpp
index 9c7470aa944..0e034a29b40 100644
--- a/hotspot/src/share/vm/classfile/defaultMethods.hpp
+++ b/hotspot/src/share/vm/classfile/defaultMethods.hpp
@@ -43,6 +43,6 @@ class DefaultMethods : AllStatic {
// default method. Overpass methods are added to the methods lists for
// the class.
static void generate_default_methods(
- InstanceKlass* klass, GrowableArray* mirandas, TRAPS);
+ InstanceKlass* klass, const GrowableArray* mirandas, TRAPS);
};
#endif // SHARE_VM_CLASSFILE_DEFAULTMETHODS_HPP
diff --git a/hotspot/src/share/vm/classfile/dictionary.hpp b/hotspot/src/share/vm/classfile/dictionary.hpp
index 19bd96e1380..1f308578220 100644
--- a/hotspot/src/share/vm/classfile/dictionary.hpp
+++ b/hotspot/src/share/vm/classfile/dictionary.hpp
@@ -54,7 +54,7 @@ private:
Symbol* name, ClassLoaderData* loader_data);
protected:
- DictionaryEntry* bucket(int i) {
+ DictionaryEntry* bucket(int i) const {
return (DictionaryEntry*)Hashtable::bucket(i);
}
@@ -323,7 +323,7 @@ class DictionaryEntry : public HashtableEntry {
}
}
- 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);
}
diff --git a/hotspot/src/share/vm/classfile/klassFactory.cpp b/hotspot/src/share/vm/classfile/klassFactory.cpp
new file mode 100644
index 00000000000..14af5574021
--- /dev/null
+++ b/hotspot/src/share/vm/classfile/klassFactory.cpp
@@ -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(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* 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;
+}
diff --git a/hotspot/src/share/vm/classfile/klassFactory.hpp b/hotspot/src/share/vm/classfile/klassFactory.hpp
new file mode 100644
index 00000000000..107c8d3576d
--- /dev/null
+++ b/hotspot/src/share/vm/classfile/klassFactory.hpp
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#ifndef SHARE_VM_CLASSFILE_KLASSFACTORY_HPP
+#define SHARE_VM_CLASSFILE_KLASSFACTORY_HPP
+
+#include "memory/allocation.inline.hpp"
+#include "runtime/handles.hpp"
+
+class ClassFileStream;
+class ClassLoaderData;
+template
+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* cp_patches,
+ TempNewSymbol* parsed_name,
+ TRAPS);
+};
+
+#endif // SHARE_VM_CLASSFILE_KLASSFACTORY_HPP
diff --git a/hotspot/src/share/vm/classfile/stringTable.cpp b/hotspot/src/share/vm/classfile/stringTable.cpp
index 7298d848097..59a78bbb221 100644
--- a/hotspot/src/share/vm/classfile/stringTable.cpp
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp
@@ -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"
diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp
index b268e08bdba..ae5dc8b7c20 100644
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp
@@ -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"
diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp
index 2d519c629ef..420bf3f36b0 100644
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp
@@ -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 @@ instanceKlassHandle SystemDictionary::handle_parallel_super_load(
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 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
- KlassHandle host_klass,
+ const Klass* host_klass,
GrowableArray