mirror of
https://github.com/openjdk/jdk9u.git
synced 2025-12-10 13:21:36 -06:00
Merge
This commit is contained in:
commit
eab53bafad
@ -417,9 +417,43 @@ b25838a28195f4b6dab34668411eedd2d366a16c jdk-9+169
|
||||
2c25fc24103251f9711a1c280c31e1e41016d90f jdk-9+172
|
||||
88d7fd969e7df0e07a53b201cfd29393ca33ede9 jdk-9+173
|
||||
5466f409346e0446ee9a6daeb7f5d75c8fc76823 jdk-9+174
|
||||
023f93e511bae768203c33bb8681f82ee75014da jdk-9.0.1+00
|
||||
023f93e511bae768203c33bb8681f82ee75014da jdk-9.0.3+00
|
||||
8f7227c6012b0051ea4e0bcee040c627bf699b88 jdk-9+175
|
||||
84777531d994ef70163d35078ec9c4127f2eadb5 jdk-9+176
|
||||
a4371edb589c60db01142e45c317adb9ccbcb083 jdk-9+177
|
||||
ec4159ebe7050fcc5dcee8a2d150cf948ecc97db jdk-9+178
|
||||
252475ccfd84cc249f8d6faf4b7806b5e2c384ce jdk-9+179
|
||||
d2982a786f53814367698e63efe6349c9128e1db jdk-9+180
|
||||
b656dea9398ef601f7fc08d1a5157a560e0ccbe0 jdk-9+181
|
||||
d73368c690d4f1ab188cf306f4b27218e28596b6 jdk-9.0.3+1
|
||||
ede48839f34b0b74210e2e081872a3c12d5339ab jdk-9.0.3+2
|
||||
086e9950ebfa8a0239018ade61f59b7c539bacc9 jdk-9.0.3+3
|
||||
2c95bee2722f2396b709b384473c07291a7d1e4b jdk-9.0.3+4
|
||||
d24281b60e0bb6d441ec3a9440e7daa322bbc822 jdk-9.0.3+5
|
||||
489c57f8e1c0f6fa34de86f8ed8f98a809cba4a9 jdk-9.0.3+6
|
||||
9d5aca497123931d52625b3539a8549d98728622 jdk-9.0.3+7
|
||||
eaa4ea516c7f1e31c8e0faaec3ef981eb2919ae3 jdk-9.0.3+8
|
||||
a31dfd85bee9c16aac1e65dfbe81d1c5fe443c2c jdk-9.0.3+9
|
||||
9acb1002f33e257e932a188632969e45cc32e66c jdk-9.0.1+10
|
||||
9acb1002f33e257e932a188632969e45cc32e66c jdk-9.0.1+10
|
||||
0000000000000000000000000000000000000000 jdk-9.0.1+10
|
||||
0000000000000000000000000000000000000000 jdk-9.0.1+10
|
||||
5a9191c980ca3ada63b234e2b9ec6dc23bd37595 jdk-9.0.1+10
|
||||
e6edc89f5b2dc6dacd6041305e942a3f04a25ce5 jdk-9.0.1+11
|
||||
3a64fdb24a8c26e2d7d32864dad4425a9496b90d jdk-9.0.4+00
|
||||
726bf8524f7d3780518ada8648488ad4a7bfe6a2 jdk-9.0.4+1
|
||||
8055b6778ac8fc6bb165082230951cc8f146f8fd jdk-9.0.4+2
|
||||
572ea0db1d87a1d2fcc01f73ffbcfb78bd5688f4 jdk-9.0.4+3
|
||||
0053ace2e9e484fb52d00ec961e24805d0aae04a jdk-9.0.4+4
|
||||
73d63ccf56f46f258f367ed72633f0f5cc229680 jdk-9.0.4+5
|
||||
86219e4c9f8cd730bacd2f6080b6ac1dea7a0226 jdk-9.0.4+6
|
||||
9aba57f3071362ed7f2326d737506863b9d2646f jdk-9.0.4+7
|
||||
a4f0515fe6da55cfe74dec3e6e30b69c9693d133 jdk-9.0.4+8
|
||||
a4f0515fe6da55cfe74dec3e6e30b69c9693d133 jdk-9.0.4+8
|
||||
0000000000000000000000000000000000000000 jdk-9.0.4+8
|
||||
0000000000000000000000000000000000000000 jdk-9.0.4+8
|
||||
953d306b203e7d0808cb842a51e006fddc41b6c2 jdk-9.0.4+8
|
||||
c6f4c28a56ef14fb9a41303390b9584976765502 jdk-9.0.4+9
|
||||
409c6b8aa5cae19a701ddd2fb09f85fb9af7da78 jdk-9.0.4+10
|
||||
620cbf135de96df32c78c2693cfbf275dec1cb4d jdk-9.0.4+11
|
||||
|
||||
@ -1 +1,2 @@
|
||||
project=jdk9
|
||||
bugids=dup
|
||||
|
||||
37
ADDITIONAL_LICENSE_INFO
Normal file
37
ADDITIONAL_LICENSE_INFO
Normal file
@ -0,0 +1,37 @@
|
||||
ADDITIONAL INFORMATION ABOUT LICENSING
|
||||
|
||||
Certain files distributed by Oracle America, Inc. and/or its affiliates are
|
||||
subject to the following clarification and special exception to the GPLv2,
|
||||
based on the GNU Project exception for its Classpath libraries, known as the
|
||||
GNU Classpath Exception.
|
||||
|
||||
Note that Oracle includes multiple, independent programs in this software
|
||||
package. Some of those programs are provided under licenses deemed
|
||||
incompatible with the GPLv2 by the Free Software Foundation and others.
|
||||
For example, the package includes programs licensed under the Apache
|
||||
License, Version 2.0 and may include FreeType. Such programs are licensed
|
||||
to you under their original licenses.
|
||||
|
||||
Oracle facilitates your further distribution of this package by adding the
|
||||
Classpath Exception to the necessary parts of its GPLv2 code, which permits
|
||||
you to use that code in combination with other independent modules not
|
||||
licensed under the GPLv2. However, note that this would not permit you to
|
||||
commingle code under an incompatible license with Oracle's GPLv2 licensed
|
||||
code by, for example, cutting and pasting such code into a file also
|
||||
containing Oracle's GPLv2 licensed code and then distributing the result.
|
||||
|
||||
Additionally, if you were to remove the Classpath Exception from any of the
|
||||
files to which it applies and distribute the result, you would likely be
|
||||
required to license some or all of the other code in that distribution under
|
||||
the GPLv2 as well, and since the GPLv2 is incompatible with the license terms
|
||||
of some items included in the distribution by Oracle, removing the Classpath
|
||||
Exception could therefore effectively compromise your ability to further
|
||||
distribute the package.
|
||||
|
||||
Failing to distribute notices associated with some files may also create
|
||||
unexpected legal consequences.
|
||||
|
||||
Proceed with caution and we recommend that you obtain the advice of a lawyer
|
||||
skilled in open source matters before removing the Classpath Exception or
|
||||
making modifications to this package which may subsequently be redistributed
|
||||
and/or involve the use of third party software.
|
||||
@ -1090,10 +1090,6 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS],
|
||||
# We can build without it.
|
||||
LDD="true"
|
||||
fi
|
||||
BASIC_PATH_PROGS(OTOOL, otool)
|
||||
if test "x$OTOOL" = "x"; then
|
||||
OTOOL="true"
|
||||
fi
|
||||
BASIC_PATH_PROGS(READELF, [greadelf readelf])
|
||||
BASIC_PATH_PROGS(DOT, dot)
|
||||
BASIC_PATH_PROGS(HG, hg)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -443,20 +443,31 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE],
|
||||
fi
|
||||
AC_MSG_RESULT([$BUNDLE_FREETYPE])
|
||||
|
||||
fi # end freetype needed
|
||||
|
||||
FREETYPE_LICENSE=""
|
||||
if test "x$with_freetype_license" = "xyes"; then
|
||||
AC_MSG_ERROR([--with-freetype-license must have a value])
|
||||
elif test "x$with_freetype_license" != "x"; then
|
||||
AC_MSG_CHECKING([for freetype license])
|
||||
AC_MSG_RESULT([$with_freetype_license])
|
||||
FREETYPE_LICENSE="$with_freetype_license"
|
||||
BASIC_FIXUP_PATH(FREETYPE_LICENSE)
|
||||
if test ! -f "$FREETYPE_LICENSE"; then
|
||||
AC_MSG_ERROR([$FREETYPE_LICENSE cannot be found])
|
||||
if test "x$BUNDLE_FREETYPE" = xyes; then
|
||||
FREETYPE_LICENSE=""
|
||||
AC_MSG_CHECKING([for freetype license])
|
||||
if test "x$with_freetype_license" = "xyes"; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([--with-freetype-license must have a value])
|
||||
elif test "x$with_freetype_license" != "x"; then
|
||||
AC_MSG_RESULT([$with_freetype_license])
|
||||
FREETYPE_LICENSE="$with_freetype_license"
|
||||
BASIC_FIXUP_PATH(FREETYPE_LICENSE)
|
||||
if test ! -f "$FREETYPE_LICENSE"; then
|
||||
AC_MSG_ERROR([$FREETYPE_LICENSE cannot be found])
|
||||
fi
|
||||
else
|
||||
if test "x$with_freetype" != "x" && test -f $with_freetype/freetype.md; then
|
||||
FREETYPE_LICENSE="$with_freetype/freetype.md"
|
||||
AC_MSG_RESULT([$FREETYPE_LICENSE])
|
||||
BASIC_FIXUP_PATH(FREETYPE_LICENSE)
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
fi # end freetype needed
|
||||
|
||||
AC_SUBST(FREETYPE_BUNDLE_LIB_PATH)
|
||||
AC_SUBST(FREETYPE_CFLAGS)
|
||||
|
||||
@ -483,6 +483,7 @@ GNM:=@GNM@
|
||||
STRIP:=@STRIP@
|
||||
|
||||
LIPO:=@LIPO@
|
||||
INSTALL_NAME_TOOL:=@INSTALL_NAME_TOOL@
|
||||
|
||||
# Options to linker to specify a mapfile.
|
||||
# (Note absence of := assignment, because we do not want to evaluate the macro body here)
|
||||
|
||||
@ -628,6 +628,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA],
|
||||
if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then
|
||||
BASIC_PATH_PROGS(LIPO, lipo)
|
||||
BASIC_FIXUP_EXECUTABLE(LIPO)
|
||||
BASIC_REQUIRE_PROGS(OTOOL, otool)
|
||||
BASIC_FIXUP_EXECUTABLE(OTOOL)
|
||||
BASIC_REQUIRE_PROGS(INSTALL_NAME_TOOL, install_name_tool)
|
||||
BASIC_FIXUP_EXECUTABLE(INSTALL_NAME_TOOL)
|
||||
fi
|
||||
|
||||
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,7 +27,7 @@
|
||||
|
||||
DEFAULT_VERSION_MAJOR=9
|
||||
DEFAULT_VERSION_MINOR=0
|
||||
DEFAULT_VERSION_SECURITY=0
|
||||
DEFAULT_VERSION_SECURITY=4
|
||||
DEFAULT_VERSION_PATCH=0
|
||||
|
||||
LAUNCHER_NAME=openjdk
|
||||
|
||||
@ -387,7 +387,7 @@ var getJibProfilesCommon = function (input, data) {
|
||||
// on such hardware.
|
||||
if (input.build_cpu == "sparcv9") {
|
||||
var cpu_brand = $EXEC("bash -c \"kstat -m cpu_info | grep brand | head -n1 | awk '{ print \$2 }'\"");
|
||||
if (cpu_brand.trim().match('SPARC-.7')) {
|
||||
if (cpu_brand.trim().match('SPARC-.[78]')) {
|
||||
boot_jdk_revision = "8u20";
|
||||
boot_jdk_subdirpart = "1.8.0_20";
|
||||
}
|
||||
@ -435,7 +435,7 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
"macosx-x64": {
|
||||
target_os: "macosx",
|
||||
target_cpu: "x64",
|
||||
dependencies: ["devkit"],
|
||||
dependencies: ["devkit", "freetype"],
|
||||
configure_args: concat(common.configure_args_64bit, "--with-zlib=system"),
|
||||
},
|
||||
|
||||
@ -728,9 +728,9 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
jdk: {
|
||||
local: "bundles/\\(jdk.*bin.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/linux-x64/jdk-" + data.version
|
||||
"bundles/openjdk/GPL/linux-x64/openjdk-" + data.version
|
||||
+ "_linux-x64_bin.tar.gz",
|
||||
"bundles/openjdk/GPL/linux-x64/\\1"
|
||||
"bundles/openjdk/GPL/linux-x64/open\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
@ -741,17 +741,17 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
test: {
|
||||
local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/linux-x64/jdk-" + data.version
|
||||
"bundles/openjdk/GPL/linux-x64/openjdk-" + data.version
|
||||
+ "_linux-x64_bin-tests.tar.gz",
|
||||
"bundles/openjdk/GPL/linux-x64/\\1"
|
||||
"bundles/openjdk/GPL/linux-x64/open\\1"
|
||||
]
|
||||
},
|
||||
jdk_symbols: {
|
||||
local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/linux-x64/jdk-" + data.version
|
||||
"bundles/openjdk/GPL/linux-x64/openjdk-" + data.version
|
||||
+ "_linux-x64_bin-symbols.tar.gz",
|
||||
"bundles/openjdk/GPL/linux-x64/\\1"
|
||||
"bundles/openjdk/GPL/linux-x64/open\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
@ -771,27 +771,27 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
jdk: {
|
||||
local: "bundles/\\(jdk.*bin.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/linux-x86/jdk-" + data.version
|
||||
"bundles/openjdk/GPL/linux-x86/openjdk-" + data.version
|
||||
+ "_linux-x86_bin.tar.gz",
|
||||
"bundles/openjdk/GPL/linux-x86/\\1"
|
||||
"bundles/openjdk/GPL/linux-x86/open\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
jdk_symbols: {
|
||||
local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/linux-x86/jdk-" + data.version
|
||||
"bundles/openjdk/GPL/linux-x86/openjdk-" + data.version
|
||||
+ "_linux-x86_bin-symbols.tar.gz",
|
||||
"bundles/openjdk/GPL/linux-x86/\\1"
|
||||
"bundles/openjdk/GPL/linux-x86/open\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
test: {
|
||||
local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/linux-x86/jdk-" + data.version
|
||||
"bundles/openjdk/GPL/linux-x86/openjdk-" + data.version
|
||||
+ "_linux-x86_bin-tests.tar.gz",
|
||||
"bundles/openjdk/GPL/linux-x86/\\1"
|
||||
"bundles/openjdk/GPL/linux-x86/open\\1"
|
||||
]
|
||||
},
|
||||
jre: {
|
||||
@ -814,41 +814,84 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
}
|
||||
},
|
||||
|
||||
"windows-x86-open": {
|
||||
"macosx-x64-open": {
|
||||
artifacts: {
|
||||
jdk: {
|
||||
local: "bundles/\\(jdk.*bin.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/windows-x86/jdk-" + data.version
|
||||
+ "_windows-x86_bin.tar.gz",
|
||||
"bundles/openjdk/GPL/windows-x86/\\1"
|
||||
"bundles/openjdk/GPL/osx-x64/openjdk-" + data.version
|
||||
+ "_osx-x64_bin.tar.gz",
|
||||
"bundles/openjdk/GPL/osx-x64/open\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
jre: {
|
||||
local: "bundles/\\(jre.*bin.tar.gz\\)",
|
||||
remote: "bundles/openjdk/GPL/windows-x86/\\1"
|
||||
remote: "bundles/openjdk/GPL/osx-x64/\\1",
|
||||
},
|
||||
test: {
|
||||
local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/windows-x86/jdk-" + data.version
|
||||
+ "_windows-x86_bin-tests.tar.gz",
|
||||
"bundles/openjdk/GPL/windows-x86/\\1"
|
||||
"bundles/openjdk/GPL/osx-x64/openjdk-" + data.version
|
||||
+ "_osx-x64_bin-tests.tar.gz",
|
||||
"bundles/openjdk/GPL/osx-x64/open\\1"
|
||||
]
|
||||
},
|
||||
jdk_symbols: {
|
||||
local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/windows-x86/jdk-" + data.version
|
||||
+ "_windows-x86_bin-symbols.tar.gz",
|
||||
"bundles/openjdk/GPL/windows-x86/\\1"
|
||||
"bundles/openjdk/GPL/osx-x64/openjdk-" + data.version
|
||||
+ "_osx-x64_bin-symbols.tar.gz",
|
||||
"bundles/openjdk/GPL/osx-x64/open\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
jre_symbols: {
|
||||
local: "bundles/\\(jre.*bin-symbols.tar.gz\\)",
|
||||
remote: "bundles/openjdk/GPL/windows-x86/\\1",
|
||||
remote: "bundles/openjdk/GPL/osx-x64/\\1",
|
||||
},
|
||||
doc_api_spec: {
|
||||
local: "bundles/\\(jdk.*doc-api-spec.tar.gz\\)",
|
||||
remote: "bundles/openjdk/GPL/osx-x64/\\1",
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
"windows-x64-open": {
|
||||
artifacts: {
|
||||
jdk: {
|
||||
local: "bundles/\\(jdk.*bin.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/windows-x64/openjdk-" + data.version
|
||||
+ "_windows-x64_bin.tar.gz",
|
||||
"bundles/openjdk/GPL/windows-x64/open\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
jre: {
|
||||
local: "bundles/\\(jre.*bin.tar.gz\\)",
|
||||
remote: "bundles/openjdk/GPL/windows-x64/\\1"
|
||||
},
|
||||
test: {
|
||||
local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/windows-x64/openjdk-" + data.version
|
||||
+ "_windows-x64_bin-tests.tar.gz",
|
||||
"bundles/openjdk/GPL/windows-x64/open\\1"
|
||||
]
|
||||
},
|
||||
jdk_symbols: {
|
||||
local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/windows-x64/openjdk-" + data.version
|
||||
+ "_windows-x64_bin-symbols.tar.gz",
|
||||
"bundles/openjdk/GPL/windows-x64/open\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
jre_symbols: {
|
||||
local: "bundles/\\(jre.*bin-symbols.tar.gz\\)",
|
||||
remote: "bundles/openjdk/GPL/windows-x64/\\1",
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -880,10 +923,11 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
profiles["linux-x64-ri"] = clone(profiles["linux-x64-open"]);
|
||||
profiles["linux-x86-ri"] = clone(profiles["linux-x86-open"]);
|
||||
profiles["linux-x86-ri-debug"] = clone(profiles["linux-x86-open-debug"]);
|
||||
profiles["windows-x86-ri"] = clone(profiles["windows-x86-open"]);
|
||||
profiles["macosx-x64-ri"] = clone(profiles["macosx-x64-open"]);
|
||||
profiles["windows-x64-ri"] = clone(profiles["windows-x64-open"]);
|
||||
|
||||
// Generate artifacts for ri profiles
|
||||
[ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "windows-x86-ri" ]
|
||||
[ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x64-ri" ]
|
||||
.forEach(function (name) {
|
||||
// Rewrite all remote dirs to "bundles/openjdk/BCL/..."
|
||||
for (artifactName in profiles[name].artifacts) {
|
||||
@ -893,16 +937,6 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
}
|
||||
});
|
||||
|
||||
// The windows ri profile needs to add the freetype license file
|
||||
profilesRiFreetype = {
|
||||
"windows-x86-ri": {
|
||||
configure_args: "--with-freetype-license="
|
||||
+ input.get("freetype", "install_path")
|
||||
+ "/freetype-2.7.1-v120-x86/freetype.md"
|
||||
}
|
||||
};
|
||||
profiles = concatObjects(profiles, profilesRiFreetype);
|
||||
|
||||
// Generate the missing platform attributes
|
||||
profiles = generatePlatformAttributes(profiles);
|
||||
profiles = generateDefaultMakeTargetsConfigureArg(common, profiles);
|
||||
@ -934,6 +968,12 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
? input.target_os + "_x64"
|
||||
: input.target_platform);
|
||||
|
||||
var freetype_version = {
|
||||
windows_x64: "2.7.1-v120+1.1",
|
||||
windows_x86: "2.7.1-v120+1.1",
|
||||
macosx_x64: "2.7.1-Xcode6.3-MacOSX10.9+1.0"
|
||||
}[input.target_platform];
|
||||
|
||||
var dependencies = {
|
||||
|
||||
boot_jdk: {
|
||||
@ -998,7 +1038,7 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
freetype: {
|
||||
organization: common.organization,
|
||||
ext: "tar.gz",
|
||||
revision: "2.7.1-v120+1.0",
|
||||
revision: freetype_version,
|
||||
module: "freetype-" + input.target_platform
|
||||
},
|
||||
|
||||
@ -1200,7 +1240,8 @@ var versionArgs = function(input, common) {
|
||||
if (input.build_type == "promoted") {
|
||||
args = concat(args,
|
||||
// This needs to be changed when we start building release candidates
|
||||
"--with-version-pre=ea",
|
||||
// 'ea' for EA builds and empty value for 'fcs'
|
||||
"--with-version-pre=",
|
||||
"--without-version-opt");
|
||||
} else {
|
||||
args = concat(args, "--with-version-opt=" + common.build_id);
|
||||
|
||||
@ -577,9 +577,35 @@ d53171650a2cc6c6f699c966c533b914ca9c0602 jdk-9+171
|
||||
1ae9e84f68b359420d2d153ecfe5ee2903e33a2e jdk-9+172
|
||||
e64b1cb48d6e7703928a9d1da106fc27f8cb65fd jdk-9+173
|
||||
944791f8160185bffa13fbb821fc09b6198f1f25 jdk-9+174
|
||||
ca47dcfdd35129fe3ab2dab71b2601d7a0ff07c0 jdk-9.0.1+00
|
||||
ca47dcfdd35129fe3ab2dab71b2601d7a0ff07c0 jdk-9.0.3+00
|
||||
8f04d457168b9f1f4a1b2c37f49e0513ca9d33a7 jdk-9+175
|
||||
2ab74e5dbdc2b6a962c865500cafd23cf387dc60 jdk-9+176
|
||||
1ca8f038fceb88c640badf9bd18905205bc63b43 jdk-9+177
|
||||
9d032191f82fca5ba0aac98682f69c4ff0f1283d jdk-9+178
|
||||
d2661aa42bff322badbe6c1337fc638d2e0f5730 jdk-9+179
|
||||
d7baadc223e790c08bc69bf7e553bce65b4e7e40 jdk-9+180
|
||||
4a443796f6f57842d6a0434ac27ca3d1033ccc20 jdk-9+181
|
||||
8297b62a7b62bafe42c7d567a5752f7a82bafab8 jdk-9.0.3+1
|
||||
d2efdbb193a02613867c8949f783d2905f7a28fc jdk-9.0.3+2
|
||||
68f9ff7c5eedfd41f9c10959e41024efbd3aa79c jdk-9.0.3+3
|
||||
82584ea6464de2e0a59e9fc00173e18a85dc45d8 jdk-9.0.3+4
|
||||
c45e75533bae7b5db5c626bf9233b4226934d582 jdk-9.0.3+5
|
||||
4c0248d117fabf46c5931cdd09e543c3d89b68a5 jdk-9.0.3+6
|
||||
fca264c9fa3ce57b3f4d662242d38b44fb442c87 jdk-9.0.3+7
|
||||
1f5a9c0ddb4b8da443f70fc5d135b320f6e0b78a jdk-9.0.3+8
|
||||
a10c11fed5bdc5202523baee3cf391cc0e0cfcaa jdk-9.0.3+9
|
||||
172baf6c99c5e9fdd72a6f3729f6ec8cd6b48183 jdk-9.0.1+10
|
||||
3546eb2ee2693043eb107d980ce5b72fe7f8f47a jdk-9.0.1+11
|
||||
5be37d3ef648d06850aa164d8b22ac7539559e80 jdk-9.0.4+00
|
||||
46290b7298be50f9a70d27465d50d1675732f0af jdk-9.0.4+1
|
||||
dab4c60adabfb8ea35cfcd96a7218994a84d652f jdk-9.0.4+2
|
||||
deed95e4b4cba997b3cc13b62e33615fd11bc902 jdk-9.0.4+3
|
||||
ce49d719fd4d5f0ff12a1906d9d8b651a7a7d60c jdk-9.0.4+4
|
||||
11116cc619ac1b0d00cdcd47e8a7eb2339207bbf jdk-9.0.4+5
|
||||
f3ba0e190ffcc82f1ed0dd8275a51096123514b6 jdk-9.0.4+6
|
||||
e020892c9b441ff0855479ad4de63a9eb4b59bf7 jdk-9.0.4+7
|
||||
d74a282dcd6d05cc3752c8e29a526eb9216fa08c jdk-9.0.4+8
|
||||
a825ddfdd78e3277e6275a469f3cd2be23759c13 jdk-9.0.4+9
|
||||
a8e5681c2532b4d21567bbee5d3dd42027118e72 jdk-9.0.4+10
|
||||
f6418daf023ea194db63519e3d13ca6c252028ed jdk-9.0.4+11
|
||||
|
||||
@ -1 +1,2 @@
|
||||
project=jdk9
|
||||
bugids=dup
|
||||
|
||||
37
hotspot/ADDITIONAL_LICENSE_INFO
Normal file
37
hotspot/ADDITIONAL_LICENSE_INFO
Normal file
@ -0,0 +1,37 @@
|
||||
ADDITIONAL INFORMATION ABOUT LICENSING
|
||||
|
||||
Certain files distributed by Oracle America, Inc. and/or its affiliates are
|
||||
subject to the following clarification and special exception to the GPLv2,
|
||||
based on the GNU Project exception for its Classpath libraries, known as the
|
||||
GNU Classpath Exception.
|
||||
|
||||
Note that Oracle includes multiple, independent programs in this software
|
||||
package. Some of those programs are provided under licenses deemed
|
||||
incompatible with the GPLv2 by the Free Software Foundation and others.
|
||||
For example, the package includes programs licensed under the Apache
|
||||
License, Version 2.0 and may include FreeType. Such programs are licensed
|
||||
to you under their original licenses.
|
||||
|
||||
Oracle facilitates your further distribution of this package by adding the
|
||||
Classpath Exception to the necessary parts of its GPLv2 code, which permits
|
||||
you to use that code in combination with other independent modules not
|
||||
licensed under the GPLv2. However, note that this would not permit you to
|
||||
commingle code under an incompatible license with Oracle's GPLv2 licensed
|
||||
code by, for example, cutting and pasting such code into a file also
|
||||
containing Oracle's GPLv2 licensed code and then distributing the result.
|
||||
|
||||
Additionally, if you were to remove the Classpath Exception from any of the
|
||||
files to which it applies and distribute the result, you would likely be
|
||||
required to license some or all of the other code in that distribution under
|
||||
the GPLv2 as well, and since the GPLv2 is incompatible with the license terms
|
||||
of some items included in the distribution by Oracle, removing the Classpath
|
||||
Exception could therefore effectively compromise your ability to further
|
||||
distribute the package.
|
||||
|
||||
Failing to distribute notices associated with some files may also create
|
||||
unexpected legal consequences.
|
||||
|
||||
Proceed with caution and we recommend that you obtain the advice of a lawyer
|
||||
skilled in open source matters before removing the Classpath Exception or
|
||||
making modifications to this package which may subsequently be redistributed
|
||||
and/or involve the use of third party software.
|
||||
@ -927,8 +927,12 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register scan_temp,
|
||||
Label& L_no_such_interface) {
|
||||
assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
|
||||
Label& L_no_such_interface,
|
||||
bool return_method) {
|
||||
assert_different_registers(recv_klass, intf_klass, scan_temp);
|
||||
assert_different_registers(method_result, intf_klass, scan_temp);
|
||||
assert(recv_klass != method_result || !return_method,
|
||||
"recv_klass can be destroyed when method isn't needed");
|
||||
assert(itable_index.is_constant() || itable_index.as_register() == method_result,
|
||||
"caller must use same register for non-constant itable index as for method");
|
||||
|
||||
@ -946,12 +950,14 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
lea(scan_temp, Address(recv_klass, scan_temp, Address::lsl(3)));
|
||||
add(scan_temp, scan_temp, vtable_base);
|
||||
|
||||
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
||||
assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
|
||||
// lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
|
||||
lea(recv_klass, Address(recv_klass, itable_index, Address::lsl(3)));
|
||||
if (itentry_off)
|
||||
add(recv_klass, recv_klass, itentry_off);
|
||||
if (return_method) {
|
||||
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
||||
assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
|
||||
// lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
|
||||
lea(recv_klass, Address(recv_klass, itable_index, Address::lsl(3)));
|
||||
if (itentry_off)
|
||||
add(recv_klass, recv_klass, itentry_off);
|
||||
}
|
||||
|
||||
// for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
|
||||
// if (scan->interface() == intf) {
|
||||
@ -985,8 +991,10 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
bind(found_method);
|
||||
|
||||
// Got a hit.
|
||||
ldr(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
|
||||
ldr(method_result, Address(recv_klass, scan_temp));
|
||||
if (return_method) {
|
||||
ldrw(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
|
||||
ldr(method_result, Address(recv_klass, scan_temp, Address::uxtw(0)));
|
||||
}
|
||||
}
|
||||
|
||||
// virtual method calling
|
||||
@ -1005,7 +1013,8 @@ void MacroAssembler::lookup_virtual_method(Register recv_klass,
|
||||
ldr(method_result, Address(method_result, vtable_offset_in_bytes));
|
||||
} else {
|
||||
vtable_offset_in_bytes += vtable_index.as_constant() * wordSize;
|
||||
ldr(method_result, Address(recv_klass, vtable_offset_in_bytes));
|
||||
ldr(method_result,
|
||||
form_address(rscratch1, recv_klass, vtable_offset_in_bytes, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -870,7 +870,8 @@ public:
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register scan_temp,
|
||||
Label& no_such_interface);
|
||||
Label& no_such_interface,
|
||||
bool return_method = true);
|
||||
|
||||
// virtual method calling
|
||||
// n.b. x86 allows RegisterOrConstant for vtable_index
|
||||
|
||||
@ -773,7 +773,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
__ load_klass(rscratch1, receiver);
|
||||
__ ldr(tmp, Address(holder, CompiledICHolder::holder_klass_offset()));
|
||||
__ cmp(rscratch1, tmp);
|
||||
__ ldr(rmethod, Address(holder, CompiledICHolder::holder_method_offset()));
|
||||
__ ldr(rmethod, Address(holder, CompiledICHolder::holder_metadata_offset()));
|
||||
__ br(Assembler::EQ, ok);
|
||||
__ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
|
||||
|
||||
|
||||
@ -3279,11 +3279,11 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
transition(vtos, vtos);
|
||||
assert(byte_no == f1_byte, "use this argument");
|
||||
|
||||
prepare_invoke(byte_no, r0, rmethod, // get f1 Klass*, f2 itable index
|
||||
prepare_invoke(byte_no, r0, rmethod, // get f1 Klass*, f2 Method*
|
||||
r2, r3); // recv, flags
|
||||
|
||||
// r0: interface klass (from f1)
|
||||
// rmethod: itable index (from f2)
|
||||
// rmethod: method (from f2)
|
||||
// r2: receiver
|
||||
// r3: flags
|
||||
|
||||
@ -3302,10 +3302,27 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
__ null_check(r2, oopDesc::klass_offset_in_bytes());
|
||||
__ load_klass(r3, r2);
|
||||
|
||||
Label no_such_interface, no_such_method;
|
||||
|
||||
// Receiver subtype check against REFC.
|
||||
// Superklass in r0. Subklass in r3. Blows rscratch2, r13
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
r3, r0, noreg,
|
||||
// outputs: scan temp. reg, scan temp. reg
|
||||
rscratch2, r13,
|
||||
no_such_interface,
|
||||
/*return_method=*/false);
|
||||
|
||||
// profile this call
|
||||
__ profile_virtual_call(r3, r13, r19);
|
||||
|
||||
Label no_such_interface, no_such_method;
|
||||
// Get declaring interface class from method, and itable index
|
||||
__ ldr(r0, Address(rmethod, Method::const_offset()));
|
||||
__ ldr(r0, Address(r0, ConstMethod::constants_offset()));
|
||||
__ ldr(r0, Address(r0, ConstantPool::pool_holder_offset_in_bytes()));
|
||||
__ ldrw(rmethod, Address(rmethod, Method::itable_index_offset()));
|
||||
__ subw(rmethod, rmethod, Method::itable_index_max);
|
||||
__ negw(rmethod, rmethod);
|
||||
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
r3, r0, rmethod,
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "interp_masm_aarch64.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/compiledICHolder.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/klassVtable.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
@ -62,8 +63,8 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (CountCompiledCalls) {
|
||||
__ lea(r19, ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
|
||||
__ incrementw(Address(r19));
|
||||
__ lea(r16, ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
|
||||
__ incrementw(Address(r16));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -72,13 +73,13 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
|
||||
// get receiver klass
|
||||
address npe_addr = __ pc();
|
||||
__ load_klass(r19, j_rarg0);
|
||||
__ load_klass(r16, j_rarg0);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (DebugVtables) {
|
||||
Label L;
|
||||
// check offset vs vtable length
|
||||
__ ldrw(rscratch1, Address(r19, Klass::vtable_length_offset()));
|
||||
__ ldrw(rscratch1, Address(r16, Klass::vtable_length_offset()));
|
||||
__ cmpw(rscratch1, vtable_index * vtableEntry::size());
|
||||
__ br(Assembler::GT, L);
|
||||
__ enter();
|
||||
@ -90,7 +91,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
__ lookup_virtual_method(r19, vtable_index, rmethod);
|
||||
__ lookup_virtual_method(r16, vtable_index, rmethod);
|
||||
|
||||
if (DebugVtables) {
|
||||
Label L;
|
||||
@ -140,28 +141,44 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
#endif
|
||||
|
||||
// Entry arguments:
|
||||
// rscratch2: Interface
|
||||
// rscratch2: CompiledICHolder
|
||||
// j_rarg0: Receiver
|
||||
|
||||
// Free registers (non-args) are r0 (interface), rmethod
|
||||
|
||||
// Most registers are in use; we'll use r16, rmethod, r10, r11
|
||||
const Register recv_klass_reg = r10;
|
||||
const Register holder_klass_reg = r16; // declaring interface klass (DECC)
|
||||
const Register resolved_klass_reg = rmethod; // resolved interface klass (REFC)
|
||||
const Register temp_reg = r11;
|
||||
const Register icholder_reg = rscratch2;
|
||||
|
||||
Label L_no_such_interface;
|
||||
|
||||
__ ldr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset()));
|
||||
__ ldr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset()));
|
||||
|
||||
// get receiver (need to skip return address on top of stack)
|
||||
|
||||
assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
|
||||
// get receiver klass (also an implicit null-check)
|
||||
address npe_addr = __ pc();
|
||||
__ load_klass(recv_klass_reg, j_rarg0);
|
||||
|
||||
// Most registers are in use; we'll use r0, rmethod, r10, r11
|
||||
__ load_klass(r10, j_rarg0);
|
||||
// Receiver subtype check against REFC.
|
||||
// Destroys recv_klass_reg value.
|
||||
__ lookup_interface_method(// inputs: rec. class, interface
|
||||
recv_klass_reg, resolved_klass_reg, noreg,
|
||||
// outputs: scan temp. reg1, scan temp. reg2
|
||||
recv_klass_reg, temp_reg,
|
||||
L_no_such_interface,
|
||||
/*return_method=*/false);
|
||||
|
||||
Label throw_icce;
|
||||
|
||||
// Get Method* and entrypoint for compiler
|
||||
// Get selected method from declaring class and itable index
|
||||
__ load_klass(recv_klass_reg, j_rarg0); // restore recv_klass_reg
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
r10, rscratch2, itable_index,
|
||||
// outputs: method, scan temp. reg
|
||||
rmethod, r11,
|
||||
throw_icce);
|
||||
recv_klass_reg, holder_klass_reg, itable_index,
|
||||
// outputs: method, scan temp. reg
|
||||
rmethod, temp_reg,
|
||||
L_no_such_interface);
|
||||
|
||||
// method (rmethod): Method*
|
||||
// j_rarg0: receiver
|
||||
@ -183,7 +200,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
__ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset()));
|
||||
__ br(rscratch1);
|
||||
|
||||
__ bind(throw_icce);
|
||||
__ bind(L_no_such_interface);
|
||||
__ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
|
||||
|
||||
__ flush();
|
||||
@ -205,11 +222,11 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
||||
int size = DebugVtables ? 216 : 0;
|
||||
if (CountCompiledCalls)
|
||||
size += 6 * 4;
|
||||
// FIXME
|
||||
// FIXME: vtable stubs only need 36 bytes
|
||||
if (is_vtable_stub)
|
||||
size += 52;
|
||||
else
|
||||
size += 104;
|
||||
size += 176;
|
||||
return size;
|
||||
|
||||
// In order to tune these parameters, run the JVM with VM options
|
||||
@ -217,33 +234,58 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
||||
// actual itable stubs. Run it with -Xmx31G -XX:+UseCompressedOops.
|
||||
//
|
||||
// If Universe::narrow_klass_base is nonzero, decoding a compressed
|
||||
// class can take zeveral instructions. Run it with -Xmx31G
|
||||
// -XX:+UseCompressedOops.
|
||||
// class can take zeveral instructions.
|
||||
//
|
||||
// The JVM98 app. _202_jess has a megamorphic interface call.
|
||||
// The itable code looks like this:
|
||||
// Decoding VtableStub itbl[1]@12
|
||||
// ldr w10, [x1,#8]
|
||||
// lsl x10, x10, #3
|
||||
// ldr w11, [x10,#280]
|
||||
// add x11, x10, x11, uxtx #3
|
||||
// add x11, x11, #0x1b8
|
||||
// ldr x12, [x11]
|
||||
// cmp x9, x12
|
||||
// b.eq success
|
||||
// loop:
|
||||
// cbz x12, throw_icce
|
||||
// add x11, x11, #0x10
|
||||
// ldr x12, [x11]
|
||||
// cmp x9, x12
|
||||
// b.ne loop
|
||||
// success:
|
||||
// ldr x11, [x11,#8]
|
||||
// ldr x12, [x10,x11]
|
||||
// ldr x8, [x12,#72]
|
||||
// br x8
|
||||
// throw_icce:
|
||||
// b throw_ICCE_entry
|
||||
|
||||
// ldr xmethod, [xscratch2,#CompiledICHolder::holder_klass_offset]
|
||||
// ldr x0, [xscratch2]
|
||||
// ldr w10, [x1,#oopDesc::klass_offset_in_bytes]
|
||||
// mov xheapbase, #0x3c000000 // #narrow_klass_base
|
||||
// movk xheapbase, #0x3f7, lsl #32
|
||||
// add x10, xheapbase, x10
|
||||
// mov xheapbase, #0xe7ff0000 // #heapbase
|
||||
// movk xheapbase, #0x3f7, lsl #32
|
||||
// ldr w11, [x10,#vtable_length_offset]
|
||||
// add x11, x10, x11, uxtx #3
|
||||
// add x11, x11, #itableMethodEntry::method_offset_in_bytes
|
||||
// ldr x10, [x11]
|
||||
// cmp xmethod, x10
|
||||
// b.eq found_method
|
||||
// search:
|
||||
// cbz x10, no_such_interface
|
||||
// add x11, x11, #0x10
|
||||
// ldr x10, [x11]
|
||||
// cmp xmethod, x10
|
||||
// b.ne search
|
||||
// found_method:
|
||||
// ldr w10, [x1,#oopDesc::klass_offset_in_bytes]
|
||||
// mov xheapbase, #0x3c000000 // #narrow_klass_base
|
||||
// movk xheapbase, #0x3f7, lsl #32
|
||||
// add x10, xheapbase, x10
|
||||
// mov xheapbase, #0xe7ff0000 // #heapbase
|
||||
// movk xheapbase, #0x3f7, lsl #32
|
||||
// ldr w11, [x10,#vtable_length_offset]
|
||||
// add x11, x10, x11, uxtx #3
|
||||
// add x11, x11, #itableMethodEntry::method_offset_in_bytes
|
||||
// add x10, x10, #itentry_off
|
||||
// ldr xmethod, [x11]
|
||||
// cmp x0, xmethod
|
||||
// b.eq found_method2
|
||||
// search2:
|
||||
// cbz xmethod, 0x000003ffa872e6cc
|
||||
// add x11, x11, #0x10
|
||||
// ldr xmethod, [x11]
|
||||
// cmp x0, xmethod
|
||||
// b.ne search2
|
||||
// found_method2:
|
||||
// ldr w11, [x11,#itableOffsetEntry::offset_offset_in_bytes]
|
||||
// ldr xmethod, [x10,w11,uxtw]
|
||||
// ldr xscratch1, [xmethod,#Method::from_compiled_offset]
|
||||
// br xscratch1
|
||||
// no_such_interface:
|
||||
// b throw_ICCE_entry
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -2475,49 +2475,65 @@ void MacroAssembler::store_sized_value(Register src, Address dst, size_t size_in
|
||||
// On success, the result will be in method_result, and execution falls through.
|
||||
// On failure, execution transfers to the given label.
|
||||
void MacroAssembler::lookup_interface_method(Register Rklass,
|
||||
Register Rinterf,
|
||||
Register Rindex,
|
||||
Register Rintf,
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register temp_reg1,
|
||||
Register temp_reg2,
|
||||
Register Rscan,
|
||||
Register Rtmp,
|
||||
Label& L_no_such_interface) {
|
||||
|
||||
assert_different_registers(Rklass, Rinterf, temp_reg1, temp_reg2, Rindex);
|
||||
assert_different_registers(Rklass, Rintf, Rscan, Rtmp);
|
||||
|
||||
Register Ritable = temp_reg1;
|
||||
const int entry_size = itableOffsetEntry::size() * HeapWordSize;
|
||||
assert(itableOffsetEntry::interface_offset_in_bytes() == 0, "not added for convenience");
|
||||
|
||||
// Compute start of first itableOffsetEntry (which is at the end of the vtable)
|
||||
const int base = in_bytes(Klass::vtable_start_offset());
|
||||
const int scale = exact_log2(vtableEntry::size_in_bytes());
|
||||
ldr_s32(temp_reg2, Address(Rklass, Klass::vtable_length_offset())); // Get length of vtable
|
||||
add(Ritable, Rklass, base);
|
||||
add(Ritable, Ritable, AsmOperand(temp_reg2, lsl, scale));
|
||||
ldr_s32(Rtmp, Address(Rklass, Klass::vtable_length_offset())); // Get length of vtable
|
||||
add(Rscan, Rklass, base);
|
||||
add(Rscan, Rscan, AsmOperand(Rtmp, lsl, scale));
|
||||
|
||||
Label entry, search;
|
||||
// Search through the itable for an interface equal to incoming Rintf
|
||||
// itable looks like [intface][offset][intface][offset][intface][offset]
|
||||
|
||||
b(entry);
|
||||
Label loop;
|
||||
bind(loop);
|
||||
ldr(Rtmp, Address(Rscan, entry_size, post_indexed));
|
||||
#ifdef AARCH64
|
||||
Label found;
|
||||
cmp(Rtmp, Rintf);
|
||||
b(found, eq);
|
||||
cbnz(Rtmp, loop);
|
||||
#else
|
||||
cmp(Rtmp, Rintf); // set ZF and CF if interface is found
|
||||
cmn(Rtmp, 0, ne); // check if tmp == 0 and clear CF if it is
|
||||
b(loop, ne);
|
||||
#endif // AARCH64
|
||||
|
||||
bind(search);
|
||||
add(Ritable, Ritable, itableOffsetEntry::size() * HeapWordSize);
|
||||
#ifdef AARCH64
|
||||
b(L_no_such_interface);
|
||||
bind(found);
|
||||
#else
|
||||
// CF == 0 means we reached the end of itable without finding icklass
|
||||
b(L_no_such_interface, cc);
|
||||
#endif // !AARCH64
|
||||
|
||||
bind(entry);
|
||||
|
||||
// Check that the entry is non-null. A null entry means that the receiver
|
||||
// class doesn't implement the interface, and wasn't the same as the
|
||||
// receiver class checked when the interface was resolved.
|
||||
|
||||
ldr(temp_reg2, Address(Ritable, itableOffsetEntry::interface_offset_in_bytes()));
|
||||
cbz(temp_reg2, L_no_such_interface);
|
||||
|
||||
cmp(Rinterf, temp_reg2);
|
||||
b(search, ne);
|
||||
|
||||
ldr_s32(temp_reg2, Address(Ritable, itableOffsetEntry::offset_offset_in_bytes()));
|
||||
add(temp_reg2, temp_reg2, Rklass); // Add offset to Klass*
|
||||
assert(itableMethodEntry::size() * HeapWordSize == wordSize, "adjust the scaling in the code below");
|
||||
assert(itableMethodEntry::method_offset_in_bytes() == 0, "adjust the offset in the code below");
|
||||
|
||||
ldr(method_result, Address::indexed_ptr(temp_reg2, Rindex));
|
||||
if (method_result != noreg) {
|
||||
// Interface found at previous position of Rscan, now load the method
|
||||
ldr_s32(Rtmp, Address(Rscan, itableOffsetEntry::offset_offset_in_bytes() - entry_size));
|
||||
if (itable_index.is_register()) {
|
||||
add(Rtmp, Rtmp, Rklass); // Add offset to Klass*
|
||||
assert(itableMethodEntry::size() * HeapWordSize == wordSize, "adjust the scaling in the code below");
|
||||
assert(itableMethodEntry::method_offset_in_bytes() == 0, "adjust the offset in the code below");
|
||||
ldr(method_result, Address::indexed_ptr(Rtmp, itable_index.as_register()));
|
||||
} else {
|
||||
int method_offset = itableMethodEntry::size() * HeapWordSize * itable_index.as_constant() +
|
||||
itableMethodEntry::method_offset_in_bytes();
|
||||
add_slow(method_result, Rklass, method_offset);
|
||||
ldr(method_result, Address(method_result, Rtmp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
|
||||
@ -1316,7 +1316,7 @@ public:
|
||||
|
||||
void lookup_interface_method(Register recv_klass,
|
||||
Register intf_klass,
|
||||
Register itable_index,
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register temp_reg1,
|
||||
Register temp_reg2,
|
||||
|
||||
@ -987,7 +987,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
|
||||
__ load_klass(receiver_klass, receiver);
|
||||
__ ldr(holder_klass, Address(Ricklass, CompiledICHolder::holder_klass_offset()));
|
||||
__ ldr(Rmethod, Address(Ricklass, CompiledICHolder::holder_method_offset()));
|
||||
__ ldr(Rmethod, Address(Ricklass, CompiledICHolder::holder_metadata_offset()));
|
||||
__ cmp(receiver_klass, holder_klass);
|
||||
|
||||
#ifdef AARCH64
|
||||
|
||||
@ -4192,7 +4192,7 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
const Register Rflags = R3_tmp;
|
||||
const Register Rklass = R3_tmp;
|
||||
|
||||
prepare_invoke(byte_no, Rinterf, Rindex, Rrecv, Rflags);
|
||||
prepare_invoke(byte_no, Rinterf, Rmethod, Rrecv, Rflags);
|
||||
|
||||
// Special case of invokeinterface called for virtual method of
|
||||
// java.lang.Object. See cpCacheOop.cpp for details.
|
||||
@ -4201,56 +4201,39 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
Label notMethod;
|
||||
__ tbz(Rflags, ConstantPoolCacheEntry::is_forced_virtual_shift, notMethod);
|
||||
|
||||
__ mov(Rmethod, Rindex);
|
||||
invokevirtual_helper(Rmethod, Rrecv, Rflags);
|
||||
__ bind(notMethod);
|
||||
|
||||
// Get receiver klass into Rklass - also a null check
|
||||
__ load_klass(Rklass, Rrecv);
|
||||
|
||||
Label no_such_interface;
|
||||
|
||||
// Receiver subtype check against REFC.
|
||||
__ lookup_interface_method(// inputs: rec. class, interface
|
||||
Rklass, Rinterf, noreg,
|
||||
// outputs: scan temp. reg1, scan temp. reg2
|
||||
noreg, Ritable, Rtemp,
|
||||
no_such_interface);
|
||||
|
||||
// profile this call
|
||||
__ profile_virtual_call(R0_tmp, Rklass);
|
||||
|
||||
// Compute start of first itableOffsetEntry (which is at the end of the vtable)
|
||||
const int base = in_bytes(Klass::vtable_start_offset());
|
||||
assert(vtableEntry::size() == 1, "adjust the scaling in the code below");
|
||||
__ ldr_s32(Rtemp, Address(Rklass, Klass::vtable_length_offset())); // Get length of vtable
|
||||
__ add(Ritable, Rklass, base);
|
||||
__ add(Ritable, Ritable, AsmOperand(Rtemp, lsl, LogBytesPerWord));
|
||||
// Get declaring interface class from method
|
||||
__ ldr(Rtemp, Address(Rmethod, Method::const_offset()));
|
||||
__ ldr(Rtemp, Address(Rtemp, ConstMethod::constants_offset()));
|
||||
__ ldr(Rinterf, Address(Rtemp, ConstantPool::pool_holder_offset_in_bytes()));
|
||||
|
||||
Label entry, search, interface_ok;
|
||||
// Get itable index from method
|
||||
__ ldr_s32(Rtemp, Address(Rmethod, Method::itable_index_offset()));
|
||||
__ add(Rtemp, Rtemp, (-Method::itable_index_max)); // small negative constant is too large for an immediate on arm32
|
||||
__ neg(Rindex, Rtemp);
|
||||
|
||||
__ b(entry);
|
||||
|
||||
__ bind(search);
|
||||
__ add(Ritable, Ritable, itableOffsetEntry::size() * HeapWordSize);
|
||||
|
||||
__ bind(entry);
|
||||
|
||||
// Check that the entry is non-null. A null entry means that the receiver
|
||||
// class doesn't implement the interface, and wasn't the same as the
|
||||
// receiver class checked when the interface was resolved.
|
||||
|
||||
__ ldr(Rtemp, Address(Ritable, itableOffsetEntry::interface_offset_in_bytes()));
|
||||
__ cbnz(Rtemp, interface_ok);
|
||||
|
||||
// throw exception
|
||||
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::throw_IncompatibleClassChangeError));
|
||||
|
||||
// the call_VM checks for exception, so we should never return here.
|
||||
__ should_not_reach_here();
|
||||
|
||||
__ bind(interface_ok);
|
||||
|
||||
__ cmp(Rinterf, Rtemp);
|
||||
__ b(search, ne);
|
||||
|
||||
__ ldr_s32(Rtemp, Address(Ritable, itableOffsetEntry::offset_offset_in_bytes()));
|
||||
__ add(Rtemp, Rtemp, Rklass); // Add offset to Klass*
|
||||
assert(itableMethodEntry::size() == 1, "adjust the scaling in the code below");
|
||||
|
||||
__ ldr(Rmethod, Address::indexed_ptr(Rtemp, Rindex));
|
||||
__ lookup_interface_method(// inputs: rec. class, interface
|
||||
Rklass, Rinterf, Rindex,
|
||||
// outputs: scan temp. reg1, scan temp. reg2
|
||||
Rmethod, Ritable, Rtemp,
|
||||
no_such_interface);
|
||||
|
||||
// Rmethod: Method* to call
|
||||
|
||||
@ -4272,6 +4255,13 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
|
||||
// do the call
|
||||
__ jump_from_interpreted(Rmethod);
|
||||
|
||||
// throw exception
|
||||
__ bind(no_such_interface);
|
||||
__ restore_method();
|
||||
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
|
||||
// the call_VM checks for exception, so we should never return here.
|
||||
__ should_not_reach_here();
|
||||
}
|
||||
|
||||
void TemplateTable::invokehandle(int byte_no) {
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "interp_masm_arm.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/compiledICHolder.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/klassVtable.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
@ -118,67 +119,48 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
|
||||
// R0-R3 / R0-R7 registers hold the arguments and cannot be spoiled
|
||||
const Register Rclass = AARCH64_ONLY(R9) NOT_AARCH64(R4);
|
||||
const Register Rlength = AARCH64_ONLY(R10) NOT_AARCH64(R5);
|
||||
const Register Rintf = AARCH64_ONLY(R10) NOT_AARCH64(R5);
|
||||
const Register Rscan = AARCH64_ONLY(R11) NOT_AARCH64(R6);
|
||||
const Register tmp = Rtemp;
|
||||
|
||||
assert_different_registers(Ricklass, Rclass, Rlength, Rscan, tmp);
|
||||
assert_different_registers(Ricklass, Rclass, Rintf, Rscan, Rtemp);
|
||||
|
||||
// Calculate the start of itable (itable goes after vtable)
|
||||
const int scale = exact_log2(vtableEntry::size_in_bytes());
|
||||
address npe_addr = __ pc();
|
||||
__ load_klass(Rclass, R0);
|
||||
__ ldr_s32(Rlength, Address(Rclass, Klass::vtable_length_offset()));
|
||||
|
||||
__ add(Rscan, Rclass, in_bytes(Klass::vtable_start_offset()));
|
||||
__ add(Rscan, Rscan, AsmOperand(Rlength, lsl, scale));
|
||||
Label L_no_such_interface;
|
||||
|
||||
// Search through the itable for an interface equal to incoming Ricklass
|
||||
// itable looks like [intface][offset][intface][offset][intface][offset]
|
||||
const int entry_size = itableOffsetEntry::size() * HeapWordSize;
|
||||
assert(itableOffsetEntry::interface_offset_in_bytes() == 0, "not added for convenience");
|
||||
// Receiver subtype check against REFC.
|
||||
__ ldr(Rintf, Address(Ricklass, CompiledICHolder::holder_klass_offset()));
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
Rclass, Rintf, noreg,
|
||||
// outputs: temp reg1, temp reg2
|
||||
noreg, Rscan, Rtemp,
|
||||
L_no_such_interface);
|
||||
|
||||
Label loop;
|
||||
__ bind(loop);
|
||||
__ ldr(tmp, Address(Rscan, entry_size, post_indexed));
|
||||
#ifdef AARCH64
|
||||
Label found;
|
||||
__ cmp(tmp, Ricklass);
|
||||
__ b(found, eq);
|
||||
__ cbnz(tmp, loop);
|
||||
#else
|
||||
__ cmp(tmp, Ricklass); // set ZF and CF if interface is found
|
||||
__ cmn(tmp, 0, ne); // check if tmp == 0 and clear CF if it is
|
||||
__ b(loop, ne);
|
||||
#endif // AARCH64
|
||||
|
||||
assert(StubRoutines::throw_IncompatibleClassChangeError_entry() != NULL, "Check initialization order");
|
||||
#ifdef AARCH64
|
||||
__ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, tmp);
|
||||
__ bind(found);
|
||||
#else
|
||||
// CF == 0 means we reached the end of itable without finding icklass
|
||||
__ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, noreg, cc);
|
||||
#endif // !AARCH64
|
||||
|
||||
// Interface found at previous position of Rscan, now load the method oop
|
||||
__ ldr_s32(tmp, Address(Rscan, itableOffsetEntry::offset_offset_in_bytes() - entry_size));
|
||||
{
|
||||
const int method_offset = itableMethodEntry::size() * HeapWordSize * itable_index +
|
||||
itableMethodEntry::method_offset_in_bytes();
|
||||
__ add_slow(Rmethod, Rclass, method_offset);
|
||||
}
|
||||
__ ldr(Rmethod, Address(Rmethod, tmp));
|
||||
// Get Method* and entry point for compiler
|
||||
__ ldr(Rintf, Address(Ricklass, CompiledICHolder::holder_metadata_offset()));
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
Rclass, Rintf, itable_index,
|
||||
// outputs: temp reg1, temp reg2, temp reg3
|
||||
Rmethod, Rscan, Rtemp,
|
||||
L_no_such_interface);
|
||||
|
||||
address ame_addr = __ pc();
|
||||
|
||||
#ifdef AARCH64
|
||||
__ ldr(tmp, Address(Rmethod, Method::from_compiled_offset()));
|
||||
__ br(tmp);
|
||||
__ ldr(Rtemp, Address(Rmethod, Method::from_compiled_offset()));
|
||||
__ br(Rtemp);
|
||||
#else
|
||||
__ ldr(PC, Address(Rmethod, Method::from_compiled_offset()));
|
||||
#endif // AARCH64
|
||||
|
||||
__ bind(L_no_such_interface);
|
||||
|
||||
assert(StubRoutines::throw_IncompatibleClassChangeError_entry() != NULL, "check initialization order");
|
||||
__ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, Rtemp);
|
||||
|
||||
masm->flush();
|
||||
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
@ -205,7 +187,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
||||
instr_count = NOT_AARCH64(4) AARCH64_ONLY(5);
|
||||
} else {
|
||||
// itable stub size
|
||||
instr_count = NOT_AARCH64(20) AARCH64_ONLY(20);
|
||||
instr_count = NOT_AARCH64(31) AARCH64_ONLY(31);
|
||||
}
|
||||
|
||||
#ifdef AARCH64
|
||||
|
||||
@ -1786,11 +1786,10 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register scan_temp,
|
||||
Register sethi_temp,
|
||||
Label& L_no_such_interface) {
|
||||
Register temp2,
|
||||
Label& L_no_such_interface,
|
||||
bool return_method) {
|
||||
assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
|
||||
assert(itable_index.is_constant() || itable_index.as_register() == method_result,
|
||||
"caller must use same register for non-constant itable index as for method");
|
||||
|
||||
// Compute start of first itableOffsetEntry (which is at the end of the vtable).
|
||||
int vtable_base = in_bytes(Klass::vtable_start_offset());
|
||||
@ -1808,15 +1807,17 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
add(scan_temp, recv_klass, scan_temp);
|
||||
|
||||
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
||||
if (itable_index.is_register()) {
|
||||
Register itable_offset = itable_index.as_register();
|
||||
sldi(itable_offset, itable_offset, logMEsize);
|
||||
if (itentry_off) addi(itable_offset, itable_offset, itentry_off);
|
||||
add(recv_klass, itable_offset, recv_klass);
|
||||
} else {
|
||||
long itable_offset = (long)itable_index.as_constant();
|
||||
load_const_optimized(sethi_temp, (itable_offset<<logMEsize)+itentry_off); // static address, no relocation
|
||||
add(recv_klass, sethi_temp, recv_klass);
|
||||
if (return_method) {
|
||||
if (itable_index.is_register()) {
|
||||
Register itable_offset = itable_index.as_register();
|
||||
sldi(method_result, itable_offset, logMEsize);
|
||||
if (itentry_off) { addi(method_result, method_result, itentry_off); }
|
||||
add(method_result, method_result, recv_klass);
|
||||
} else {
|
||||
long itable_offset = (long)itable_index.as_constant();
|
||||
// static address, no relocation
|
||||
add_const_optimized(method_result, recv_klass, (itable_offset << logMEsize) + itentry_off, temp2);
|
||||
}
|
||||
}
|
||||
|
||||
// for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
|
||||
@ -1829,12 +1830,12 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
for (int peel = 1; peel >= 0; peel--) {
|
||||
// %%%% Could load both offset and interface in one ldx, if they were
|
||||
// in the opposite order. This would save a load.
|
||||
ld(method_result, itableOffsetEntry::interface_offset_in_bytes(), scan_temp);
|
||||
ld(temp2, itableOffsetEntry::interface_offset_in_bytes(), scan_temp);
|
||||
|
||||
// Check that this entry is non-null. A null entry means that
|
||||
// the receiver class doesn't implement the interface, and wasn't the
|
||||
// same as when the caller was compiled.
|
||||
cmpd(CCR0, method_result, intf_klass);
|
||||
cmpd(CCR0, temp2, intf_klass);
|
||||
|
||||
if (peel) {
|
||||
beq(CCR0, found_method);
|
||||
@ -1847,7 +1848,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
|
||||
bind(search);
|
||||
|
||||
cmpdi(CCR0, method_result, 0);
|
||||
cmpdi(CCR0, temp2, 0);
|
||||
beq(CCR0, L_no_such_interface);
|
||||
addi(scan_temp, scan_temp, scan_step);
|
||||
}
|
||||
@ -1855,9 +1856,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
bind(found_method);
|
||||
|
||||
// Got a hit.
|
||||
int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
|
||||
lwz(scan_temp, ito_offset, scan_temp);
|
||||
ldx(method_result, scan_temp, recv_klass);
|
||||
if (return_method) {
|
||||
int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
|
||||
lwz(scan_temp, ito_offset, scan_temp);
|
||||
ldx(method_result, scan_temp, method_result);
|
||||
}
|
||||
}
|
||||
|
||||
// virtual method calling
|
||||
|
||||
@ -517,7 +517,8 @@ class MacroAssembler: public Assembler {
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register temp_reg, Register temp2_reg,
|
||||
Label& no_such_interface);
|
||||
Label& no_such_interface,
|
||||
bool return_method = true);
|
||||
|
||||
// virtual method calling
|
||||
void lookup_virtual_method(Register recv_klass,
|
||||
|
||||
@ -1185,7 +1185,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
// Argument is valid and klass is as expected, continue.
|
||||
|
||||
// Extract method from inline cache, verified entry point needs it.
|
||||
__ ld(R19_method, CompiledICHolder::holder_method_offset(), ic);
|
||||
__ ld(R19_method, CompiledICHolder::holder_metadata_offset(), ic);
|
||||
assert(R19_method == ic, "the inline cache register is dead here");
|
||||
|
||||
__ ld(code, method_(code));
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2017 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -3478,11 +3478,11 @@ void TemplateTable::invokestatic(int byte_no) {
|
||||
void TemplateTable::invokeinterface_object_method(Register Rrecv_klass,
|
||||
Register Rret,
|
||||
Register Rflags,
|
||||
Register Rindex,
|
||||
Register Rmethod,
|
||||
Register Rtemp1,
|
||||
Register Rtemp2) {
|
||||
|
||||
assert_different_registers(Rindex, Rret, Rrecv_klass, Rflags, Rtemp1, Rtemp2);
|
||||
assert_different_registers(Rmethod, Rret, Rrecv_klass, Rflags, Rtemp1, Rtemp2);
|
||||
Label LnotFinal;
|
||||
|
||||
// Check for vfinal.
|
||||
@ -3494,14 +3494,14 @@ void TemplateTable::invokeinterface_object_method(Register Rrecv_klass,
|
||||
// Final call case.
|
||||
__ profile_final_call(Rtemp1, Rscratch);
|
||||
// Argument and return type profiling.
|
||||
__ profile_arguments_type(Rindex, Rscratch, Rrecv_klass /* scratch */, true);
|
||||
__ profile_arguments_type(Rmethod, Rscratch, Rrecv_klass /* scratch */, true);
|
||||
// Do the final call - the index (f2) contains the method.
|
||||
__ call_from_interpreter(Rindex, Rret, Rscratch, Rrecv_klass /* scratch */);
|
||||
__ call_from_interpreter(Rmethod, Rret, Rscratch, Rrecv_klass /* scratch */);
|
||||
|
||||
// Non-final callc case.
|
||||
__ bind(LnotFinal);
|
||||
__ profile_virtual_call(Rrecv_klass, Rtemp1, Rscratch, false);
|
||||
generate_vtable_call(Rrecv_klass, Rindex, Rret, Rscratch);
|
||||
generate_vtable_call(Rrecv_klass, Rmethod, Rret, Rscratch);
|
||||
}
|
||||
|
||||
void TemplateTable::invokeinterface(int byte_no) {
|
||||
@ -3510,58 +3510,61 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
|
||||
const Register Rscratch1 = R11_scratch1,
|
||||
Rscratch2 = R12_scratch2,
|
||||
Rscratch3 = R9_ARG7,
|
||||
Rscratch4 = R10_ARG8,
|
||||
Rtable_addr = Rscratch2,
|
||||
Rmethod = R6_ARG4,
|
||||
Rmethod2 = R9_ARG7,
|
||||
Rinterface_klass = R5_ARG3,
|
||||
Rret_type = R8_ARG6,
|
||||
Rret_addr = Rret_type,
|
||||
Rindex = R6_ARG4,
|
||||
Rreceiver = R4_ARG2,
|
||||
Rrecv_klass = Rreceiver,
|
||||
Rret_addr = R8_ARG6,
|
||||
Rindex = R10_ARG8,
|
||||
Rreceiver = R3_ARG1,
|
||||
Rrecv_klass = R4_ARG2,
|
||||
Rflags = R7_ARG5;
|
||||
|
||||
prepare_invoke(byte_no, Rinterface_klass, Rret_addr, Rindex, Rreceiver, Rflags, Rscratch1);
|
||||
prepare_invoke(byte_no, Rinterface_klass, Rret_addr, Rmethod, Rreceiver, Rflags, Rscratch1);
|
||||
|
||||
// Get receiver klass.
|
||||
__ null_check_throw(Rreceiver, oopDesc::klass_offset_in_bytes(), Rscratch3);
|
||||
__ null_check_throw(Rreceiver, oopDesc::klass_offset_in_bytes(), Rscratch2);
|
||||
__ load_klass(Rrecv_klass, Rreceiver);
|
||||
|
||||
// Check corner case object method.
|
||||
Label LobjectMethod;
|
||||
|
||||
Label LobjectMethod, L_no_such_interface, Lthrow_ame;
|
||||
__ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_forced_virtual_shift);
|
||||
__ btrue(CCR0, LobjectMethod);
|
||||
|
||||
// Fallthrough: The normal invokeinterface case.
|
||||
__ lookup_interface_method(Rrecv_klass, Rinterface_klass, noreg, noreg, Rscratch1, Rscratch2,
|
||||
L_no_such_interface, /*return_method=*/false);
|
||||
|
||||
__ profile_virtual_call(Rrecv_klass, Rscratch1, Rscratch2, false);
|
||||
|
||||
// Find entry point to call.
|
||||
Label Lthrow_icc, Lthrow_ame;
|
||||
// Result will be returned in Rindex.
|
||||
__ mr(Rscratch4, Rrecv_klass);
|
||||
__ mr(Rscratch3, Rindex);
|
||||
__ lookup_interface_method(Rrecv_klass, Rinterface_klass, Rindex, Rindex, Rscratch1, Rscratch2, Lthrow_icc);
|
||||
|
||||
__ cmpdi(CCR0, Rindex, 0);
|
||||
// Get declaring interface class from method
|
||||
__ ld(Rinterface_klass, in_bytes(Method::const_offset()), Rmethod);
|
||||
__ ld(Rinterface_klass, in_bytes(ConstMethod::constants_offset()), Rinterface_klass);
|
||||
__ ld(Rinterface_klass, ConstantPool::pool_holder_offset_in_bytes(), Rinterface_klass);
|
||||
|
||||
// Get itable index from method
|
||||
__ lwa(Rindex, in_bytes(Method::itable_index_offset()), Rmethod);
|
||||
__ subfic(Rindex, Rindex, Method::itable_index_max);
|
||||
|
||||
__ lookup_interface_method(Rrecv_klass, Rinterface_klass, Rindex, Rmethod2, Rscratch1, Rscratch2,
|
||||
L_no_such_interface);
|
||||
|
||||
__ cmpdi(CCR0, Rmethod2, 0);
|
||||
__ beq(CCR0, Lthrow_ame);
|
||||
// Found entry. Jump off!
|
||||
// Argument and return type profiling.
|
||||
__ profile_arguments_type(Rindex, Rscratch1, Rscratch2, true);
|
||||
__ call_from_interpreter(Rindex, Rret_addr, Rscratch1, Rscratch2);
|
||||
__ profile_arguments_type(Rmethod2, Rscratch1, Rscratch2, true);
|
||||
//__ profile_called_method(Rindex, Rscratch1);
|
||||
__ call_from_interpreter(Rmethod2, Rret_addr, Rscratch1, Rscratch2);
|
||||
|
||||
// Vtable entry was NULL => Throw abstract method error.
|
||||
__ bind(Lthrow_ame);
|
||||
__ mr(Rrecv_klass, Rscratch4);
|
||||
__ mr(Rindex, Rscratch3);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
|
||||
|
||||
// Interface was not found => Throw incompatible class change error.
|
||||
__ bind(Lthrow_icc);
|
||||
__ mr(Rrecv_klass, Rscratch4);
|
||||
__ bind(L_no_such_interface);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
|
||||
|
||||
__ should_not_reach_here();
|
||||
DEBUG_ONLY( __ should_not_reach_here(); )
|
||||
|
||||
// Special case of invokeinterface called for virtual method of
|
||||
// java.lang.Object. See ConstantPoolCacheEntry::set_method() for details:
|
||||
@ -3569,7 +3572,7 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
// to handle this corner case. This code isn't produced by javac, but could
|
||||
// be produced by another compliant java compiler.
|
||||
__ bind(LobjectMethod);
|
||||
invokeinterface_object_method(Rrecv_klass, Rret_addr, Rflags, Rindex, Rscratch1, Rscratch2);
|
||||
invokeinterface_object_method(Rrecv_klass, Rret_addr, Rflags, Rmethod, Rscratch1, Rscratch2);
|
||||
}
|
||||
|
||||
void TemplateTable::invokedynamic(int byte_no) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017 SAP SE. All rights reserved.
|
||||
* 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,6 +28,7 @@
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "interp_masm_ppc.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/compiledICHolder.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/klassVtable.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
@ -55,17 +56,22 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
// PPC port: use fixed size.
|
||||
const int code_length = VtableStub::pd_code_size_limit(true);
|
||||
VtableStub* s = new (code_length) VtableStub(true, vtable_index);
|
||||
|
||||
// Can be NULL if there is no free space in the code cache.
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
CodeBuffer cb(s->entry_point(), code_length);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
address start_pc;
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (CountCompiledCalls) {
|
||||
__ load_const(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr());
|
||||
__ lwz(R12_scratch2, 0, R11_scratch1);
|
||||
int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true);
|
||||
__ lwz(R12_scratch2, offs, R11_scratch1);
|
||||
__ addi(R12_scratch2, R12_scratch2, 1);
|
||||
__ stw(R12_scratch2, 0, R11_scratch1);
|
||||
__ stw(R12_scratch2, offs, R11_scratch1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -116,6 +122,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
__ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
|
||||
__ mtctr(R12_scratch2);
|
||||
__ bctr();
|
||||
|
||||
masm->flush();
|
||||
|
||||
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
|
||||
@ -125,10 +132,16 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
return s;
|
||||
}
|
||||
|
||||
VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
// PPC port: use fixed size.
|
||||
const int code_length = VtableStub::pd_code_size_limit(false);
|
||||
VtableStub* s = new (code_length) VtableStub(false, vtable_index);
|
||||
VtableStub* s = new (code_length) VtableStub(false, itable_index);
|
||||
|
||||
// Can be NULL if there is no free space in the code cache.
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
CodeBuffer cb(s->entry_point(), code_length);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
@ -136,10 +149,10 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (CountCompiledCalls) {
|
||||
__ load_const(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr());
|
||||
__ lwz(R12_scratch2, 0, R11_scratch1);
|
||||
int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true);
|
||||
__ lwz(R12_scratch2, offs, R11_scratch1);
|
||||
__ addi(R12_scratch2, R12_scratch2, 1);
|
||||
__ stw(R12_scratch2, 0, R11_scratch1);
|
||||
__ stw(R12_scratch2, offs, R11_scratch1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -148,62 +161,28 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
// Entry arguments:
|
||||
// R19_method: Interface
|
||||
// R3_ARG1: Receiver
|
||||
//
|
||||
|
||||
const Register rcvr_klass = R11_scratch1;
|
||||
const Register vtable_len = R12_scratch2;
|
||||
const Register itable_entry_addr = R21_tmp1;
|
||||
const Register itable_interface = R22_tmp2;
|
||||
Label L_no_such_interface;
|
||||
const Register rcvr_klass = R11_scratch1,
|
||||
interface = R12_scratch2,
|
||||
tmp1 = R21_tmp1,
|
||||
tmp2 = R22_tmp2;
|
||||
|
||||
// Get receiver klass.
|
||||
|
||||
// We might implicit NULL fault here.
|
||||
address npe_addr = __ pc(); // npe = null pointer exception
|
||||
__ null_check(R3_ARG1, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL);
|
||||
__ load_klass(rcvr_klass, R3_ARG1);
|
||||
|
||||
BLOCK_COMMENT("Load start of itable entries into itable_entry.");
|
||||
__ lwz(vtable_len, in_bytes(Klass::vtable_length_offset()), rcvr_klass);
|
||||
__ slwi(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
|
||||
__ add(itable_entry_addr, vtable_len, rcvr_klass);
|
||||
// Receiver subtype check against REFC.
|
||||
__ ld(interface, CompiledICHolder::holder_klass_offset(), R19_method);
|
||||
__ lookup_interface_method(rcvr_klass, interface, noreg,
|
||||
R0, tmp1, tmp2,
|
||||
L_no_such_interface, /*return_method=*/ false);
|
||||
|
||||
// Loop over all itable entries until desired interfaceOop(Rinterface) found.
|
||||
BLOCK_COMMENT("Increment itable_entry_addr in loop.");
|
||||
const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
|
||||
__ addi(itable_entry_addr, itable_entry_addr, vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes());
|
||||
|
||||
const int itable_offset_search_inc = itableOffsetEntry::size() * wordSize;
|
||||
Label search;
|
||||
__ bind(search);
|
||||
__ ld(itable_interface, 0, itable_entry_addr);
|
||||
|
||||
// Handle IncompatibleClassChangeError in itable stubs.
|
||||
// If the entry is NULL then we've reached the end of the table
|
||||
// without finding the expected interface, so throw an exception.
|
||||
BLOCK_COMMENT("Handle IncompatibleClassChangeError in itable stubs.");
|
||||
Label throw_icce;
|
||||
__ cmpdi(CCR1, itable_interface, 0);
|
||||
__ cmpd(CCR0, itable_interface, R19_method);
|
||||
__ addi(itable_entry_addr, itable_entry_addr, itable_offset_search_inc);
|
||||
__ beq(CCR1, throw_icce);
|
||||
__ bne(CCR0, search);
|
||||
|
||||
// Entry found and itable_entry_addr points to it, get offset of vtable for interface.
|
||||
|
||||
const Register vtable_offset = R12_scratch2;
|
||||
const Register itable_method = R11_scratch1;
|
||||
|
||||
const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() -
|
||||
itableOffsetEntry::interface_offset_in_bytes()) -
|
||||
itable_offset_search_inc;
|
||||
__ lwz(vtable_offset, vtable_offset_offset, itable_entry_addr);
|
||||
|
||||
// Compute itableMethodEntry and get method and entry point for compiler.
|
||||
const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) +
|
||||
itableMethodEntry::method_offset_in_bytes();
|
||||
|
||||
__ add(itable_method, rcvr_klass, vtable_offset);
|
||||
__ ld(R19_method, method_offset, itable_method);
|
||||
// Get Method* and entrypoint for compiler
|
||||
__ ld(interface, CompiledICHolder::holder_metadata_offset(), R19_method);
|
||||
__ lookup_interface_method(rcvr_klass, interface, itable_index,
|
||||
R19_method, tmp1, tmp2,
|
||||
L_no_such_interface, /*return_method=*/ true);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (DebugVtables) {
|
||||
@ -219,7 +198,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
address ame_addr = __ pc(); // ame = abstract method error
|
||||
|
||||
// Must do an explicit check if implicit checks are disabled.
|
||||
__ null_check(R19_method, in_bytes(Method::from_compiled_offset()), &throw_icce);
|
||||
__ null_check(R19_method, in_bytes(Method::from_compiled_offset()), &L_no_such_interface);
|
||||
__ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
|
||||
__ mtctr(R12_scratch2);
|
||||
__ bctr();
|
||||
@ -229,8 +208,8 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
// We force resolving of the call site by jumping to the "handle
|
||||
// wrong method" stub, and so let the interpreter runtime do all the
|
||||
// dirty work.
|
||||
__ bind(throw_icce);
|
||||
__ load_const(R11_scratch1, SharedRuntime::get_handle_wrong_method_stub());
|
||||
__ bind(L_no_such_interface);
|
||||
__ load_const_optimized(R11_scratch1, SharedRuntime::get_handle_wrong_method_stub(), R12_scratch2);
|
||||
__ mtctr(R11_scratch1);
|
||||
__ bctr();
|
||||
|
||||
@ -245,14 +224,15 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
||||
if (DebugVtables || CountCompiledCalls || VerifyOops) {
|
||||
return 1000;
|
||||
} else {
|
||||
int decode_klass_size = MacroAssembler::instr_size_for_decode_klass_not_null();
|
||||
if (is_vtable_stub) {
|
||||
return 20 + decode_klass_size + 8 + 8; // Plain + cOops + Traps + safety
|
||||
} else {
|
||||
return 96 + decode_klass_size + 12 + 8; // Plain + cOops + Traps + safety
|
||||
}
|
||||
}
|
||||
int size = is_vtable_stub ? 20 + 8 : 164 + 20; // Plain + safety
|
||||
if (UseCompressedClassPointers) {
|
||||
size += MacroAssembler::instr_size_for_decode_klass_not_null();
|
||||
}
|
||||
if (!ImplicitNullChecks || !os::zero_page_read_protected()) {
|
||||
size += is_vtable_stub ? 8 : 12;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int VtableStub::pd_code_alignment() {
|
||||
|
||||
@ -291,7 +291,7 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
|
||||
length.set_instruction(x->length());
|
||||
length.load_item();
|
||||
}
|
||||
if (needs_store_check) {
|
||||
if (needs_store_check || x->check_boolean()) {
|
||||
value.load_item();
|
||||
} else {
|
||||
value.load_for_store(x->elt_type());
|
||||
@ -341,11 +341,14 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
|
||||
// Needs GC write barriers.
|
||||
pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */,
|
||||
true /* do_load */, false /* patch */, NULL);
|
||||
__ move(value.result(), array_addr, null_check_info);
|
||||
// Seems to be a precise.
|
||||
}
|
||||
|
||||
LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info);
|
||||
__ move(result, array_addr, null_check_info);
|
||||
|
||||
if (obj_store) {
|
||||
// Precise card mark
|
||||
post_barrier(LIR_OprFact::address(array_addr), value.result());
|
||||
} else {
|
||||
__ move(value.result(), array_addr, null_check_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -842,6 +842,38 @@ void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state,
|
||||
verify_oop(Z_tos, state);
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::narrow(Register result, Register ret_type) {
|
||||
get_method(ret_type);
|
||||
z_lg(ret_type, Address(ret_type, in_bytes(Method::const_offset())));
|
||||
z_lb(ret_type, Address(ret_type, in_bytes(ConstMethod::result_type_offset())));
|
||||
|
||||
Label notBool, notByte, notChar, done;
|
||||
|
||||
// common case first
|
||||
compareU32_and_branch(ret_type, T_INT, bcondEqual, done);
|
||||
|
||||
compareU32_and_branch(ret_type, T_BOOLEAN, bcondNotEqual, notBool);
|
||||
z_nilf(result, 0x1);
|
||||
z_bru(done);
|
||||
|
||||
bind(notBool);
|
||||
compareU32_and_branch(ret_type, T_BYTE, bcondNotEqual, notByte);
|
||||
z_lbr(result, result);
|
||||
z_bru(done);
|
||||
|
||||
bind(notByte);
|
||||
compareU32_and_branch(ret_type, T_CHAR, bcondNotEqual, notChar);
|
||||
z_nilf(result, 0xffff);
|
||||
z_bru(done);
|
||||
|
||||
bind(notChar);
|
||||
// compareU32_and_branch(ret_type, T_SHORT, bcondNotEqual, notShort);
|
||||
z_lhr(result, result);
|
||||
|
||||
// Nothing to do for T_INT
|
||||
bind(done);
|
||||
}
|
||||
|
||||
// remove activation
|
||||
//
|
||||
// Unlock the receiver if this is a synchronized method.
|
||||
|
||||
@ -86,6 +86,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
void dispatch_next_noverify_oop(TosState state, int step = 0);
|
||||
void dispatch_via(TosState state, address* table);
|
||||
|
||||
void narrow(Register result, Register ret_type);
|
||||
|
||||
// Jump to an invoked target.
|
||||
void prepare_to_jump_from_interpreted(Register method);
|
||||
void jump_from_interpreted(Register method, Register temp);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -2731,8 +2731,8 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register temp1_reg,
|
||||
Register temp2_reg,
|
||||
Label& no_such_interface) {
|
||||
Label& no_such_interface,
|
||||
bool return_method) {
|
||||
|
||||
const Register vtable_len = temp1_reg; // Used to compute itable_entry_addr.
|
||||
const Register itable_entry_addr = Z_R1_scratch;
|
||||
@ -2741,11 +2741,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
BLOCK_COMMENT("lookup_interface_method {");
|
||||
|
||||
// Load start of itable entries into itable_entry_addr.
|
||||
z_llgf(vtable_len, Address(recv_klass, InstanceKlass::vtable_length_offset()));
|
||||
z_llgf(vtable_len, Address(recv_klass, Klass::vtable_length_offset()));
|
||||
z_sllg(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
|
||||
|
||||
// Loop over all itable entries until desired interfaceOop(Rinterface) found.
|
||||
const int vtable_base_offset = in_bytes(InstanceKlass::vtable_start_offset());
|
||||
const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
|
||||
|
||||
add2reg_with_index(itable_entry_addr,
|
||||
vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes(),
|
||||
@ -2767,38 +2767,36 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
z_brne(search);
|
||||
|
||||
// Entry found and itable_entry_addr points to it, get offset of vtable for interface.
|
||||
if (return_method) {
|
||||
const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() -
|
||||
itableOffsetEntry::interface_offset_in_bytes()) -
|
||||
itable_offset_search_inc;
|
||||
|
||||
const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() -
|
||||
itableOffsetEntry::interface_offset_in_bytes()) -
|
||||
itable_offset_search_inc;
|
||||
// Compute itableMethodEntry and get method and entry point
|
||||
// we use addressing with index and displacement, since the formula
|
||||
// for computing the entry's offset has a fixed and a dynamic part,
|
||||
// the latter depending on the matched interface entry and on the case,
|
||||
// that the itable index has been passed as a register, not a constant value.
|
||||
int method_offset = itableMethodEntry::method_offset_in_bytes();
|
||||
// Fixed part (displacement), common operand.
|
||||
Register itable_offset = method_result; // Dynamic part (index register).
|
||||
|
||||
// Compute itableMethodEntry and get method and entry point
|
||||
// we use addressing with index and displacement, since the formula
|
||||
// for computing the entry's offset has a fixed and a dynamic part,
|
||||
// the latter depending on the matched interface entry and on the case,
|
||||
// that the itable index has been passed as a register, not a constant value.
|
||||
int method_offset = itableMethodEntry::method_offset_in_bytes();
|
||||
// Fixed part (displacement), common operand.
|
||||
Register itable_offset; // Dynamic part (index register).
|
||||
if (itable_index.is_register()) {
|
||||
// Compute the method's offset in that register, for the formula, see the
|
||||
// else-clause below.
|
||||
z_sllg(itable_offset, itable_index.as_register(), exact_log2(itableMethodEntry::size() * wordSize));
|
||||
z_agf(itable_offset, vtable_offset_offset, itable_entry_addr);
|
||||
} else {
|
||||
// Displacement increases.
|
||||
method_offset += itableMethodEntry::size() * wordSize * itable_index.as_constant();
|
||||
|
||||
if (itable_index.is_register()) {
|
||||
// Compute the method's offset in that register, for the formula, see the
|
||||
// else-clause below.
|
||||
itable_offset = itable_index.as_register();
|
||||
// Load index from itable.
|
||||
z_llgf(itable_offset, vtable_offset_offset, itable_entry_addr);
|
||||
}
|
||||
|
||||
z_sllg(itable_offset, itable_offset, exact_log2(itableMethodEntry::size() * wordSize));
|
||||
z_agf(itable_offset, vtable_offset_offset, itable_entry_addr);
|
||||
} else {
|
||||
itable_offset = Z_R1_scratch;
|
||||
// Displacement increases.
|
||||
method_offset += itableMethodEntry::size() * wordSize * itable_index.as_constant();
|
||||
|
||||
// Load index from itable.
|
||||
z_llgf(itable_offset, vtable_offset_offset, itable_entry_addr);
|
||||
// Finally load the method's oop.
|
||||
z_lg(method_result, method_offset, itable_offset, recv_klass);
|
||||
}
|
||||
|
||||
// Finally load the method's oop.
|
||||
z_lg(method_result, method_offset, itable_offset, recv_klass);
|
||||
BLOCK_COMMENT("} lookup_interface_method");
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -650,8 +650,8 @@ class MacroAssembler: public Assembler {
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register temp1_reg,
|
||||
Register temp2_reg,
|
||||
Label& no_such_interface);
|
||||
Label& no_such_interface,
|
||||
bool return_method = true);
|
||||
|
||||
// virtual method calling
|
||||
void lookup_virtual_method(Register recv_klass,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -491,7 +491,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
|
||||
Label L_no_such_interface;
|
||||
__ lookup_interface_method(temp1_recv_klass, temp3_intf,
|
||||
// Note: next two args must be the same:
|
||||
Z_index, Z_method, temp2, noreg,
|
||||
Z_index, Z_method, temp2,
|
||||
L_no_such_interface);
|
||||
jump_from_method_handle(_masm, Z_method, temp2, Z_R0, for_compiler_entry);
|
||||
|
||||
|
||||
@ -2628,9 +2628,9 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
Label skip_fixup;
|
||||
{
|
||||
Label ic_miss;
|
||||
const int klass_offset = oopDesc::klass_offset_in_bytes();
|
||||
const int holder_klass_offset = CompiledICHolder::holder_klass_offset();
|
||||
const int holder_method_offset = CompiledICHolder::holder_method_offset();
|
||||
const int klass_offset = oopDesc::klass_offset_in_bytes();
|
||||
const int holder_klass_offset = CompiledICHolder::holder_klass_offset();
|
||||
const int holder_metadata_offset = CompiledICHolder::holder_metadata_offset();
|
||||
|
||||
// Out-of-line call to ic_miss handler.
|
||||
__ call_ic_miss_handler(ic_miss, 0x11, 0, Z_R1_scratch);
|
||||
@ -2659,7 +2659,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
// This def MUST MATCH code in gen_c2i_adapter!
|
||||
const Register code = Z_R11;
|
||||
|
||||
__ z_lg(Z_method, holder_method_offset, Z_method);
|
||||
__ z_lg(Z_method, holder_metadata_offset, Z_method);
|
||||
__ load_and_test_long(Z_R0, method_(code));
|
||||
__ z_brne(ic_miss); // Cache miss: call runtime to handle this.
|
||||
|
||||
|
||||
@ -2314,6 +2314,12 @@ address TemplateInterpreterGenerator::generate_earlyret_entry_for (TosState stat
|
||||
__ store_const(Address(RjvmtiState, JvmtiThreadState::earlyret_state_offset()),
|
||||
JvmtiThreadState::earlyret_inactive, 4, 4, Z_R0_scratch);
|
||||
|
||||
if (state == itos) {
|
||||
// Narrow result if state is itos but result type is smaller.
|
||||
// Need to narrow in the return bytecode rather than in generate_return_entry
|
||||
// since compiled code callers expect the result to already be narrowed.
|
||||
__ narrow(Z_tos, Z_tmp_1); /* fall through */
|
||||
}
|
||||
__ remove_activation(state,
|
||||
Z_tmp_1, // retaddr
|
||||
false, // throw_monitor_exception
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1174,8 +1174,20 @@ void TemplateTable::bastore() {
|
||||
__ pop_i(Z_ARG3);
|
||||
__ pop_ptr(Z_tmp_2);
|
||||
// Z_tos : value
|
||||
// Z_ARG3 : index
|
||||
// Z_ARG3 : index
|
||||
// Z_tmp_2 : array
|
||||
|
||||
// Need to check whether array is boolean or byte
|
||||
// since both types share the bastore bytecode.
|
||||
__ load_klass(Z_tmp_1, Z_tmp_2);
|
||||
__ z_llgf(Z_tmp_1, Address(Z_tmp_1, Klass::layout_helper_offset()));
|
||||
__ z_tmll(Z_tmp_1, Klass::layout_helper_boolean_diffbit());
|
||||
Label L_skip;
|
||||
__ z_bfalse(L_skip);
|
||||
// if it is a T_BOOLEAN array, mask the stored value to 0/1
|
||||
__ z_nilf(Z_tos, 0x1);
|
||||
__ bind(L_skip);
|
||||
|
||||
// No index shift necessary - pass 0.
|
||||
index_check(Z_tmp_2, Z_ARG3, 0); // Prefer index in Z_ARG3.
|
||||
__ z_stc(Z_tos,
|
||||
@ -2321,6 +2333,13 @@ void TemplateTable::_return(TosState state) {
|
||||
__ bind(skip_register_finalizer);
|
||||
}
|
||||
|
||||
if (state == itos) {
|
||||
// Narrow result if state is itos but result type is smaller.
|
||||
// Need to narrow in the return bytecode rather than in generate_return_entry
|
||||
// since compiled code callers expect the result to already be narrowed.
|
||||
__ narrow(Z_tos, Z_tmp_1); /* fall through */
|
||||
}
|
||||
|
||||
__ remove_activation(state, Z_R14);
|
||||
__ z_br(Z_R14);
|
||||
}
|
||||
@ -3526,66 +3545,67 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
transition(vtos, vtos);
|
||||
|
||||
assert(byte_no == f1_byte, "use this argument");
|
||||
Register interface = Z_tos;
|
||||
Register index = Z_ARG3;
|
||||
Register receiver = Z_tmp_1;
|
||||
Register flags = Z_ARG5;
|
||||
Register klass = Z_ARG2,
|
||||
method = Z_ARG3,
|
||||
interface = Z_ARG4,
|
||||
flags = Z_ARG5,
|
||||
receiver = Z_tmp_1;
|
||||
|
||||
BLOCK_COMMENT("invokeinterface {");
|
||||
|
||||
// Destroys Z_ARG1 and Z_ARG2, thus use Z_ARG4 and copy afterwards.
|
||||
prepare_invoke(byte_no, Z_ARG4, index, // Get f1 klassOop, f2 itable index.
|
||||
prepare_invoke(byte_no, interface, method, // Get f1 klassOop, f2 itable index.
|
||||
receiver, flags);
|
||||
|
||||
// Z_R14 (== Z_bytecode) : return entry
|
||||
|
||||
__ z_lgr(interface, Z_ARG4);
|
||||
|
||||
// Special case of invokeinterface called for virtual method of
|
||||
// java.lang.Object. See cpCacheOop.cpp for details.
|
||||
// This code isn't produced by javac, but could be produced by
|
||||
// another compliant java compiler.
|
||||
Label notMethod;
|
||||
NearLabel notMethod, no_such_interface, no_such_method;
|
||||
__ testbit(flags, ConstantPoolCacheEntry::is_forced_virtual_shift);
|
||||
__ z_brz(notMethod);
|
||||
invokevirtual_helper(index, receiver, flags);
|
||||
invokevirtual_helper(method, receiver, flags);
|
||||
__ bind(notMethod);
|
||||
|
||||
// Get receiver klass into klass - also a null check.
|
||||
Register klass = flags;
|
||||
|
||||
__ restore_locals();
|
||||
__ load_klass(klass, receiver);
|
||||
|
||||
__ lookup_interface_method(klass, interface, noreg, noreg, /*temp*/Z_ARG1,
|
||||
no_such_interface, /*return_method=*/false);
|
||||
|
||||
// Profile this call.
|
||||
__ profile_virtual_call(klass, Z_ARG2/*mdp*/, Z_ARG4/*scratch*/);
|
||||
__ profile_virtual_call(klass, Z_ARG1/*mdp*/, flags/*scratch*/);
|
||||
|
||||
NearLabel no_such_interface, no_such_method;
|
||||
Register method = Z_tmp_2;
|
||||
// Find entry point to call.
|
||||
|
||||
// TK 2010-08-24: save the index to Z_ARG4. needed in case of an error
|
||||
// in throw_AbstractMethodErrorByTemplateTable
|
||||
__ z_lgr(Z_ARG4, index);
|
||||
// TK 2011-03-24: copy also klass because it could be changed in
|
||||
// lookup_interface_method
|
||||
__ z_lgr(Z_ARG2, klass);
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
klass, interface, index,
|
||||
// outputs: method, scan temp. reg
|
||||
method, Z_tmp_2, Z_R1_scratch,
|
||||
no_such_interface);
|
||||
// Get declaring interface class from method
|
||||
__ z_lg(interface, Address(method, Method::const_offset()));
|
||||
__ z_lg(interface, Address(interface, ConstMethod::constants_offset()));
|
||||
__ z_lg(interface, Address(interface, ConstantPool::pool_holder_offset_in_bytes()));
|
||||
|
||||
// Get itable index from method
|
||||
Register index = receiver,
|
||||
method2 = flags;
|
||||
__ z_lgf(index, Address(method, Method::itable_index_offset()));
|
||||
__ z_aghi(index, -Method::itable_index_max);
|
||||
__ z_lcgr(index, index);
|
||||
|
||||
__ lookup_interface_method(klass, interface, index, method2, Z_tmp_2,
|
||||
no_such_interface);
|
||||
|
||||
// Check for abstract method error.
|
||||
// Note: This should be done more efficiently via a throw_abstract_method_error
|
||||
// interpreter entry point and a conditional jump to it in case of a null
|
||||
// method.
|
||||
__ compareU64_and_branch(method, (intptr_t) 0,
|
||||
__ compareU64_and_branch(method2, (intptr_t) 0,
|
||||
Assembler::bcondZero, no_such_method);
|
||||
|
||||
__ profile_arguments_type(Z_ARG3, method, Z_ARG5, true);
|
||||
__ profile_arguments_type(Z_tmp_1, method2, Z_tmp_2, true);
|
||||
|
||||
// Do the call.
|
||||
__ jump_from_interpreted(method, Z_ARG5);
|
||||
__ jump_from_interpreted(method2, Z_tmp_2);
|
||||
__ should_not_reach_here();
|
||||
|
||||
// exception handling code follows...
|
||||
@ -3597,12 +3617,8 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
// Throw exception.
|
||||
__ restore_bcp(); // Bcp must be correct for exception handler (was destroyed).
|
||||
__ restore_locals(); // Make sure locals pointer is correct as well (was destroyed).
|
||||
// TK 2010-08-24: Call throw_AbstractMethodErrorByTemplateTable now with the
|
||||
// relevant information for generating a better error message
|
||||
__ call_VM(noreg,
|
||||
CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::throw_AbstractMethodError),
|
||||
Z_ARG2, interface, Z_ARG4);
|
||||
CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
|
||||
// The call_VM checks for exception, so we should never return here.
|
||||
__ should_not_reach_here();
|
||||
|
||||
@ -3611,12 +3627,8 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
// Throw exception.
|
||||
__ restore_bcp(); // Bcp must be correct for exception handler (was destroyed).
|
||||
__ restore_locals(); // Make sure locals pointer is correct as well (was destroyed).
|
||||
// TK 2010-08-24: Call throw_IncompatibleClassChangeErrorByTemplateTable now with the
|
||||
// relevant information for generating a better error message
|
||||
__ call_VM(noreg,
|
||||
CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::throw_IncompatibleClassChangeError),
|
||||
Z_ARG2, interface);
|
||||
CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
|
||||
// The call_VM checks for exception, so we should never return here.
|
||||
__ should_not_reach_here();
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
|
||||
* 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,6 +28,7 @@
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "interp_masm_s390.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/compiledICHolder.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/klassVtable.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
@ -57,7 +58,6 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
ResourceMark rm;
|
||||
CodeBuffer cb(s->entry_point(), code_length);
|
||||
MacroAssembler *masm = new MacroAssembler(&cb);
|
||||
address start_pc;
|
||||
int padding_bytes = 0;
|
||||
|
||||
#if (!defined(PRODUCT) && defined(COMPILER2))
|
||||
@ -144,9 +144,9 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
return s;
|
||||
}
|
||||
|
||||
VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
const int code_length = VtableStub::pd_code_size_limit(false);
|
||||
VtableStub *s = new(code_length) VtableStub(false, vtable_index);
|
||||
VtableStub *s = new(code_length) VtableStub(false, itable_index);
|
||||
if (s == NULL) { // Indicates OOM in the code cache.
|
||||
return NULL;
|
||||
}
|
||||
@ -154,7 +154,6 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
ResourceMark rm;
|
||||
CodeBuffer cb(s->entry_point(), code_length);
|
||||
MacroAssembler *masm = new MacroAssembler(&cb);
|
||||
address start_pc;
|
||||
int padding_bytes = 0;
|
||||
|
||||
#if (!defined(PRODUCT) && defined(COMPILER2))
|
||||
@ -174,11 +173,9 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
// Entry arguments:
|
||||
// Z_method: Interface
|
||||
// Z_ARG1: Receiver
|
||||
const Register rcvr_klass = Z_tmp_1; // Used to compute itable_entry_addr.
|
||||
// Use extra reg to avoid re-load.
|
||||
const Register vtable_len = Z_tmp_2; // Used to compute itable_entry_addr.
|
||||
const Register itable_entry_addr = Z_R1_scratch;
|
||||
const Register itable_interface = Z_R0_scratch;
|
||||
NearLabel no_such_interface;
|
||||
const Register rcvr_klass = Z_tmp_1,
|
||||
interface = Z_tmp_2;
|
||||
|
||||
// Get receiver klass.
|
||||
// Must do an explicit check if implicit checks are disabled.
|
||||
@ -186,50 +183,15 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
__ null_check(Z_ARG1, Z_R1_scratch, oopDesc::klass_offset_in_bytes());
|
||||
__ load_klass(rcvr_klass, Z_ARG1);
|
||||
|
||||
// Load start of itable entries into itable_entry.
|
||||
__ z_llgf(vtable_len, Address(rcvr_klass, InstanceKlass::vtable_length_offset()));
|
||||
__ z_sllg(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
|
||||
// Receiver subtype check against REFC.
|
||||
__ z_lg(interface, Address(Z_method, CompiledICHolder::holder_klass_offset()));
|
||||
__ lookup_interface_method(rcvr_klass, interface, noreg,
|
||||
noreg, Z_R1, no_such_interface, /*return_method=*/ false);
|
||||
|
||||
// Loop over all itable entries until desired interfaceOop(Rinterface) found.
|
||||
const int vtable_base_offset = in_bytes(InstanceKlass::vtable_start_offset());
|
||||
// Count unused bytes.
|
||||
start_pc = __ pc();
|
||||
__ add2reg_with_index(itable_entry_addr, vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes(), rcvr_klass, vtable_len);
|
||||
padding_bytes += 20 - (__ pc() - start_pc);
|
||||
|
||||
const int itable_offset_search_inc = itableOffsetEntry::size() * wordSize;
|
||||
Label search;
|
||||
__ bind(search);
|
||||
|
||||
// Handle IncompatibleClassChangeError in itable stubs.
|
||||
// If the entry is NULL then we've reached the end of the table
|
||||
// without finding the expected interface, so throw an exception.
|
||||
NearLabel throw_icce;
|
||||
__ load_and_test_long(itable_interface, Address(itable_entry_addr));
|
||||
__ z_bre(throw_icce); // Throw the exception out-of-line.
|
||||
// Count unused bytes.
|
||||
start_pc = __ pc();
|
||||
__ add2reg(itable_entry_addr, itable_offset_search_inc);
|
||||
padding_bytes += 20 - (__ pc() - start_pc);
|
||||
__ z_cgr(itable_interface, Z_method);
|
||||
__ z_brne(search);
|
||||
|
||||
// Entry found. Itable_entry_addr points to the subsequent entry (itable_offset_search_inc too far).
|
||||
// Get offset of vtable for interface.
|
||||
|
||||
const Register vtable_offset = Z_R1_scratch;
|
||||
const Register itable_method = rcvr_klass; // Calculated before.
|
||||
|
||||
const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() -
|
||||
itableOffsetEntry::interface_offset_in_bytes()) -
|
||||
itable_offset_search_inc;
|
||||
__ z_llgf(vtable_offset, vtable_offset_offset, itable_entry_addr);
|
||||
|
||||
// Compute itableMethodEntry and get method and entry point for compiler.
|
||||
const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) +
|
||||
itableMethodEntry::method_offset_in_bytes();
|
||||
|
||||
__ z_lg(Z_method, method_offset, vtable_offset, itable_method);
|
||||
// Get Method* and entrypoint for compiler
|
||||
__ z_lg(interface, Address(Z_method, CompiledICHolder::holder_metadata_offset()));
|
||||
__ lookup_interface_method(rcvr_klass, interface, itable_index,
|
||||
Z_method, Z_R1, no_such_interface, /*return_method=*/ true);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (DebugVtables) {
|
||||
@ -244,13 +206,13 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
address ame_addr = __ pc();
|
||||
// Must do an explicit check if implicit checks are disabled.
|
||||
if (!ImplicitNullChecks) {
|
||||
__ compare64_and_branch(Z_method, (intptr_t) 0, Assembler::bcondEqual, throw_icce);
|
||||
__ compare64_and_branch(Z_method, (intptr_t) 0, Assembler::bcondEqual, no_such_interface);
|
||||
}
|
||||
__ z_lg(Z_R1_scratch, in_bytes(Method::from_compiled_offset()), Z_method);
|
||||
__ z_br(Z_R1_scratch);
|
||||
|
||||
// Handle IncompatibleClassChangeError in itable stubs.
|
||||
__ bind(throw_icce);
|
||||
__ bind(no_such_interface);
|
||||
// Count unused bytes
|
||||
// worst case actual size
|
||||
// We force resolving of the call site by jumping to
|
||||
@ -273,13 +235,12 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
||||
if (CountCompiledCalls) {
|
||||
size += 6 * 4;
|
||||
}
|
||||
if (is_vtable_stub) {
|
||||
size += 52;
|
||||
} else {
|
||||
size += 104;
|
||||
size += is_vtable_stub ? 36 : 140;
|
||||
if (UseCompressedClassPointers) {
|
||||
size += MacroAssembler::instr_size_for_decode_klass_not_null();
|
||||
}
|
||||
if (Universe::narrow_klass_base() != NULL) {
|
||||
size += 16; // A guess.
|
||||
if (!ImplicitNullChecks) {
|
||||
size += 36;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -2069,9 +2069,10 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
Register method_result,
|
||||
Register scan_temp,
|
||||
Register sethi_temp,
|
||||
Label& L_no_such_interface) {
|
||||
Label& L_no_such_interface,
|
||||
bool return_method) {
|
||||
assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
|
||||
assert(itable_index.is_constant() || itable_index.as_register() == method_result,
|
||||
assert(!return_method || itable_index.is_constant() || itable_index.as_register() == method_result,
|
||||
"caller must use same register for non-constant itable index as for method");
|
||||
|
||||
Label L_no_such_interface_restore;
|
||||
@ -2103,11 +2104,13 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
add(scan_temp, itb_offset, scan_temp);
|
||||
add(recv_klass, scan_temp, scan_temp);
|
||||
|
||||
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
||||
RegisterOrConstant itable_offset = itable_index;
|
||||
itable_offset = regcon_sll_ptr(itable_index, exact_log2(itableMethodEntry::size() * wordSize), itable_offset);
|
||||
itable_offset = regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes(), itable_offset);
|
||||
add(recv_klass, ensure_simm13_or_reg(itable_offset, sethi_temp), recv_klass);
|
||||
if (return_method) {
|
||||
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
||||
RegisterOrConstant itable_offset = itable_index;
|
||||
itable_offset = regcon_sll_ptr(itable_index, exact_log2(itableMethodEntry::size() * wordSize), itable_offset);
|
||||
itable_offset = regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes(), itable_offset);
|
||||
add(recv_klass, ensure_simm13_or_reg(itable_offset, sethi_temp), recv_klass);
|
||||
}
|
||||
|
||||
// for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
|
||||
// if (scan->interface() == intf) {
|
||||
@ -2142,12 +2145,14 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
|
||||
bind(L_found_method);
|
||||
|
||||
// Got a hit.
|
||||
int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
|
||||
// scan_temp[-scan_step] points to the vtable offset we need
|
||||
ito_offset -= scan_step;
|
||||
lduw(scan_temp, ito_offset, scan_temp);
|
||||
ld_ptr(recv_klass, scan_temp, method_result);
|
||||
if (return_method) {
|
||||
// Got a hit.
|
||||
int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
|
||||
// scan_temp[-scan_step] points to the vtable offset we need
|
||||
ito_offset -= scan_step;
|
||||
lduw(scan_temp, ito_offset, scan_temp);
|
||||
ld_ptr(recv_klass, scan_temp, method_result);
|
||||
}
|
||||
|
||||
if (did_save) {
|
||||
Label L_done;
|
||||
|
||||
@ -1290,7 +1290,8 @@ public:
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register temp_reg, Register temp2_reg,
|
||||
Label& no_such_interface);
|
||||
Label& no_such_interface,
|
||||
bool return_method = true);
|
||||
|
||||
// virtual method calling
|
||||
void lookup_virtual_method(Register recv_klass,
|
||||
|
||||
@ -1079,7 +1079,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
|
||||
Label ok, ok2;
|
||||
__ brx(Assembler::equal, false, Assembler::pt, ok);
|
||||
__ delayed()->ld_ptr(G5_method, CompiledICHolder::holder_method_offset(), G5_method);
|
||||
__ delayed()->ld_ptr(G5_method, CompiledICHolder::holder_metadata_offset(), G5_method);
|
||||
__ jump_to(ic_miss, G3_scratch);
|
||||
__ delayed()->nop();
|
||||
|
||||
|
||||
@ -3173,15 +3173,15 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
assert(byte_no == f1_byte, "use this argument");
|
||||
|
||||
const Register Rinterface = G1_scratch;
|
||||
const Register Rmethod = Lscratch;
|
||||
const Register Rret = G3_scratch;
|
||||
const Register Rindex = Lscratch;
|
||||
const Register O0_recv = O0;
|
||||
const Register O1_flags = O1;
|
||||
const Register O2_Klass = O2;
|
||||
const Register Rscratch = G4_scratch;
|
||||
assert_different_registers(Rscratch, G5_method);
|
||||
|
||||
prepare_invoke(byte_no, Rinterface, Rret, Rindex, O0_recv, O1_flags);
|
||||
prepare_invoke(byte_no, Rinterface, Rret, Rmethod, O0_recv, O1_flags);
|
||||
|
||||
// get receiver klass
|
||||
__ null_check(O0_recv, oopDesc::klass_offset_in_bytes());
|
||||
@ -3201,55 +3201,40 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
|
||||
__ bind(notMethod);
|
||||
|
||||
Register Rtemp = O1_flags;
|
||||
|
||||
Label L_no_such_interface;
|
||||
|
||||
// Receiver subtype check against REFC.
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
O2_Klass, Rinterface, noreg,
|
||||
// outputs: temp reg1, temp reg2, temp reg3
|
||||
G5_method, Rscratch, Rtemp,
|
||||
L_no_such_interface,
|
||||
/*return_method=*/false);
|
||||
|
||||
__ profile_virtual_call(O2_Klass, O4);
|
||||
|
||||
//
|
||||
// find entry point to call
|
||||
//
|
||||
|
||||
// compute start of first itableOffsetEntry (which is at end of vtable)
|
||||
const int base = in_bytes(Klass::vtable_start_offset());
|
||||
Label search;
|
||||
Register Rtemp = O1_flags;
|
||||
// Get declaring interface class from method
|
||||
__ ld_ptr(Rmethod, Method::const_offset(), Rinterface);
|
||||
__ ld_ptr(Rinterface, ConstMethod::constants_offset(), Rinterface);
|
||||
__ ld_ptr(Rinterface, ConstantPool::pool_holder_offset_in_bytes(), Rinterface);
|
||||
|
||||
__ ld(O2_Klass, in_bytes(Klass::vtable_length_offset()), Rtemp);
|
||||
__ sll(Rtemp, LogBytesPerWord, Rtemp); // Rscratch *= 4;
|
||||
if (Assembler::is_simm13(base)) {
|
||||
__ add(Rtemp, base, Rtemp);
|
||||
} else {
|
||||
__ set(base, Rscratch);
|
||||
__ add(Rscratch, Rtemp, Rtemp);
|
||||
}
|
||||
__ add(O2_Klass, Rtemp, Rscratch);
|
||||
// Get itable index from method
|
||||
const Register Rindex = G5_method;
|
||||
__ ld(Rmethod, Method::itable_index_offset(), Rindex);
|
||||
__ sub(Rindex, Method::itable_index_max, Rindex);
|
||||
__ neg(Rindex);
|
||||
|
||||
__ bind(search);
|
||||
|
||||
__ ld_ptr(Rscratch, itableOffsetEntry::interface_offset_in_bytes(), Rtemp);
|
||||
{
|
||||
Label ok;
|
||||
|
||||
// Check that entry is non-null. Null entries are probably a bytecode
|
||||
// problem. If the interface isn't implemented by the receiver class,
|
||||
// the VM should throw IncompatibleClassChangeError. linkResolver checks
|
||||
// this too but that's only if the entry isn't already resolved, so we
|
||||
// need to check again.
|
||||
__ br_notnull_short( Rtemp, Assembler::pt, ok);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
|
||||
__ should_not_reach_here();
|
||||
__ bind(ok);
|
||||
}
|
||||
|
||||
__ cmp(Rinterface, Rtemp);
|
||||
__ brx(Assembler::notEqual, true, Assembler::pn, search);
|
||||
__ delayed()->add(Rscratch, itableOffsetEntry::size() * wordSize, Rscratch);
|
||||
|
||||
// entry found and Rscratch points to it
|
||||
__ ld(Rscratch, itableOffsetEntry::offset_offset_in_bytes(), Rscratch);
|
||||
|
||||
assert(itableMethodEntry::method_offset_in_bytes() == 0, "adjust instruction below");
|
||||
__ sll(Rindex, exact_log2(itableMethodEntry::size() * wordSize), Rindex); // Rindex *= 8;
|
||||
__ add(Rscratch, Rindex, Rscratch);
|
||||
__ ld_ptr(O2_Klass, Rscratch, G5_method);
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
O2_Klass, Rinterface, Rindex,
|
||||
// outputs: method, scan temp reg, temp reg
|
||||
G5_method, Rscratch, Rtemp,
|
||||
L_no_such_interface);
|
||||
|
||||
// Check for abstract method error.
|
||||
{
|
||||
@ -3266,6 +3251,10 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
__ profile_arguments_type(G5_method, Rcall, Gargs, true);
|
||||
__ profile_called_method(G5_method, Rscratch);
|
||||
__ call_from_interpreter(Rcall, Gargs, Rret);
|
||||
|
||||
__ bind(L_no_such_interface);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
|
||||
__ should_not_reach_here();
|
||||
}
|
||||
|
||||
void TemplateTable::invokehandle(int byte_no) {
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "interp_masm_sparc.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/compiledICHolder.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/klassVtable.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
@ -140,7 +141,8 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
Register G3_Klass = G3_scratch;
|
||||
Register G5_interface = G5; // Passed in as an argument
|
||||
Register G5_icholder = G5; // Passed in as an argument
|
||||
Register G4_interface = G4_scratch;
|
||||
Label search;
|
||||
|
||||
// Entry arguments:
|
||||
@ -164,14 +166,26 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
}
|
||||
#endif /* PRODUCT */
|
||||
|
||||
Label throw_icce;
|
||||
Label L_no_such_interface;
|
||||
|
||||
Register L5_method = L5;
|
||||
|
||||
// Receiver subtype check against REFC.
|
||||
__ ld_ptr(G5_icholder, CompiledICHolder::holder_klass_offset(), G4_interface);
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
G3_Klass, G5_interface, itable_index,
|
||||
G3_Klass, G4_interface, itable_index,
|
||||
// outputs: scan temp. reg1, scan temp. reg2
|
||||
L5_method, L2, L3,
|
||||
L_no_such_interface,
|
||||
/*return_method=*/ false);
|
||||
|
||||
// Get Method* and entrypoint for compiler
|
||||
__ ld_ptr(G5_icholder, CompiledICHolder::holder_metadata_offset(), G4_interface);
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
G3_Klass, G4_interface, itable_index,
|
||||
// outputs: method, scan temp. reg
|
||||
L5_method, L2, L3,
|
||||
throw_icce);
|
||||
L_no_such_interface);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (DebugVtables) {
|
||||
@ -197,7 +211,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
__ JMP(G3_scratch, 0);
|
||||
__ delayed()->nop();
|
||||
|
||||
__ bind(throw_icce);
|
||||
__ bind(L_no_such_interface);
|
||||
AddressLiteral icce(StubRoutines::throw_IncompatibleClassChangeError_entry());
|
||||
__ jump_to(icce, G3_scratch);
|
||||
__ delayed()->restore();
|
||||
@ -232,7 +246,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
||||
MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
|
||||
return basic + slop;
|
||||
} else {
|
||||
const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord +
|
||||
const int basic = (48 LP64_ONLY(+ 6)) * BytesPerInstWord +
|
||||
// shift;add for load_klass (only shift with zero heap based)
|
||||
(UseCompressedClassPointers ?
|
||||
MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
|
||||
|
||||
@ -5733,8 +5733,13 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register scan_temp,
|
||||
Label& L_no_such_interface) {
|
||||
assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
|
||||
Label& L_no_such_interface,
|
||||
bool return_method) {
|
||||
assert_different_registers(recv_klass, intf_klass, scan_temp);
|
||||
assert_different_registers(method_result, intf_klass, scan_temp);
|
||||
assert(recv_klass != method_result || !return_method,
|
||||
"recv_klass can be destroyed when method isn't needed");
|
||||
|
||||
assert(itable_index.is_constant() || itable_index.as_register() == method_result,
|
||||
"caller must use same register for non-constant itable index as for method");
|
||||
|
||||
@ -5751,9 +5756,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
// %%% Could store the aligned, prescaled offset in the klassoop.
|
||||
lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));
|
||||
|
||||
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
||||
assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
|
||||
lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
|
||||
if (return_method) {
|
||||
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
||||
assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
|
||||
lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
|
||||
}
|
||||
|
||||
// for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
|
||||
// if (scan->interface() == intf) {
|
||||
@ -5787,9 +5794,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
|
||||
bind(found_method);
|
||||
|
||||
// Got a hit.
|
||||
movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
|
||||
movptr(method_result, Address(recv_klass, scan_temp, Address::times_1));
|
||||
if (return_method) {
|
||||
// Got a hit.
|
||||
movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
|
||||
movptr(method_result, Address(recv_klass, scan_temp, Address::times_1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -538,7 +538,8 @@ class MacroAssembler: public Assembler {
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register scan_temp,
|
||||
Label& no_such_interface);
|
||||
Label& no_such_interface,
|
||||
bool return_method = true);
|
||||
|
||||
// virtual method calling
|
||||
void lookup_virtual_method(Register recv_klass,
|
||||
|
||||
@ -952,7 +952,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
Label missed;
|
||||
__ movptr(temp, Address(receiver, oopDesc::klass_offset_in_bytes()));
|
||||
__ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset()));
|
||||
__ movptr(rbx, Address(holder, CompiledICHolder::holder_method_offset()));
|
||||
__ movptr(rbx, Address(holder, CompiledICHolder::holder_metadata_offset()));
|
||||
__ jcc(Assembler::notEqual, missed);
|
||||
// Method might have been compiled since the call site was patched to
|
||||
// interpreted if that is the case treat it as a miss so we can get
|
||||
|
||||
@ -942,7 +942,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
{
|
||||
__ load_klass(temp, receiver);
|
||||
__ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset()));
|
||||
__ movptr(rbx, Address(holder, CompiledICHolder::holder_method_offset()));
|
||||
__ movptr(rbx, Address(holder, CompiledICHolder::holder_metadata_offset()));
|
||||
__ jcc(Assembler::equal, ok);
|
||||
__ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
|
||||
|
||||
|
||||
@ -3695,11 +3695,11 @@ void TemplateTable::fast_invokevfinal(int byte_no) {
|
||||
void TemplateTable::invokeinterface(int byte_no) {
|
||||
transition(vtos, vtos);
|
||||
assert(byte_no == f1_byte, "use this argument");
|
||||
prepare_invoke(byte_no, rax, rbx, // get f1 Klass*, f2 itable index
|
||||
prepare_invoke(byte_no, rax, rbx, // get f1 Klass*, f2 Method*
|
||||
rcx, rdx); // recv, flags
|
||||
|
||||
// rax: interface klass (from f1)
|
||||
// rbx: itable index (from f2)
|
||||
// rax: reference klass (from f1)
|
||||
// rbx: method (from f2)
|
||||
// rcx: receiver
|
||||
// rdx: flags
|
||||
|
||||
@ -3721,10 +3721,28 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
__ null_check(rcx, oopDesc::klass_offset_in_bytes());
|
||||
__ load_klass(rdx, rcx);
|
||||
|
||||
Label no_such_interface, no_such_method;
|
||||
|
||||
// Receiver subtype check against REFC.
|
||||
// Superklass in rax. Subklass in rdx. Blows rcx, rdi.
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
rdx, rax, noreg,
|
||||
// outputs: scan temp. reg, scan temp. reg
|
||||
rbcp, rlocals,
|
||||
no_such_interface,
|
||||
/*return_method=*/false);
|
||||
|
||||
// profile this call
|
||||
__ restore_bcp(); // rbcp was destroyed by receiver type check
|
||||
__ profile_virtual_call(rdx, rbcp, rlocals);
|
||||
|
||||
Label no_such_interface, no_such_method;
|
||||
// Get declaring interface class from method, and itable index
|
||||
__ movptr(rax, Address(rbx, Method::const_offset()));
|
||||
__ movptr(rax, Address(rax, ConstMethod::constants_offset()));
|
||||
__ movptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes()));
|
||||
__ movl(rbx, Address(rbx, Method::itable_index_offset()));
|
||||
__ subl(rbx, Method::itable_index_max);
|
||||
__ negl(rbx);
|
||||
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
rdx, rax, rbx,
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "interp_masm_x86.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/compiledICHolder.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/klassVtable.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
@ -147,7 +148,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
// Entry arguments:
|
||||
// rax,: Interface
|
||||
// rax: CompiledICHolder
|
||||
// rcx: Receiver
|
||||
|
||||
#ifndef PRODUCT
|
||||
@ -155,25 +156,42 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
__ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
|
||||
}
|
||||
#endif /* PRODUCT */
|
||||
// get receiver (need to skip return address on top of stack)
|
||||
|
||||
assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
|
||||
|
||||
// get receiver klass (also an implicit null-check)
|
||||
address npe_addr = __ pc();
|
||||
__ movptr(rsi, Address(rcx, oopDesc::klass_offset_in_bytes()));
|
||||
|
||||
// Most registers are in use; we'll use rax, rbx, rsi, rdi
|
||||
// (If we need to make rsi, rdi callee-save, do a push/pop here.)
|
||||
const Register method = rbx;
|
||||
Label throw_icce;
|
||||
const Register recv_klass_reg = rsi;
|
||||
const Register holder_klass_reg = rax; // declaring interface klass (DECC)
|
||||
const Register resolved_klass_reg = rbx; // resolved interface klass (REFC)
|
||||
const Register temp_reg = rdi;
|
||||
|
||||
// Get Method* and entrypoint for compiler
|
||||
const Register icholder_reg = rax;
|
||||
__ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset()));
|
||||
__ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset()));
|
||||
|
||||
Label L_no_such_interface;
|
||||
|
||||
// get receiver klass (also an implicit null-check)
|
||||
address npe_addr = __ pc();
|
||||
assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
|
||||
__ load_klass(recv_klass_reg, rcx);
|
||||
|
||||
// Receiver subtype check against REFC.
|
||||
// Destroys recv_klass_reg value.
|
||||
__ lookup_interface_method(// inputs: rec. class, interface
|
||||
recv_klass_reg, resolved_klass_reg, noreg,
|
||||
// outputs: scan temp. reg1, scan temp. reg2
|
||||
recv_klass_reg, temp_reg,
|
||||
L_no_such_interface,
|
||||
/*return_method=*/false);
|
||||
|
||||
// Get selected method from declaring class and itable index
|
||||
const Register method = rbx;
|
||||
__ load_klass(recv_klass_reg, rcx); // restore recv_klass_reg
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
rsi, rax, itable_index,
|
||||
recv_klass_reg, holder_klass_reg, itable_index,
|
||||
// outputs: method, scan temp. reg
|
||||
method, rdi,
|
||||
throw_icce);
|
||||
method, temp_reg,
|
||||
L_no_such_interface);
|
||||
|
||||
// method (rbx): Method*
|
||||
// rcx: receiver
|
||||
@ -193,9 +211,10 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
address ame_addr = __ pc();
|
||||
__ jmp(Address(method, Method::from_compiled_offset()));
|
||||
|
||||
__ bind(throw_icce);
|
||||
__ bind(L_no_such_interface);
|
||||
__ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
|
||||
masm->flush();
|
||||
|
||||
__ flush();
|
||||
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d",
|
||||
@ -220,7 +239,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
||||
return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
|
||||
} else {
|
||||
// Itable stub size
|
||||
return (DebugVtables ? 256 : 66) + (CountCompiledCalls ? 6 : 0);
|
||||
return (DebugVtables ? 256 : 110) + (CountCompiledCalls ? 6 : 0);
|
||||
}
|
||||
// In order to tune these parameters, run the JVM with VM options
|
||||
// +PrintMiscellaneous and +WizardMode to see information about
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "interp_masm_x86.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/compiledICHolder.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/klassVtable.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
@ -147,36 +148,50 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
#endif
|
||||
|
||||
// Entry arguments:
|
||||
// rax: Interface
|
||||
// rax: CompiledICHolder
|
||||
// j_rarg0: Receiver
|
||||
|
||||
// Free registers (non-args) are rax (interface), rbx
|
||||
|
||||
// get receiver (need to skip return address on top of stack)
|
||||
|
||||
assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
|
||||
// get receiver klass (also an implicit null-check)
|
||||
address npe_addr = __ pc();
|
||||
|
||||
// Most registers are in use; we'll use rax, rbx, r10, r11
|
||||
// (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them)
|
||||
__ load_klass(r10, j_rarg0);
|
||||
const Register recv_klass_reg = r10;
|
||||
const Register holder_klass_reg = rax; // declaring interface klass (DECC)
|
||||
const Register resolved_klass_reg = rbx; // resolved interface klass (REFC)
|
||||
const Register temp_reg = r11;
|
||||
|
||||
Label L_no_such_interface;
|
||||
|
||||
const Register icholder_reg = rax;
|
||||
__ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset()));
|
||||
__ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset()));
|
||||
|
||||
// get receiver klass (also an implicit null-check)
|
||||
assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
|
||||
address npe_addr = __ pc();
|
||||
__ load_klass(recv_klass_reg, j_rarg0);
|
||||
|
||||
// Receiver subtype check against REFC.
|
||||
// Destroys recv_klass_reg value.
|
||||
__ lookup_interface_method(// inputs: rec. class, interface
|
||||
recv_klass_reg, resolved_klass_reg, noreg,
|
||||
// outputs: scan temp. reg1, scan temp. reg2
|
||||
recv_klass_reg, temp_reg,
|
||||
L_no_such_interface,
|
||||
/*return_method=*/false);
|
||||
|
||||
// Get selected method from declaring class and itable index
|
||||
const Register method = rbx;
|
||||
__ load_klass(recv_klass_reg, j_rarg0); // restore recv_klass_reg
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
recv_klass_reg, holder_klass_reg, itable_index,
|
||||
// outputs: method, scan temp. reg
|
||||
method, temp_reg,
|
||||
L_no_such_interface);
|
||||
|
||||
// If we take a trap while this arg is on the stack we will not
|
||||
// be able to walk the stack properly. This is not an issue except
|
||||
// when there are mistakes in this assembly code that could generate
|
||||
// a spurious fault. Ask me how I know...
|
||||
|
||||
const Register method = rbx;
|
||||
Label throw_icce;
|
||||
|
||||
// Get Method* and entrypoint for compiler
|
||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
||||
r10, rax, itable_index,
|
||||
// outputs: method, scan temp. reg
|
||||
method, r11,
|
||||
throw_icce);
|
||||
|
||||
// method (rbx): Method*
|
||||
// j_rarg0: receiver
|
||||
|
||||
@ -197,7 +212,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
address ame_addr = __ pc();
|
||||
__ jmp(Address(method, Method::from_compiled_offset()));
|
||||
|
||||
__ bind(throw_icce);
|
||||
__ bind(L_no_such_interface);
|
||||
__ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
|
||||
|
||||
__ flush();
|
||||
@ -224,8 +239,8 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
||||
(UseCompressedClassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
|
||||
} else {
|
||||
// Itable stub size
|
||||
return (DebugVtables ? 512 : 74) + (CountCompiledCalls ? 13 : 0) +
|
||||
(UseCompressedClassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
|
||||
return (DebugVtables ? 512 : 140) + (CountCompiledCalls ? 13 : 0) +
|
||||
(UseCompressedClassPointers ? 2 * MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
|
||||
}
|
||||
// In order to tune these parameters, run the JVM with VM options
|
||||
// +PrintMiscellaneous and +WizardMode to see information about
|
||||
|
||||
@ -183,3 +183,9 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
|
||||
// This is just a stub.
|
||||
}
|
||||
#endif //PRODUCT
|
||||
|
||||
@ -40,10 +40,10 @@ public class CompiledICHolder extends VMObject {
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("CompiledICHolder");
|
||||
holderMethod = new MetadataField(type.getAddressField("_holder_method"), 0);
|
||||
holderKlass = new MetadataField(type.getAddressField("_holder_klass"), 0);
|
||||
headerSize = type.getSize();
|
||||
Type type = db.lookupType("CompiledICHolder");
|
||||
holderMetadata = new MetadataField(type.getAddressField("_holder_metadata"), 0);
|
||||
holderKlass = new MetadataField(type.getAddressField("_holder_klass"), 0);
|
||||
headerSize = type.getSize();
|
||||
}
|
||||
|
||||
public CompiledICHolder(Address addr) {
|
||||
@ -55,12 +55,12 @@ public class CompiledICHolder extends VMObject {
|
||||
private static long headerSize;
|
||||
|
||||
// Fields
|
||||
private static MetadataField holderMethod;
|
||||
private static MetadataField holderMetadata;
|
||||
private static MetadataField holderKlass;
|
||||
|
||||
// Accessors for declared fields
|
||||
public Method getHolderMethod() { return (Method) holderMethod.getValue(this); }
|
||||
public Klass getHolderKlass() { return (Klass) holderKlass.getValue(this); }
|
||||
public Metadata getHolderMetadata() { return (Metadata) holderMetadata.getValue(this); }
|
||||
public Klass getHolderKlass() { return (Klass) holderKlass.getValue(this); }
|
||||
|
||||
public void printValueOn(PrintStream tty) {
|
||||
tty.print("CompiledICHolder");
|
||||
|
||||
@ -273,7 +273,7 @@ void AOTCompiledMethod::metadata_do(void f(Metadata*)) {
|
||||
CompiledIC *ic = CompiledIC_at(&iter);
|
||||
if (ic->is_icholder_call()) {
|
||||
CompiledICHolder* cichk = ic->cached_icholder();
|
||||
f(cichk->holder_method());
|
||||
f(cichk->holder_metadata());
|
||||
f(cichk->holder_klass());
|
||||
} else {
|
||||
// Get Klass* or NULL (if value is -1) from GOT cell of virtual call PLT stub.
|
||||
|
||||
@ -230,10 +230,13 @@ bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod
|
||||
#ifdef ASSERT
|
||||
int index = call_info->resolved_method()->itable_index();
|
||||
assert(index == itable_index, "CallInfo pre-computes this");
|
||||
#endif //ASSERT
|
||||
InstanceKlass* k = call_info->resolved_method()->method_holder();
|
||||
assert(k->verify_itable_index(itable_index), "sanity check");
|
||||
InlineCacheBuffer::create_transition_stub(this, k, entry);
|
||||
#endif //ASSERT
|
||||
CompiledICHolder* holder = new CompiledICHolder(call_info->resolved_method()->method_holder(),
|
||||
call_info->resolved_klass()());
|
||||
holder->claim();
|
||||
InlineCacheBuffer::create_transition_stub(this, holder, entry);
|
||||
} else {
|
||||
assert(call_info->call_kind() == CallInfo::vtable_call, "either itable or vtable");
|
||||
// Can be different than selected_method->vtable_index(), due to package-private etc.
|
||||
@ -517,7 +520,14 @@ void CompiledIC::compute_monomorphic_entry(const methodHandle& method,
|
||||
|
||||
bool CompiledIC::is_icholder_entry(address entry) {
|
||||
CodeBlob* cb = CodeCache::find_blob_unsafe(entry);
|
||||
return (cb != NULL && cb->is_adapter_blob());
|
||||
if (cb != NULL && cb->is_adapter_blob()) {
|
||||
return true;
|
||||
}
|
||||
// itable stubs also use CompiledICHolder
|
||||
if (VtableStubs::is_entry_point(entry) && VtableStubs::stub_containing(entry)->is_itable_stub()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site, const CompiledMethod* cm) {
|
||||
|
||||
@ -45,11 +45,11 @@
|
||||
// \ / \ /
|
||||
// [4] \ / [4] \->-/
|
||||
// \->- Megamorphic -<-/
|
||||
// (Method*)
|
||||
// (CompiledICHolder*)
|
||||
//
|
||||
// The text in paranteses () refere to the value of the inline cache receiver (mov instruction)
|
||||
// The text in parentheses () refers to the value of the inline cache receiver (mov instruction)
|
||||
//
|
||||
// The numbers in square brackets refere to the kind of transition:
|
||||
// The numbers in square brackets refer to the kind of transition:
|
||||
// [1]: Initial fixup. Receiver it found from debug information
|
||||
// [2]: Compilation of a method
|
||||
// [3]: Recompilation of a method (note: only entry is changed. The Klass* must stay the same)
|
||||
|
||||
@ -417,8 +417,7 @@ void CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClos
|
||||
// yet be marked below. (We check this further below).
|
||||
CompiledICHolder* cichk_oop = ic->cached_icholder();
|
||||
|
||||
if (cichk_oop->holder_method()->method_holder()->is_loader_alive(is_alive) &&
|
||||
cichk_oop->holder_klass()->is_loader_alive(is_alive)) {
|
||||
if (cichk_oop->is_loader_alive(is_alive)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -1577,7 +1577,7 @@ void nmethod::metadata_do(void f(Metadata*)) {
|
||||
CompiledIC *ic = CompiledIC_at(&iter);
|
||||
if (ic->is_icholder_call()) {
|
||||
CompiledICHolder* cichk = ic->cached_icholder();
|
||||
f(cichk->holder_method());
|
||||
f(cichk->holder_metadata());
|
||||
f(cichk->holder_klass());
|
||||
} else {
|
||||
Metadata* ic_oop = ic->cached_metadata();
|
||||
|
||||
@ -2538,13 +2538,35 @@ run:
|
||||
|
||||
// this could definitely be cleaned up QQQ
|
||||
Method* callee;
|
||||
Klass* iclass = cache->f1_as_klass();
|
||||
// InstanceKlass* interface = (InstanceKlass*) iclass;
|
||||
Method *interface_method = cache->f2_as_interface_method();
|
||||
InstanceKlass* iclass = interface_method->method_holder();
|
||||
|
||||
// get receiver
|
||||
int parms = cache->parameter_size();
|
||||
oop rcvr = STACK_OBJECT(-parms);
|
||||
CHECK_NULL(rcvr);
|
||||
InstanceKlass* int2 = (InstanceKlass*) rcvr->klass();
|
||||
|
||||
// Receiver subtype check against resolved interface klass (REFC).
|
||||
{
|
||||
Klass* refc = cache->f1_as_klass();
|
||||
itableOffsetEntry* scan;
|
||||
for (scan = (itableOffsetEntry*) int2->start_of_itable();
|
||||
scan->interface_klass() != NULL;
|
||||
scan++) {
|
||||
if (scan->interface_klass() == refc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check that the entry is non-null. A null entry means
|
||||
// that the receiver class doesn't implement the
|
||||
// interface, and wasn't the same as when the caller was
|
||||
// compiled.
|
||||
if (scan->interface_klass() == NULL) {
|
||||
VM_JAVA_ERROR(vmSymbols::java_lang_IncompatibleClassChangeError(), "", note_no_trap);
|
||||
}
|
||||
}
|
||||
|
||||
itableOffsetEntry* ki = (itableOffsetEntry*) int2->start_of_itable();
|
||||
int i;
|
||||
for ( i = 0 ; i < int2->itable_length() ; i++, ki++ ) {
|
||||
@ -2556,7 +2578,8 @@ run:
|
||||
if (i == int2->itable_length()) {
|
||||
VM_JAVA_ERROR(vmSymbols::java_lang_IncompatibleClassChangeError(), "", note_no_trap);
|
||||
}
|
||||
int mindex = cache->f2_as_index();
|
||||
int mindex = interface_method->itable_index();
|
||||
|
||||
itableMethodEntry* im = ki->first_method_entry(rcvr->klass());
|
||||
callee = im[mindex].method();
|
||||
if (callee == NULL) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -795,7 +795,7 @@ void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code byte
|
||||
// it is not an interface. The receiver for invokespecial calls within interface
|
||||
// methods must be checked for every call.
|
||||
InstanceKlass* sender = pool->pool_holder();
|
||||
sender = sender->is_anonymous() ? sender->host_klass() : sender;
|
||||
sender = sender->has_host_klass() ? sender->host_klass() : sender;
|
||||
|
||||
switch (info.call_kind()) {
|
||||
case CallInfo::direct_call:
|
||||
@ -813,6 +813,7 @@ void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code byte
|
||||
case CallInfo::itable_call:
|
||||
cp_cache_entry->set_itable_call(
|
||||
bytecode,
|
||||
info.resolved_klass(),
|
||||
info.resolved_method(),
|
||||
info.itable_index());
|
||||
break;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1061,11 +1061,7 @@ void LinkResolver::resolve_special_call(CallInfo& result,
|
||||
const LinkInfo& link_info,
|
||||
TRAPS) {
|
||||
methodHandle resolved_method = linktime_resolve_special_method(link_info, CHECK);
|
||||
runtime_resolve_special_method(result, resolved_method,
|
||||
link_info.resolved_klass(),
|
||||
link_info.current_klass(),
|
||||
recv,
|
||||
link_info.check_access(), CHECK);
|
||||
runtime_resolve_special_method(result, link_info, resolved_method, recv, CHECK);
|
||||
}
|
||||
|
||||
// throws linktime exceptions
|
||||
@ -1148,11 +1144,11 @@ methodHandle LinkResolver::linktime_resolve_special_method(const LinkInfo& link_
|
||||
|
||||
// throws runtime exceptions
|
||||
void LinkResolver::runtime_resolve_special_method(CallInfo& result,
|
||||
const LinkInfo& link_info,
|
||||
const methodHandle& resolved_method,
|
||||
KlassHandle resolved_klass,
|
||||
KlassHandle current_klass,
|
||||
Handle recv,
|
||||
bool check_access, TRAPS) {
|
||||
Handle recv, TRAPS) {
|
||||
|
||||
KlassHandle resolved_klass = link_info.resolved_klass();
|
||||
|
||||
// resolved method is selected method unless we have an old-style lookup
|
||||
// for a superclass method
|
||||
@ -1160,12 +1156,13 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
|
||||
// no checks for shadowing
|
||||
methodHandle sel_method(THREAD, resolved_method());
|
||||
|
||||
if (check_access &&
|
||||
if (link_info.check_access() &&
|
||||
// check if the method is not <init>
|
||||
resolved_method->name() != vmSymbols::object_initializer_name()) {
|
||||
|
||||
// check if this is an old-style super call and do a new lookup if so
|
||||
// check if this is an old-style super call and do a new lookup if so
|
||||
// a) check if ACC_SUPER flag is set for the current class
|
||||
KlassHandle current_klass = link_info.current_klass();
|
||||
if ((current_klass->is_super() || !AllowNonVirtualCalls) &&
|
||||
// b) check if the class of the resolved_klass is a superclass
|
||||
// (not supertype in order to exclude interface classes) of the current class.
|
||||
@ -1185,6 +1182,9 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
resolved_method->name(),
|
||||
resolved_method->signature()));
|
||||
// check loader constraints if found a different method
|
||||
} else if (sel_method() != resolved_method()) {
|
||||
check_method_loader_constraints(link_info, sel_method, "method", CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -227,11 +227,10 @@ class LinkResolver: AllStatic {
|
||||
static methodHandle linktime_resolve_interface_method (const LinkInfo& link_info, TRAPS);
|
||||
|
||||
static void runtime_resolve_special_method (CallInfo& result,
|
||||
const LinkInfo& link_info,
|
||||
const methodHandle& resolved_method,
|
||||
KlassHandle resolved_klass,
|
||||
KlassHandle current_klass,
|
||||
Handle recv,
|
||||
bool check_access, TRAPS);
|
||||
Handle recv, TRAPS);
|
||||
|
||||
static void runtime_resolve_virtual_method (CallInfo& result,
|
||||
const methodHandle& resolved_method,
|
||||
KlassHandle resolved_klass,
|
||||
|
||||
@ -32,8 +32,8 @@ volatile int CompiledICHolder::_live_count;
|
||||
volatile int CompiledICHolder::_live_not_claimed_count;
|
||||
|
||||
|
||||
CompiledICHolder::CompiledICHolder(Method* method, Klass* klass)
|
||||
: _holder_method(method), _holder_klass(klass) {
|
||||
CompiledICHolder::CompiledICHolder(Metadata* metadata, Klass* klass)
|
||||
: _holder_metadata(metadata), _holder_klass(klass) {
|
||||
#ifdef ASSERT
|
||||
Atomic::inc(&_live_count);
|
||||
Atomic::inc(&_live_not_claimed_count);
|
||||
@ -47,12 +47,28 @@ CompiledICHolder::~CompiledICHolder() {
|
||||
}
|
||||
#endif // ASSERT
|
||||
|
||||
bool CompiledICHolder::is_loader_alive(BoolObjectClosure* is_alive) {
|
||||
if (_holder_metadata->is_method()) {
|
||||
if (!((Method*)_holder_metadata)->method_holder()->is_loader_alive(is_alive)) {
|
||||
return false;
|
||||
}
|
||||
} else if (_holder_metadata->is_klass()) {
|
||||
if (!((Klass*)_holder_metadata)->is_loader_alive(is_alive)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!_holder_klass->is_loader_alive(is_alive)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Printing
|
||||
|
||||
void CompiledICHolder::print_on(outputStream* st) const {
|
||||
st->print("%s", internal_name());
|
||||
st->print(" - method: "); holder_method()->print_value_on(st); st->cr();
|
||||
st->print(" - klass: "); holder_klass()->print_value_on(st); st->cr();
|
||||
st->print(" - metadata: "); holder_metadata()->print_value_on(st); st->cr();
|
||||
st->print(" - klass: "); holder_klass()->print_value_on(st); st->cr();
|
||||
}
|
||||
|
||||
void CompiledICHolder::print_value_on(outputStream* st) const {
|
||||
@ -63,7 +79,7 @@ void CompiledICHolder::print_value_on(outputStream* st) const {
|
||||
// Verification
|
||||
|
||||
void CompiledICHolder::verify_on(outputStream* st) {
|
||||
guarantee(holder_method()->is_method(), "should be method");
|
||||
guarantee(holder_metadata()->is_method() || holder_metadata()->is_klass(), "should be method or klass");
|
||||
guarantee(holder_klass()->is_klass(), "should be klass");
|
||||
}
|
||||
|
||||
|
||||
@ -29,8 +29,9 @@
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
// A CompiledICHolder* is a helper object for the inline cache implementation.
|
||||
// It holds an intermediate value (method+klass pair) used when converting from
|
||||
// compiled to an interpreted call.
|
||||
// It holds:
|
||||
// (1) (method+klass pair) when converting from compiled to an interpreted call
|
||||
// (2) (klass+klass pair) when calling itable stub from megamorphic compiled call
|
||||
//
|
||||
// These are always allocated in the C heap and are freed during a
|
||||
// safepoint by the ICBuffer logic. It's unsafe to free them earlier
|
||||
@ -45,32 +46,33 @@ class CompiledICHolder : public CHeapObj<mtCompiler> {
|
||||
static volatile int _live_not_claimed_count; // allocated but not yet in use so not
|
||||
// reachable by iterating over nmethods
|
||||
|
||||
Method* _holder_method;
|
||||
Metadata* _holder_metadata;
|
||||
Klass* _holder_klass; // to avoid name conflict with oopDesc::_klass
|
||||
CompiledICHolder* _next;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
CompiledICHolder(Method* method, Klass* klass);
|
||||
CompiledICHolder(Metadata* metadata, Klass* klass);
|
||||
~CompiledICHolder() NOT_DEBUG_RETURN;
|
||||
|
||||
static int live_count() { return _live_count; }
|
||||
static int live_not_claimed_count() { return _live_not_claimed_count; }
|
||||
|
||||
// accessors
|
||||
Method* holder_method() const { return _holder_method; }
|
||||
Klass* holder_klass() const { return _holder_klass; }
|
||||
Metadata* holder_metadata() const { return _holder_metadata; }
|
||||
|
||||
void set_holder_method(Method* m) { _holder_method = m; }
|
||||
void set_holder_klass(Klass* k) { _holder_klass = k; }
|
||||
void set_holder_metadata(Metadata* m) { _holder_metadata = m; }
|
||||
void set_holder_klass(Klass* k) { _holder_klass = k; }
|
||||
|
||||
// interpreter support (offsets in bytes)
|
||||
static int holder_method_offset() { return offset_of(CompiledICHolder, _holder_method); }
|
||||
static int holder_metadata_offset() { return offset_of(CompiledICHolder, _holder_metadata); }
|
||||
static int holder_klass_offset() { return offset_of(CompiledICHolder, _holder_klass); }
|
||||
|
||||
CompiledICHolder* next() { return _next; }
|
||||
void set_next(CompiledICHolder* n) { _next = n; }
|
||||
|
||||
bool is_loader_alive(BoolObjectClosure* is_alive);
|
||||
|
||||
// Verify
|
||||
void verify_on(outputStream* st);
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -958,7 +958,7 @@ class SymbolHashMap: public CHeapObj<mtSymbol> {
|
||||
delete(cur);
|
||||
}
|
||||
}
|
||||
delete _buckets;
|
||||
FREE_C_HEAP_ARRAY(SymbolHashMapBucket, _buckets);
|
||||
}
|
||||
}; // End SymbolHashMap class
|
||||
|
||||
|
||||
@ -255,14 +255,16 @@ void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, method
|
||||
set_direct_or_vtable_call(invoke_code, method, index, false);
|
||||
}
|
||||
|
||||
void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code, const methodHandle& method, int index) {
|
||||
void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code,
|
||||
KlassHandle referenced_klass,
|
||||
const methodHandle& method, int index) {
|
||||
assert(method->method_holder()->verify_itable_index(index), "");
|
||||
assert(invoke_code == Bytecodes::_invokeinterface, "");
|
||||
InstanceKlass* interf = method->method_holder();
|
||||
assert(interf->is_interface(), "must be an interface");
|
||||
assert(!method->is_final_method(), "interfaces do not have final methods; cannot link to one here");
|
||||
set_f1(interf);
|
||||
set_f2(index);
|
||||
set_f1(referenced_klass());
|
||||
set_f2((intx)method());
|
||||
set_method_flags(as_TosState(method->result_type()),
|
||||
0, // no option bits
|
||||
method()->size_of_parameters());
|
||||
@ -434,10 +436,23 @@ oop ConstantPoolCacheEntry::method_type_if_resolved(const constantPoolHandle& cp
|
||||
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
|
||||
void log_adjust(const char* entry_type, Method* old_method, Method* new_method, bool* trace_name_printed) {
|
||||
if (log_is_enabled(Info, redefine, class, update)) {
|
||||
ResourceMark rm;
|
||||
if (!(*trace_name_printed)) {
|
||||
log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
|
||||
*trace_name_printed = true;
|
||||
}
|
||||
log_debug(redefine, class, update, constantpool)
|
||||
("cpc %s entry update: %s(%s)", entry_type, new_method->name()->as_C_string(), new_method->signature()->as_C_string());
|
||||
}
|
||||
}
|
||||
|
||||
// RedefineClasses() API support:
|
||||
// If this ConstantPoolCacheEntry refers to old_method then update it
|
||||
// to refer to new_method.
|
||||
bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
|
||||
void ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
|
||||
Method* new_method, bool * trace_name_printed) {
|
||||
|
||||
if (is_vfinal()) {
|
||||
@ -446,63 +461,35 @@ bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
|
||||
// match old_method so need an update
|
||||
// NOTE: can't use set_f2_as_vfinal_method as it asserts on different values
|
||||
_f2 = (intptr_t)new_method;
|
||||
if (log_is_enabled(Info, redefine, class, update)) {
|
||||
ResourceMark rm;
|
||||
if (!(*trace_name_printed)) {
|
||||
log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
|
||||
*trace_name_printed = true;
|
||||
}
|
||||
log_debug(redefine, class, update, constantpool)
|
||||
("cpc vf-entry update: %s(%s)", new_method->name()->as_C_string(), new_method->signature()->as_C_string());
|
||||
}
|
||||
return true;
|
||||
log_adjust("vfinal", old_method, new_method, trace_name_printed);
|
||||
}
|
||||
|
||||
// f1() is not used with virtual entries so bail out
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_f1 == NULL) {
|
||||
// NULL f1() means this is a virtual entry so bail out
|
||||
// We are assuming that the vtable index does not need change.
|
||||
return false;
|
||||
}
|
||||
assert (_f1 != NULL, "should not call with uninteresting entry");
|
||||
|
||||
if (_f1 == old_method) {
|
||||
if (!(_f1->is_method())) {
|
||||
// _f1 is a Klass* for an interface, _f2 is the method
|
||||
if (f2_as_interface_method() == old_method) {
|
||||
_f2 = (intptr_t)new_method;
|
||||
log_adjust("interface", old_method, new_method, trace_name_printed);
|
||||
}
|
||||
} else if (_f1 == old_method) {
|
||||
_f1 = new_method;
|
||||
if (log_is_enabled(Info, redefine, class, update)) {
|
||||
ResourceMark rm;
|
||||
if (!(*trace_name_printed)) {
|
||||
log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
|
||||
*trace_name_printed = true;
|
||||
}
|
||||
log_debug(redefine, class, update, constantpool)
|
||||
("cpc entry update: %s(%s)", new_method->name()->as_C_string(), new_method->signature()->as_C_string());
|
||||
}
|
||||
return true;
|
||||
log_adjust("special, static or dynamic", old_method, new_method, trace_name_printed);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// a constant pool cache entry should never contain old or obsolete methods
|
||||
bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() {
|
||||
if (is_vfinal()) {
|
||||
// virtual and final so _f2 contains method ptr instead of vtable index
|
||||
Metadata* f2 = (Metadata*)_f2;
|
||||
// Return false if _f2 refers to an old or an obsolete method.
|
||||
// _f2 == NULL || !_f2->is_method() are just as unexpected here.
|
||||
return (f2 != NULL NOT_PRODUCT(&& f2->is_valid()) && f2->is_method() &&
|
||||
!((Method*)f2)->is_old() && !((Method*)f2)->is_obsolete());
|
||||
} else if (_f1 == NULL ||
|
||||
(NOT_PRODUCT(_f1->is_valid() &&) !_f1->is_method())) {
|
||||
// _f1 == NULL || !_f1->is_method() are OK here
|
||||
Method* m = get_interesting_method_entry(NULL);
|
||||
// return false if m refers to a non-deleted old or obsolete method
|
||||
if (m != NULL) {
|
||||
assert(m->is_valid() && m->is_method(), "m is a valid method");
|
||||
return !m->is_old() && !m->is_obsolete(); // old is always set for old and obsolete
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
// return false if _f1 refers to a non-deleted old or obsolete method
|
||||
return (NOT_PRODUCT(_f1->is_valid() &&) _f1->is_method() &&
|
||||
(f1_as_method()->is_deleted() ||
|
||||
(!f1_as_method()->is_old() && !f1_as_method()->is_obsolete())));
|
||||
}
|
||||
|
||||
Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) {
|
||||
@ -519,10 +506,11 @@ Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) {
|
||||
return NULL;
|
||||
} else {
|
||||
if (!(_f1->is_method())) {
|
||||
// _f1 can also contain a Klass* for an interface
|
||||
return NULL;
|
||||
// _f1 is a Klass* for an interface
|
||||
m = f2_as_interface_method();
|
||||
} else {
|
||||
m = f1_as_method();
|
||||
}
|
||||
m = f1_as_method();
|
||||
}
|
||||
assert(m != NULL && m->is_method(), "sanity check");
|
||||
if (m == NULL || !m->is_method() || (k != NULL && m->method_holder() != k)) {
|
||||
|
||||
@ -249,6 +249,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
void set_itable_call(
|
||||
Bytecodes::Code invoke_code, // the bytecode used; must be invokeinterface
|
||||
KlassHandle referenced_klass, // the referenced klass in the InterfaceMethodref
|
||||
const methodHandle& method, // the resolved interface method
|
||||
int itable_index // index into itable for the method
|
||||
);
|
||||
@ -345,6 +346,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||
bool is_f1_null() const { Metadata* f1 = f1_ord(); return f1 == NULL; } // classifies a CPC entry as unbound
|
||||
int f2_as_index() const { assert(!is_vfinal(), ""); return (int) _f2; }
|
||||
Method* f2_as_vfinal_method() const { assert(is_vfinal(), ""); return (Method*)_f2; }
|
||||
Method* f2_as_interface_method() const { assert(bytecode_1() == Bytecodes::_invokeinterface, ""); return (Method*)_f2; }
|
||||
int field_index() const { assert(is_field_entry(), ""); return (_flags & field_index_mask); }
|
||||
int parameter_size() const { assert(is_method_entry(), ""); return (_flags & parameter_size_mask); }
|
||||
bool is_volatile() const { return (_flags & (1 << is_volatile_shift)) != 0; }
|
||||
@ -377,7 +379,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||
// trace_name_printed is set to true if the current call has
|
||||
// printed the klass name so that other routines in the adjust_*
|
||||
// group don't print the klass name.
|
||||
bool adjust_method_entry(Method* old_method, Method* new_method,
|
||||
void adjust_method_entry(Method* old_method, Method* new_method,
|
||||
bool* trace_name_printed);
|
||||
bool check_no_old_or_obsolete_entries();
|
||||
Method* get_interesting_method_entry(Klass* k);
|
||||
|
||||
@ -625,9 +625,11 @@ class InstanceKlass: public Klass {
|
||||
InstanceKlass* host_klass() const {
|
||||
InstanceKlass** hk = adr_host_klass();
|
||||
if (hk == NULL) {
|
||||
assert(!is_anonymous(), "Anonymous classes have host klasses");
|
||||
return NULL;
|
||||
} else {
|
||||
assert(*hk != NULL, "host klass should always be set if the address is not null");
|
||||
assert(is_anonymous(), "Only anonymous classes have host klasses");
|
||||
return *hk;
|
||||
}
|
||||
}
|
||||
@ -639,6 +641,9 @@ class InstanceKlass: public Klass {
|
||||
*addr = host;
|
||||
}
|
||||
}
|
||||
bool has_host_klass() const {
|
||||
return adr_host_klass() != NULL;
|
||||
}
|
||||
bool is_anonymous() const {
|
||||
return (_misc_flags & _misc_is_anonymous) != 0;
|
||||
}
|
||||
|
||||
@ -1173,7 +1173,6 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
|
||||
Array<Method*>* methods = InstanceKlass::cast(interf_h())->methods();
|
||||
int nof_methods = methods->length();
|
||||
HandleMark hm;
|
||||
assert(nof_methods > 0, "at least one method must exist for interface to be in vtable");
|
||||
Handle interface_loader (THREAD, InstanceKlass::cast(interf_h())->class_loader());
|
||||
|
||||
int ime_count = method_count_for_interface(interf_h());
|
||||
@ -1350,8 +1349,10 @@ void visit_all_interfaces(Array<Klass*>* transitive_intf, InterfaceVisiterClosur
|
||||
}
|
||||
}
|
||||
|
||||
// Only count interfaces with at least one method
|
||||
if (method_count > 0) {
|
||||
// Visit all interfaces which either have any methods or can participate in receiver type check.
|
||||
// We do not bother to count methods in transitive interfaces, although that would allow us to skip
|
||||
// this step in the rare case of a zero-method interface extending another zero-method interface.
|
||||
if (method_count > 0 || InstanceKlass::cast(intf)->transitive_interfaces()->length() > 0) {
|
||||
blk->doit(intf, method_count);
|
||||
}
|
||||
}
|
||||
|
||||
@ -700,6 +700,7 @@ class Method : public Metadata {
|
||||
static ByteSize from_interpreted_offset() { return byte_offset_of(Method, _from_interpreted_entry ); }
|
||||
static ByteSize interpreter_entry_offset() { return byte_offset_of(Method, _i2i_entry ); }
|
||||
static ByteSize signature_handler_offset() { return in_ByteSize(sizeof(Method) + wordSize); }
|
||||
static ByteSize itable_index_offset() { return byte_offset_of(Method, _vtable_index ); }
|
||||
|
||||
// for code generation
|
||||
static int method_data_offset_in_bytes() { return offset_of(Method, _method_data); }
|
||||
|
||||
@ -2839,7 +2839,7 @@ jni_Get##Result##ArrayRegion(JNIEnv *env, ElementType##Array array, jsize start,
|
||||
EntryProbe; \
|
||||
DT_VOID_RETURN_MARK(Get##Result##ArrayRegion); \
|
||||
typeArrayOop src = typeArrayOop(JNIHandles::resolve_non_null(array)); \
|
||||
if (start < 0 || len < 0 || ((unsigned int)start + (unsigned int)len > (unsigned int)src->length())) { \
|
||||
if (start < 0 || len < 0 || (start > src->length() - len)) { \
|
||||
THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); \
|
||||
} else { \
|
||||
if (len > 0) { \
|
||||
@ -2889,7 +2889,7 @@ jni_Set##Result##ArrayRegion(JNIEnv *env, ElementType##Array array, jsize start,
|
||||
EntryProbe; \
|
||||
DT_VOID_RETURN_MARK(Set##Result##ArrayRegion); \
|
||||
typeArrayOop dst = typeArrayOop(JNIHandles::resolve_non_null(array)); \
|
||||
if (start < 0 || len < 0 || ((unsigned int)start + (unsigned int)len > (unsigned int)dst->length())) { \
|
||||
if (start < 0 || len < 0 || (start > dst->length() - len)) { \
|
||||
THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); \
|
||||
} else { \
|
||||
if (len > 0) { \
|
||||
@ -3126,7 +3126,7 @@ JNI_ENTRY(void, jni_GetStringRegion(JNIEnv *env, jstring string, jsize start, js
|
||||
DT_VOID_RETURN_MARK(GetStringRegion);
|
||||
oop s = JNIHandles::resolve_non_null(string);
|
||||
int s_len = java_lang_String::length(s);
|
||||
if (start < 0 || len < 0 || start + len > s_len) {
|
||||
if (start < 0 || len < 0 || start > s_len - len) {
|
||||
THROW(vmSymbols::java_lang_StringIndexOutOfBoundsException());
|
||||
} else {
|
||||
if (len > 0) {
|
||||
@ -3152,7 +3152,7 @@ JNI_ENTRY(void, jni_GetStringUTFRegion(JNIEnv *env, jstring string, jsize start,
|
||||
DT_VOID_RETURN_MARK(GetStringUTFRegion);
|
||||
oop s = JNIHandles::resolve_non_null(string);
|
||||
int s_len = java_lang_String::length(s);
|
||||
if (start < 0 || len < 0 || start + len > s_len) {
|
||||
if (start < 0 || len < 0 || start > s_len - len) {
|
||||
THROW(vmSymbols::java_lang_StringIndexOutOfBoundsException());
|
||||
} else {
|
||||
//%note jni_7
|
||||
|
||||
@ -230,7 +230,7 @@ typedef CompactHashtable<Symbol*, char> SymbolCompactHashTable;
|
||||
nonstatic_field(ArrayKlass, _dimension, int) \
|
||||
volatile_nonstatic_field(ArrayKlass, _higher_dimension, Klass*) \
|
||||
volatile_nonstatic_field(ArrayKlass, _lower_dimension, Klass*) \
|
||||
nonstatic_field(CompiledICHolder, _holder_method, Method*) \
|
||||
nonstatic_field(CompiledICHolder, _holder_metadata, Metadata*) \
|
||||
nonstatic_field(CompiledICHolder, _holder_klass, Klass*) \
|
||||
nonstatic_field(ConstantPool, _tags, Array<u1>*) \
|
||||
nonstatic_field(ConstantPool, _cache, ConstantPoolCache*) \
|
||||
|
||||
52
hotspot/test/native/code/test_vtableStub.cpp
Normal file
52
hotspot/test/native/code/test_vtableStub.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
TEST_VM(code, vtableStubs) {
|
||||
// Should be in VM to use locks
|
||||
ThreadInVMfromNative ThreadInVMfromNative(JavaThread::current());
|
||||
|
||||
VtableStubs::find_vtable_stub(0); // min vtable index
|
||||
for (int i = 0; i < 15; i++) {
|
||||
VtableStubs::find_vtable_stub((1 << i) - 1);
|
||||
VtableStubs::find_vtable_stub((1 << i));
|
||||
}
|
||||
VtableStubs::find_vtable_stub((1 << 15) - 1); // max vtable index
|
||||
}
|
||||
|
||||
TEST_VM(code, itableStubs) {
|
||||
// Should be in VM to use locks
|
||||
ThreadInVMfromNative ThreadInVMfromNative(JavaThread::current());
|
||||
|
||||
VtableStubs::find_itable_stub(0); // min itable index
|
||||
for (int i = 0; i < 15; i++) {
|
||||
VtableStubs::find_itable_stub((1 << i) - 1);
|
||||
VtableStubs::find_itable_stub((1 << i));
|
||||
}
|
||||
VtableStubs::find_itable_stub((1 << 15) - 1); // max itable index
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8174962
|
||||
* @summary Redefine class with interface method call
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @modules java.compiler
|
||||
* java.instrument
|
||||
* jdk.jartool/sun.tools.jar
|
||||
* @run main RedefineClassHelper
|
||||
* @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+update*=trace RedefineInterfaceCall
|
||||
*/
|
||||
|
||||
import static jdk.test.lib.Asserts.assertEquals;
|
||||
|
||||
interface I1 { default int m() { return 0; } }
|
||||
interface I2 extends I1 {}
|
||||
|
||||
public class RedefineInterfaceCall {
|
||||
|
||||
public static class C implements I2 {
|
||||
public int test(I2 i) {
|
||||
return i.m(); // invokeinterface cpCacheEntry
|
||||
}
|
||||
}
|
||||
|
||||
static String newI1 =
|
||||
"interface I1 { default int m() { return 1; } }";
|
||||
|
||||
static String newC =
|
||||
"public class RedefineInterfaceCall$C implements I2 { " +
|
||||
" public int test(I2 i) { " +
|
||||
" return i.m(); " +
|
||||
" } " +
|
||||
"} ";
|
||||
|
||||
static int test(I2 i) {
|
||||
return i.m(); // invokeinterface cpCacheEntry
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
C c = new C();
|
||||
|
||||
assertEquals(test(c), 0);
|
||||
assertEquals(c.test(c), 0);
|
||||
|
||||
RedefineClassHelper.redefineClass(C.class, newC);
|
||||
|
||||
assertEquals(c.test(c), 0);
|
||||
|
||||
RedefineClassHelper.redefineClass(I1.class, newI1);
|
||||
|
||||
assertEquals(test(c), 1);
|
||||
assertEquals(c.test(c), 1);
|
||||
|
||||
RedefineClassHelper.redefineClass(C.class, newC);
|
||||
|
||||
assertEquals(c.test(c), 1);
|
||||
}
|
||||
}
|
||||
@ -62,8 +62,8 @@ public class TransformTestCommon {
|
||||
String parent, String child)
|
||||
throws Exception {
|
||||
|
||||
String parentSharedMatch = parent + " source: shared objects file";
|
||||
String childSharedMatch = child + " source: shared objects file";
|
||||
String parentSharedMatch = " " + parent + " source: shared objects file";
|
||||
String childSharedMatch = " " + child + " source: shared objects file";
|
||||
|
||||
if (entry.isParentExpectedShared)
|
||||
out.shouldContain(parentSharedMatch);
|
||||
|
||||
@ -80,8 +80,8 @@ ifneq ($(MAN_DIR), )
|
||||
endif
|
||||
|
||||
LEGAL_NOTICES := \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_legal/java.base \
|
||||
$(call FindModuleLegalDirs, $(MODULE)) \
|
||||
$(call uniq, $(SUPPORT_OUTPUTDIR)/modules_legal/java.base \
|
||||
$(call FindModuleLegalDirs, $(MODULE))) \
|
||||
#
|
||||
|
||||
LEGAL_NOTICES_PATH := $(call PathList, $(LEGAL_NOTICES))
|
||||
|
||||
@ -39,8 +39,6 @@ include MakeBase.gmk
|
||||
# revisions of all repos will be stored in a file in the top dir, which is then
|
||||
# used when creating the tracker file.
|
||||
|
||||
STORED_SOURCE_REVISION := $(TOPDIR)/.src-rev
|
||||
|
||||
# Are we using mercurial?
|
||||
ifneq ($(and $(HG), $(wildcard $(TOPDIR)/.hg)), )
|
||||
|
||||
@ -108,7 +106,15 @@ else
|
||||
$(call LogInfo, No mercurial configuration present$(COMMA) not updating .src-rev)
|
||||
|
||||
$(SOURCE_REVISION_TRACKER): $(STORED_SOURCE_REVISION)
|
||||
$(install-file)
|
||||
$(call MakeDir, $(@D))
|
||||
$(RM) $@
|
||||
# Only include revisions for repos that are included in the current
|
||||
# source set.
|
||||
for r in `cat $<`; do \
|
||||
if [ -d "$(TOPDIR)/`$(ECHO) $$r | $(CUT) -d':' -f1`" ]; then \
|
||||
$(PRINTF) "$$r " >> $@; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
create-source-revision-tracker: $(SOURCE_REVISION_TRACKER)
|
||||
else
|
||||
|
||||
@ -342,11 +342,25 @@ endif # HAS_FILE_FUNCTION
|
||||
# the build was created from
|
||||
SOURCE_REVISION_TRACKER := $(SUPPORT_OUTPUTDIR)/src-rev/source-revision-tracker
|
||||
|
||||
# Locate all hg repositories included in the forest, as absolute paths
|
||||
# A cache of the mercurial information which can be dropped in the top of the
|
||||
# source tree for inclusion in a source bundle.
|
||||
STORED_SOURCE_REVISION := $(TOPDIR)/.src-rev
|
||||
|
||||
# Locate all hg repositories included in the forest, as absolute paths. Use .hg
|
||||
# dirs if present, otherwise parse the .src-rev file and match dirs.
|
||||
FindAllReposAbs = \
|
||||
$(strip $(sort $(dir $(filter-out $(SRC_ROOT)/build/%, $(wildcard \
|
||||
$(addprefix $(SRC_ROOT)/, .hg */.hg */*/.hg */*/*/.hg) \
|
||||
)))))
|
||||
$(if $(and $(HG), $(wildcard $(TOPDIR)/.hg)), \
|
||||
$(strip $(sort $(dir $(filter-out $(SRC_ROOT)/build/%, $(wildcard \
|
||||
$(addprefix $(SRC_ROOT)/, .hg */.hg */*/.hg */*/*/.hg)))))) \
|
||||
, \
|
||||
$(if $(wildcard $(STORED_SOURCE_REVISION)), \
|
||||
$(strip $(foreach r, $(call ReadFile, $(STORED_SOURCE_REVISION)), \
|
||||
$(wildcard $(TOPDIR)/$(firstword $(subst :,$(SPACE),$r))/) \
|
||||
)) \
|
||||
, \
|
||||
$(error No mercurial or .src-rev available, cannot list repositories) \
|
||||
) \
|
||||
)
|
||||
|
||||
# Locate all hg repositories included in the forest, as relative paths
|
||||
FindAllReposRel = \
|
||||
|
||||
@ -397,8 +397,10 @@ LEGAL_SUBDIRS += share/legal
|
||||
# $1 - Module to find legal dirs for
|
||||
FindModuleLegalDirs = \
|
||||
$(strip $(wildcard \
|
||||
$(addsuffix /$(strip $1), $(IMPORT_MODULES_LEGAL)) \
|
||||
$(foreach sub, $(LEGAL_SUBDIRS), $(addsuffix /$(strip $1)/$(sub), $(TOP_SRC_DIRS)))))
|
||||
$(addsuffix /$(strip $1), $(SUPPORT_OUTPUTDIR)/modules_legal \
|
||||
$(IMPORT_MODULES_LEGAL)) \
|
||||
$(foreach sub, $(LEGAL_SUBDIRS), $(addsuffix /$(strip $1)/$(sub), $(TOP_SRC_DIRS))) \
|
||||
))
|
||||
|
||||
################################################################################
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user