diff --git a/.hgtags b/.hgtags
index fed35de2f35..d58e898362d 100644
--- a/.hgtags
+++ b/.hgtags
@@ -465,3 +465,4 @@ d8c634b016c628622c9abbdc6bf50509e5dedbec jdk-10+35
4f830b447edf04fb4a52151a5ad44d9bb60723cd jdk-10+37
e569e83139fdfbecfeb3cd9014d560917787f158 jdk-10+38
5b834ec962366e00d4445352a999a3ac14e26f64 jdk-10+39
+860326263d1f6a83996d7da0f4c66806ae4aa1eb jdk-10+40
diff --git a/make/autoconf/generated-configure.sh b/make/autoconf/generated-configure.sh
index c762c36d07b..7273f41f592 100644
--- a/make/autoconf/generated-configure.sh
+++ b/make/autoconf/generated-configure.sh
@@ -902,6 +902,9 @@ VERSION_PATCH
VERSION_UPDATE
VERSION_INTERIM
VERSION_FEATURE
+VENDOR_URL_VM_BUG
+VENDOR_URL_BUG
+VENDOR_URL
COMPANY_NAME
MACOSX_BUNDLE_ID_BASE
MACOSX_BUNDLE_NAME_BASE
@@ -1150,6 +1153,9 @@ with_version_major
with_version_minor
with_version_security
with_vendor_name
+with_vendor_url
+with_vendor_bug_url
+with_vendor_vm_bug_url
with_version_string
with_version_pre
with_version_opt
@@ -2074,7 +2080,16 @@ Optional Packages:
compatibility and is ignored
--with-version-security Deprecated. Option is kept for backwards
compatibility and is ignored
- --with-vendor-name Set vendor name [not specified]
+ --with-vendor-name Set vendor name. Among others, used to set the
+ 'java.vendor' and 'java.vm.vendor' system
+ properties. [not specified]
+ --with-vendor-url Set the 'java.vendor.url' system property [not
+ specified]
+ --with-vendor-bug-url Set the 'java.vendor.url.bug' system property [not
+ specified]
+ --with-vendor-vm-bug-url
+ Sets the bug URL which will be displayed when the VM
+ crashes [not specified]
--with-version-string Set version string [calculated]
--with-version-pre Set the base part of the version 'PRE' field
(pre-release identifier) ['internal']
@@ -5176,7 +5191,7 @@ VS_SDK_PLATFORM_NAME_2013=
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1513805283
+DATE_WHEN_GENERATED=1516225089
###############################################################################
#
@@ -25072,12 +25087,62 @@ fi
if test "x$with_vendor_name" = xyes; then
as_fn_error $? "--with-vendor-name must have a value" "$LINENO" 5
elif ! [[ $with_vendor_name =~ ^[[:print:]]*$ ]] ; then
- as_fn_error $? "--with--vendor-name contains non-printing characters: $with_vendor_name" "$LINENO" 5
- else
+ as_fn_error $? "--with-vendor-name contains non-printing characters: $with_vendor_name" "$LINENO" 5
+ elif test "x$with_vendor_name" != x; then
+ # Only set COMPANY_NAME if '--with-vendor-name' was used and is not empty.
+ # Otherwise we will use the value from "version-numbers" included above.
COMPANY_NAME="$with_vendor_name"
fi
+ # The vendor URL, if any
+
+# Check whether --with-vendor-url was given.
+if test "${with_vendor_url+set}" = set; then :
+ withval=$with_vendor_url;
+fi
+
+ if test "x$with_vendor_url" = xyes; then
+ as_fn_error $? "--with-vendor-url must have a value" "$LINENO" 5
+ elif ! [[ $with_vendor_url =~ ^[[:print:]]*$ ]] ; then
+ as_fn_error $? "--with-vendor-url contains non-printing characters: $with_vendor_url" "$LINENO" 5
+ else
+ VENDOR_URL="$with_vendor_url"
+ fi
+
+
+ # The vendor bug URL, if any
+
+# Check whether --with-vendor-bug-url was given.
+if test "${with_vendor_bug_url+set}" = set; then :
+ withval=$with_vendor_bug_url;
+fi
+
+ if test "x$with_vendor_bug_url" = xyes; then
+ as_fn_error $? "--with-vendor-bug-url must have a value" "$LINENO" 5
+ elif ! [[ $with_vendor_bug_url =~ ^[[:print:]]*$ ]] ; then
+ as_fn_error $? "--with-vendor-bug-url contains non-printing characters: $with_vendor_bug_url" "$LINENO" 5
+ else
+ VENDOR_URL_BUG="$with_vendor_bug_url"
+ fi
+
+
+ # The vendor VM bug URL, if any
+
+# Check whether --with-vendor-vm-bug-url was given.
+if test "${with_vendor_vm_bug_url+set}" = set; then :
+ withval=$with_vendor_vm_bug_url;
+fi
+
+ if test "x$with_vendor_vm_bug_url" = xyes; then
+ as_fn_error $? "--with-vendor-vm-bug-url must have a value" "$LINENO" 5
+ elif ! [[ $with_vendor_vm_bug_url =~ ^[[:print:]]*$ ]] ; then
+ as_fn_error $? "--with-vendor-vm-bug-url contains non-printing characters: $with_vendor_vm_bug_url" "$LINENO" 5
+ else
+ VENDOR_URL_VM_BUG="$with_vendor_vm_bug_url"
+ fi
+
+
# Override version from arguments
# If --with-version-string is set, process it first. It is possible to
diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4
index a3024a3c45a..b6580cd372e 100644
--- a/make/autoconf/jdk-version.m4
+++ b/make/autoconf/jdk-version.m4
@@ -80,16 +80,55 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
# The vendor name, if any
AC_ARG_WITH(vendor-name, [AS_HELP_STRING([--with-vendor-name],
- [Set vendor name @<:@not specified@:>@])])
+ [Set vendor name. Among others, used to set the 'java.vendor'
+ and 'java.vm.vendor' system properties. @<:@not specified@:>@])])
if test "x$with_vendor_name" = xyes; then
AC_MSG_ERROR([--with-vendor-name must have a value])
elif [ ! [[ $with_vendor_name =~ ^[[:print:]]*$ ]] ]; then
- AC_MSG_ERROR([--with--vendor-name contains non-printing characters: $with_vendor_name])
- else
+ AC_MSG_ERROR([--with-vendor-name contains non-printing characters: $with_vendor_name])
+ elif test "x$with_vendor_name" != x; then
+ # Only set COMPANY_NAME if '--with-vendor-name' was used and is not empty.
+ # Otherwise we will use the value from "version-numbers" included above.
COMPANY_NAME="$with_vendor_name"
fi
AC_SUBST(COMPANY_NAME)
+ # The vendor URL, if any
+ AC_ARG_WITH(vendor-url, [AS_HELP_STRING([--with-vendor-url],
+ [Set the 'java.vendor.url' system property @<:@not specified@:>@])])
+ if test "x$with_vendor_url" = xyes; then
+ AC_MSG_ERROR([--with-vendor-url must have a value])
+ elif [ ! [[ $with_vendor_url =~ ^[[:print:]]*$ ]] ]; then
+ AC_MSG_ERROR([--with-vendor-url contains non-printing characters: $with_vendor_url])
+ else
+ VENDOR_URL="$with_vendor_url"
+ fi
+ AC_SUBST(VENDOR_URL)
+
+ # The vendor bug URL, if any
+ AC_ARG_WITH(vendor-bug-url, [AS_HELP_STRING([--with-vendor-bug-url],
+ [Set the 'java.vendor.url.bug' system property @<:@not specified@:>@])])
+ if test "x$with_vendor_bug_url" = xyes; then
+ AC_MSG_ERROR([--with-vendor-bug-url must have a value])
+ elif [ ! [[ $with_vendor_bug_url =~ ^[[:print:]]*$ ]] ]; then
+ AC_MSG_ERROR([--with-vendor-bug-url contains non-printing characters: $with_vendor_bug_url])
+ else
+ VENDOR_URL_BUG="$with_vendor_bug_url"
+ fi
+ AC_SUBST(VENDOR_URL_BUG)
+
+ # The vendor VM bug URL, if any
+ AC_ARG_WITH(vendor-vm-bug-url, [AS_HELP_STRING([--with-vendor-vm-bug-url],
+ [Sets the bug URL which will be displayed when the VM crashes @<:@not specified@:>@])])
+ if test "x$with_vendor_vm_bug_url" = xyes; then
+ AC_MSG_ERROR([--with-vendor-vm-bug-url must have a value])
+ elif [ ! [[ $with_vendor_vm_bug_url =~ ^[[:print:]]*$ ]] ]; then
+ AC_MSG_ERROR([--with-vendor-vm-bug-url contains non-printing characters: $with_vendor_vm_bug_url])
+ else
+ VENDOR_URL_VM_BUG="$with_vendor_vm_bug_url"
+ fi
+ AC_SUBST(VENDOR_URL_VM_BUG)
+
# Override version from arguments
# If --with-version-string is set, process it first. It is possible to
diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in
index 4fa633f26c9..307a28a3f53 100644
--- a/make/autoconf/spec.gmk.in
+++ b/make/autoconf/spec.gmk.in
@@ -142,6 +142,20 @@ IMPORT_MODULES_MAKE:=@IMPORT_MODULES_MAKE@
COPYRIGHT_YEAR:=@COPYRIGHT_YEAR@
+# Platform naming variables
+LAUNCHER_NAME:=@LAUNCHER_NAME@
+PRODUCT_NAME:=@PRODUCT_NAME@
+PRODUCT_SUFFIX:=@PRODUCT_SUFFIX@
+JDK_RC_PLATFORM_NAME:=@JDK_RC_PLATFORM_NAME@
+COMPANY_NAME:=@COMPANY_NAME@
+HOTSPOT_VM_DISTRO:=@HOTSPOT_VM_DISTRO@
+MACOSX_BUNDLE_NAME_BASE=@MACOSX_BUNDLE_NAME_BASE@
+MACOSX_BUNDLE_ID_BASE=@MACOSX_BUNDLE_ID_BASE@
+USERNAME:=@USERNAME@
+VENDOR_URL:=@VENDOR_URL@
+VENDOR_URL_BUG:=@VENDOR_URL_BUG@
+VENDOR_URL_VM_BUG:=@VENDOR_URL_VM_BUG@
+
# New (JEP-223) version information
## Building blocks of the version string
@@ -201,16 +215,30 @@ VERSION_CFLAGS := \
-DVERSION_CLASSFILE_MINOR=$(VERSION_CLASSFILE_MINOR) \
#
-# Platform naming variables
-LAUNCHER_NAME:=@LAUNCHER_NAME@
-PRODUCT_NAME:=@PRODUCT_NAME@
-PRODUCT_SUFFIX:=@PRODUCT_SUFFIX@
-JDK_RC_PLATFORM_NAME:=@JDK_RC_PLATFORM_NAME@
-COMPANY_NAME:=@COMPANY_NAME@
-HOTSPOT_VM_DISTRO:=@HOTSPOT_VM_DISTRO@
-MACOSX_BUNDLE_NAME_BASE=@MACOSX_BUNDLE_NAME_BASE@
-MACOSX_BUNDLE_ID_BASE=@MACOSX_BUNDLE_ID_BASE@
-USERNAME:=@USERNAME@
+ifneq ($(COMPANY_NAME),)
+ # COMPANY_NAME is set to "N/A" in $AUTOCONF_DIR/version-numbers by default,
+ # but can be customized with the '--with-vendor-name' configure option.
+ # Only export "VENDOR" to the build if COMPANY_NAME contains a real value.
+ # Otherwise the default value for VENDOR, which is used to set the "java.vendor"
+ # and "java.vm.vendor" properties is hard-coded into the source code (i.e. in
+ # System.c in the jdk for "vm.vendor" and vm_version.cpp in the VM for "java.vm.vendor")
+ ifneq ($(COMPANY_NAME), N/A)
+ VERSION_CFLAGS += -DVENDOR='"$(COMPANY_NAME)"'
+ endif
+endif
+
+# Only export VENDOR_URL, VENDOR_URL_BUG and VENDOR_VM_URL_BUG to the build if
+# they are not empty. Otherwise, default values which are defined in the sources
+# will be used.
+ifneq ($(VENDOR_URL),)
+ VERSION_CFLAGS += -DVENDOR_URL='"$(VENDOR_URL)"'
+endif
+ifneq ($(VENDOR_URL_BUG),)
+ VERSION_CFLAGS += -DVENDOR_URL_BUG='"$(VENDOR_URL_BUG)"'
+endif
+ifneq ($(VENDOR_URL_VM_BUG),)
+ VERSION_CFLAGS += -DVENDOR_URL_VM_BUG='"$(VENDOR_URL_VM_BUG)"'
+endif
# Different naming strings generated from the above information.
RUNTIME_NAME=$(PRODUCT_NAME) $(PRODUCT_SUFFIX)
diff --git a/make/data/jdwp/jdwp.spec b/make/data/jdwp/jdwp.spec
index 0b7afa76a9c..a33f31ed41c 100644
--- a/make/data/jdwp/jdwp.spec
+++ b/make/data/jdwp/jdwp.spec
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -869,7 +869,6 @@ JDWP "Java(tm) Debug Wire Protocol"
"section in "
"The Java™ Virtual Machine Specification. "
"Since JDWP version 1.5."
- "
(Out
(referenceType refType "The reference type ID.")
)
@@ -2723,7 +2722,6 @@ JDWP "Java(tm) Debug Wire Protocol"
"
"
"The events that are grouped in a composite event are restricted in the "
"following ways: "
- "
"
"
"
"- Only with other thread start events for the same thread:"
"
"
diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk
index 7be0c043f4a..de8213232b6 100644
--- a/make/hotspot/lib/CompileJvm.gmk
+++ b/make/hotspot/lib/CompileJvm.gmk
@@ -222,6 +222,7 @@ $(eval $(call SetupNativeCompilation, BUILD_LIBJVM, \
CFLAGS_DEBUG_SYMBOLS := $(JVM_CFLAGS_SYMBOLS), \
CXXFLAGS_DEBUG_SYMBOLS := $(JVM_CFLAGS_SYMBOLS), \
vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \
+ arguments.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \
DISABLED_WARNINGS_clang := tautological-compare, \
DISABLED_WARNINGS_xlc := 1540-0216 1540-0198 1540-1090 1540-1639 \
1540-1088 1500-010, \
diff --git a/make/jdk/src/classes/build/tools/jdwpgen/AbstractCommandNode.java b/make/jdk/src/classes/build/tools/jdwpgen/AbstractCommandNode.java
index b4b17196088..d007c584b69 100644
--- a/make/jdk/src/classes/build/tools/jdwpgen/AbstractCommandNode.java
+++ b/make/jdk/src/classes/build/tools/jdwpgen/AbstractCommandNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,8 +30,8 @@ import java.io.*;
class AbstractCommandNode extends AbstractNamedNode {
void document(PrintWriter writer) {
- writer.println("");
+ writer.println("" + name +
+ " Command (" + nameNode.value() + ")
");
writer.println(comment());
writer.println("");
for (Node node : components) {
diff --git a/make/jdk/src/classes/build/tools/jdwpgen/AbstractNamedNode.java b/make/jdk/src/classes/build/tools/jdwpgen/AbstractNamedNode.java
index a71b8949e3d..764558be1a7 100644
--- a/make/jdk/src/classes/build/tools/jdwpgen/AbstractNamedNode.java
+++ b/make/jdk/src/classes/build/tools/jdwpgen/AbstractNamedNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -62,8 +62,8 @@ abstract class AbstractNamedNode extends Node {
}
void document(PrintWriter writer) {
- writer.println("");
+ writer.println("" + name +
+ " Command Set
");
for (Node node : components) {
node.document(writer);
}
diff --git a/make/jdk/src/classes/build/tools/jdwpgen/AbstractTypeListNode.java b/make/jdk/src/classes/build/tools/jdwpgen/AbstractTypeListNode.java
index eea9b9314a9..5ceae49b811 100644
--- a/make/jdk/src/classes/build/tools/jdwpgen/AbstractTypeListNode.java
+++ b/make/jdk/src/classes/build/tools/jdwpgen/AbstractTypeListNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,11 +43,11 @@ abstract class AbstractTypeListNode extends AbstractNamedNode {
if (components.isEmpty()) {
writer.println("- (None)");
} else {
- writer.println("
");
+ writer.println("");
for (int i = maxStructIndent; i > 0; --i) {
- writer.print("");
+ writer.print(" | ");
}
- writer.println(" | | ");
+ writer.println(" | | ");
writer.println("");
for (Node node : components) {
node.document(writer);
diff --git a/make/jdk/src/classes/build/tools/jdwpgen/CommandSetNode.java b/make/jdk/src/classes/build/tools/jdwpgen/CommandSetNode.java
index 738cf61be5b..440e138ccb9 100644
--- a/make/jdk/src/classes/build/tools/jdwpgen/CommandSetNode.java
+++ b/make/jdk/src/classes/build/tools/jdwpgen/CommandSetNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,8 +38,8 @@ class CommandSetNode extends AbstractNamedNode {
}
void document(PrintWriter writer) {
- writer.println("" + name +
- " Command Set (" +
+ writer.println("" + name +
+ " Command Set (" +
nameNode.value() + ")");
writer.println(comment());
for (Node node : components) {
@@ -51,11 +51,13 @@ class CommandSetNode extends AbstractNamedNode {
writer.print("- ");
writer.println(name() + " Command Set (" +
nameNode.value() + ")");
- writer.println("
");
- for (Node node : components) {
- node.documentIndex(writer);
+ if (components.size() > 0) {
+ writer.println("");
+ for (Node node : components) {
+ node.documentIndex(writer);
+ }
+ writer.println(" ");
}
- writer.println(" ");
}
void genJavaClassSpecifics(PrintWriter writer, int depth) {
diff --git a/make/jdk/src/classes/build/tools/jdwpgen/ConstantSetNode.java b/make/jdk/src/classes/build/tools/jdwpgen/ConstantSetNode.java
index 280136766d4..4990cb2740e 100644
--- a/make/jdk/src/classes/build/tools/jdwpgen/ConstantSetNode.java
+++ b/make/jdk/src/classes/build/tools/jdwpgen/ConstantSetNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -54,15 +54,15 @@ class ConstantSetNode extends AbstractNamedNode {
}
void document(PrintWriter writer) {
- writer.println("");
+ writer.println("" + name +
+ " Constants");
writer.println(comment());
- writer.println("");
- writer.println(" | | ");
+ writer.println("");
+ writer.println(" | | ");
ConstantNode n;
for (Node node : components) {
n = (ConstantNode)node;
- writer.println("");
+ writer.println("");
n.document(writer);
}
writer.println(" | ");
diff --git a/make/jdk/src/classes/build/tools/jdwpgen/ErrorSetNode.java b/make/jdk/src/classes/build/tools/jdwpgen/ErrorSetNode.java
index 2cfe505a858..50dd0af39d4 100644
--- a/make/jdk/src/classes/build/tools/jdwpgen/ErrorSetNode.java
+++ b/make/jdk/src/classes/build/tools/jdwpgen/ErrorSetNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,7 +43,7 @@ class ErrorSetNode extends AbstractSimpleNode {
if (components.isEmpty()) {
writer.println("- (None)");
} else {
- writer.println("
");
+ writer.println("");
for (Node node : components) {
node.document(writer);
}
diff --git a/make/jdk/src/classes/build/tools/jdwpgen/RootNode.java b/make/jdk/src/classes/build/tools/jdwpgen/RootNode.java
index 2361f335949..da485d66a61 100644
--- a/make/jdk/src/classes/build/tools/jdwpgen/RootNode.java
+++ b/make/jdk/src/classes/build/tools/jdwpgen/RootNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,11 +41,22 @@ class RootNode extends AbstractNamedNode {
void document(PrintWriter writer) {
writer.println("");
- writer.println("" + comment() + "");
- writer.println("");
+ writer.println("");
+ writer.println("");
+ writer.println("");
+ writer.println("" + comment() + "");
+ writer.println("");
+ writer.println("");
+ writer.println("");
+ writer.println("");
for (Node node : components) {
node.documentIndex(writer);
}
+ writer.println(" ");
for (Node node : components) {
node.document(writer);
}
diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk
index 40df7d1ee42..511f9022304 100644
--- a/make/test/JtregNativeHotspot.gmk
+++ b/make/test/JtregNativeHotspot.gmk
@@ -44,6 +44,7 @@ $(eval $(call IncludeCustomExtension, test/JtregNativeHotspot.gmk))
# Add more directories here when needed.
BUILD_HOTSPOT_JTREG_NATIVE_SRC += \
$(TOPDIR)/test/hotspot/jtreg/gc/g1/TestJNIWeakG1 \
+ $(TOPDIR)/test/hotspot/jtreg/gc/stress/TestJNIBlockFullGC \
$(TOPDIR)/test/hotspot/jtreg/gc/stress/gclocker \
$(TOPDIR)/test/hotspot/jtreg/gc/cslocker \
$(TOPDIR)/test/hotspot/jtreg/native_sanity \
diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp
index a92e19ab8c6..23d0c691ce1 100644
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp
@@ -2295,23 +2295,32 @@ public:
rf(Vn, 5), rf(Rd, 0);
}
-#define INSN(NAME, opc, opc2) \
+#define INSN(NAME, opc, opc2, isSHR) \
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int shift){ \
starti; \
- /* The encodings for the immh:immb fields (bits 22:16) are \
- * 0001 xxx 8B/16B, shift = xxx \
- * 001x xxx 4H/8H, shift = xxxx \
- * 01xx xxx 2S/4S, shift = xxxxx \
- * 1xxx xxx 1D/2D, shift = xxxxxx (1D is RESERVED) \
+ /* The encodings for the immh:immb fields (bits 22:16) in *SHR are \
+ * 0001 xxx 8B/16B, shift = 16 - UInt(immh:immb) \
+ * 001x xxx 4H/8H, shift = 32 - UInt(immh:immb) \
+ * 01xx xxx 2S/4S, shift = 64 - UInt(immh:immb) \
+ * 1xxx xxx 1D/2D, shift = 128 - UInt(immh:immb) \
+ * (1D is RESERVED) \
+ * for SHL shift is calculated as: \
+ * 0001 xxx 8B/16B, shift = UInt(immh:immb) - 8 \
+ * 001x xxx 4H/8H, shift = UInt(immh:immb) - 16 \
+ * 01xx xxx 2S/4S, shift = UInt(immh:immb) - 32 \
+ * 1xxx xxx 1D/2D, shift = UInt(immh:immb) - 64 \
+ * (1D is RESERVED) \
*/ \
assert((1 << ((T>>1)+3)) > shift, "Invalid Shift value"); \
+ int cVal = (1 << (((T >> 1) + 3) + (isSHR ? 1 : 0))); \
+ int encodedShift = isSHR ? cVal - shift : cVal + shift; \
f(0, 31), f(T & 1, 30), f(opc, 29), f(0b011110, 28, 23), \
- f((1 << ((T>>1)+3))|shift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0); \
+ f(encodedShift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0); \
}
- INSN(shl, 0, 0b010101);
- INSN(sshr, 0, 0b000001);
- INSN(ushr, 1, 0b000001);
+ INSN(shl, 0, 0b010101, /* isSHR = */ false);
+ INSN(sshr, 0, 0b000001, /* isSHR = */ true);
+ INSN(ushr, 1, 0b000001, /* isSHR = */ true);
#undef INSN
diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
index 0a5b696b575..de3fec9b9da 100644
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
@@ -774,7 +774,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()));
diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp
index ea4d7782983..7bdc89a67d8 100644
--- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp
@@ -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
diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.hpp b/src/hotspot/cpu/arm/macroAssembler_arm.hpp
index 79f4b1ba588..4462a38cab5 100644
--- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp
+++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp
@@ -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,
diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
index 666cbd8860e..cdf27391943 100644
--- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
+++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
@@ -984,7 +984,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
diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp
index 9eb74775ab1..3b35418b01a 100644
--- a/src/hotspot/cpu/arm/templateTable_arm.cpp
+++ b/src/hotspot/cpu/arm/templateTable_arm.cpp
@@ -4198,7 +4198,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.
@@ -4207,56 +4207,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
@@ -4278,6 +4261,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) {
@@ -4345,7 +4335,6 @@ void TemplateTable::_new() {
Label done;
Label initialize_header;
Label initialize_object; // including clearing the fields
- Label allocate_shared;
const bool allow_shared_alloc =
Universe::heap()->supports_inline_contig_alloc();
@@ -4390,13 +4379,19 @@ void TemplateTable::_new() {
// Klass::_lh_instance_slow_path_bit is really a bit mask, not bit number
__ tbnz(Rsize, exact_log2(Klass::_lh_instance_slow_path_bit), slow_case);
+ // Allocate the instance:
+ // If TLAB is enabled:
+ // Try to allocate in the TLAB.
+ // If fails, go to the slow path.
+ // Else If inline contiguous allocations are enabled:
+ // Try to allocate in eden.
+ // If fails due to heap end, go to slow path.
//
- // Allocate the instance
- // 1) Try to allocate in the TLAB
- // 2) if fail and the object is large allocate in the shared Eden
- // 3) if the above fails (or is not applicable), go to a slow case
- // (creates a new TLAB, etc.)
-
+ // If TLAB is enabled OR inline contiguous is enabled:
+ // Initialize the allocation.
+ // Exit.
+ //
+ // Go to slow path.
if (UseTLAB) {
const Register Rtlab_top = R1_tmp;
const Register Rtlab_end = R2_tmp;
@@ -4406,7 +4401,7 @@ void TemplateTable::_new() {
__ ldr(Rtlab_end, Address(Rthread, in_bytes(JavaThread::tlab_end_offset())));
__ add(Rtlab_top, Robj, Rsize);
__ cmp(Rtlab_top, Rtlab_end);
- __ b(allow_shared_alloc ? allocate_shared : slow_case, hi);
+ __ b(slow_case, hi);
__ str(Rtlab_top, Address(Rthread, JavaThread::tlab_top_offset()));
if (ZeroTLAB) {
// the fields have been already cleared
@@ -4415,45 +4410,43 @@ void TemplateTable::_new() {
// initialize both the header and fields
__ b(initialize_object);
}
- }
+ } else {
+ // Allocation in the shared Eden, if allowed.
+ if (allow_shared_alloc) {
+ const Register Rheap_top_addr = R2_tmp;
+ const Register Rheap_top = R5_tmp;
+ const Register Rheap_end = Rtemp;
+ assert_different_registers(Robj, Rklass, Rsize, Rheap_top_addr, Rheap_top, Rheap_end, LR);
- // Allocation in the shared Eden, if allowed.
- if (allow_shared_alloc) {
- __ bind(allocate_shared);
+ // heap_end now (re)loaded in the loop since also used as a scratch register in the CAS
+ __ ldr_literal(Rheap_top_addr, Lheap_top_addr);
- const Register Rheap_top_addr = R2_tmp;
- const Register Rheap_top = R5_tmp;
- const Register Rheap_end = Rtemp;
- assert_different_registers(Robj, Rklass, Rsize, Rheap_top_addr, Rheap_top, Rheap_end, LR);
-
- // heap_end now (re)loaded in the loop since also used as a scratch register in the CAS
- __ ldr_literal(Rheap_top_addr, Lheap_top_addr);
-
- Label retry;
- __ bind(retry);
+ Label retry;
+ __ bind(retry);
#ifdef AARCH64
- __ ldxr(Robj, Rheap_top_addr);
+ __ ldxr(Robj, Rheap_top_addr);
#else
- __ ldr(Robj, Address(Rheap_top_addr));
+ __ ldr(Robj, Address(Rheap_top_addr));
#endif // AARCH64
- __ ldr(Rheap_end, Address(Rheap_top_addr, (intptr_t)Universe::heap()->end_addr()-(intptr_t)Universe::heap()->top_addr()));
- __ add(Rheap_top, Robj, Rsize);
- __ cmp(Rheap_top, Rheap_end);
- __ b(slow_case, hi);
+ __ ldr(Rheap_end, Address(Rheap_top_addr, (intptr_t)Universe::heap()->end_addr()-(intptr_t)Universe::heap()->top_addr()));
+ __ add(Rheap_top, Robj, Rsize);
+ __ cmp(Rheap_top, Rheap_end);
+ __ b(slow_case, hi);
- // Update heap top atomically.
- // If someone beats us on the allocation, try again, otherwise continue.
+ // Update heap top atomically.
+ // If someone beats us on the allocation, try again, otherwise continue.
#ifdef AARCH64
- __ stxr(Rtemp2, Rheap_top, Rheap_top_addr);
- __ cbnz_w(Rtemp2, retry);
+ __ stxr(Rtemp2, Rheap_top, Rheap_top_addr);
+ __ cbnz_w(Rtemp2, retry);
#else
- __ atomic_cas_bool(Robj, Rheap_top, Rheap_top_addr, 0, Rheap_end/*scratched*/);
- __ b(retry, ne);
+ __ atomic_cas_bool(Robj, Rheap_top, Rheap_top_addr, 0, Rheap_end/*scratched*/);
+ __ b(retry, ne);
#endif // AARCH64
- __ incr_allocated_bytes(Rsize, Rtemp);
+ __ incr_allocated_bytes(Rsize, Rtemp);
+ }
}
if (UseTLAB || allow_shared_alloc) {
diff --git a/src/hotspot/cpu/arm/vtableStubs_arm.cpp b/src/hotspot/cpu/arm/vtableStubs_arm.cpp
index 8b980aba563..06432c1ee88 100644
--- a/src/hotspot/cpu/arm/vtableStubs_arm.cpp
+++ b/src/hotspot/cpu/arm/vtableStubs_arm.cpp
@@ -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
diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp
index 875c5dfdfdf..01b910db057 100644
--- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -34,8 +34,8 @@
#include "runtime/basicLock.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/os.hpp"
-#include "runtime/stubRoutines.hpp"
#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
#include "utilities/align.hpp"
diff --git a/src/hotspot/cpu/ppc/c1_globals_ppc.hpp b/src/hotspot/cpu/ppc/c1_globals_ppc.hpp
index b641852e8a3..66f6f913636 100644
--- a/src/hotspot/cpu/ppc/c1_globals_ppc.hpp
+++ b/src/hotspot/cpu/ppc/c1_globals_ppc.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -33,36 +33,36 @@
// (see c1_globals.hpp)
#ifndef TIERED
-define_pd_global(bool, BackgroundCompilation, true );
-define_pd_global(bool, CICompileOSR, true );
-define_pd_global(bool, InlineIntrinsics, true );
-define_pd_global(bool, PreferInterpreterNativeStubs, false);
-define_pd_global(bool, ProfileTraps, false);
-define_pd_global(bool, UseOnStackReplacement, true );
-define_pd_global(bool, TieredCompilation, false);
-define_pd_global(intx, CompileThreshold, 1000 );
+define_pd_global(bool, BackgroundCompilation, true);
+define_pd_global(bool, CICompileOSR, true);
+define_pd_global(bool, InlineIntrinsics, true);
+define_pd_global(bool, PreferInterpreterNativeStubs, false);
+define_pd_global(bool, ProfileTraps, false);
+define_pd_global(bool, UseOnStackReplacement, true);
+define_pd_global(bool, TieredCompilation, false);
+define_pd_global(intx, CompileThreshold, 1000);
-define_pd_global(intx, OnStackReplacePercentage, 1400 );
-define_pd_global(bool, UseTLAB, true );
-define_pd_global(bool, ProfileInterpreter, false);
-define_pd_global(intx, FreqInlineSize, 325 );
-define_pd_global(bool, ResizeTLAB, true );
-define_pd_global(intx, ReservedCodeCacheSize, 32*M );
-define_pd_global(intx, CodeCacheExpansionSize, 32*K );
-define_pd_global(uintx,CodeCacheMinBlockLength, 1);
-define_pd_global(uintx,MetaspaceSize, 12*M );
-define_pd_global(bool, NeverActAsServerClassMachine, true );
-define_pd_global(intx, NewSizeThreadIncrease, 16*K );
-define_pd_global(uint64_t,MaxRAM, 1ULL*G);
-define_pd_global(intx, InitialCodeCacheSize, 160*K);
+define_pd_global(intx, OnStackReplacePercentage, 1400);
+define_pd_global(bool, UseTLAB, true);
+define_pd_global(bool, ProfileInterpreter, false);
+define_pd_global(intx, FreqInlineSize, 325 );
+define_pd_global(bool, ResizeTLAB, true);
+define_pd_global(uintx, ReservedCodeCacheSize, 32*M);
+define_pd_global(uintx, CodeCacheExpansionSize, 32*K);
+define_pd_global(uintx, CodeCacheMinBlockLength, 1);
+define_pd_global(size_t, MetaspaceSize, 12*M);
+define_pd_global(bool, NeverActAsServerClassMachine, true);
+define_pd_global(size_t, NewSizeThreadIncrease, 16*K);
+define_pd_global(uint64_t, MaxRAM, 1ULL*G);
+define_pd_global(uintx, InitialCodeCacheSize, 160*K);
#endif // !TIERED
-define_pd_global(bool, UseTypeProfile, false);
-define_pd_global(bool, RoundFPResults, false);
+define_pd_global(bool, UseTypeProfile, false);
+define_pd_global(bool, RoundFPResults, false);
-define_pd_global(bool, LIRFillDelaySlots, false);
-define_pd_global(bool, OptimizeSinglePrecision, false);
-define_pd_global(bool, CSEArrayLength, true );
-define_pd_global(bool, TwoOperandLIRForm, false);
+define_pd_global(bool, LIRFillDelaySlots, false);
+define_pd_global(bool, OptimizeSinglePrecision, false);
+define_pd_global(bool, CSEArrayLength, true);
+define_pd_global(bool, TwoOperandLIRForm, false);
#endif // CPU_PPC_VM_C1_GLOBALS_PPC_HPP
diff --git a/src/hotspot/cpu/ppc/c2_globals_ppc.hpp b/src/hotspot/cpu/ppc/c2_globals_ppc.hpp
index fd61e5ddb56..a947e45febf 100644
--- a/src/hotspot/cpu/ppc/c2_globals_ppc.hpp
+++ b/src/hotspot/cpu/ppc/c2_globals_ppc.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -39,7 +39,7 @@ define_pd_global(bool, PreferInterpreterNativeStubs, false);
define_pd_global(bool, ProfileTraps, true);
define_pd_global(bool, UseOnStackReplacement, true);
define_pd_global(bool, ProfileInterpreter, true);
-define_pd_global(bool, TieredCompilation, true);
+define_pd_global(bool, TieredCompilation, trueInTiered);
define_pd_global(intx, CompileThreshold, 10000);
define_pd_global(intx, OnStackReplacePercentage, 140);
@@ -78,27 +78,27 @@ define_pd_global(bool, SuperWordLoopUnrollAnalysis, false);
// x.f = 0
// loc = x.f
// NullCheck loc
-define_pd_global(bool, OptoScheduling, false);
-define_pd_global(bool, IdealizeClearArrayNode, true);
+define_pd_global(bool, OptoScheduling, false);
+define_pd_global(bool, IdealizeClearArrayNode, true);
-define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize
-define_pd_global(intx, ReservedCodeCacheSize, 256*M);
-define_pd_global(intx, NonProfiledCodeHeapSize, 125*M);
-define_pd_global(intx, ProfiledCodeHeapSize, 126*M);
-define_pd_global(intx, NonNMethodCodeHeapSize, 5*M );
-define_pd_global(intx, CodeCacheExpansionSize, 64*K);
+define_pd_global(uintx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize
+define_pd_global(uintx, ReservedCodeCacheSize, 256*M);
+define_pd_global(uintx, NonProfiledCodeHeapSize, 125*M);
+define_pd_global(uintx, ProfiledCodeHeapSize, 126*M);
+define_pd_global(uintx, NonNMethodCodeHeapSize, 5*M );
+define_pd_global(uintx, CodeCacheExpansionSize, 64*K);
// Ergonomics related flags
-define_pd_global(uint64_t, MaxRAM, 4ULL*G);
-define_pd_global(uintx, CodeCacheMinBlockLength, 4);
-define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
+define_pd_global(uint64_t, MaxRAM, 128ULL*G);
+define_pd_global(uintx, CodeCacheMinBlockLength, 4);
+define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
-define_pd_global(bool, TrapBasedRangeChecks, true);
+define_pd_global(bool, TrapBasedRangeChecks, true);
// Heap related flags
-define_pd_global(size_t, MetaspaceSize, ScaleForWordSize(16*M));
+define_pd_global(size_t, MetaspaceSize, ScaleForWordSize(16*M));
// Ergonomics related flags
-define_pd_global(bool, NeverActAsServerClassMachine, false);
+define_pd_global(bool, NeverActAsServerClassMachine, false);
#endif // CPU_PPC_VM_C2_GLOBALS_PPC_HPP
diff --git a/src/hotspot/cpu/ppc/c2_init_ppc.cpp b/src/hotspot/cpu/ppc/c2_init_ppc.cpp
index 4df27d43d1b..5326bd01a08 100644
--- a/src/hotspot/cpu/ppc/c2_init_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c2_init_ppc.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -29,11 +29,11 @@
#include "runtime/globals.hpp"
#include "utilities/debug.hpp"
-// processor dependent initialization for ppc
+// Processor dependent initialization of C2 compiler for ppc.
void Compile::pd_compiler2_init() {
- // Power7 and later
+ // Power7 and later.
if (PowerArchitecturePPC64 > 6) {
if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
FLAG_SET_ERGO(bool, UsePopCountInstruction, true);
diff --git a/src/hotspot/cpu/ppc/globals_ppc.hpp b/src/hotspot/cpu/ppc/globals_ppc.hpp
index 1e1fbb6f6f3..6d96ad05ee4 100644
--- a/src/hotspot/cpu/ppc/globals_ppc.hpp
+++ b/src/hotspot/cpu/ppc/globals_ppc.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2017 SAP SE. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -86,14 +86,14 @@ define_pd_global(intx, InitArrayShortSize, 9*BytesPerLong);
define_pd_global(bool, ThreadLocalHandshakes, true);
// Platform dependent flag handling: flags only defined on this platform.
-#define ARCH_FLAGS(develop, \
- product, \
- diagnostic, \
+#define ARCH_FLAGS(develop, \
+ product, \
+ diagnostic, \
experimental, \
- notproduct, \
- range, \
- constraint, \
- writeable) \
+ notproduct, \
+ range, \
+ constraint, \
+ writeable) \
\
product(uintx, PowerArchitecturePPC64, 0, \
"CPU Version: x for PowerX. Currently recognizes Power5 to " \
diff --git a/src/hotspot/cpu/ppc/icache_ppc.cpp b/src/hotspot/cpu/ppc/icache_ppc.cpp
index 916d3d72590..6901efc37b7 100644
--- a/src/hotspot/cpu/ppc/icache_ppc.cpp
+++ b/src/hotspot/cpu/ppc/icache_ppc.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2013 SAP SE. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -24,7 +24,6 @@
*/
#include "precompiled.hpp"
-#include "assembler_ppc.inline.hpp"
#include "runtime/icache.hpp"
// Use inline assembler to implement icache flush.
@@ -32,7 +31,7 @@ int ICache::ppc64_flush_icache(address start, int lines, int magic) {
address end = start + (unsigned int)lines*ICache::line_size;
assert(start <= end, "flush_icache parms");
- // store modified cache lines from data cache
+ // Store modified cache lines from data cache.
for (address a = start; a < end; a += ICache::line_size) {
__asm__ __volatile__(
"dcbst 0, %0 \n"
@@ -48,7 +47,7 @@ int ICache::ppc64_flush_icache(address start, int lines, int magic) {
:
: "memory");
- // invalidate respective cache lines in instruction cache
+ // Invalidate respective cache lines in instruction cache.
for (address a = start; a < end; a += ICache::line_size) {
__asm__ __volatile__(
"icbi 0, %0 \n"
@@ -57,7 +56,7 @@ int ICache::ppc64_flush_icache(address start, int lines, int magic) {
: "memory");
}
- // discard fetched instructions
+ // Discard fetched instructions.
__asm__ __volatile__(
"isync \n"
:
@@ -71,6 +70,8 @@ void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flu
*flush_icache_stub = (ICache::flush_icache_stub_t)ICache::ppc64_flush_icache;
- // First call to flush itself
+ // First call to flush itself.
+ // Pointless since we call C, but it is expected to get
+ // executed during VM_Version::determine_features().
ICache::invalidate_range((address)(*flush_icache_stub), 0);
}
diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
index 742a8ef5a50..18bb92ed6a9 100644
--- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2017 SAP SE. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -32,6 +32,10 @@
#include "runtime/safepointMechanism.hpp"
#include "runtime/sharedRuntime.hpp"
+// Implementation of InterpreterMacroAssembler.
+
+// This file specializes the assembler with interpreter-specific macros.
+
#ifdef PRODUCT
#define BLOCK_COMMENT(str) // nothing
#else
diff --git a/src/hotspot/cpu/ppc/jniFastGetField_ppc.cpp b/src/hotspot/cpu/ppc/jniFastGetField_ppc.cpp
index 8447e1c37d9..e696fa1fef4 100644
--- a/src/hotspot/cpu/ppc/jniFastGetField_ppc.cpp
+++ b/src/hotspot/cpu/ppc/jniFastGetField_ppc.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2013 SAP SE. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -24,7 +24,7 @@
*/
#include "precompiled.hpp"
-#include "assembler_ppc.inline.hpp"
+#include "asm/assembler.inline.hpp"
#include "memory/resourceArea.hpp"
#include "prims/jniFastGetField.hpp"
#include "prims/jvm_misc.hpp"
diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
index 660daf0502e..cecb696b079 100644
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, 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.
*
@@ -1788,11 +1788,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());
@@ -1810,15 +1809,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<itable(); scan->interface() != NULL; scan += scan_step) {
@@ -1831,12 +1832,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);
@@ -1849,7 +1850,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);
}
@@ -1857,9 +1858,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
@@ -2880,10 +2883,6 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
//assert(ObjectMonitor::recursions_size_in_bytes() == 8, "unexpected size");
asm_assert_mem8_is_zero(ObjectMonitor::recursions_offset_in_bytes(), temp,
"monitor->_recursions should be 0", -1);
- // Invariant 2: OwnerIsThread shouldn't be 0.
- //assert(ObjectMonitor::OwnerIsThread_size_in_bytes() == 4, "unexpected size");
- //asm_assert_mem4_isnot_zero(ObjectMonitor::OwnerIsThread_offset_in_bytes(), temp,
- // "monitor->OwnerIsThread shouldn't be 0", -1);
# endif
#if INCLUDE_RTM_OPT
diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp
index 2f51dfc8275..ee48fc2ff37 100644
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp
@@ -519,7 +519,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,
diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp
index 8fbd5b4198c..0d386f4134a 100644
--- a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp
+++ b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -26,7 +26,6 @@
#ifndef CPU_PPC_VM_NATIVEINST_PPC_HPP
#define CPU_PPC_VM_NATIVEINST_PPC_HPP
-#include "asm/assembler.hpp"
#include "asm/macroAssembler.hpp"
#include "memory/allocation.hpp"
#include "runtime/icache.hpp"
diff --git a/src/hotspot/cpu/ppc/runtime_ppc.cpp b/src/hotspot/cpu/ppc/runtime_ppc.cpp
index 984eb01f53f..9d96d8d35a6 100644
--- a/src/hotspot/cpu/ppc/runtime_ppc.cpp
+++ b/src/hotspot/cpu/ppc/runtime_ppc.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -25,7 +25,6 @@
#include "precompiled.hpp"
#ifdef COMPILER2
-#include "asm/assembler.inline.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/vmreg.hpp"
diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
index 2b918f068b1..db6169179b6 100644
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2017 SAP SE. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 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
@@ -1188,7 +1188,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));
@@ -1912,8 +1912,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// - *_slot_offset Indicates offset from SP in number of stack slots.
// - *_offset Indicates offset from SP in bytes.
- int stack_slots = c_calling_convention(out_sig_bt, out_regs, out_regs2, total_c_args) // 1+2)
- + SharedRuntime::out_preserve_stack_slots(); // See c_calling_convention.
+ int stack_slots = c_calling_convention(out_sig_bt, out_regs, out_regs2, total_c_args) + // 1+2)
+ SharedRuntime::out_preserve_stack_slots(); // See c_calling_convention.
// Now the space for the inbound oop handle area.
int total_save_slots = num_java_iarg_registers * VMRegImpl::slots_per_word;
@@ -2044,7 +2044,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
OopMap *oop_map = new OopMap(stack_slots * 2, 0 /* arg_slots*/);
if (is_critical_native) {
- check_needs_gc_for_critical_native(masm, stack_slots, total_in_args, oop_handle_slot_offset, oop_maps, in_regs, in_sig_bt, r_temp_1);
+ check_needs_gc_for_critical_native(masm, stack_slots, total_in_args, oop_handle_slot_offset,
+ oop_maps, in_regs, in_sig_bt, r_temp_1);
}
// Move arguments from register/stack to register/stack.
diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp
index 16cb6149f77..7c535a4e20f 100644
--- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp
+++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, 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.
*
@@ -40,6 +40,10 @@
#include "runtime/thread.inline.hpp"
#include "utilities/align.hpp"
+// Declaration and definition of StubGenerator (no .hpp file).
+// For a more detailed description of the stub routine structure
+// see the comment in stubRoutines.hpp.
+
#define __ _masm->
#ifdef PRODUCT
diff --git a/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp b/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp
index f5591669bcd..a310e7ea682 100644
--- a/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, 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.
*
@@ -23,6 +23,7 @@
*
*/
+#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "runtime/stubRoutines.hpp"
diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
index 27a1d62a7d9..f68593ab635 100644
--- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
+++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2017, SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -582,25 +582,6 @@ address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(con
return entry;
}
-#if 0
-// Call special ClassCastException constructor taking object to cast
-// and target class as arguments.
-address TemplateInterpreterGenerator::generate_ClassCastException_verbose_handler() {
- address entry = __ pc();
-
- // Expression stack must be empty before entering the VM if an
- // exception happened.
- __ empty_expression_stack();
-
- // Thread will be loaded to R3_ARG1.
- // Target class oop is in register R5_ARG3 by convention!
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException_verbose), R17_tos, R5_ARG3);
- // Above call must not return here since exception pending.
- DEBUG_ONLY(__ should_not_reach_here();)
- return entry;
-}
-#endif
-
address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
address entry = __ pc();
// Expression stack must be empty before entering the VM if an
@@ -1896,7 +1877,6 @@ address TemplateInterpreterGenerator::generate_CRC32_update_entry() {
return NULL;
}
-
/**
* Method entry for static native methods:
* int java.util.zip.CRC32.updateBytes( int crc, byte[] b, int off, int len)
diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
index 47a340c93c8..a10cd495d11 100644
--- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
@@ -3486,11 +3486,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.
@@ -3502,14 +3502,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) {
@@ -3518,58 +3518,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:
@@ -3577,7 +3580,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) {
diff --git a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp
index d2f6117b37e..480e3e55fa2 100644
--- a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp
@@ -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() {
diff --git a/src/hotspot/cpu/s390/bytes_s390.hpp b/src/hotspot/cpu/s390/bytes_s390.hpp
index f01ea07a2e2..3b62a2e02ad 100644
--- a/src/hotspot/cpu/s390/bytes_s390.hpp
+++ b/src/hotspot/cpu/s390/bytes_s390.hpp
@@ -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, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018 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
@@ -42,11 +42,6 @@ class Bytes: AllStatic {
//
// In short, it makes no sense on z/Architecture to piecemeal get or put unaligned data.
- // Only swap on little endian machines => suffix `_le'.
- static inline u2 swap_u2_le(u2 x) { return x; }
- static inline u4 swap_u4_le(u4 x) { return x; }
- static inline u8 swap_u8_le(u8 x) { return x; }
-
static inline u2 get_native_u2(address p) { return *(u2*)p; }
static inline u4 get_native_u4(address p) { return *(u4*)p; }
static inline u8 get_native_u8(address p) { return *(u8*)p; }
@@ -55,7 +50,8 @@ class Bytes: AllStatic {
static inline void put_native_u4(address p, u4 x) { *(u4*)p = x; }
static inline void put_native_u8(address p, u8 x) { *(u8*)p = x; }
-#include "bytes_linux_s390.inline.hpp"
+ // The following header contains the implementations of swap_u2, swap_u4, and swap_u8.
+#include OS_CPU_HEADER_INLINE(bytes)
// Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering)
static inline u2 get_Java_u2(address p) { return get_native_u2(p); }
diff --git a/src/hotspot/cpu/s390/c1_globals_s390.hpp b/src/hotspot/cpu/s390/c1_globals_s390.hpp
index fac7d539f33..3869fb85342 100644
--- a/src/hotspot/cpu/s390/c1_globals_s390.hpp
+++ b/src/hotspot/cpu/s390/c1_globals_s390.hpp
@@ -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, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018 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
@@ -48,7 +48,7 @@ define_pd_global(bool, UseTLAB, true);
define_pd_global(bool, ProfileInterpreter, false);
define_pd_global(intx, FreqInlineSize, 325);
define_pd_global(bool, ResizeTLAB, true);
-define_pd_global(intx, ReservedCodeCacheSize, 32*M);
+define_pd_global(uintx, ReservedCodeCacheSize, 32*M);
define_pd_global(uintx, NonProfiledCodeHeapSize, 13*M);
define_pd_global(uintx, ProfiledCodeHeapSize, 14*M);
define_pd_global(uintx, NonNMethodCodeHeapSize, 5*M);
diff --git a/src/hotspot/cpu/s390/c2_globals_s390.hpp b/src/hotspot/cpu/s390/c2_globals_s390.hpp
index 86a1d102e21..7d944b9481b 100644
--- a/src/hotspot/cpu/s390/c2_globals_s390.hpp
+++ b/src/hotspot/cpu/s390/c2_globals_s390.hpp
@@ -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, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018 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
@@ -58,7 +58,7 @@ define_pd_global(intx, LoopUnrollLimit, 60);
define_pd_global(intx, LoopPercentProfileLimit, 10);
define_pd_global(intx, MinJumpTableSize, 18);
-// Peephole and CISC spilling both break the graph, and so makes the
+// Peephole and CISC spilling both break the graph, and so make the
// scheduler sick.
define_pd_global(bool, OptoPeephole, false);
define_pd_global(bool, UseCISCSpill, true);
diff --git a/src/hotspot/cpu/s390/globals_s390.hpp b/src/hotspot/cpu/s390/globals_s390.hpp
index a277d468ae5..2354e5ab045 100644
--- a/src/hotspot/cpu/s390/globals_s390.hpp
+++ b/src/hotspot/cpu/s390/globals_s390.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2017 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2018 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
@@ -87,7 +87,14 @@ define_pd_global(intx, InitArrayShortSize, 1*BytesPerLong);
define_pd_global(bool, ThreadLocalHandshakes, true);
-#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint, writeable) \
+#define ARCH_FLAGS(develop, \
+ product, \
+ diagnostic, \
+ experimental, \
+ notproduct, \
+ range, \
+ constraint, \
+ writeable) \
\
/* Reoptimize code-sequences of calls at runtime, e.g. replace an */ \
/* indirect call by a direct call. */ \
diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp
index 0f1e35b7b39..01358f5909d 100644
--- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp
@@ -2806,8 +2806,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;
@@ -2842,38 +2842,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");
}
diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp
index e542529cf5a..9e10d35e775 100644
--- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp
@@ -671,8 +671,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,
diff --git a/src/hotspot/cpu/s390/methodHandles_s390.cpp b/src/hotspot/cpu/s390/methodHandles_s390.cpp
index 8f7f8c769ea..fc86c820942 100644
--- a/src/hotspot/cpu/s390/methodHandles_s390.cpp
+++ b/src/hotspot/cpu/s390/methodHandles_s390.cpp
@@ -498,7 +498,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);
diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
index 9d9148689eb..f54ce47be10 100644
--- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
+++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
@@ -2660,9 +2660,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);
@@ -2691,7 +2691,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.
diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp
index a3cfc35e09e..41be97abf0e 100644
--- a/src/hotspot/cpu/s390/templateTable_s390.cpp
+++ b/src/hotspot/cpu/s390/templateTable_s390.cpp
@@ -3557,66 +3557,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...
@@ -3628,12 +3629,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();
@@ -3642,12 +3639,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();
diff --git a/src/hotspot/cpu/s390/vtableStubs_s390.cpp b/src/hotspot/cpu/s390/vtableStubs_s390.cpp
index de0a351ea04..513994d2e0d 100644
--- a/src/hotspot/cpu/s390/vtableStubs_s390.cpp
+++ b/src/hotspot/cpu/s390/vtableStubs_s390.cpp
@@ -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, Klass::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(Klass::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;
}
diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp
index e961840db88..bb8c3f8fa01 100644
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp
+++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp
@@ -2058,9 +2058,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;
@@ -2092,11 +2093,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) {
@@ -2131,12 +2134,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;
diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp
index e76d5953b3d..62beb5c390a 100644
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp
+++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp
@@ -1277,7 +1277,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,
diff --git a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp
index 2f257f5c5ca..d2583485d79 100644
--- a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp
+++ b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp
@@ -904,7 +904,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();
diff --git a/src/hotspot/cpu/sparc/templateTable_sparc.cpp b/src/hotspot/cpu/sparc/templateTable_sparc.cpp
index f478fac9383..c135a163633 100644
--- a/src/hotspot/cpu/sparc/templateTable_sparc.cpp
+++ b/src/hotspot/cpu/sparc/templateTable_sparc.cpp
@@ -3081,15 +3081,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());
@@ -3109,55 +3109,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.
{
@@ -3174,6 +3159,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) {
diff --git a/src/hotspot/cpu/sparc/vtableStubs_sparc.cpp b/src/hotspot/cpu/sparc/vtableStubs_sparc.cpp
index 3249b3a26f3..ff87ad081f5 100644
--- a/src/hotspot/cpu/sparc/vtableStubs_sparc.cpp
+++ b/src/hotspot/cpu/sparc/vtableStubs_sparc.cpp
@@ -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 = 34 * BytesPerInstWord +
+ const int basic = 54 * BytesPerInstWord +
// shift;add for load_klass (only shift with zero heap based)
(UseCompressedClassPointers ?
MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
index 112321cce78..fb24dc232b4 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
@@ -5809,8 +5809,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");
@@ -5827,9 +5832,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) {
@@ -5863,9 +5870,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));
+ }
}
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp
index 17799eec67b..61e29e9b092 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp
@@ -544,7 +544,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,
diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp
index afd3525e70f..8ee5c022d0a 100644
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp
@@ -957,7 +957,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
diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
index b02015a08c2..d3efcb5d394 100644
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
@@ -949,7 +949,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()));
diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp
index 306a0640c0c..6f4914d869e 100644
--- a/src/hotspot/cpu/x86/templateTable_x86.cpp
+++ b/src/hotspot/cpu/x86/templateTable_x86.cpp
@@ -3712,11 +3712,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
@@ -3738,10 +3738,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,
diff --git a/src/hotspot/cpu/x86/vtableStubs_x86_32.cpp b/src/hotspot/cpu/x86/vtableStubs_x86_32.cpp
index 3a5c7d0f38b..8de43afb375 100644
--- a/src/hotspot/cpu/x86/vtableStubs_x86_32.cpp
+++ b/src/hotspot/cpu/x86/vtableStubs_x86_32.cpp
@@ -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
diff --git a/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp b/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp
index 6c0a2fcb6af..f17330d26e9 100644
--- a/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp
+++ b/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp
@@ -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
diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp
index 0325824e021..b0a5435e3e7 100644
--- a/src/hotspot/os/aix/os_aix.cpp
+++ b/src/hotspot/os/aix/os_aix.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, 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.
*
@@ -1723,7 +1723,7 @@ void os::signal_notify(int sig) {
local_sem_post();
}
-static int check_pending_signals(bool wait) {
+static int check_pending_signals() {
Atomic::store(0, &sigint_count);
for (;;) {
for (int i = 0; i < NSIG + 1; i++) {
@@ -1732,9 +1732,6 @@ static int check_pending_signals(bool wait) {
return i;
}
}
- if (!wait) {
- return -1;
- }
JavaThread *thread = JavaThread::current();
ThreadBlockInVM tbivm(thread);
@@ -1763,12 +1760,8 @@ static int check_pending_signals(bool wait) {
}
}
-int os::signal_lookup() {
- return check_pending_signals(false);
-}
-
int os::signal_wait() {
- return check_pending_signals(true);
+ return check_pending_signals();
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
index 64afc14318c..b04d402f14f 100644
--- a/src/hotspot/os/bsd/os_bsd.cpp
+++ b/src/hotspot/os/bsd/os_bsd.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -52,13 +52,13 @@
#include "runtime/orderAccess.inline.hpp"
#include "runtime/osThread.hpp"
#include "runtime/perfMemory.hpp"
+#include "runtime/semaphore.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/timer.hpp"
-#include "semaphore_bsd.hpp"
#include "services/attachListener.hpp"
#include "services/memTracker.hpp"
#include "services/runtimeService.hpp"
@@ -91,7 +91,6 @@
# include
# include
# include
-# include
# include
# include
# include
@@ -1829,135 +1828,28 @@ int os::sigexitnum_pd() {
// a counter for each possible signal value
static volatile jint pending_signals[NSIG+1] = { 0 };
-
-// Bsd(POSIX) specific hand shaking semaphore.
-#ifdef __APPLE__
-typedef semaphore_t os_semaphore_t;
-
- #define SEM_INIT(sem, value) semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, value)
- #define SEM_WAIT(sem) semaphore_wait(sem)
- #define SEM_POST(sem) semaphore_signal(sem)
- #define SEM_DESTROY(sem) semaphore_destroy(mach_task_self(), sem)
-#else
-typedef sem_t os_semaphore_t;
-
- #define SEM_INIT(sem, value) sem_init(&sem, 0, value)
- #define SEM_WAIT(sem) sem_wait(&sem)
- #define SEM_POST(sem) sem_post(&sem)
- #define SEM_DESTROY(sem) sem_destroy(&sem)
-#endif
-
-#ifdef __APPLE__
-// OS X doesn't support unamed POSIX semaphores, so the implementation in os_posix.cpp can't be used.
-
-static const char* sem_init_strerror(kern_return_t value) {
- switch (value) {
- case KERN_INVALID_ARGUMENT: return "Invalid argument";
- case KERN_RESOURCE_SHORTAGE: return "Resource shortage";
- default: return "Unknown";
- }
-}
-
-OSXSemaphore::OSXSemaphore(uint value) {
- kern_return_t ret = SEM_INIT(_semaphore, value);
-
- guarantee(ret == KERN_SUCCESS, "Failed to create semaphore: %s", sem_init_strerror(ret));
-}
-
-OSXSemaphore::~OSXSemaphore() {
- SEM_DESTROY(_semaphore);
-}
-
-void OSXSemaphore::signal(uint count) {
- for (uint i = 0; i < count; i++) {
- kern_return_t ret = SEM_POST(_semaphore);
-
- assert(ret == KERN_SUCCESS, "Failed to signal semaphore");
- }
-}
-
-void OSXSemaphore::wait() {
- kern_return_t ret;
- while ((ret = SEM_WAIT(_semaphore)) == KERN_ABORTED) {
- // Semaphore was interrupted. Retry.
- }
- assert(ret == KERN_SUCCESS, "Failed to wait on semaphore");
-}
-
-jlong OSXSemaphore::currenttime() {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (tv.tv_sec * NANOSECS_PER_SEC) + (tv.tv_usec * 1000);
-}
-
-bool OSXSemaphore::trywait() {
- return timedwait(0, 0);
-}
-
-bool OSXSemaphore::timedwait(unsigned int sec, int nsec) {
- kern_return_t kr = KERN_ABORTED;
- mach_timespec_t waitspec;
- waitspec.tv_sec = sec;
- waitspec.tv_nsec = nsec;
-
- jlong starttime = currenttime();
-
- kr = semaphore_timedwait(_semaphore, waitspec);
- while (kr == KERN_ABORTED) {
- jlong totalwait = (sec * NANOSECS_PER_SEC) + nsec;
-
- jlong current = currenttime();
- jlong passedtime = current - starttime;
-
- if (passedtime >= totalwait) {
- waitspec.tv_sec = 0;
- waitspec.tv_nsec = 0;
- } else {
- jlong waittime = totalwait - (current - starttime);
- waitspec.tv_sec = waittime / NANOSECS_PER_SEC;
- waitspec.tv_nsec = waittime % NANOSECS_PER_SEC;
- }
-
- kr = semaphore_timedwait(_semaphore, waitspec);
- }
-
- return kr == KERN_SUCCESS;
-}
-
-#else
-// Use POSIX implementation of semaphores.
-
-struct timespec PosixSemaphore::create_timespec(unsigned int sec, int nsec) {
- struct timespec ts;
- unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec);
-
- return ts;
-}
-
-#endif // __APPLE__
-
-static os_semaphore_t sig_sem;
-
-#ifdef __APPLE__
-static OSXSemaphore sr_semaphore;
-#else
-static PosixSemaphore sr_semaphore;
-#endif
+static Semaphore* sig_sem = NULL;
void os::signal_init_pd() {
// Initialize signal structures
::memset((void*)pending_signals, 0, sizeof(pending_signals));
// Initialize signal semaphore
- ::SEM_INIT(sig_sem, 0);
+ sig_sem = new Semaphore();
}
void os::signal_notify(int sig) {
- Atomic::inc(&pending_signals[sig]);
- ::SEM_POST(sig_sem);
+ if (sig_sem != NULL) {
+ Atomic::inc(&pending_signals[sig]);
+ sig_sem->signal();
+ } else {
+ // Signal thread is not created with ReduceSignalUsage and signal_init_pd
+ // initialization isn't called.
+ assert(ReduceSignalUsage, "signal semaphore should be created");
+ }
}
-static int check_pending_signals(bool wait) {
+static int check_pending_signals() {
Atomic::store(0, &sigint_count);
for (;;) {
for (int i = 0; i < NSIG + 1; i++) {
@@ -1966,9 +1858,6 @@ static int check_pending_signals(bool wait) {
return i;
}
}
- if (!wait) {
- return -1;
- }
JavaThread *thread = JavaThread::current();
ThreadBlockInVM tbivm(thread);
@@ -1976,7 +1865,7 @@ static int check_pending_signals(bool wait) {
do {
thread->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
- ::SEM_WAIT(sig_sem);
+ sig_sem->wait();
// were we externally suspended while we were waiting?
threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
@@ -1985,7 +1874,7 @@ static int check_pending_signals(bool wait) {
// another thread suspended us. We don't want to continue running
// while suspended because that would surprise the thread that
// suspended us.
- ::SEM_POST(sig_sem);
+ sig_sem->signal();
thread->java_suspend_self();
}
@@ -1993,12 +1882,8 @@ static int check_pending_signals(bool wait) {
}
}
-int os::signal_lookup() {
- return check_pending_signals(false);
-}
-
int os::signal_wait() {
- return check_pending_signals(true);
+ return check_pending_signals();
}
////////////////////////////////////////////////////////////////////////////////
@@ -2663,6 +2548,12 @@ static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontex
//
// Currently only ever called on the VMThread or JavaThread
//
+#ifdef __APPLE__
+static OSXSemaphore sr_semaphore;
+#else
+static PosixSemaphore sr_semaphore;
+#endif
+
static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) {
// Save and restore errno to avoid confusing native code with EINTR
// after sigsuspend.
diff --git a/src/hotspot/os/bsd/semaphore_bsd.cpp b/src/hotspot/os/bsd/semaphore_bsd.cpp
new file mode 100644
index 00000000000..fb365911a7f
--- /dev/null
+++ b/src/hotspot/os/bsd/semaphore_bsd.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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/precompiled.hpp"
+#include "semaphore_bsd.hpp"
+#include "utilities/debug.hpp"
+
+#include
+
+#ifdef __APPLE__
+// OS X doesn't support unamed POSIX semaphores, so the implementation in os_posix.cpp can't be used.
+
+static const char* sem_init_strerror(kern_return_t value) {
+ switch (value) {
+ case KERN_INVALID_ARGUMENT: return "Invalid argument";
+ case KERN_RESOURCE_SHORTAGE: return "Resource shortage";
+ default: return "Unknown";
+ }
+}
+
+OSXSemaphore::OSXSemaphore(uint value) {
+ kern_return_t ret = semaphore_create(mach_task_self(), &_semaphore, SYNC_POLICY_FIFO, value);
+
+ guarantee(ret == KERN_SUCCESS, "Failed to create semaphore: %s", sem_init_strerror(ret));
+}
+
+OSXSemaphore::~OSXSemaphore() {
+ semaphore_destroy(mach_task_self(), _semaphore);
+}
+
+void OSXSemaphore::signal(uint count) {
+ for (uint i = 0; i < count; i++) {
+ kern_return_t ret = semaphore_signal(_semaphore);
+
+ assert(ret == KERN_SUCCESS, "Failed to signal semaphore");
+ }
+}
+
+void OSXSemaphore::wait() {
+ kern_return_t ret;
+ while ((ret = semaphore_wait(_semaphore)) == KERN_ABORTED) {
+ // Semaphore was interrupted. Retry.
+ }
+ assert(ret == KERN_SUCCESS, "Failed to wait on semaphore");
+}
+
+int64_t OSXSemaphore::currenttime() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec * NANOSECS_PER_SEC) + (tv.tv_usec * 1000);
+}
+
+bool OSXSemaphore::trywait() {
+ return timedwait(0, 0);
+}
+
+bool OSXSemaphore::timedwait(unsigned int sec, int nsec) {
+ kern_return_t kr = KERN_ABORTED;
+ mach_timespec_t waitspec;
+ waitspec.tv_sec = sec;
+ waitspec.tv_nsec = nsec;
+
+ int64_t starttime = currenttime();
+
+ kr = semaphore_timedwait(_semaphore, waitspec);
+ while (kr == KERN_ABORTED) {
+ int64_t totalwait = (sec * NANOSECS_PER_SEC) + nsec;
+
+ int64_t current = currenttime();
+ int64_t passedtime = current - starttime;
+
+ if (passedtime >= totalwait) {
+ waitspec.tv_sec = 0;
+ waitspec.tv_nsec = 0;
+ } else {
+ int64_t waittime = totalwait - (current - starttime);
+ waitspec.tv_sec = waittime / NANOSECS_PER_SEC;
+ waitspec.tv_nsec = waittime % NANOSECS_PER_SEC;
+ }
+
+ kr = semaphore_timedwait(_semaphore, waitspec);
+ }
+
+ return kr == KERN_SUCCESS;
+}
+#endif // __APPLE__
diff --git a/src/hotspot/os/bsd/semaphore_bsd.hpp b/src/hotspot/os/bsd/semaphore_bsd.hpp
index 9ee7dbe33ce..901d81eab0b 100644
--- a/src/hotspot/os/bsd/semaphore_bsd.hpp
+++ b/src/hotspot/os/bsd/semaphore_bsd.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -53,7 +53,7 @@ class OSXSemaphore : public CHeapObj{
bool timedwait(unsigned int sec, int nsec);
private:
- static jlong currenttime();
+ static int64_t currenttime();
};
typedef OSXSemaphore SemaphoreImpl;
diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
index a91fac1b9fe..6c64bd21626 100644
--- a/src/hotspot/os/linux/os_linux.cpp
+++ b/src/hotspot/os/linux/os_linux.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -95,7 +95,6 @@
# include
# include
# include
-# include
# include
# include
# include
@@ -2479,11 +2478,11 @@ void* os::user_handler() {
return CAST_FROM_FN_PTR(void*, UserHandler);
}
-struct timespec PosixSemaphore::create_timespec(unsigned int sec, int nsec) {
+static struct timespec create_semaphore_timespec(unsigned int sec, int nsec) {
struct timespec ts;
// Semaphore's are always associated with CLOCK_REALTIME
os::Linux::clock_gettime(CLOCK_REALTIME, &ts);
- // see unpackTime for discussion on overflow checking
+ // see os_posix.cpp for discussion on overflow checking
if (sec >= MAX_SECS) {
ts.tv_sec += MAX_SECS;
ts.tv_nsec = 0;
@@ -2535,7 +2534,7 @@ int os::sigexitnum_pd() {
static volatile jint pending_signals[NSIG+1] = { 0 };
// Linux(POSIX) specific hand shaking semaphore.
-static sem_t sig_sem;
+static Semaphore* sig_sem = NULL;
static PosixSemaphore sr_semaphore;
void os::signal_init_pd() {
@@ -2543,15 +2542,21 @@ void os::signal_init_pd() {
::memset((void*)pending_signals, 0, sizeof(pending_signals));
// Initialize signal semaphore
- ::sem_init(&sig_sem, 0, 0);
+ sig_sem = new Semaphore();
}
void os::signal_notify(int sig) {
- Atomic::inc(&pending_signals[sig]);
- ::sem_post(&sig_sem);
+ if (sig_sem != NULL) {
+ Atomic::inc(&pending_signals[sig]);
+ sig_sem->signal();
+ } else {
+ // Signal thread is not created with ReduceSignalUsage and signal_init_pd
+ // initialization isn't called.
+ assert(ReduceSignalUsage, "signal semaphore should be created");
+ }
}
-static int check_pending_signals(bool wait) {
+static int check_pending_signals() {
Atomic::store(0, &sigint_count);
for (;;) {
for (int i = 0; i < NSIG + 1; i++) {
@@ -2560,9 +2565,6 @@ static int check_pending_signals(bool wait) {
return i;
}
}
- if (!wait) {
- return -1;
- }
JavaThread *thread = JavaThread::current();
ThreadBlockInVM tbivm(thread);
@@ -2570,7 +2572,7 @@ static int check_pending_signals(bool wait) {
do {
thread->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
- ::sem_wait(&sig_sem);
+ sig_sem->wait();
// were we externally suspended while we were waiting?
threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
@@ -2579,7 +2581,7 @@ static int check_pending_signals(bool wait) {
// another thread suspended us. We don't want to continue running
// while suspended because that would surprise the thread that
// suspended us.
- ::sem_post(&sig_sem);
+ sig_sem->signal();
thread->java_suspend_self();
}
@@ -2587,12 +2589,8 @@ static int check_pending_signals(bool wait) {
}
}
-int os::signal_lookup() {
- return check_pending_signals(false);
-}
-
int os::signal_wait() {
- return check_pending_signals(true);
+ return check_pending_signals();
}
////////////////////////////////////////////////////////////////////////////////
@@ -4317,7 +4315,7 @@ static bool do_suspend(OSThread* osthread) {
// managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED
while (true) {
- if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) {
+ if (sr_semaphore.timedwait(create_semaphore_timespec(0, 2 * NANOSECS_PER_MILLISEC))) {
break;
} else {
// timeout
@@ -4351,7 +4349,7 @@ static void do_resume(OSThread* osthread) {
while (true) {
if (sr_notify(osthread) == 0) {
- if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) {
+ if (sr_semaphore.timedwait(create_semaphore_timespec(0, 2 * NANOSECS_PER_MILLISEC))) {
if (osthread->sr.is_running()) {
return;
}
diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp
index dcee2bd9359..1019b6b1277 100644
--- a/src/hotspot/os/posix/os_posix.cpp
+++ b/src/hotspot/os/posix/os_posix.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,14 +31,8 @@
#include "utilities/macros.hpp"
#include "utilities/vmError.hpp"
-#ifndef __APPLE__
-// POSIX unamed semaphores are not supported on OS X.
-#include "semaphore_posix.hpp"
-#endif
-
#include
#include
-#include
#include
#include
#include
@@ -1499,67 +1493,6 @@ void os::ThreadCrashProtection::check_crash_protection(int sig,
}
}
-// POSIX unamed semaphores are not supported on OS X.
-#ifndef __APPLE__
-
-PosixSemaphore::PosixSemaphore(uint value) {
- int ret = sem_init(&_semaphore, 0, value);
-
- guarantee_with_errno(ret == 0, "Failed to initialize semaphore");
-}
-
-PosixSemaphore::~PosixSemaphore() {
- sem_destroy(&_semaphore);
-}
-
-void PosixSemaphore::signal(uint count) {
- for (uint i = 0; i < count; i++) {
- int ret = sem_post(&_semaphore);
-
- assert_with_errno(ret == 0, "sem_post failed");
- }
-}
-
-void PosixSemaphore::wait() {
- int ret;
-
- do {
- ret = sem_wait(&_semaphore);
- } while (ret != 0 && errno == EINTR);
-
- assert_with_errno(ret == 0, "sem_wait failed");
-}
-
-bool PosixSemaphore::trywait() {
- int ret;
-
- do {
- ret = sem_trywait(&_semaphore);
- } while (ret != 0 && errno == EINTR);
-
- assert_with_errno(ret == 0 || errno == EAGAIN, "trywait failed");
-
- return ret == 0;
-}
-
-bool PosixSemaphore::timedwait(struct timespec ts) {
- while (true) {
- int result = sem_timedwait(&_semaphore, &ts);
- if (result == 0) {
- return true;
- } else if (errno == EINTR) {
- continue;
- } else if (errno == ETIMEDOUT) {
- return false;
- } else {
- assert_with_errno(false, "timedwait failed");
- return false;
- }
- }
-}
-
-#endif // __APPLE__
-
// Shared pthread_mutex/cond based PlatformEvent implementation.
// Not currently usable by Solaris.
diff --git a/src/hotspot/os/posix/semaphore_posix.cpp b/src/hotspot/os/posix/semaphore_posix.cpp
new file mode 100644
index 00000000000..6e02ea402f6
--- /dev/null
+++ b/src/hotspot/os/posix/semaphore_posix.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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/precompiled.hpp"
+#ifndef __APPLE__
+#include "runtime/os.hpp"
+// POSIX unamed semaphores are not supported on OS X.
+#include "semaphore_posix.hpp"
+#include
+
+#define check_with_errno(check_type, cond, msg) \
+ do { \
+ int err = errno; \
+ check_type(cond, "%s; error='%s' (errno=%s)", msg, os::strerror(err), \
+ os::errno_name(err)); \
+} while (false)
+
+#define assert_with_errno(cond, msg) check_with_errno(assert, cond, msg)
+#define guarantee_with_errno(cond, msg) check_with_errno(guarantee, cond, msg)
+
+PosixSemaphore::PosixSemaphore(uint value) {
+ int ret = sem_init(&_semaphore, 0, value);
+
+ guarantee_with_errno(ret == 0, "Failed to initialize semaphore");
+}
+
+PosixSemaphore::~PosixSemaphore() {
+ sem_destroy(&_semaphore);
+}
+
+void PosixSemaphore::signal(uint count) {
+ for (uint i = 0; i < count; i++) {
+ int ret = sem_post(&_semaphore);
+
+ assert_with_errno(ret == 0, "sem_post failed");
+ }
+}
+
+void PosixSemaphore::wait() {
+ int ret;
+
+ do {
+ ret = sem_wait(&_semaphore);
+ } while (ret != 0 && errno == EINTR);
+
+ assert_with_errno(ret == 0, "sem_wait failed");
+}
+
+bool PosixSemaphore::trywait() {
+ int ret;
+
+ do {
+ ret = sem_trywait(&_semaphore);
+ } while (ret != 0 && errno == EINTR);
+
+ assert_with_errno(ret == 0 || errno == EAGAIN, "trywait failed");
+
+ return ret == 0;
+}
+
+bool PosixSemaphore::timedwait(struct timespec ts) {
+ while (true) {
+ int result = sem_timedwait(&_semaphore, &ts);
+ if (result == 0) {
+ return true;
+ } else if (errno == EINTR) {
+ continue;
+ } else if (errno == ETIMEDOUT) {
+ return false;
+ } else {
+ assert_with_errno(false, "timedwait failed");
+ return false;
+ }
+ }
+}
+#endif // __APPLE__
+
diff --git a/src/hotspot/os/posix/semaphore_posix.hpp b/src/hotspot/os/posix/semaphore_posix.hpp
index 8d76bf1062e..1fda6741fe0 100644
--- a/src/hotspot/os/posix/semaphore_posix.hpp
+++ b/src/hotspot/os/posix/semaphore_posix.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,15 +45,7 @@ class PosixSemaphore : public CHeapObj {
void wait();
bool trywait();
- bool timedwait(unsigned int sec, int nsec) {
- return timedwait(create_timespec(sec, nsec));
- }
-
- private:
bool timedwait(struct timespec ts);
-
- // OS specific implementation to create a timespec suitable for semaphores.
- struct timespec create_timespec(unsigned int set, int nsec);
};
typedef PosixSemaphore SemaphoreImpl;
diff --git a/src/hotspot/os/solaris/os_solaris.cpp b/src/hotspot/os/solaris/os_solaris.cpp
index ef7c1deaea4..bb81998b34e 100644
--- a/src/hotspot/os/solaris/os_solaris.cpp
+++ b/src/hotspot/os/solaris/os_solaris.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2062,7 +2062,7 @@ void* os::user_handler() {
return CAST_FROM_FN_PTR(void*, UserHandler);
}
-struct timespec PosixSemaphore::create_timespec(unsigned int sec, int nsec) {
+static struct timespec create_semaphore_timespec(unsigned int sec, int nsec) {
struct timespec ts;
unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec);
@@ -2100,7 +2100,7 @@ static int Sigexit = 0;
static jint *pending_signals = NULL;
static int *preinstalled_sigs = NULL;
static struct sigaction *chainedsigactions = NULL;
-static sema_t sig_sem;
+static Semaphore* sig_sem = NULL;
typedef int (*version_getting_t)();
version_getting_t os::Solaris::get_libjsig_version = NULL;
@@ -2115,6 +2115,7 @@ void os::Solaris::init_signal_mem() {
Sigexit = Maxsignum+1;
assert(Maxsignum >0, "Unable to obtain max signal number");
+ // Initialize signal structures
// pending_signals has one int per signal
// The additional signal is for SIGEXIT - exit signal to signal_thread
pending_signals = (jint *)os::malloc(sizeof(jint) * (Sigexit+1), mtInternal);
@@ -2132,21 +2133,22 @@ void os::Solaris::init_signal_mem() {
}
void os::signal_init_pd() {
- int ret;
-
- ret = ::sema_init(&sig_sem, 0, NULL, NULL);
- assert(ret == 0, "sema_init() failed");
+ // Initialize signal semaphore
+ sig_sem = new Semaphore();
}
-void os::signal_notify(int signal_number) {
- int ret;
-
- Atomic::inc(&pending_signals[signal_number]);
- ret = ::sema_post(&sig_sem);
- assert(ret == 0, "sema_post() failed");
+void os::signal_notify(int sig) {
+ if (sig_sem != NULL) {
+ Atomic::inc(&pending_signals[sig]);
+ sig_sem->signal();
+ } else {
+ // Signal thread is not created with ReduceSignalUsage and signal_init_pd
+ // initialization isn't called.
+ assert(ReduceSignalUsage, "signal semaphore should be created");
+ }
}
-static int check_pending_signals(bool wait_for_signal) {
+static int check_pending_signals() {
int ret;
while (true) {
for (int i = 0; i < Sigexit + 1; i++) {
@@ -2155,19 +2157,13 @@ static int check_pending_signals(bool wait_for_signal) {
return i;
}
}
- if (!wait_for_signal) {
- return -1;
- }
JavaThread *thread = JavaThread::current();
ThreadBlockInVM tbivm(thread);
bool threadIsSuspended;
do {
thread->set_suspend_equivalent();
- // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
- while ((ret = ::sema_wait(&sig_sem)) == EINTR)
- ;
- assert(ret == 0, "sema_wait() failed");
+ sig_sem->wait();
// were we externally suspended while we were waiting?
threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
@@ -2176,8 +2172,7 @@ static int check_pending_signals(bool wait_for_signal) {
// another thread suspended us. We don't want to continue running
// while suspended because that would surprise the thread that
// suspended us.
- ret = ::sema_post(&sig_sem);
- assert(ret == 0, "sema_post() failed");
+ sig_sem->signal();
thread->java_suspend_self();
}
@@ -2185,12 +2180,8 @@ static int check_pending_signals(bool wait_for_signal) {
}
}
-int os::signal_lookup() {
- return check_pending_signals(false);
-}
-
int os::signal_wait() {
- return check_pending_signals(true);
+ return check_pending_signals();
}
////////////////////////////////////////////////////////////////////////////////
@@ -3599,7 +3590,7 @@ static bool do_suspend(OSThread* osthread) {
// managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED
while (true) {
- if (sr_semaphore.timedwait(0, 2000 * NANOSECS_PER_MILLISEC)) {
+ if (sr_semaphore.timedwait(create_semaphore_timespec(0, 2000 * NANOSECS_PER_MILLISEC))) {
break;
} else {
// timeout
@@ -3633,7 +3624,7 @@ static void do_resume(OSThread* osthread) {
while (true) {
if (sr_notify(osthread) == 0) {
- if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) {
+ if (sr_semaphore.timedwait(create_semaphore_timespec(0, 2 * NANOSECS_PER_MILLISEC))) {
if (osthread->sr.is_running()) {
return;
}
diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp
index 656a119d4d4..d4202ca878c 100644
--- a/src/hotspot/os/windows/os_windows.cpp
+++ b/src/hotspot/os/windows/os_windows.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -62,7 +62,6 @@
#include "runtime/threadCritical.hpp"
#include "runtime/timer.hpp"
#include "runtime/vm_version.hpp"
-#include "semaphore_windows.hpp"
#include "services/attachListener.hpp"
#include "services/memTracker.hpp"
#include "services/runtimeService.hpp"
@@ -1845,36 +1844,6 @@ int os::get_last_error() {
return (int)error;
}
-WindowsSemaphore::WindowsSemaphore(uint value) {
- _semaphore = ::CreateSemaphore(NULL, value, LONG_MAX, NULL);
-
- guarantee(_semaphore != NULL, "CreateSemaphore failed with error code: %lu", GetLastError());
-}
-
-WindowsSemaphore::~WindowsSemaphore() {
- ::CloseHandle(_semaphore);
-}
-
-void WindowsSemaphore::signal(uint count) {
- if (count > 0) {
- BOOL ret = ::ReleaseSemaphore(_semaphore, count, NULL);
-
- assert(ret != 0, "ReleaseSemaphore failed with error code: %lu", GetLastError());
- }
-}
-
-void WindowsSemaphore::wait() {
- DWORD ret = ::WaitForSingleObject(_semaphore, INFINITE);
- assert(ret != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError());
- assert(ret == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", ret);
-}
-
-bool WindowsSemaphore::trywait() {
- DWORD ret = ::WaitForSingleObject(_semaphore, 0);
- assert(ret != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError());
- return ret == WAIT_OBJECT_0;
-}
-
// sun.misc.Signal
// NOTE that this is a workaround for an apparent kernel bug where if
// a signal handler for SIGBREAK is installed then that signal handler
@@ -1966,13 +1935,14 @@ int os::sigexitnum_pd() {
// a counter for each possible signal value, including signal_thread exit signal
static volatile jint pending_signals[NSIG+1] = { 0 };
-static HANDLE sig_sem = NULL;
+static Semaphore* sig_sem = NULL;
void os::signal_init_pd() {
// Initialize signal structures
memset((void*)pending_signals, 0, sizeof(pending_signals));
- sig_sem = ::CreateSemaphore(NULL, 0, NSIG+1, NULL);
+ // Initialize signal semaphore
+ sig_sem = new Semaphore();
// Programs embedding the VM do not want it to attempt to receive
// events like CTRL_LOGOFF_EVENT, which are used to implement the
@@ -1994,17 +1964,18 @@ void os::signal_init_pd() {
}
}
-void os::signal_notify(int signal_number) {
- BOOL ret;
+void os::signal_notify(int sig) {
if (sig_sem != NULL) {
- Atomic::inc(&pending_signals[signal_number]);
- ret = ::ReleaseSemaphore(sig_sem, 1, NULL);
- assert(ret != 0, "ReleaseSemaphore() failed");
+ Atomic::inc(&pending_signals[sig]);
+ sig_sem->signal();
+ } else {
+ // Signal thread is not created with ReduceSignalUsage and signal_init_pd
+ // initialization isn't called.
+ assert(ReduceSignalUsage, "signal semaphore should be created");
}
}
-static int check_pending_signals(bool wait_for_signal) {
- DWORD ret;
+static int check_pending_signals() {
while (true) {
for (int i = 0; i < NSIG + 1; i++) {
jint n = pending_signals[i];
@@ -2012,10 +1983,6 @@ static int check_pending_signals(bool wait_for_signal) {
return i;
}
}
- if (!wait_for_signal) {
- return -1;
- }
-
JavaThread *thread = JavaThread::current();
ThreadBlockInVM tbivm(thread);
@@ -2024,8 +1991,7 @@ static int check_pending_signals(bool wait_for_signal) {
do {
thread->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
- ret = ::WaitForSingleObject(sig_sem, INFINITE);
- assert(ret == WAIT_OBJECT_0, "WaitForSingleObject() failed");
+ sig_sem->wait();
// were we externally suspended while we were waiting?
threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
@@ -2034,8 +2000,7 @@ static int check_pending_signals(bool wait_for_signal) {
// another thread suspended us. We don't want to continue running
// while suspended because that would surprise the thread that
// suspended us.
- ret = ::ReleaseSemaphore(sig_sem, 1, NULL);
- assert(ret != 0, "ReleaseSemaphore() failed");
+ sig_sem->signal();
thread->java_suspend_self();
}
@@ -2043,12 +2008,8 @@ static int check_pending_signals(bool wait_for_signal) {
}
}
-int os::signal_lookup() {
- return check_pending_signals(false);
-}
-
int os::signal_wait() {
- return check_pending_signals(true);
+ return check_pending_signals();
}
// Implicit OS exception handling
@@ -4394,13 +4355,49 @@ FILE* os::open(int fd, const char* mode) {
// Is a (classpath) directory empty?
bool os::dir_is_empty(const char* path) {
- WIN32_FIND_DATA fd;
- HANDLE f = FindFirstFile(path, &fd);
- if (f == INVALID_HANDLE_VALUE) {
- return true;
+ char* search_path = (char*)os::malloc(strlen(path) + 3, mtInternal);
+ if (search_path == NULL) {
+ errno = ENOMEM;
+ return false;
}
- FindClose(f);
- return false;
+ strcpy(search_path, path);
+ // Append "*", or possibly "\\*", to path
+ if (path[1] == ':' &&
+ (path[2] == '\0' ||
+ (path[2] == '\\' && path[3] == '\0'))) {
+ // No '\\' needed for cases like "Z:" or "Z:\"
+ strcat(search_path, "*");
+ }
+ else {
+ strcat(search_path, "\\*");
+ }
+ errno_t err = ERROR_SUCCESS;
+ wchar_t* wpath = create_unc_path(search_path, err);
+ if (err != ERROR_SUCCESS) {
+ if (wpath != NULL) {
+ destroy_unc_path(wpath);
+ }
+ os::free(search_path);
+ errno = err;
+ return false;
+ }
+ WIN32_FIND_DATAW fd;
+ HANDLE f = ::FindFirstFileW(wpath, &fd);
+ destroy_unc_path(wpath);
+ bool is_empty = true;
+ if (f != INVALID_HANDLE_VALUE) {
+ while (is_empty && ::FindNextFileW(f, &fd)) {
+ // An empty directory contains only the current directory file
+ // and the previous directory file.
+ if ((wcscmp(fd.cFileName, L".") != 0) &&
+ (wcscmp(fd.cFileName, L"..") != 0)) {
+ is_empty = false;
+ }
+ }
+ FindClose(f);
+ }
+ os::free(search_path);
+ return is_empty;
}
// create binary file, rewriting existing file if required
diff --git a/src/hotspot/os/windows/semaphore_windows.cpp b/src/hotspot/os/windows/semaphore_windows.cpp
new file mode 100644
index 00000000000..189184abd7b
--- /dev/null
+++ b/src/hotspot/os/windows/semaphore_windows.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 "semaphore_windows.hpp"
+#include "utilities/debug.hpp"
+
+#include
+#include
+
+WindowsSemaphore::WindowsSemaphore(uint value) {
+ _semaphore = ::CreateSemaphore(NULL, value, LONG_MAX, NULL);
+
+ guarantee(_semaphore != NULL, "CreateSemaphore failed with error code: %lu", GetLastError());
+}
+
+WindowsSemaphore::~WindowsSemaphore() {
+ ::CloseHandle(_semaphore);
+}
+
+void WindowsSemaphore::signal(uint count) {
+ if (count > 0) {
+ BOOL ret = ::ReleaseSemaphore(_semaphore, count, NULL);
+
+ assert(ret != 0, "ReleaseSemaphore failed with error code: %lu", GetLastError());
+ }
+}
+
+void WindowsSemaphore::wait() {
+ DWORD ret = ::WaitForSingleObject(_semaphore, INFINITE);
+ assert(ret != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError());
+ assert(ret == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", ret);
+}
+
+bool WindowsSemaphore::trywait() {
+ DWORD ret = ::WaitForSingleObject(_semaphore, 0);
+ assert(ret != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError());
+ return ret == WAIT_OBJECT_0;
+}
diff --git a/src/hotspot/share/aot/aotCompiledMethod.cpp b/src/hotspot/share/aot/aotCompiledMethod.cpp
index b04e04e0a86..b6a70ff1cbc 100644
--- a/src/hotspot/share/aot/aotCompiledMethod.cpp
+++ b/src/hotspot/share/aot/aotCompiledMethod.cpp
@@ -270,7 +270,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.
diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp
index 088078dd216..3368cc01048 100644
--- a/src/hotspot/share/ci/ciInstanceKlass.cpp
+++ b/src/hotspot/share/ci/ciInstanceKlass.cpp
@@ -34,35 +34,12 @@
#include "oops/oop.inline.hpp"
#include "oops/fieldStreams.hpp"
#include "runtime/fieldDescriptor.hpp"
-#if INCLUDE_ALL_GCS
-# include "gc/g1/g1SATBCardTableModRefBS.hpp"
-#endif
// ciInstanceKlass
//
// This class represents a Klass* in the HotSpot virtual machine
// whose Klass part in an InstanceKlass.
-// ------------------------------------------------------------------
-// ensure_metadata_alive
-//
-// Ensure that the metadata wrapped by the ciMetadata is kept alive by GC.
-// This is primarily useful for metadata which is considered as weak roots
-// by the GC but need to be strong roots if reachable from a current compilation.
-// InstanceKlass are created for both weak and strong metadata. Ensuring this metadata
-// alive covers the cases where there are weak roots without performance cost.
-//
-static void ensure_metadata_alive(oop metadata_holder) {
-#if INCLUDE_ALL_GCS
- if (!UseG1GC) {
- return;
- }
- if (metadata_holder != NULL) {
- G1SATBCardTableModRefBS::enqueue(metadata_holder);
- }
-#endif
-}
-
// ------------------------------------------------------------------
// ciInstanceKlass::ciInstanceKlass
@@ -88,8 +65,12 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
_has_injected_fields = -1;
_implementor = NULL; // we will fill these lazily
- oop holder = ik->klass_holder();
- ensure_metadata_alive(holder);
+ // Ensure that the metadata wrapped by the ciMetadata is kept alive by GC.
+ // This is primarily useful for metadata which is considered as weak roots
+ // by the GC but need to be strong roots if reachable from a current compilation.
+ // InstanceKlass are created for both weak and strong metadata. Ensuring this metadata
+ // alive covers the cases where there are weak roots without performance cost.
+ oop holder = ik->klass_holder_phantom();
if (ik->is_anonymous()) {
// Though ciInstanceKlass records class loader oop, it's not enough to keep
// VM anonymous classes alive (loader == NULL). Klass holder should be used instead.
diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp
index fd5c0632143..29801d2033b 100644
--- a/src/hotspot/share/classfile/classLoaderData.cpp
+++ b/src/hotspot/share/classfile/classLoaderData.cpp
@@ -63,6 +63,7 @@
#include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
+#include "oops/access.inline.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
@@ -75,9 +76,6 @@
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1SATBCardTableModRefBS.hpp"
-#endif // INCLUDE_ALL_GCS
#if INCLUDE_TRACE
#include "trace/tracing.hpp"
#endif
@@ -759,18 +757,9 @@ void ClassLoaderData::remove_handle(OopHandle h) {
oop* ptr = h.ptr_raw();
if (ptr != NULL) {
assert(_handles.contains(ptr), "Got unexpected handle " PTR_FORMAT, p2i(ptr));
-#if INCLUDE_ALL_GCS
- // This barrier is used by G1 to remember the old oop values, so
- // that we don't forget any objects that were live at the snapshot at
- // the beginning.
- if (UseG1GC) {
- oop obj = *ptr;
- if (obj != NULL) {
- G1SATBCardTableModRefBS::enqueue(obj);
- }
- }
-#endif
- *ptr = NULL;
+ // This root is not walked in safepoints, and hence requires an appropriate
+ // decorator that e.g. maintains the SATB invariant in SATB collectors.
+ RootAccess::oop_store(ptr, oop(NULL));
}
}
diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp
index 6437ecfed5d..41b9a3fa32c 100644
--- a/src/hotspot/share/classfile/classLoaderData.hpp
+++ b/src/hotspot/share/classfile/classLoaderData.hpp
@@ -217,6 +217,7 @@ class ClassLoaderData : public CHeapObj {
friend class ClassLoaderDataGraphKlassIteratorAtomic;
friend class ClassLoaderDataGraphKlassIteratorStatic;
friend class ClassLoaderDataGraphMetaspaceIterator;
+ friend class InstanceKlass;
friend class MetaDataFactory;
friend class Method;
diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp
index a1c7766d9ff..a7d1e39797a 100644
--- a/src/hotspot/share/classfile/javaClasses.cpp
+++ b/src/hotspot/share/classfile/javaClasses.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,8 @@
#include "code/dependencyContext.hpp"
#include "code/pcDesc.hpp"
#include "interpreter/interpreter.hpp"
+#include "logging/log.hpp"
+#include "logging/logStream.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp"
@@ -104,52 +106,59 @@ InjectedField* JavaClasses::get_injected(Symbol* class_name, int* field_count) {
}
-static bool find_field(InstanceKlass* ik,
- Symbol* name_symbol, Symbol* signature_symbol,
- fieldDescriptor* fd,
- bool is_static = false, bool allow_super = false) {
- if (allow_super || is_static) {
- return ik->find_field(name_symbol, signature_symbol, is_static, fd) != NULL;
- } else {
- return ik->find_local_field(name_symbol, signature_symbol, fd);
- }
-}
-
// Helpful routine for computing field offsets at run time rather than hardcoding them
-static void
-compute_offset(int &dest_offset,
- Klass* klass, Symbol* name_symbol, Symbol* signature_symbol,
- bool is_static = false, bool allow_super = false) {
+// Finds local fields only, including static fields. Static field offsets are from the
+// beginning of the mirror.
+static void compute_offset(int &dest_offset,
+ InstanceKlass* ik, Symbol* name_symbol, Symbol* signature_symbol,
+ bool is_static = false) {
fieldDescriptor fd;
- InstanceKlass* ik = InstanceKlass::cast(klass);
- if (!find_field(ik, name_symbol, signature_symbol, &fd, is_static, allow_super)) {
+ if (ik == NULL) {
ResourceMark rm;
- tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string());
+ log_error(class)("Mismatch JDK version for field: %s type: %s", name_symbol->as_C_string(), signature_symbol->as_C_string());
+ vm_exit_during_initialization("Invalid layout of preloaded class");
+ }
+
+ if (!ik->find_local_field(name_symbol, signature_symbol, &fd) || fd.is_static() != is_static) {
+ ResourceMark rm;
+ log_error(class)("Invalid layout of %s field: %s type: %s", ik->external_name(),
+ name_symbol->as_C_string(), signature_symbol->as_C_string());
#ifndef PRODUCT
- ik->print();
- tty->print_cr("all fields:");
- for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
- tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int());
- }
+ // Prints all fields and offsets
+ Log(class) lt;
+ LogStream ls(lt.error());
+ ik->print_on(&ls);
#endif //PRODUCT
vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:class+load=info to see the origin of the problem class");
}
dest_offset = fd.offset();
}
+// Overloading to pass name as a string.
+static void compute_offset(int& dest_offset, InstanceKlass* ik,
+ const char* name_string, Symbol* signature_symbol,
+ bool is_static = false) {
+ TempNewSymbol name = SymbolTable::probe(name_string, (int)strlen(name_string));
+ if (name == NULL) {
+ ResourceMark rm;
+ log_error(class)("Name %s should be in the SymbolTable since its class is loaded", name_string);
+ vm_exit_during_initialization("Invalid layout of preloaded class", ik->external_name());
+ }
+ compute_offset(dest_offset, ik, name, signature_symbol, is_static);
+}
+
// Same as above but for "optional" offsets that might not be present in certain JDK versions
+// Old versions should be cleaned out since Hotspot only supports the current JDK, and this
+// function should be removed.
static void
compute_optional_offset(int& dest_offset,
- Klass* klass, Symbol* name_symbol, Symbol* signature_symbol,
- bool allow_super = false) {
+ InstanceKlass* ik, Symbol* name_symbol, Symbol* signature_symbol) {
fieldDescriptor fd;
- InstanceKlass* ik = InstanceKlass::cast(klass);
- if (find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
+ if (ik->find_local_field(name_symbol, signature_symbol, &fd)) {
dest_offset = fd.offset();
}
}
-
int java_lang_String::value_offset = 0;
int java_lang_String::hash_offset = 0;
int java_lang_String::coder_offset = 0;
@@ -163,10 +172,10 @@ bool java_lang_String::is_instance(oop obj) {
void java_lang_String::compute_offsets() {
assert(!initialized, "offsets should be initialized only once");
- Klass* k = SystemDictionary::String_klass();
+ InstanceKlass* k = SystemDictionary::String_klass();
compute_offset(value_offset, k, vmSymbols::value_name(), vmSymbols::byte_array_signature());
- compute_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature());
- compute_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature());
+ compute_offset(hash_offset, k, "hash", vmSymbols::int_signature());
+ compute_offset(coder_offset, k, "coder", vmSymbols::byte_signature());
initialized = true;
}
@@ -619,12 +628,12 @@ char* java_lang_String::as_utf8_string(oop java_string, int start, int len, char
bool java_lang_String::equals(oop java_string, jchar* chars, int len) {
assert(java_string->klass() == SystemDictionary::String_klass(),
"must be java_string");
- typeArrayOop value = java_lang_String::value(java_string);
- int length = java_lang_String::length(java_string);
+ typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
+ int length = java_lang_String::length(java_string);
if (length != len) {
return false;
}
- bool is_latin1 = java_lang_String::is_latin1(java_string);
+ bool is_latin1 = java_lang_String::is_latin1(java_string);
if (!is_latin1) {
for (int i = 0; i < len; i++) {
if (value->char_at(i) != chars[i]) {
@@ -646,12 +655,12 @@ bool java_lang_String::equals(oop str1, oop str2) {
"must be java String");
assert(str2->klass() == SystemDictionary::String_klass(),
"must be java String");
- typeArrayOop value1 = java_lang_String::value(str1);
- int length1 = java_lang_String::length(str1);
- bool is_latin1 = java_lang_String::is_latin1(str1);
- typeArrayOop value2 = java_lang_String::value(str2);
- int length2 = java_lang_String::length(str2);
- bool is_latin2 = java_lang_String::is_latin1(str2);
+ typeArrayOop value1 = java_lang_String::value_no_keepalive(str1);
+ int length1 = java_lang_String::length(value1);
+ bool is_latin1 = java_lang_String::is_latin1(str1);
+ typeArrayOop value2 = java_lang_String::value_no_keepalive(str2);
+ int length2 = java_lang_String::length(value2);
+ bool is_latin2 = java_lang_String::is_latin1(str2);
if ((length1 != length2) || (is_latin1 != is_latin2)) {
// Strings of different size or with different
@@ -659,7 +668,7 @@ bool java_lang_String::equals(oop str1, oop str2) {
return false;
}
int blength1 = value1->length();
- for (int i = 0; i < value1->length(); i++) {
+ for (int i = 0; i < blength1; i++) {
if (value1->byte_at(i) != value2->byte_at(i)) {
return false;
}
@@ -669,7 +678,7 @@ bool java_lang_String::equals(oop str1, oop str2) {
void java_lang_String::print(oop java_string, outputStream* st) {
assert(java_string->klass() == SystemDictionary::String_klass(), "must be java_string");
- typeArrayOop value = java_lang_String::value(java_string);
+ typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
if (value == NULL) {
// This can happen if, e.g., printing a String
@@ -1161,25 +1170,11 @@ void java_lang_Class::compute_offsets() {
assert(!offsets_computed, "offsets should be initialized only once");
offsets_computed = true;
- Klass* k = SystemDictionary::Class_klass();
- // The classRedefinedCount field is only present starting in 1.5,
- // so don't go fatal.
- compute_optional_offset(classRedefinedCount_offset,
- k, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature());
-
- // Needs to be optional because the old build runs Queens during bootstrapping
- // and jdk8-9 doesn't have coordinated pushes yet.
- compute_optional_offset(_class_loader_offset,
- k, vmSymbols::classLoader_name(),
- vmSymbols::classloader_signature());
-
- compute_offset(_component_mirror_offset,
- k, vmSymbols::componentType_name(),
- vmSymbols::class_signature());
-
- compute_offset(_module_offset,
- k, vmSymbols::module_name(),
- vmSymbols::module_signature());
+ InstanceKlass* k = SystemDictionary::Class_klass();
+ compute_offset(classRedefinedCount_offset, k, "classRedefinedCount", vmSymbols::int_signature());
+ compute_offset(_class_loader_offset, k, "classLoader", vmSymbols::classloader_signature());
+ compute_offset(_component_mirror_offset, k, "componentType", vmSymbols::class_signature());
+ compute_offset(_module_offset, k, "module", vmSymbols::module_signature());
// Init lock is a C union with component_mirror. Only instanceKlass mirrors have
// init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops
@@ -1234,24 +1229,22 @@ int java_lang_Thread::_park_event_offset = 0 ;
void java_lang_Thread::compute_offsets() {
assert(_group_offset == 0, "offsets should be initialized only once");
- Klass* k = SystemDictionary::Thread_klass();
+ InstanceKlass* k = SystemDictionary::Thread_klass();
compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
compute_offset(_group_offset, k, vmSymbols::group_name(), vmSymbols::threadgroup_signature());
- compute_offset(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), vmSymbols::classloader_signature());
- compute_offset(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(), vmSymbols::accesscontrolcontext_signature());
+ compute_offset(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(),
+ vmSymbols::classloader_signature());
+ compute_offset(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(),
+ vmSymbols::accesscontrolcontext_signature());
compute_offset(_priority_offset, k, vmSymbols::priority_name(), vmSymbols::int_signature());
compute_offset(_daemon_offset, k, vmSymbols::daemon_name(), vmSymbols::bool_signature());
- compute_offset(_eetop_offset, k, vmSymbols::eetop_name(), vmSymbols::long_signature());
- compute_offset(_stillborn_offset, k, vmSymbols::stillborn_name(), vmSymbols::bool_signature());
- // The stackSize field is only present starting in 1.4, so don't go fatal.
- compute_optional_offset(_stackSize_offset, k, vmSymbols::stackSize_name(), vmSymbols::long_signature());
- // The tid and thread_status fields are only present starting in 1.5, so don't go fatal.
- compute_optional_offset(_tid_offset, k, vmSymbols::thread_id_name(), vmSymbols::long_signature());
- compute_optional_offset(_thread_status_offset, k, vmSymbols::thread_status_name(), vmSymbols::int_signature());
- // The parkBlocker field is only present starting in 1.6, so don't go fatal.
- compute_optional_offset(_park_blocker_offset, k, vmSymbols::park_blocker_name(), vmSymbols::object_signature());
- compute_optional_offset(_park_event_offset, k, vmSymbols::park_event_name(),
- vmSymbols::long_signature());
+ compute_offset(_eetop_offset, k, "eetop", vmSymbols::long_signature());
+ compute_offset(_stillborn_offset, k, "stillborn", vmSymbols::bool_signature());
+ compute_offset(_stackSize_offset, k, "stackSize", vmSymbols::long_signature());
+ compute_offset(_tid_offset, k, "tid", vmSymbols::long_signature());
+ compute_offset(_thread_status_offset, k, "threadStatus", vmSymbols::int_signature());
+ compute_offset(_park_blocker_offset, k, "parkBlocker", vmSymbols::object_signature());
+ compute_offset(_park_event_offset, k, "nativeParkEventPointer", vmSymbols::long_signature());
}
@@ -1486,7 +1479,7 @@ bool java_lang_ThreadGroup::is_daemon(oop java_thread_group) {
void java_lang_ThreadGroup::compute_offsets() {
assert(_parent_offset == 0, "offsets should be initialized only once");
- Klass* k = SystemDictionary::ThreadGroup_klass();
+ InstanceKlass* k = SystemDictionary::ThreadGroup_klass();
compute_offset(_parent_offset, k, vmSymbols::parent_name(), vmSymbols::threadgroup_signature());
compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
@@ -1501,8 +1494,13 @@ void java_lang_ThreadGroup::compute_offsets() {
void java_lang_Throwable::compute_offsets() {
- Klass* k = SystemDictionary::Throwable_klass();
- compute_offset(depth_offset, k, vmSymbols::depth_name(), vmSymbols::int_signature());
+ InstanceKlass* k = SystemDictionary::Throwable_klass();
+ compute_offset(backtrace_offset, k, "backtrace", vmSymbols::object_signature());
+ compute_offset(detailMessage_offset, k, "detailMessage", vmSymbols::string_signature());
+ compute_offset(stackTrace_offset, k, "stackTrace", vmSymbols::java_lang_StackTraceElement_array());
+ compute_offset(depth_offset, k, "depth", vmSymbols::int_signature());
+ compute_offset(static_unassigned_stacktrace_offset, k, "UNASSIGNED_STACK", vmSymbols::java_lang_StackTraceElement_array(),
+ /*is_static*/true);
}
oop java_lang_Throwable::unassigned_stacktrace() {
@@ -2270,23 +2268,23 @@ void java_lang_StackFrameInfo::to_stack_trace_element(Handle stackFrame, Handle
}
void java_lang_StackFrameInfo::compute_offsets() {
- Klass* k = SystemDictionary::StackFrameInfo_klass();
- compute_offset(_memberName_offset, k, vmSymbols::memberName_name(), vmSymbols::object_signature());
- compute_offset(_bci_offset, k, vmSymbols::bci_name(), vmSymbols::short_signature());
+ InstanceKlass* k = SystemDictionary::StackFrameInfo_klass();
+ compute_offset(_memberName_offset, k, "memberName", vmSymbols::object_signature());
+ compute_offset(_bci_offset, k, "bci", vmSymbols::short_signature());
STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}
void java_lang_LiveStackFrameInfo::compute_offsets() {
- Klass* k = SystemDictionary::LiveStackFrameInfo_klass();
- compute_offset(_monitors_offset, k, vmSymbols::monitors_name(), vmSymbols::object_array_signature());
- compute_offset(_locals_offset, k, vmSymbols::locals_name(), vmSymbols::object_array_signature());
- compute_offset(_operands_offset, k, vmSymbols::operands_name(), vmSymbols::object_array_signature());
- compute_offset(_mode_offset, k, vmSymbols::mode_name(), vmSymbols::int_signature());
+ InstanceKlass* k = SystemDictionary::LiveStackFrameInfo_klass();
+ compute_offset(_monitors_offset, k, "monitors", vmSymbols::object_array_signature());
+ compute_offset(_locals_offset, k, "locals", vmSymbols::object_array_signature());
+ compute_offset(_operands_offset, k, "operands", vmSymbols::object_array_signature());
+ compute_offset(_mode_offset, k, "mode", vmSymbols::int_signature());
}
void java_lang_reflect_AccessibleObject::compute_offsets() {
- Klass* k = SystemDictionary::reflect_AccessibleObject_klass();
- compute_offset(override_offset, k, vmSymbols::override_name(), vmSymbols::bool_signature());
+ InstanceKlass* k = SystemDictionary::reflect_AccessibleObject_klass();
+ compute_offset(override_offset, k, "override", vmSymbols::bool_signature());
}
jboolean java_lang_reflect_AccessibleObject::override(oop reflect) {
@@ -2300,7 +2298,7 @@ void java_lang_reflect_AccessibleObject::set_override(oop reflect, jboolean valu
}
void java_lang_reflect_Method::compute_offsets() {
- Klass* k = SystemDictionary::reflect_Method_klass();
+ InstanceKlass* k = SystemDictionary::reflect_Method_klass();
compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature());
compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
compute_offset(returnType_offset, k, vmSymbols::returnType_name(), vmSymbols::class_signature());
@@ -2481,7 +2479,7 @@ void java_lang_reflect_Method::set_type_annotations(oop method, oop value) {
}
void java_lang_reflect_Constructor::compute_offsets() {
- Klass* k = SystemDictionary::reflect_Constructor_klass();
+ InstanceKlass* k = SystemDictionary::reflect_Constructor_klass();
compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature());
compute_offset(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), vmSymbols::class_array_signature());
compute_offset(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), vmSymbols::class_array_signature());
@@ -2623,7 +2621,7 @@ void java_lang_reflect_Constructor::set_type_annotations(oop constructor, oop va
}
void java_lang_reflect_Field::compute_offsets() {
- Klass* k = SystemDictionary::reflect_Field_klass();
+ InstanceKlass* k = SystemDictionary::reflect_Field_klass();
compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature());
compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
compute_offset(type_offset, k, vmSymbols::type_name(), vmSymbols::class_signature());
@@ -2747,22 +2745,17 @@ void java_lang_reflect_Field::set_type_annotations(oop field, oop value) {
}
void reflect_ConstantPool::compute_offsets() {
- Klass* k = SystemDictionary::reflect_ConstantPool_klass();
- // This null test can be removed post beta
- if (k != NULL) {
- // The field is called ConstantPool* in the sun.reflect.ConstantPool class.
- compute_offset(_oop_offset, k, vmSymbols::ConstantPool_name(), vmSymbols::object_signature());
- }
+ InstanceKlass* k = SystemDictionary::reflect_ConstantPool_klass();
+ // The field is called ConstantPool* in the sun.reflect.ConstantPool class.
+ compute_offset(_oop_offset, k, "constantPoolOop", vmSymbols::object_signature());
}
void java_lang_reflect_Parameter::compute_offsets() {
- Klass* k = SystemDictionary::reflect_Parameter_klass();
- if(NULL != k) {
- compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
- compute_offset(modifiers_offset, k, vmSymbols::modifiers_name(), vmSymbols::int_signature());
- compute_offset(index_offset, k, vmSymbols::index_name(), vmSymbols::int_signature());
- compute_offset(executable_offset, k, vmSymbols::executable_name(), vmSymbols::executable_signature());
- }
+ InstanceKlass* k = SystemDictionary::reflect_Parameter_klass();
+ compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
+ compute_offset(modifiers_offset, k, vmSymbols::modifiers_name(), vmSymbols::int_signature());
+ compute_offset(index_offset, k, vmSymbols::index_name(), vmSymbols::int_signature());
+ compute_offset(executable_offset, k, vmSymbols::executable_name(), vmSymbols::executable_signature());
}
Handle java_lang_reflect_Parameter::create(TRAPS) {
@@ -2836,12 +2829,10 @@ Handle java_lang_Module::create(Handle loader, Handle module_name, TRAPS) {
}
void java_lang_Module::compute_offsets() {
- Klass* k = SystemDictionary::Module_klass();
- if(NULL != k) {
- compute_offset(loader_offset, k, vmSymbols::loader_name(), vmSymbols::classloader_signature());
- compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
- MODULE_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
- }
+ InstanceKlass* k = SystemDictionary::Module_klass();
+ compute_offset(loader_offset, k, vmSymbols::loader_name(), vmSymbols::classloader_signature());
+ compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
+ MODULE_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}
@@ -2921,12 +2912,8 @@ ConstantPool* reflect_ConstantPool::get_cp(oop reflect) {
}
void reflect_UnsafeStaticFieldAccessorImpl::compute_offsets() {
- Klass* k = SystemDictionary::reflect_UnsafeStaticFieldAccessorImpl_klass();
- // This null test can be removed post beta
- if (k != NULL) {
- compute_offset(_base_offset, k,
- vmSymbols::base_name(), vmSymbols::object_signature());
- }
+ InstanceKlass* k = SystemDictionary::reflect_UnsafeStaticFieldAccessorImpl_klass();
+ compute_offset(_base_offset, k, "base", vmSymbols::object_signature());
}
oop java_lang_boxing_object::initialize_and_allocate(BasicType type, TRAPS) {
@@ -3084,6 +3071,13 @@ bool java_lang_ref_Reference::is_referent_field(oop obj, ptrdiff_t offset) {
}
// Support for java_lang_ref_SoftReference
+//
+
+void java_lang_ref_SoftReference::compute_offsets() {
+ InstanceKlass* k = SystemDictionary::SoftReference_klass();
+ compute_offset(timestamp_offset, k, "timestamp", vmSymbols::long_signature());
+ compute_offset(static_clock_offset, k, "clock", vmSymbols::long_signature(), true);
+}
jlong java_lang_ref_SoftReference::timestamp(oop ref) {
return ref->long_field(timestamp_offset);
@@ -3113,10 +3107,8 @@ oop java_lang_invoke_DirectMethodHandle::member(oop dmh) {
}
void java_lang_invoke_DirectMethodHandle::compute_offsets() {
- Klass* k = SystemDictionary::DirectMethodHandle_klass();
- if (k != NULL) {
- compute_offset(_member_offset, k, vmSymbols::member_name(), vmSymbols::java_lang_invoke_MemberName_signature());
- }
+ InstanceKlass* k = SystemDictionary::DirectMethodHandle_klass();
+ compute_offset(_member_offset, k, "member", vmSymbols::java_lang_invoke_MemberName_signature());
}
// Support for java_lang_invoke_MethodHandle
@@ -3137,16 +3129,13 @@ int java_lang_invoke_ResolvedMethodName::_vmholder_offset;
int java_lang_invoke_LambdaForm::_vmentry_offset;
void java_lang_invoke_MethodHandle::compute_offsets() {
- Klass* k = SystemDictionary::MethodHandle_klass();
- if (k != NULL) {
- compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_lang_invoke_MethodType_signature());
- compute_offset(_form_offset, k, vmSymbols::form_name(), vmSymbols::java_lang_invoke_LambdaForm_signature());
- }
+ InstanceKlass* k = SystemDictionary::MethodHandle_klass();
+ compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_lang_invoke_MethodType_signature());
+ compute_offset(_form_offset, k, "form", vmSymbols::java_lang_invoke_LambdaForm_signature());
}
void java_lang_invoke_MemberName::compute_offsets() {
- Klass* k = SystemDictionary::MemberName_klass();
- assert (k != NULL, "jdk mismatch");
+ InstanceKlass* k = SystemDictionary::MemberName_klass();
compute_offset(_clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature());
compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::object_signature());
@@ -3156,15 +3145,15 @@ void java_lang_invoke_MemberName::compute_offsets() {
}
void java_lang_invoke_ResolvedMethodName::compute_offsets() {
- Klass* k = SystemDictionary::ResolvedMethodName_klass();
+ InstanceKlass* k = SystemDictionary::ResolvedMethodName_klass();
assert(k != NULL, "jdk mismatch");
RESOLVEDMETHOD_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}
void java_lang_invoke_LambdaForm::compute_offsets() {
- Klass* k = SystemDictionary::LambdaForm_klass();
+ InstanceKlass* k = SystemDictionary::LambdaForm_klass();
assert (k != NULL, "jdk mismatch");
- compute_offset(_vmentry_offset, k, vmSymbols::vmentry_name(), vmSymbols::java_lang_invoke_MemberName_signature());
+ compute_offset(_vmentry_offset, k, "vmentry", vmSymbols::java_lang_invoke_MemberName_signature());
}
bool java_lang_invoke_LambdaForm::is_instance(oop obj) {
@@ -3305,11 +3294,9 @@ int java_lang_invoke_MethodType::_rtype_offset;
int java_lang_invoke_MethodType::_ptypes_offset;
void java_lang_invoke_MethodType::compute_offsets() {
- Klass* k = SystemDictionary::MethodType_klass();
- if (k != NULL) {
- compute_offset(_rtype_offset, k, vmSymbols::rtype_name(), vmSymbols::class_signature());
- compute_offset(_ptypes_offset, k, vmSymbols::ptypes_name(), vmSymbols::class_array_signature());
- }
+ InstanceKlass* k = SystemDictionary::MethodType_klass();
+ compute_offset(_rtype_offset, k, "rtype", vmSymbols::class_signature());
+ compute_offset(_ptypes_offset, k, "ptypes", vmSymbols::class_array_signature());
}
void java_lang_invoke_MethodType::print_signature(oop mt, outputStream* st) {
@@ -3392,12 +3379,10 @@ int java_lang_invoke_CallSite::_target_offset;
int java_lang_invoke_CallSite::_context_offset;
void java_lang_invoke_CallSite::compute_offsets() {
- Klass* k = SystemDictionary::CallSite_klass();
- if (k != NULL) {
- compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_lang_invoke_MethodHandle_signature());
- compute_offset(_context_offset, k, vmSymbols::context_name(),
- vmSymbols::java_lang_invoke_MethodHandleNatives_CallSiteContext_signature());
- }
+ InstanceKlass* k = SystemDictionary::CallSite_klass();
+ compute_offset(_target_offset, k, "target", vmSymbols::java_lang_invoke_MethodHandle_signature());
+ compute_offset(_context_offset, k, "context",
+ vmSymbols::java_lang_invoke_MethodHandleNatives_CallSiteContext_signature());
}
oop java_lang_invoke_CallSite::context(oop call_site) {
@@ -3412,10 +3397,8 @@ oop java_lang_invoke_CallSite::context(oop call_site) {
int java_lang_invoke_MethodHandleNatives_CallSiteContext::_vmdependencies_offset;
void java_lang_invoke_MethodHandleNatives_CallSiteContext::compute_offsets() {
- Klass* k = SystemDictionary::Context_klass();
- if (k != NULL) {
- CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
- }
+ InstanceKlass* k = SystemDictionary::Context_klass();
+ CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}
DependencyContext java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) {
@@ -3434,28 +3417,12 @@ int java_security_AccessControlContext::_isAuthorized_offset = -1;
void java_security_AccessControlContext::compute_offsets() {
assert(_isPrivileged_offset == 0, "offsets should be initialized only once");
- fieldDescriptor fd;
- InstanceKlass* ik = SystemDictionary::AccessControlContext_klass();
+ InstanceKlass* k = SystemDictionary::AccessControlContext_klass();
- if (!ik->find_local_field(vmSymbols::context_name(), vmSymbols::protectiondomain_signature(), &fd)) {
- fatal("Invalid layout of java.security.AccessControlContext");
- }
- _context_offset = fd.offset();
-
- if (!ik->find_local_field(vmSymbols::privilegedContext_name(), vmSymbols::accesscontrolcontext_signature(), &fd)) {
- fatal("Invalid layout of java.security.AccessControlContext");
- }
- _privilegedContext_offset = fd.offset();
-
- if (!ik->find_local_field(vmSymbols::isPrivileged_name(), vmSymbols::bool_signature(), &fd)) {
- fatal("Invalid layout of java.security.AccessControlContext");
- }
- _isPrivileged_offset = fd.offset();
-
- // The offset may not be present for bootstrapping with older JDK.
- if (ik->find_local_field(vmSymbols::isAuthorized_name(), vmSymbols::bool_signature(), &fd)) {
- _isAuthorized_offset = fd.offset();
- }
+ compute_offset(_context_offset, k, "context", vmSymbols::protectiondomain_signature());
+ compute_offset(_privilegedContext_offset, k, "privilegedContext", vmSymbols::accesscontrolcontext_signature());
+ compute_offset(_isPrivileged_offset, k, "isPrivileged", vmSymbols::bool_signature());
+ compute_offset(_isAuthorized_offset, k, "isAuthorized", vmSymbols::bool_signature());
}
@@ -3504,16 +3471,17 @@ void java_lang_ClassLoader::compute_offsets() {
assert(!offsets_computed, "offsets should be initialized only once");
offsets_computed = true;
- // The field indicating parallelCapable (parallelLockMap) is only present starting in 7,
- Klass* k1 = SystemDictionary::ClassLoader_klass();
- compute_optional_offset(parallelCapable_offset,
- k1, vmSymbols::parallelCapable_name(), vmSymbols::concurrenthashmap_signature());
+ InstanceKlass* k1 = SystemDictionary::ClassLoader_klass();
+ compute_offset(parallelCapable_offset,
+ k1, "parallelLockMap", vmSymbols::concurrenthashmap_signature());
compute_offset(name_offset,
k1, vmSymbols::name_name(), vmSymbols::string_signature());
compute_offset(unnamedModule_offset,
- k1, vmSymbols::unnamedModule_name(), vmSymbols::module_signature());
+ k1, "unnamedModule", vmSymbols::module_signature());
+
+ compute_offset(parent_offset, k1, "parent", vmSymbols::classloader_signature());
CLASSLOADER_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}
@@ -3600,19 +3568,18 @@ oop java_lang_ClassLoader::unnamedModule(oop loader) {
}
// Support for java_lang_System
-int java_lang_System::in_offset_in_bytes() {
- return (InstanceMirrorKlass::offset_of_static_fields() + static_in_offset);
+//
+void java_lang_System::compute_offsets() {
+ InstanceKlass* k = SystemDictionary::System_klass();
+ compute_offset(static_in_offset, k, "in", vmSymbols::input_stream_signature(), true);
+ compute_offset(static_out_offset, k, "out", vmSymbols::print_stream_signature(), true);
+ compute_offset(static_err_offset, k, "err", vmSymbols::print_stream_signature(), true);
+ compute_offset(static_security_offset, k, "security", vmSymbols::security_manager_signature(), true);
}
-
-int java_lang_System::out_offset_in_bytes() {
- return (InstanceMirrorKlass::offset_of_static_fields() + static_out_offset);
-}
-
-
-int java_lang_System::err_offset_in_bytes() {
- return (InstanceMirrorKlass::offset_of_static_fields() + static_err_offset);
-}
+int java_lang_System::in_offset_in_bytes() { return static_in_offset; }
+int java_lang_System::out_offset_in_bytes() { return static_out_offset; }
+int java_lang_System::err_offset_in_bytes() { return static_err_offset; }
bool java_lang_System::has_security_manager() {
@@ -3682,7 +3649,6 @@ int java_lang_ref_Reference::referent_offset;
int java_lang_ref_Reference::queue_offset;
int java_lang_ref_Reference::next_offset;
int java_lang_ref_Reference::discovered_offset;
-int java_lang_ref_Reference::number_of_fake_oop_fields;
int java_lang_ref_SoftReference::timestamp_offset;
int java_lang_ref_SoftReference::static_clock_offset;
int java_lang_ClassLoader::parent_offset;
@@ -3717,6 +3683,17 @@ int reflect_UnsafeStaticFieldAccessorImpl::_base_offset;
// Support for java_lang_StackTraceElement
+void java_lang_StackTraceElement::compute_offsets() {
+ InstanceKlass* k = SystemDictionary::StackTraceElement_klass();
+ compute_offset(declaringClassObject_offset, k, "declaringClassObject", vmSymbols::class_signature());
+ compute_offset(classLoaderName_offset, k, "classLoaderName", vmSymbols::string_signature());
+ compute_offset(moduleName_offset, k, "moduleName", vmSymbols::string_signature());
+ compute_offset(moduleVersion_offset, k, "moduleVersion", vmSymbols::string_signature());
+ compute_offset(declaringClass_offset, k, "declaringClass", vmSymbols::string_signature());
+ compute_offset(methodName_offset, k, "methodName", vmSymbols::string_signature());
+ compute_offset(fileName_offset, k, "fileName", vmSymbols::string_signature());
+ compute_offset(lineNumber_offset, k, "lineNumber", vmSymbols::int_signature());
+}
void java_lang_StackTraceElement::set_fileName(oop element, oop value) {
element->obj_field_put(fileName_offset, value);
@@ -3776,6 +3753,16 @@ void java_lang_LiveStackFrameInfo::set_mode(oop element, int value) {
// Support for java Assertions - java_lang_AssertionStatusDirectives.
+void java_lang_AssertionStatusDirectives::compute_offsets() {
+ InstanceKlass* k = SystemDictionary::AssertionStatusDirectives_klass();
+ compute_offset(classes_offset, k, "classes", vmSymbols::string_array_signature());
+ compute_offset(classEnabled_offset, k, "classEnabled", vmSymbols::bool_array_signature());
+ compute_offset(packages_offset, k, "packages", vmSymbols::string_array_signature());
+ compute_offset(packageEnabled_offset, k, "packageEnabled", vmSymbols::bool_array_signature());
+ compute_offset(deflt_offset, k, "deflt", vmSymbols::bool_signature());
+}
+
+
void java_lang_AssertionStatusDirectives::set_classes(oop o, oop val) {
o->obj_field_put(classes_offset, val);
}
@@ -3804,18 +3791,18 @@ int java_nio_Buffer::limit_offset() {
void java_nio_Buffer::compute_offsets() {
- Klass* k = SystemDictionary::nio_Buffer_klass();
+ InstanceKlass* k = SystemDictionary::nio_Buffer_klass();
assert(k != NULL, "must be loaded in 1.4+");
- compute_offset(_limit_offset, k, vmSymbols::limit_name(), vmSymbols::int_signature());
+ compute_offset(_limit_offset, k, "limit", vmSymbols::int_signature());
}
void java_util_concurrent_locks_AbstractOwnableSynchronizer::initialize(TRAPS) {
if (_owner_offset != 0) return;
SystemDictionary::load_abstract_ownable_synchronizer_klass(CHECK);
- Klass* k = SystemDictionary::abstract_ownable_synchronizer_klass();
+ InstanceKlass* k = SystemDictionary::abstract_ownable_synchronizer_klass();
compute_offset(_owner_offset, k,
- vmSymbols::exclusive_owner_thread_name(), vmSymbols::thread_signature());
+ "exclusiveOwnerThread", vmSymbols::thread_signature());
}
oop java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(oop obj) {
@@ -3823,71 +3810,37 @@ oop java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(
return obj->obj_field(_owner_offset);
}
+static int member_offset(int hardcoded_offset) {
+ return (hardcoded_offset * heapOopSize) + instanceOopDesc::base_offset_in_bytes();
+}
+
// Compute hard-coded offsets
// Invoked before SystemDictionary::initialize, so pre-loaded classes
// are not available to determine the offset_of_static_fields.
void JavaClasses::compute_hard_coded_offsets() {
- const int x = heapOopSize;
- const int header = instanceOopDesc::base_offset_in_bytes();
-
- // Throwable Class
- java_lang_Throwable::backtrace_offset = java_lang_Throwable::hc_backtrace_offset * x + header;
- java_lang_Throwable::detailMessage_offset = java_lang_Throwable::hc_detailMessage_offset * x + header;
- java_lang_Throwable::stackTrace_offset = java_lang_Throwable::hc_stackTrace_offset * x + header;
- java_lang_Throwable::static_unassigned_stacktrace_offset = java_lang_Throwable::hc_static_unassigned_stacktrace_offset * x;
// java_lang_boxing_object
- java_lang_boxing_object::value_offset = java_lang_boxing_object::hc_value_offset + header;
- java_lang_boxing_object::long_value_offset = align_up((java_lang_boxing_object::hc_value_offset + header), BytesPerLong);
-
- // java_lang_ref_Reference:
- java_lang_ref_Reference::referent_offset = java_lang_ref_Reference::hc_referent_offset * x + header;
- java_lang_ref_Reference::queue_offset = java_lang_ref_Reference::hc_queue_offset * x + header;
- java_lang_ref_Reference::next_offset = java_lang_ref_Reference::hc_next_offset * x + header;
- java_lang_ref_Reference::discovered_offset = java_lang_ref_Reference::hc_discovered_offset * x + header;
- // Artificial fields for java_lang_ref_Reference
- // The first field is for the discovered field added in 1.4
- java_lang_ref_Reference::number_of_fake_oop_fields = 1;
-
- // java_lang_ref_SoftReference Class
- java_lang_ref_SoftReference::timestamp_offset = align_up((java_lang_ref_SoftReference::hc_timestamp_offset * x + header), BytesPerLong);
- // Don't multiply static fields because they are always in wordSize units
- java_lang_ref_SoftReference::static_clock_offset = java_lang_ref_SoftReference::hc_static_clock_offset * x;
-
- // java_lang_ClassLoader
- java_lang_ClassLoader::parent_offset = java_lang_ClassLoader::hc_parent_offset * x + header;
-
- // java_lang_System
- java_lang_System::static_in_offset = java_lang_System::hc_static_in_offset * x;
- java_lang_System::static_out_offset = java_lang_System::hc_static_out_offset * x;
- java_lang_System::static_err_offset = java_lang_System::hc_static_err_offset * x;
- java_lang_System::static_security_offset = java_lang_System::hc_static_security_offset * x;
-
- // java_lang_StackTraceElement
- java_lang_StackTraceElement::declaringClassObject_offset = java_lang_StackTraceElement::hc_declaringClassObject_offset * x + header;
- java_lang_StackTraceElement::classLoaderName_offset = java_lang_StackTraceElement::hc_classLoaderName_offset * x + header;
- java_lang_StackTraceElement::moduleName_offset = java_lang_StackTraceElement::hc_moduleName_offset * x + header;
- java_lang_StackTraceElement::moduleVersion_offset = java_lang_StackTraceElement::hc_moduleVersion_offset * x + header;
- java_lang_StackTraceElement::declaringClass_offset = java_lang_StackTraceElement::hc_declaringClass_offset * x + header;
- java_lang_StackTraceElement::methodName_offset = java_lang_StackTraceElement::hc_methodName_offset * x + header;
- java_lang_StackTraceElement::fileName_offset = java_lang_StackTraceElement::hc_fileName_offset * x + header;
- java_lang_StackTraceElement::lineNumber_offset = java_lang_StackTraceElement::hc_lineNumber_offset * x + header;
- java_lang_AssertionStatusDirectives::classes_offset = java_lang_AssertionStatusDirectives::hc_classes_offset * x + header;
- java_lang_AssertionStatusDirectives::classEnabled_offset = java_lang_AssertionStatusDirectives::hc_classEnabled_offset * x + header;
- java_lang_AssertionStatusDirectives::packages_offset = java_lang_AssertionStatusDirectives::hc_packages_offset * x + header;
- java_lang_AssertionStatusDirectives::packageEnabled_offset = java_lang_AssertionStatusDirectives::hc_packageEnabled_offset * x + header;
- java_lang_AssertionStatusDirectives::deflt_offset = java_lang_AssertionStatusDirectives::hc_deflt_offset * x + header;
+ java_lang_boxing_object::value_offset = member_offset(java_lang_boxing_object::hc_value_offset);
+ java_lang_boxing_object::long_value_offset = align_up(member_offset(java_lang_boxing_object::hc_value_offset), BytesPerLong);
+ // java_lang_ref_Reference
+ java_lang_ref_Reference::referent_offset = member_offset(java_lang_ref_Reference::hc_referent_offset);
+ java_lang_ref_Reference::queue_offset = member_offset(java_lang_ref_Reference::hc_queue_offset);
+ java_lang_ref_Reference::next_offset = member_offset(java_lang_ref_Reference::hc_next_offset);
+ java_lang_ref_Reference::discovered_offset = member_offset(java_lang_ref_Reference::hc_discovered_offset);
}
// Compute non-hard-coded field offsets of all the classes in this file
void JavaClasses::compute_offsets() {
// java_lang_Class::compute_offsets was called earlier in bootstrap
+ java_lang_System::compute_offsets();
java_lang_ClassLoader::compute_offsets();
java_lang_Throwable::compute_offsets();
java_lang_Thread::compute_offsets();
java_lang_ThreadGroup::compute_offsets();
+ java_lang_AssertionStatusDirectives::compute_offsets();
+ java_lang_ref_SoftReference::compute_offsets();
java_lang_invoke_MethodHandle::compute_offsets();
java_lang_invoke_DirectMethodHandle::compute_offsets();
java_lang_invoke_MemberName::compute_offsets();
@@ -3910,6 +3863,7 @@ void JavaClasses::compute_offsets() {
reflect_UnsafeStaticFieldAccessorImpl::compute_offsets();
java_lang_reflect_Parameter::compute_offsets();
java_lang_Module::compute_offsets();
+ java_lang_StackTraceElement::compute_offsets();
java_lang_StackFrameInfo::compute_offsets();
java_lang_LiveStackFrameInfo::compute_offsets();
@@ -3947,62 +3901,6 @@ bool JavaClasses::check_offset(const char *klass_name, int hardcoded_offset, con
}
}
-
-bool JavaClasses::check_static_offset(const char *klass_name, int hardcoded_offset, const char *field_name, const char* field_sig) {
- EXCEPTION_MARK;
- fieldDescriptor fd;
- TempNewSymbol klass_sym = SymbolTable::new_symbol(klass_name, CATCH);
- Klass* k = SystemDictionary::resolve_or_fail(klass_sym, true, CATCH);
- InstanceKlass* ik = InstanceKlass::cast(k);
- TempNewSymbol f_name = SymbolTable::new_symbol(field_name, CATCH);
- TempNewSymbol f_sig = SymbolTable::new_symbol(field_sig, CATCH);
- if (!ik->find_local_field(f_name, f_sig, &fd)) {
- tty->print_cr("Static field %s.%s not found", klass_name, field_name);
- return false;
- }
- if (!fd.is_static()) {
- tty->print_cr("Static field %s.%s appears to be nonstatic", klass_name, field_name);
- return false;
- }
- if (fd.offset() == hardcoded_offset + InstanceMirrorKlass::offset_of_static_fields()) {
- return true;
- } else {
- tty->print_cr("Offset of static field %s.%s is hardcoded as %d but should really be %d.", klass_name, field_name, hardcoded_offset, fd.offset() - InstanceMirrorKlass::offset_of_static_fields());
- return false;
- }
-}
-
-
-bool JavaClasses::check_constant(const char *klass_name, int hardcoded_constant, const char *field_name, const char* field_sig) {
- EXCEPTION_MARK;
- fieldDescriptor fd;
- TempNewSymbol klass_sym = SymbolTable::new_symbol(klass_name, CATCH);
- Klass* k = SystemDictionary::resolve_or_fail(klass_sym, true, CATCH);
- InstanceKlass* ik = InstanceKlass::cast(k);
- TempNewSymbol f_name = SymbolTable::new_symbol(field_name, CATCH);
- TempNewSymbol f_sig = SymbolTable::new_symbol(field_sig, CATCH);
- if (!ik->find_local_field(f_name, f_sig, &fd)) {
- tty->print_cr("Static field %s.%s not found", klass_name, field_name);
- return false;
- }
- if (!fd.is_static() || !fd.has_initial_value()) {
- tty->print_cr("Static field %s.%s appears to be non-constant", klass_name, field_name);
- return false;
- }
- if (!fd.initial_value_tag().is_int()) {
- tty->print_cr("Static field %s.%s is not an int", klass_name, field_name);
- return false;
- }
- jint field_value = fd.int_initial_value();
- if (field_value == hardcoded_constant) {
- return true;
- } else {
- tty->print_cr("Constant value of static field %s.%s is hardcoded as %d but should really be %d.", klass_name, field_name, hardcoded_constant, field_value);
- return false;
- }
-}
-
-
// Check the hard-coded field offsets of all the classes in this file
void JavaClasses::check_offsets() {
@@ -4014,31 +3912,6 @@ void JavaClasses::check_offsets() {
#define CHECK_LONG_OFFSET(klass_name, cpp_klass_name, field_name, field_sig) \
valid &= check_offset(klass_name, cpp_klass_name :: long_ ## field_name ## _offset, #field_name, field_sig)
-#define CHECK_STATIC_OFFSET(klass_name, cpp_klass_name, field_name, field_sig) \
- valid &= check_static_offset(klass_name, cpp_klass_name :: static_ ## field_name ## _offset, #field_name, field_sig)
-
-#define CHECK_CONSTANT(klass_name, cpp_klass_name, field_name, field_sig) \
- valid &= check_constant(klass_name, cpp_klass_name :: field_name, #field_name, field_sig)
-
- // java.lang.String
-
- CHECK_OFFSET("java/lang/String", java_lang_String, value, "[B");
- CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I");
- CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B");
-
- // java.lang.Class
-
- // Fake fields
- // CHECK_OFFSET("java/lang/Class", java_lang_Class, klass); // %%% this needs to be checked
- // CHECK_OFFSET("java/lang/Class", java_lang_Class, array_klass); // %%% this needs to be checked
-
- // java.lang.Throwable
-
- CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, backtrace, "Ljava/lang/Object;");
- CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, detailMessage, "Ljava/lang/String;");
- CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, stackTrace, "[Ljava/lang/StackTraceElement;");
- CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, depth, "I");
-
// Boxed primitive objects (java_lang_boxing_object)
CHECK_OFFSET("java/lang/Boolean", java_lang_boxing_object, value, "Z");
@@ -4050,28 +3923,6 @@ void JavaClasses::check_offsets() {
CHECK_OFFSET("java/lang/Integer", java_lang_boxing_object, value, "I");
CHECK_LONG_OFFSET("java/lang/Long", java_lang_boxing_object, value, "J");
- // java.lang.ClassLoader
-
- CHECK_OFFSET("java/lang/ClassLoader", java_lang_ClassLoader, parent, "Ljava/lang/ClassLoader;");
-
- // java.lang.System
-
- CHECK_STATIC_OFFSET("java/lang/System", java_lang_System, in, "Ljava/io/InputStream;");
- CHECK_STATIC_OFFSET("java/lang/System", java_lang_System, out, "Ljava/io/PrintStream;");
- CHECK_STATIC_OFFSET("java/lang/System", java_lang_System, err, "Ljava/io/PrintStream;");
- CHECK_STATIC_OFFSET("java/lang/System", java_lang_System, security, "Ljava/lang/SecurityManager;");
-
- // java.lang.StackTraceElement
-
- CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, declaringClassObject, "Ljava/lang/Class;");
- CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, classLoaderName, "Ljava/lang/String;");
- CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, moduleName, "Ljava/lang/String;");
- CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, moduleVersion, "Ljava/lang/String;");
- CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, declaringClass, "Ljava/lang/String;");
- CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, methodName, "Ljava/lang/String;");
- CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, fileName, "Ljava/lang/String;");
- CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, lineNumber, "I");
-
// java.lang.ref.Reference
CHECK_OFFSET("java/lang/ref/Reference", java_lang_ref_Reference, referent, "Ljava/lang/Object;");
@@ -4080,28 +3931,6 @@ void JavaClasses::check_offsets() {
// Fake field
//CHECK_OFFSET("java/lang/ref/Reference", java_lang_ref_Reference, discovered, "Ljava/lang/ref/Reference;");
- // java.lang.ref.SoftReference
-
- CHECK_OFFSET("java/lang/ref/SoftReference", java_lang_ref_SoftReference, timestamp, "J");
- CHECK_STATIC_OFFSET("java/lang/ref/SoftReference", java_lang_ref_SoftReference, clock, "J");
-
- // java.lang.AssertionStatusDirectives
- //
- // The CheckAssertionStatusDirectives boolean can be removed from here and
- // globals.hpp after the AssertionStatusDirectives class has been integrated
- // into merlin "for some time." Without it, the vm will fail with early
- // merlin builds.
-
- if (CheckAssertionStatusDirectives) {
- const char* nm = "java/lang/AssertionStatusDirectives";
- const char* sig = "[Ljava/lang/String;";
- CHECK_OFFSET(nm, java_lang_AssertionStatusDirectives, classes, sig);
- CHECK_OFFSET(nm, java_lang_AssertionStatusDirectives, classEnabled, "[Z");
- CHECK_OFFSET(nm, java_lang_AssertionStatusDirectives, packages, sig);
- CHECK_OFFSET(nm, java_lang_AssertionStatusDirectives, packageEnabled, "[Z");
- CHECK_OFFSET(nm, java_lang_AssertionStatusDirectives, deflt, "Z");
- }
-
if (!valid) vm_exit_during_initialization("Hard-coded field offset verification failed");
}
diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp
index 6ff74b80a85..2aa1f886c23 100644
--- a/src/hotspot/share/classfile/javaClasses.hpp
+++ b/src/hotspot/share/classfile/javaClasses.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -102,6 +102,7 @@ class java_lang_String : AllStatic {
// Accessors
static inline typeArrayOop value(oop java_string);
+ static inline typeArrayOop value_no_keepalive(oop java_string);
static inline unsigned int hash(oop java_string);
static inline bool is_latin1(oop java_string);
static inline int length(oop java_string);
@@ -444,9 +445,6 @@ class java_lang_Throwable: AllStatic {
hc_cause_offset = 2, // New since 1.4
hc_stackTrace_offset = 3 // New since 1.4
};
- enum {
- hc_static_unassigned_stacktrace_offset = 0 // New since 1.7
- };
// Trace constants
enum {
trace_methods_offset = 0,
@@ -878,7 +876,6 @@ class java_lang_ref_Reference: AllStatic {
static int queue_offset;
static int next_offset;
static int discovered_offset;
- static int number_of_fake_oop_fields;
// Accessors
static inline oop referent(oop ref);
@@ -902,14 +899,6 @@ class java_lang_ref_Reference: AllStatic {
class java_lang_ref_SoftReference: public java_lang_ref_Reference {
public:
- enum {
- // The timestamp is a long field and may need to be adjusted for alignment.
- hc_timestamp_offset = hc_discovered_offset + 1
- };
- enum {
- hc_static_clock_offset = 0
- };
-
static int timestamp_offset;
static int static_clock_offset;
@@ -919,6 +908,8 @@ class java_lang_ref_SoftReference: public java_lang_ref_Reference {
// Accessors for statics
static jlong clock();
static void set_clock(jlong value);
+
+ static void compute_offsets();
};
// Interface to java.lang.invoke.MethodHandle objects
@@ -1228,10 +1219,6 @@ class java_security_AccessControlContext: AllStatic {
class java_lang_ClassLoader : AllStatic {
private:
- // The fake offsets are added by the class loader when java.lang.Class is loaded
- enum {
- hc_parent_offset = 0
- };
static int _loader_data_offset;
static bool offsets_computed;
static int parent_offset;
@@ -1279,13 +1266,6 @@ class java_lang_ClassLoader : AllStatic {
class java_lang_System : AllStatic {
private:
- enum {
- hc_static_in_offset = 0,
- hc_static_out_offset = 1,
- hc_static_err_offset = 2,
- hc_static_security_offset = 3
- };
-
static int static_in_offset;
static int static_out_offset;
static int static_err_offset;
@@ -1298,6 +1278,8 @@ class java_lang_System : AllStatic {
static bool has_security_manager();
+ static void compute_offsets();
+
// Debugging
friend class JavaClasses;
};
@@ -1307,17 +1289,6 @@ class java_lang_System : AllStatic {
class java_lang_StackTraceElement: AllStatic {
private:
- enum {
- hc_declaringClassObject_offset = 0,
- hc_classLoaderName_offset = 1,
- hc_moduleName_offset = 2,
- hc_moduleVersion_offset = 3,
- hc_declaringClass_offset = 4,
- hc_methodName_offset = 5,
- hc_fileName_offset = 6,
- hc_lineNumber_offset = 7
- };
-
static int declaringClassObject_offset;
static int classLoaderName_offset;
static int moduleName_offset;
@@ -1344,6 +1315,8 @@ class java_lang_StackTraceElement: AllStatic {
static void fill_in(Handle element, InstanceKlass* holder, const methodHandle& method,
int version, int bci, Symbol* name, TRAPS);
+ static void compute_offsets();
+
// Debugging
friend class JavaClasses;
};
@@ -1416,14 +1389,6 @@ class java_lang_LiveStackFrameInfo: AllStatic {
class java_lang_AssertionStatusDirectives: AllStatic {
private:
- enum {
- hc_classes_offset,
- hc_classEnabled_offset,
- hc_packages_offset,
- hc_packageEnabled_offset,
- hc_deflt_offset
- };
-
static int classes_offset;
static int classEnabled_offset;
static int packages_offset;
@@ -1437,6 +1402,9 @@ class java_lang_AssertionStatusDirectives: AllStatic {
static void set_packages(oop obj, oop val);
static void set_packageEnabled(oop obj, oop val);
static void set_deflt(oop obj, bool val);
+
+ static void compute_offsets();
+
// Debugging
friend class JavaClasses;
};
@@ -1508,9 +1476,6 @@ class JavaClasses : AllStatic {
static InjectedField _injected_fields[];
static bool check_offset(const char *klass_name, int offset, const char *field_name, const char* field_sig) PRODUCT_RETURN0;
- static bool check_static_offset(const char *klass_name, int hardcoded_offset, const char *field_name, const char* field_sig) PRODUCT_RETURN0;
- static bool check_constant(const char *klass_name, int constant, const char *field_name, const char* field_sig) PRODUCT_RETURN0;
-
public:
enum InjectedFieldID {
ALL_INJECTED_FIELDS(DECLARE_INJECTED_FIELD_ENUM)
diff --git a/src/hotspot/share/classfile/javaClasses.inline.hpp b/src/hotspot/share/classfile/javaClasses.inline.hpp
index f4da4293a90..1ca986a4c48 100644
--- a/src/hotspot/share/classfile/javaClasses.inline.hpp
+++ b/src/hotspot/share/classfile/javaClasses.inline.hpp
@@ -26,6 +26,7 @@
#define SHARE_VM_CLASSFILE_JAVACLASSES_INLINE_HPP
#include "classfile/javaClasses.hpp"
+#include "oops/access.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/oopsHierarchy.hpp"
@@ -53,6 +54,11 @@ typeArrayOop java_lang_String::value(oop java_string) {
assert(is_instance(java_string), "must be java_string");
return (typeArrayOop) java_string->obj_field(value_offset);
}
+typeArrayOop java_lang_String::value_no_keepalive(oop java_string) {
+ assert(initialized && (value_offset > 0), "Must be initialized");
+ assert(is_instance(java_string), "must be java_string");
+ return (typeArrayOop) java_string->obj_field_access(value_offset);
+}
unsigned int java_lang_String::hash(oop java_string) {
assert(initialized && (hash_offset > 0), "Must be initialized");
assert(is_instance(java_string), "must be java_string");
@@ -68,11 +74,11 @@ bool java_lang_String::is_latin1(oop java_string) {
int java_lang_String::length(oop java_string) {
assert(initialized, "Must be initialized");
assert(is_instance(java_string), "must be java_string");
- typeArrayOop value_array = ((typeArrayOop)java_string->obj_field(value_offset));
- if (value_array == NULL) {
+ typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
+ if (value == NULL) {
return 0;
}
- int arr_length = value_array->length();
+ int arr_length = value->length();
if (!is_latin1(java_string)) {
assert((arr_length & 1) == 0, "should be even for UTF16 string");
arr_length >>= 1; // convert number of bytes to number of elements
diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp
index 307636be560..a4ba7fd7a05 100644
--- a/src/hotspot/share/classfile/stringTable.cpp
+++ b/src/hotspot/share/classfile/stringTable.cpp
@@ -35,6 +35,7 @@
#include "memory/filemap.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
+#include "oops/access.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/mutexLocker.hpp"
@@ -43,7 +44,6 @@
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1CollectedHeap.hpp"
-#include "gc/g1/g1SATBCardTableModRefBS.hpp"
#include "gc/g1/g1StringDedup.hpp"
#endif
@@ -124,6 +124,22 @@ unsigned int StringTable::hash_string(oop string) {
}
}
+oop StringTable::string_object(HashtableEntry* entry) {
+ return RootAccess::oop_load(entry->literal_addr());
+}
+
+oop StringTable::string_object_no_keepalive(HashtableEntry* entry) {
+ // The AS_NO_KEEPALIVE peeks at the oop without keeping it alive.
+ // This is *very dangerous* in general but is okay in this specific
+ // case. The subsequent oop_load keeps the oop alive if it it matched
+ // the jchar* string.
+ return RootAccess::oop_load(entry->literal_addr());
+}
+
+void StringTable::set_string_object(HashtableEntry* entry, oop string) {
+ RootAccess::oop_store(entry->literal_addr(), string);
+}
+
oop StringTable::lookup_shared(jchar* name, int len, unsigned int hash) {
assert(hash == java_lang_String::hash_code(name, len),
"hash must be computed using java_lang_String::hash_code");
@@ -131,13 +147,16 @@ oop StringTable::lookup_shared(jchar* name, int len, unsigned int hash) {
}
oop StringTable::lookup_in_main_table(int index, jchar* name,
- int len, unsigned int hash) {
+ int len, unsigned int hash) {
int count = 0;
for (HashtableEntry* l = bucket(index); l != NULL; l = l->next()) {
count++;
if (l->hash() == hash) {
- if (java_lang_String::equals(l->literal(), name, len)) {
- return l->literal();
+ if (java_lang_String::equals(string_object_no_keepalive(l), name, len)) {
+ // We must perform a new load with string_object() that keeps the string
+ // alive as we must expose the oop as strongly reachable when exiting
+ // this context, in case the oop gets published.
+ return string_object(l);
}
}
}
@@ -192,18 +211,6 @@ oop StringTable::lookup(Symbol* symbol) {
return lookup(chars, length);
}
-// Tell the GC that this string was looked up in the StringTable.
-static void ensure_string_alive(oop string) {
- // A lookup in the StringTable could return an object that was previously
- // considered dead. The SATB part of G1 needs to get notified about this
- // potential resurrection, otherwise the marking might not find the object.
-#if INCLUDE_ALL_GCS
- if (UseG1GC && string != NULL) {
- G1SATBCardTableModRefBS::enqueue(string);
- }
-#endif
-}
-
oop StringTable::lookup(jchar* name, int len) {
// shared table always uses java_lang_String::hash_code
unsigned int hash = java_lang_String::hash_code(name, len);
@@ -217,8 +224,6 @@ oop StringTable::lookup(jchar* name, int len) {
int index = the_table()->hash_to_index(hash);
string = the_table()->lookup_in_main_table(index, name, len, hash);
- ensure_string_alive(string);
-
return string;
}
@@ -238,9 +243,6 @@ oop StringTable::intern(Handle string_or_null, jchar* name,
// Found
if (found_string != NULL) {
- if (found_string != string_or_null()) {
- ensure_string_alive(found_string);
- }
return found_string;
}
@@ -276,10 +278,6 @@ oop StringTable::intern(Handle string_or_null, jchar* name,
hashValue, CHECK_NULL);
}
- if (added_or_found != string()) {
- ensure_string_alive(added_or_found);
- }
-
return added_or_found;
}
@@ -388,9 +386,9 @@ void StringTable::buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClos
while (entry != NULL) {
assert(!entry->is_shared(), "CDS not used for the StringTable");
- if (is_alive->do_object_b(entry->literal())) {
+ if (is_alive->do_object_b(string_object_no_keepalive(entry))) {
if (f != NULL) {
- f->do_oop((oop*)entry->literal_addr());
+ f->do_oop(entry->literal_addr());
}
p = entry->next_addr();
} else {
@@ -429,7 +427,7 @@ void StringTable::verify() {
for (int i = 0; i < the_table()->table_size(); ++i) {
HashtableEntry* p = the_table()->bucket(i);
for ( ; p != NULL; p = p->next()) {
- oop s = p->literal();
+ oop s = string_object_no_keepalive(p);
guarantee(s != NULL, "interned string is NULL");
unsigned int h = hash_string(s);
guarantee(p->hash() == h, "broken hash in string table entry");
@@ -448,10 +446,10 @@ void StringTable::dump(outputStream* st, bool verbose) {
for (int i = 0; i < the_table()->table_size(); ++i) {
HashtableEntry* p = the_table()->bucket(i);
for ( ; p != NULL; p = p->next()) {
- oop s = p->literal();
- typeArrayOop value = java_lang_String::value(s);
- int length = java_lang_String::length(s);
- bool is_latin1 = java_lang_String::is_latin1(s);
+ oop s = string_object_no_keepalive(p);
+ typeArrayOop value = java_lang_String::value_no_keepalive(s);
+ int length = java_lang_String::length(s);
+ bool is_latin1 = java_lang_String::is_latin1(s);
if (length <= 0) {
st->print("%d: ", length);
@@ -484,8 +482,8 @@ StringTable::VerifyRetTypes StringTable::compare_entries(
HashtableEntry* e_ptr2) {
// These entries are sanity checked by verify_and_compare_entries()
// before this function is called.
- oop str1 = e_ptr1->literal();
- oop str2 = e_ptr2->literal();
+ oop str1 = string_object_no_keepalive(e_ptr1);
+ oop str2 = string_object_no_keepalive(e_ptr2);
if (str1 == str2) {
tty->print_cr("ERROR: identical oop values (0x" PTR_FORMAT ") "
@@ -505,12 +503,12 @@ StringTable::VerifyRetTypes StringTable::compare_entries(
}
StringTable::VerifyRetTypes StringTable::verify_entry(int bkt, int e_cnt,
- HashtableEntry* e_ptr,
- StringTable::VerifyMesgModes mesg_mode) {
+ HashtableEntry* e_ptr,
+ StringTable::VerifyMesgModes mesg_mode) {
VerifyRetTypes ret = _verify_pass; // be optimistic
- oop str = e_ptr->literal();
+ oop str = string_object_no_keepalive(e_ptr);
if (str == NULL) {
if (mesg_mode == _verify_with_mesgs) {
tty->print_cr("ERROR: NULL oop value in entry @ bucket[%d][%d]", bkt,
@@ -684,7 +682,7 @@ oop StringTable::create_archived_string(oop s, Thread* THREAD) {
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
oop new_s = NULL;
- typeArrayOop v = java_lang_String::value(s);
+ typeArrayOop v = java_lang_String::value_no_keepalive(s);
typeArrayOop new_v = (typeArrayOop)MetaspaceShared::archive_heap_object(v, THREAD);
if (new_v == NULL) {
return NULL;
@@ -708,7 +706,7 @@ bool StringTable::copy_shared_string(GrowableArray *string_space,
for (int i = 0; i < the_table()->table_size(); ++i) {
HashtableEntry* bucket = the_table()->bucket(i);
for ( ; bucket != NULL; bucket = bucket->next()) {
- oop s = bucket->literal();
+ oop s = string_object_no_keepalive(bucket);
unsigned int hash = java_lang_String::hash_code(s);
if (hash == 0) {
continue;
@@ -721,7 +719,7 @@ bool StringTable::copy_shared_string(GrowableArray *string_space,
}
// set the archived string in bucket
- bucket->set_literal(new_s);
+ set_string_object(bucket, new_s);
// add to the compact table
writer->add(hash, new_s);
@@ -763,4 +761,3 @@ void StringTable::shared_oops_do(OopClosure* f) {
_shared_table.oops_do(f);
}
#endif //INCLUDE_CDS_JAVA_HEAP
-
diff --git a/src/hotspot/share/classfile/stringTable.hpp b/src/hotspot/share/classfile/stringTable.hpp
index 77538a53e5c..e0c957c67f4 100644
--- a/src/hotspot/share/classfile/stringTable.hpp
+++ b/src/hotspot/share/classfile/stringTable.hpp
@@ -76,6 +76,13 @@ private:
static unsigned int hash_string(oop string);
static unsigned int alt_hash_string(const jchar* s, int len);
+ // Accessors for the string roots in the hashtable entries.
+ // Use string_object_no_keepalive() only when the value is not returned
+ // outside of a scope where a thread transition is possible.
+ static oop string_object(HashtableEntry* entry);
+ static oop string_object_no_keepalive(HashtableEntry* entry);
+ static void set_string_object(HashtableEntry* entry, oop string);
+
StringTable() : RehashableHashtable((int)StringTableSize,
sizeof (HashtableEntry)) {}
diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp
index a14497de2b1..64116adf979 100644
--- a/src/hotspot/share/classfile/systemDictionary.cpp
+++ b/src/hotspot/share/classfile/systemDictionary.cpp
@@ -2775,7 +2775,17 @@ Handle SystemDictionary::link_method_handle_constant(Klass* caller,
java_lang_invoke_MemberName::set_name (mname(), name_str());
java_lang_invoke_MemberName::set_type (mname(), signature_str());
java_lang_invoke_MemberName::set_flags(mname(), MethodHandles::ref_kind_to_flags(ref_kind));
- MethodHandles::resolve_MemberName(mname, caller, CHECK_(empty));
+
+ if (ref_kind == JVM_REF_invokeVirtual &&
+ callee->name() == vmSymbols::java_lang_invoke_MethodHandle() &&
+ (name == vmSymbols::invoke_name() || name == vmSymbols::invokeExact_name())) {
+ // Skip resolution for j.l.i.MethodHandle.invoke()/invokeExact().
+ // They are public signature polymorphic methods, but require appendix argument
+ // which MemberName resolution doesn't handle. There's special logic on JDK side to handle them
+ // (see MethodHandles.linkMethodHandleConstant() and MethodHandles.findVirtualForMH()).
+ } else {
+ MethodHandles::resolve_MemberName(mname, caller, CHECK_(empty));
+ }
// After method/field resolution succeeded, it's safe to resolve MH signature as well.
Handle type = MethodHandles::resolve_MemberName_type(mname, caller, CHECK_(empty));
diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp
index af22cf977ee..bf2ecec35ab 100644
--- a/src/hotspot/share/classfile/systemDictionary.hpp
+++ b/src/hotspot/share/classfile/systemDictionary.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -173,6 +173,7 @@ class GCTimer;
do_klass(VolatileCallSite_klass, java_lang_invoke_VolatileCallSite, Pre ) \
/* Note: MethodHandle must be first, and VolatileCallSite last in group */ \
\
+ do_klass(AssertionStatusDirectives_klass, java_lang_AssertionStatusDirectives, Pre ) \
do_klass(StringBuffer_klass, java_lang_StringBuffer, Pre ) \
do_klass(StringBuilder_klass, java_lang_StringBuilder, Pre ) \
do_klass(internal_Unsafe_klass, jdk_internal_misc_Unsafe, Pre ) \
diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp
index ddc54315ade..7048b368d5b 100644
--- a/src/hotspot/share/classfile/vmSymbols.hpp
+++ b/src/hotspot/share/classfile/vmSymbols.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -251,7 +251,6 @@
template(compiledLambdaForm_name, "") /*fake name*/ \
template(star_name, "*") /*not really a name*/ \
template(invoke_name, "invoke") \
- template(override_name, "override") \
template(parameterTypes_name, "parameterTypes") \
template(returnType_name, "returnType") \
template(signature_name, "signature") \
@@ -265,7 +264,6 @@
template(parameter_annotations_name, "parameterAnnotations") \
template(annotation_default_name, "annotationDefault") \
template(reflect_ConstantPool, "jdk/internal/reflect/ConstantPool") \
- template(ConstantPool_name, "constantPoolOop") \
template(reflect_UnsafeStaticFieldAccessorImpl, "jdk/internal/reflect/UnsafeStaticFieldAccessorImpl")\
template(base_name, "base") \
/* Type Annotations (JDK 8 and above) */ \
@@ -304,6 +302,7 @@
/* internal up-calls made only by the JVM, via class sun.invoke.MethodHandleNatives: */ \
template(findMethodHandleType_name, "findMethodHandleType") \
template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;") \
+ template(invokeExact_name, "invokeExact") \
template(linkMethodHandleConstant_name, "linkMethodHandleConstant") \
template(linkMethodHandleConstant_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;") \
template(linkMethod_name, "linkMethod") \
@@ -340,8 +339,6 @@
template(stillborn_name, "stillborn") \
template(group_name, "group") \
template(daemon_name, "daemon") \
- template(eetop_name, "eetop") \
- template(thread_status_name, "threadStatus") \
template(run_method_name, "run") \
template(exit_method_name, "exit") \
template(add_method_name, "add") \
@@ -375,34 +372,21 @@
template(fillInStackTrace_name, "fillInStackTrace") \
template(getCause_name, "getCause") \
template(initCause_name, "initCause") \
- template(depth_name, "depth") \
template(setProperty_name, "setProperty") \
template(getProperty_name, "getProperty") \
template(context_name, "context") \
- template(privilegedContext_name, "privilegedContext") \
template(contextClassLoader_name, "contextClassLoader") \
template(inheritedAccessControlContext_name, "inheritedAccessControlContext") \
- template(isPrivileged_name, "isPrivileged") \
- template(isAuthorized_name, "isAuthorized") \
template(getClassContext_name, "getClassContext") \
template(wait_name, "wait") \
template(checkPackageAccess_name, "checkPackageAccess") \
- template(stackSize_name, "stackSize") \
- template(thread_id_name, "tid") \
template(newInstance0_name, "newInstance0") \
- template(limit_name, "limit") \
- template(member_name, "member") \
template(forName_name, "forName") \
template(forName0_name, "forName0") \
template(isJavaIdentifierStart_name, "isJavaIdentifierStart") \
template(isJavaIdentifierPart_name, "isJavaIdentifierPart") \
- template(exclusive_owner_thread_name, "exclusiveOwnerThread") \
- template(park_blocker_name, "parkBlocker") \
- template(park_event_name, "nativeParkEventPointer") \
template(cache_field_name, "cache") \
template(value_name, "value") \
- template(hash_name, "hash") \
- template(coder_name, "coder") \
template(compact_strings_name, "COMPACT_STRINGS") \
template(numberOfLeadingZeros_name, "numberOfLeadingZeros") \
template(numberOfTrailingZeros_name, "numberOfTrailingZeros") \
@@ -419,27 +403,17 @@
template(method_name, "method") \
template(vmindex_name, "vmindex") \
template(vmcount_name, "vmcount") \
- template(vmentry_name, "vmentry") \
template(flags_name, "flags") \
- template(rtype_name, "rtype") \
- template(ptypes_name, "ptypes") \
- template(form_name, "form") \
template(basicType_name, "basicType") \
template(append_name, "append") \
template(klass_name, "klass") \
template(array_klass_name, "array_klass") \
- template(memberName_name, "memberName") \
template(mid_name, "mid") \
template(cpref_name, "cpref") \
template(version_name, "version") \
- template(bci_name, "bci") \
template(methodName_name, "methodName") \
template(fileName_name, "fileName") \
template(lineNumber_name, "lineNumber") \
- template(monitors_name, "monitors") \
- template(locals_name, "locals") \
- template(operands_name, "operands") \
- template(mode_name, "mode") \
template(oop_size_name, "oop_size") \
template(static_oop_field_count_name, "static_oop_field_count") \
template(protection_domain_name, "protection_domain") \
@@ -447,9 +421,11 @@
template(loader_data_name, "loader_data") \
template(vmdependencies_name, "vmdependencies") \
template(loader_name, "loader") \
- template(module_name, "module") \
template(getModule_name, "getModule") \
template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \
+ template(input_stream_signature, "Ljava/io/InputStream;") \
+ template(print_stream_signature, "Ljava/io/PrintStream;") \
+ template(security_manager_signature, "Ljava/lang/SecurityManager;") \
template(definePackage_name, "definePackage") \
template(definePackage_signature, "(Ljava/lang/String;Ljava/lang/Module;)Ljava/lang/Package;") \
template(defineOrCheckPackage_name, "defineOrCheckPackage") \
@@ -498,6 +474,7 @@
template(short_signature, "S") \
template(bool_signature, "Z") \
template(void_signature, "V") \
+ template(bool_array_signature, "[Z") \
template(byte_array_signature, "[B") \
template(char_array_signature, "[C") \
template(int_array_signature, "[I") \
@@ -552,6 +529,7 @@
template(object_array_signature, "[Ljava/lang/Object;") \
template(class_signature, "Ljava/lang/Class;") \
template(string_signature, "Ljava/lang/String;") \
+ template(string_array_signature, "[Ljava/lang/String;") \
template(reference_signature, "Ljava/lang/ref/Reference;") \
template(sun_misc_Cleaner_signature, "Lsun/misc/Cleaner;") \
template(executable_signature, "Ljava/lang/reflect/Executable;") \
@@ -578,12 +556,6 @@
/* used by ClassFormatError when class name is not known yet */ \
template(unknown_class_name, "") \
\
- /* used to identify class loaders handling parallel class loading */ \
- template(parallelCapable_name, "parallelLockMap") \
- \
- /* used to return a class loader's unnamed module */ \
- template(unnamedModule_name, "unnamedModule") \
- \
/* JVM monitoring and management support */ \
template(java_lang_StackTraceElement_array, "[Ljava/lang/StackTraceElement;") \
template(java_lang_management_ThreadState, "java/lang/management/ThreadState") \
diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp
index 3c7105022f5..a7752b07f23 100644
--- a/src/hotspot/share/code/compiledIC.cpp
+++ b/src/hotspot/share/code/compiledIC.cpp
@@ -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) {
diff --git a/src/hotspot/share/code/compiledIC.hpp b/src/hotspot/share/code/compiledIC.hpp
index eb3053770e0..4f967957d29 100644
--- a/src/hotspot/share/code/compiledIC.hpp
+++ b/src/hotspot/share/code/compiledIC.hpp
@@ -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)
diff --git a/src/hotspot/share/code/compiledMethod.cpp b/src/hotspot/share/code/compiledMethod.cpp
index fcd5016464d..14e8d5e4403 100644
--- a/src/hotspot/share/code/compiledMethod.cpp
+++ b/src/hotspot/share/code/compiledMethod.cpp
@@ -404,8 +404,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 {
diff --git a/src/hotspot/share/code/dependencies.hpp b/src/hotspot/share/code/dependencies.hpp
index 9726375540f..90ffdf5fb7e 100644
--- a/src/hotspot/share/code/dependencies.hpp
+++ b/src/hotspot/share/code/dependencies.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -241,8 +241,18 @@ class Dependencies: public ResourceObj {
bool is_object() const { assert(is_valid(), "oops"); return _id < 0; }
Metadata* as_metadata(OopRecorder* rec) const { assert(is_metadata(), "oops"); return rec->metadata_at(index()); }
- Klass* as_klass(OopRecorder* rec) const { assert(as_metadata(rec)->is_klass(), "oops"); return (Klass*) as_metadata(rec); }
- Method* as_method(OopRecorder* rec) const { assert(as_metadata(rec)->is_method(), "oops"); return (Method*) as_metadata(rec); }
+ Klass* as_klass(OopRecorder* rec) const {
+ Metadata* m = as_metadata(rec);
+ assert(m != NULL, "as_metadata returned NULL");
+ assert(m->is_klass(), "oops");
+ return (Klass*) m;
+ }
+ Method* as_method(OopRecorder* rec) const {
+ Metadata* m = as_metadata(rec);
+ assert(m != NULL, "as_metadata returned NULL");
+ assert(m->is_method(), "oops");
+ return (Method*) m;
+ }
jobject as_object(OopRecorder* rec) const { assert(is_object(), "oops"); return rec->oop_at(index()); }
};
#endif // INCLUDE_JVMCI
diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp
index e2430e94e23..d59b7bceca9 100644
--- a/src/hotspot/share/code/nmethod.cpp
+++ b/src/hotspot/share/code/nmethod.cpp
@@ -1547,7 +1547,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();
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
index 3fbaa30250b..a77f7942955 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
@@ -445,9 +445,7 @@ HeapWord* G1CollectedHeap::allocate_new_tlab(size_t word_size) {
assert_heap_not_locked_and_not_at_safepoint();
assert(!is_humongous(word_size), "we do not allow humongous TLABs");
- uint dummy_gc_count_before;
- uint dummy_gclocker_retry_count = 0;
- return attempt_allocation(word_size, &dummy_gc_count_before, &dummy_gclocker_retry_count);
+ return attempt_allocation(word_size);
}
HeapWord*
@@ -455,62 +453,16 @@ G1CollectedHeap::mem_allocate(size_t word_size,
bool* gc_overhead_limit_was_exceeded) {
assert_heap_not_locked_and_not_at_safepoint();
- // Loop until the allocation is satisfied, or unsatisfied after GC.
- for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
- uint gc_count_before;
-
- HeapWord* result = NULL;
- if (!is_humongous(word_size)) {
- result = attempt_allocation(word_size, &gc_count_before, &gclocker_retry_count);
- } else {
- result = attempt_allocation_humongous(word_size, &gc_count_before, &gclocker_retry_count);
- }
- if (result != NULL) {
- return result;
- }
-
- // Create the garbage collection operation...
- VM_G1CollectForAllocation op(gc_count_before, word_size);
- op.set_allocation_context(AllocationContext::current());
-
- // ...and get the VM thread to execute it.
- VMThread::execute(&op);
-
- if (op.prologue_succeeded() && op.pause_succeeded()) {
- // If the operation was successful we'll return the result even
- // if it is NULL. If the allocation attempt failed immediately
- // after a Full GC, it's unlikely we'll be able to allocate now.
- HeapWord* result = op.result();
- if (result != NULL && !is_humongous(word_size)) {
- // Allocations that take place on VM operations do not do any
- // card dirtying and we have to do it here. We only have to do
- // this for non-humongous allocations, though.
- dirty_young_block(result, word_size);
- }
- return result;
- } else {
- if (gclocker_retry_count > GCLockerRetryAllocationCount) {
- return NULL;
- }
- assert(op.result() == NULL,
- "the result should be NULL if the VM op did not succeed");
- }
-
- // Give a warning if we seem to be looping forever.
- if ((QueuedAllocationWarningCount > 0) &&
- (try_count % QueuedAllocationWarningCount == 0)) {
- log_warning(gc)("G1CollectedHeap::mem_allocate retries %d times", try_count);
- }
+ if (is_humongous(word_size)) {
+ return attempt_allocation_humongous(word_size);
}
-
- ShouldNotReachHere();
- return NULL;
+ return attempt_allocation(word_size);
}
HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
- AllocationContext_t context,
- uint* gc_count_before_ret,
- uint* gclocker_retry_count_ret) {
+ AllocationContext_t context) {
+ ResourceMark rm; // For retrieving the thread names in log messages.
+
// Make sure you read the note in attempt_allocation_humongous().
assert_heap_not_locked_and_not_at_safepoint();
@@ -525,7 +477,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
// fails to perform the allocation. b) is the only case when we'll
// return NULL.
HeapWord* result = NULL;
- for (int try_count = 1; /* we'll return */; try_count += 1) {
+ for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
bool should_try_gc;
uint gc_count_before;
@@ -536,30 +488,23 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
return result;
}
- if (GCLocker::is_active_and_needs_gc()) {
- if (g1_policy()->can_expand_young_list()) {
- // No need for an ergo verbose message here,
- // can_expand_young_list() does this when it returns true.
- result = _allocator->attempt_allocation_force(word_size, context);
- if (result != NULL) {
- return result;
- }
- }
- should_try_gc = false;
- } else {
- // The GCLocker may not be active but the GCLocker initiated
- // GC may not yet have been performed (GCLocker::needs_gc()
- // returns true). In this case we do not try this GC and
- // wait until the GCLocker initiated GC is performed, and
- // then retry the allocation.
- if (GCLocker::needs_gc()) {
- should_try_gc = false;
- } else {
- // Read the GC count while still holding the Heap_lock.
- gc_count_before = total_collections();
- should_try_gc = true;
+ // If the GCLocker is active and we are bound for a GC, try expanding young gen.
+ // This is different to when only GCLocker::needs_gc() is set: try to avoid
+ // waiting because the GCLocker is active to not wait too long.
+ if (GCLocker::is_active_and_needs_gc() && g1_policy()->can_expand_young_list()) {
+ // No need for an ergo message here, can_expand_young_list() does this when
+ // it returns true.
+ result = _allocator->attempt_allocation_force(word_size, context);
+ if (result != NULL) {
+ return result;
}
}
+ // Only try a GC if the GCLocker does not signal the need for a GC. Wait until
+ // the GCLocker initiated GC has been performed and then retry. This includes
+ // the case when the GC Locker is not active but has not been performed.
+ should_try_gc = !GCLocker::needs_gc();
+ // Read the GC count while still holding the Heap_lock.
+ gc_count_before = total_collections();
}
if (should_try_gc) {
@@ -568,28 +513,33 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
GCCause::_g1_inc_collection_pause);
if (result != NULL) {
assert(succeeded, "only way to get back a non-NULL result");
+ log_trace(gc, alloc)("%s: Successfully scheduled collection returning " PTR_FORMAT,
+ Thread::current()->name(), p2i(result));
return result;
}
if (succeeded) {
- // If we get here we successfully scheduled a collection which
- // failed to allocate. No point in trying to allocate
- // further. We'll just return NULL.
- MutexLockerEx x(Heap_lock);
- *gc_count_before_ret = total_collections();
+ // We successfully scheduled a collection which failed to allocate. No
+ // point in trying to allocate further. We'll just return NULL.
+ log_trace(gc, alloc)("%s: Successfully scheduled collection failing to allocate "
+ SIZE_FORMAT " words", Thread::current()->name(), word_size);
return NULL;
}
+ log_trace(gc, alloc)("%s: Unsuccessfully scheduled collection allocating " SIZE_FORMAT " words",
+ Thread::current()->name(), word_size);
} else {
- if (*gclocker_retry_count_ret > GCLockerRetryAllocationCount) {
- MutexLockerEx x(Heap_lock);
- *gc_count_before_ret = total_collections();
+ // Failed to schedule a collection.
+ if (gclocker_retry_count > GCLockerRetryAllocationCount) {
+ log_warning(gc, alloc)("%s: Retried waiting for GCLocker too often allocating "
+ SIZE_FORMAT " words", Thread::current()->name(), word_size);
return NULL;
}
+ log_trace(gc, alloc)("%s: Stall until clear", Thread::current()->name());
// The GCLocker is either active or the GCLocker initiated
// GC has not yet been performed. Stall until it is and
// then retry the allocation.
GCLocker::stall_until_clear();
- (*gclocker_retry_count_ret) += 1;
+ gclocker_retry_count += 1;
}
// We can reach here if we were unsuccessful in scheduling a
@@ -600,6 +550,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
// first attempt (without holding the Heap_lock) here and the
// follow-on attempt will be at the start of the next loop
// iteration (after taking the Heap_lock).
+
result = _allocator->attempt_allocation(word_size, context);
if (result != NULL) {
return result;
@@ -608,8 +559,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
// Give a warning if we seem to be looping forever.
if ((QueuedAllocationWarningCount > 0) &&
(try_count % QueuedAllocationWarningCount == 0)) {
- log_warning(gc)("G1CollectedHeap::attempt_allocation_slow() "
- "retries %d times", try_count);
+ log_warning(gc, alloc)("%s: Retried allocation %u times for " SIZE_FORMAT " words",
+ Thread::current()->name(), try_count, word_size);
}
}
@@ -830,9 +781,7 @@ void G1CollectedHeap::fill_archive_regions(MemRegion* ranges, size_t count) {
}
}
-inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size,
- uint* gc_count_before_ret,
- uint* gclocker_retry_count_ret) {
+inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size) {
assert_heap_not_locked_and_not_at_safepoint();
assert(!is_humongous(word_size), "attempt_allocation() should not "
"be called for humongous allocation requests");
@@ -841,10 +790,7 @@ inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size,
HeapWord* result = _allocator->attempt_allocation(word_size, context);
if (result == NULL) {
- result = attempt_allocation_slow(word_size,
- context,
- gc_count_before_ret,
- gclocker_retry_count_ret);
+ result = attempt_allocation_slow(word_size, context);
}
assert_heap_not_locked();
if (result != NULL) {
@@ -925,9 +871,9 @@ void G1CollectedHeap::dealloc_archive_regions(MemRegion* ranges, size_t count) {
decrease_used(size_used);
}
-HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size,
- uint* gc_count_before_ret,
- uint* gclocker_retry_count_ret) {
+HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
+ ResourceMark rm; // For retrieving the thread names in log messages.
+
// The structure of this method has a lot of similarities to
// attempt_allocation_slow(). The reason these two were not merged
// into a single one is that such a method would require several "if
@@ -958,10 +904,11 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size,
// fails to perform the allocation. b) is the only case when we'll
// return NULL.
HeapWord* result = NULL;
- for (int try_count = 1; /* we'll return */; try_count += 1) {
+ for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
bool should_try_gc;
uint gc_count_before;
+
{
MutexLockerEx x(Heap_lock);
@@ -975,69 +922,63 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size,
return result;
}
- if (GCLocker::is_active_and_needs_gc()) {
- should_try_gc = false;
- } else {
- // The GCLocker may not be active but the GCLocker initiated
- // GC may not yet have been performed (GCLocker::needs_gc()
- // returns true). In this case we do not try this GC and
- // wait until the GCLocker initiated GC is performed, and
- // then retry the allocation.
- if (GCLocker::needs_gc()) {
- should_try_gc = false;
- } else {
- // Read the GC count while still holding the Heap_lock.
- gc_count_before = total_collections();
- should_try_gc = true;
- }
- }
+ // Only try a GC if the GCLocker does not signal the need for a GC. Wait until
+ // the GCLocker initiated GC has been performed and then retry. This includes
+ // the case when the GC Locker is not active but has not been performed.
+ should_try_gc = !GCLocker::needs_gc();
+ // Read the GC count while still holding the Heap_lock.
+ gc_count_before = total_collections();
}
if (should_try_gc) {
- // If we failed to allocate the humongous object, we should try to
- // do a collection pause (if we're allowed) in case it reclaims
- // enough space for the allocation to succeed after the pause.
-
bool succeeded;
result = do_collection_pause(word_size, gc_count_before, &succeeded,
GCCause::_g1_humongous_allocation);
if (result != NULL) {
assert(succeeded, "only way to get back a non-NULL result");
+ log_trace(gc, alloc)("%s: Successfully scheduled collection returning " PTR_FORMAT,
+ Thread::current()->name(), p2i(result));
return result;
}
if (succeeded) {
- // If we get here we successfully scheduled a collection which
- // failed to allocate. No point in trying to allocate
- // further. We'll just return NULL.
- MutexLockerEx x(Heap_lock);
- *gc_count_before_ret = total_collections();
+ // We successfully scheduled a collection which failed to allocate. No
+ // point in trying to allocate further. We'll just return NULL.
+ log_trace(gc, alloc)("%s: Successfully scheduled collection failing to allocate "
+ SIZE_FORMAT " words", Thread::current()->name(), word_size);
return NULL;
}
+ log_trace(gc, alloc)("%s: Unsuccessfully scheduled collection allocating " SIZE_FORMAT "",
+ Thread::current()->name(), word_size);
} else {
- if (*gclocker_retry_count_ret > GCLockerRetryAllocationCount) {
- MutexLockerEx x(Heap_lock);
- *gc_count_before_ret = total_collections();
+ // Failed to schedule a collection.
+ if (gclocker_retry_count > GCLockerRetryAllocationCount) {
+ log_warning(gc, alloc)("%s: Retried waiting for GCLocker too often allocating "
+ SIZE_FORMAT " words", Thread::current()->name(), word_size);
return NULL;
}
+ log_trace(gc, alloc)("%s: Stall until clear", Thread::current()->name());
// The GCLocker is either active or the GCLocker initiated
// GC has not yet been performed. Stall until it is and
// then retry the allocation.
GCLocker::stall_until_clear();
- (*gclocker_retry_count_ret) += 1;
+ gclocker_retry_count += 1;
}
+
// We can reach here if we were unsuccessful in scheduling a
// collection (because another thread beat us to it) or if we were
// stalled due to the GC locker. In either can we should retry the
// allocation attempt in case another thread successfully
- // performed a collection and reclaimed enough space. Give a
- // warning if we seem to be looping forever.
+ // performed a collection and reclaimed enough space.
+ // Humongous object allocation always needs a lock, so we wait for the retry
+ // in the next iteration of the loop, unlike for the regular iteration case.
+ // Give a warning if we seem to be looping forever.
if ((QueuedAllocationWarningCount > 0) &&
(try_count % QueuedAllocationWarningCount == 0)) {
- log_warning(gc)("G1CollectedHeap::attempt_allocation_humongous() "
- "retries %d times", try_count);
+ log_warning(gc, alloc)("%s: Retried allocation %u times for " SIZE_FORMAT " words",
+ Thread::current()->name(), try_count, word_size);
}
}
@@ -1339,7 +1280,6 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size,
context,
expect_null_mutator_alloc_region);
if (result != NULL) {
- assert(*gc_succeeded, "sanity");
return result;
}
@@ -1349,7 +1289,6 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size,
// do something smarter than full collection to satisfy a failed alloc.)
result = expand_and_allocate(word_size, context);
if (result != NULL) {
- assert(*gc_succeeded, "sanity");
return result;
}
@@ -1401,7 +1340,6 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size,
succeeded);
if (result != NULL) {
- assert(*succeeded, "sanity");
return result;
}
@@ -1412,7 +1350,6 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size,
// space available is large enough for the allocation, then a more
// complete compaction phase than we've tried so far might be
// appropriate.
- assert(*succeeded, "sanity");
return NULL;
}
@@ -2147,7 +2084,7 @@ void G1CollectedHeap::increment_old_marking_cycles_completed(bool concurrent) {
// This notify_all() will ensure that a thread that called
// System.gc() with (with ExplicitGCInvokesConcurrent set or not)
// and it's waiting for a full GC to finish will be woken up. It is
- // waiting in VM_G1IncCollectionPause::doit_epilogue().
+ // waiting in VM_G1CollectForAllocation::doit_epilogue().
FullGCCount_lock->notify_all();
}
@@ -2175,13 +2112,12 @@ void G1CollectedHeap::collect(GCCause::Cause cause) {
// Schedule an initial-mark evacuation pause that will start a
// concurrent cycle. We're setting word_size to 0 which means that
// we are not requesting a post-GC allocation.
- VM_G1IncCollectionPause op(gc_count_before,
- 0, /* word_size */
- true, /* should_initiate_conc_mark */
- g1_policy()->max_pause_time_ms(),
- cause);
- op.set_allocation_context(AllocationContext::current());
-
+ VM_G1CollectForAllocation op(0, /* word_size */
+ gc_count_before,
+ cause,
+ true, /* should_initiate_conc_mark */
+ g1_policy()->max_pause_time_ms(),
+ AllocationContext::current());
VMThread::execute(&op);
if (!op.pause_succeeded()) {
if (old_marking_count_before == _old_marking_cycles_started) {
@@ -2204,11 +2140,12 @@ void G1CollectedHeap::collect(GCCause::Cause cause) {
// Schedule a standard evacuation pause. We're setting word_size
// to 0 which means that we are not requesting a post-GC allocation.
- VM_G1IncCollectionPause op(gc_count_before,
- 0, /* word_size */
- false, /* should_initiate_conc_mark */
- g1_policy()->max_pause_time_ms(),
- cause);
+ VM_G1CollectForAllocation op(0, /* word_size */
+ gc_count_before,
+ cause,
+ false, /* should_initiate_conc_mark */
+ g1_policy()->max_pause_time_ms(),
+ AllocationContext::current());
VMThread::execute(&op);
} else {
// Schedule a Full GC.
@@ -2619,13 +2556,12 @@ HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size,
bool* succeeded,
GCCause::Cause gc_cause) {
assert_heap_not_locked_and_not_at_safepoint();
- VM_G1IncCollectionPause op(gc_count_before,
- word_size,
- false, /* should_initiate_conc_mark */
- g1_policy()->max_pause_time_ms(),
- gc_cause);
-
- op.set_allocation_context(AllocationContext::current());
+ VM_G1CollectForAllocation op(word_size,
+ gc_count_before,
+ gc_cause,
+ false, /* should_initiate_conc_mark */
+ g1_policy()->max_pause_time_ms(),
+ AllocationContext::current());
VMThread::execute(&op);
HeapWord* result = op.result();
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
index d268e2ef7be..ccf57f66dfa 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -125,7 +125,6 @@ class G1CollectedHeap : public CollectedHeap {
friend class VM_CollectForMetadataAllocation;
friend class VM_G1CollectForAllocation;
friend class VM_G1CollectFull;
- friend class VM_G1IncCollectionPause;
friend class VMStructs;
friend class MutatorAllocRegion;
friend class G1FullCollector;
@@ -454,35 +453,20 @@ protected:
virtual HeapWord* mem_allocate(size_t word_size,
bool* gc_overhead_limit_was_exceeded);
- // The following three methods take a gc_count_before_ret
- // parameter which is used to return the GC count if the method
- // returns NULL. Given that we are required to read the GC count
- // while holding the Heap_lock, and these paths will take the
- // Heap_lock at some point, it's easier to get them to read the GC
- // count while holding the Heap_lock before they return NULL instead
- // of the caller (namely: mem_allocate()) having to also take the
- // Heap_lock just to read the GC count.
-
// First-level mutator allocation attempt: try to allocate out of
// the mutator alloc region without taking the Heap_lock. This
// should only be used for non-humongous allocations.
- inline HeapWord* attempt_allocation(size_t word_size,
- uint* gc_count_before_ret,
- uint* gclocker_retry_count_ret);
+ inline HeapWord* attempt_allocation(size_t word_size);
// Second-level mutator allocation attempt: take the Heap_lock and
// retry the allocation attempt, potentially scheduling a GC
// pause. This should only be used for non-humongous allocations.
HeapWord* attempt_allocation_slow(size_t word_size,
- AllocationContext_t context,
- uint* gc_count_before_ret,
- uint* gclocker_retry_count_ret);
+ AllocationContext_t context);
// Takes the Heap_lock and attempts a humongous allocation. It can
// potentially schedule a GC pause.
- HeapWord* attempt_allocation_humongous(size_t word_size,
- uint* gc_count_before_ret,
- uint* gclocker_retry_count_ret);
+ HeapWord* attempt_allocation_humongous(size_t word_size);
// Allocation attempt that should be called during safepoints (e.g.,
// at the end of a successful GC). expect_null_mutator_alloc_region
@@ -1078,6 +1062,11 @@ public:
return _hrm.available() == 0;
}
+ // Returns whether there are any regions left in the heap for allocation.
+ bool has_regions_left_for_allocation() const {
+ return !is_maximal_no_gc() || num_free_regions() != 0;
+ }
+
// The current number of regions in the heap.
uint num_regions() const { return _hrm.length(); }
diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp
index 383c5955f71..f57a9ffac96 100644
--- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp
@@ -33,6 +33,7 @@
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "memory/iterator.inline.hpp"
+#include "oops/access.inline.hpp"
#include "runtime/prefetch.inline.hpp"
template
@@ -87,13 +88,13 @@ inline void G1ScanEvacuatedObjClosure::do_oop_nv(T* p) {
template
inline void G1CMOopClosure::do_oop_nv(T* p) {
- oop obj = oopDesc::load_decode_heap_oop(p);
+ oop obj = RawAccess::oop_load(p);
_task->deal_with_reference(obj);
}
template
inline void G1RootRegionScanClosure::do_oop_nv(T* p) {
- T heap_oop = oopDesc::load_heap_oop(p);
+ T heap_oop = RawAccess::oop_load(p);
if (oopDesc::is_null(heap_oop)) {
return;
}
@@ -124,7 +125,7 @@ inline static void check_obj_during_refinement(T* p, oop const obj) {
template
inline void G1ConcurrentRefineOopClosure::do_oop_nv(T* p) {
- T o = oopDesc::load_heap_oop(p);
+ T o = RawAccess::oop_load(p);
if (oopDesc::is_null(o)) {
return;
}
diff --git a/src/hotspot/share/gc/g1/g1SATBCardTableModRefBS.inline.hpp b/src/hotspot/share/gc/g1/g1SATBCardTableModRefBS.inline.hpp
index 834d284fec9..980920c28d4 100644
--- a/src/hotspot/share/gc/g1/g1SATBCardTableModRefBS.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1SATBCardTableModRefBS.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@
#include "gc/shared/accessBarrierSupport.inline.hpp"
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
-#include "oops/oop.inline.hpp"
template
inline void G1SATBCardTableModRefBS::write_ref_field_pre(T* field) {
diff --git a/src/hotspot/share/gc/g1/vm_operations_g1.cpp b/src/hotspot/share/gc/g1/vm_operations_g1.cpp
index 148fe80e3ef..b80d876d584 100644
--- a/src/hotspot/share/gc/g1/vm_operations_g1.cpp
+++ b/src/hotspot/share/gc/g1/vm_operations_g1.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,34 +33,21 @@
#include "gc/shared/isGCActiveMark.hpp"
#include "runtime/interfaceSupport.hpp"
-VM_G1CollectForAllocation::VM_G1CollectForAllocation(uint gc_count_before,
- size_t word_size)
- : VM_G1OperationWithAllocRequest(gc_count_before, word_size,
- GCCause::_allocation_failure) {
- guarantee(word_size != 0, "An allocation should always be requested with this operation.");
-}
-
-void VM_G1CollectForAllocation::doit() {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- GCCauseSetter x(g1h, _gc_cause);
-
- _result = g1h->satisfy_failed_allocation(_word_size, allocation_context(), &_pause_succeeded);
- assert(_result == NULL || _pause_succeeded,
- "if we get back a result, the pause should have succeeded");
-}
-
void VM_G1CollectFull::doit() {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
GCCauseSetter x(g1h, _gc_cause);
g1h->do_full_collection(false /* clear_all_soft_refs */);
}
-VM_G1IncCollectionPause::VM_G1IncCollectionPause(uint gc_count_before,
- size_t word_size,
- bool should_initiate_conc_mark,
- double target_pause_time_ms,
- GCCause::Cause gc_cause)
- : VM_G1OperationWithAllocRequest(gc_count_before, word_size, gc_cause),
+VM_G1CollectForAllocation::VM_G1CollectForAllocation(size_t word_size,
+ uint gc_count_before,
+ GCCause::Cause gc_cause,
+ bool should_initiate_conc_mark,
+ double target_pause_time_ms,
+ AllocationContext_t allocation_context)
+ : VM_CollectForAllocation(word_size, gc_count_before, gc_cause),
+ _pause_succeeded(false),
+ _allocation_context(allocation_context),
_should_initiate_conc_mark(should_initiate_conc_mark),
_target_pause_time_ms(target_pause_time_ms),
_should_retry_gc(false),
@@ -71,8 +58,8 @@ VM_G1IncCollectionPause::VM_G1IncCollectionPause(uint gc_count_before,
_gc_cause = gc_cause;
}
-bool VM_G1IncCollectionPause::doit_prologue() {
- bool res = VM_G1OperationWithAllocRequest::doit_prologue();
+bool VM_G1CollectForAllocation::doit_prologue() {
+ bool res = VM_CollectForAllocation::doit_prologue();
if (!res) {
if (_should_initiate_conc_mark) {
// The prologue can fail for a couple of reasons. The first is that another GC
@@ -87,7 +74,7 @@ bool VM_G1IncCollectionPause::doit_prologue() {
return res;
}
-void VM_G1IncCollectionPause::doit() {
+void VM_G1CollectForAllocation::doit() {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
assert(!_should_initiate_conc_mark || g1h->should_do_concurrent_full_gc(_gc_cause),
"only a GC locker, a System.gc(), stats update, whitebox, or a hum allocation induced GC should start a cycle");
@@ -95,7 +82,7 @@ void VM_G1IncCollectionPause::doit() {
if (_word_size > 0) {
// An allocation has been requested. So, try to do that first.
_result = g1h->attempt_allocation_at_safepoint(_word_size,
- allocation_context(),
+ _allocation_context,
false /* expect_null_cur_alloc_region */);
if (_result != NULL) {
// If we can successfully allocate before we actually do the
@@ -144,27 +131,38 @@ void VM_G1IncCollectionPause::doit() {
}
}
- _pause_succeeded =
- g1h->do_collection_pause_at_safepoint(_target_pause_time_ms);
- if (_pause_succeeded && _word_size > 0) {
- // An allocation had been requested.
- _result = g1h->attempt_allocation_at_safepoint(_word_size,
- allocation_context(),
- true /* expect_null_cur_alloc_region */);
+ // Try a partial collection of some kind.
+ _pause_succeeded = g1h->do_collection_pause_at_safepoint(_target_pause_time_ms);
+
+ if (_pause_succeeded) {
+ if (_word_size > 0) {
+ // An allocation had been requested. Do it, eventually trying a stronger
+ // kind of GC.
+ _result = g1h->satisfy_failed_allocation(_word_size, _allocation_context, &_pause_succeeded);
+ } else {
+ bool should_upgrade_to_full = !g1h->should_do_concurrent_full_gc(_gc_cause) &&
+ !g1h->has_regions_left_for_allocation();
+ if (should_upgrade_to_full) {
+ // There has been a request to perform a GC to free some space. We have no
+ // information on how much memory has been asked for. In case there are
+ // absolutely no regions left to allocate into, do a maximally compacting full GC.
+ log_info(gc, ergo)("Attempting maximally compacting collection");
+ _pause_succeeded = g1h->do_full_collection(false, /* explicit gc */
+ true /* clear_all_soft_refs */);
+ }
+ }
+ guarantee(_pause_succeeded, "Elevated collections during the safepoint must always succeed.");
} else {
assert(_result == NULL, "invariant");
- if (!_pause_succeeded) {
- // Another possible reason reason for the pause to not be successful
- // is that, again, the GC locker is active (and has become active
- // since the prologue was executed). In this case we should retry
- // the pause after waiting for the GC locker to become inactive.
- _should_retry_gc = true;
- }
+ // The only reason for the pause to not be successful is that, the GC locker is
+ // active (or has become active since the prologue was executed). In this case
+ // we should retry the pause after waiting for the GC locker to become inactive.
+ _should_retry_gc = true;
}
}
-void VM_G1IncCollectionPause::doit_epilogue() {
- VM_G1OperationWithAllocRequest::doit_epilogue();
+void VM_G1CollectForAllocation::doit_epilogue() {
+ VM_CollectForAllocation::doit_epilogue();
// If the pause was initiated by a System.gc() and
// +ExplicitGCInvokesConcurrent, we have to wait here for the cycle
diff --git a/src/hotspot/share/gc/g1/vm_operations_g1.hpp b/src/hotspot/share/gc/g1/vm_operations_g1.hpp
index 94844f72881..d05836007b6 100644
--- a/src/hotspot/share/gc/g1/vm_operations_g1.hpp
+++ b/src/hotspot/share/gc/g1/vm_operations_g1.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,26 +32,8 @@
// VM_operations for the G1 collector.
// VM_GC_Operation:
// - VM_CGC_Operation
+// - VM_G1CollectForAllocation
// - VM_G1CollectFull
-// - VM_G1OperationWithAllocRequest
-// - VM_G1CollectForAllocation
-// - VM_G1IncCollectionPause
-
-class VM_G1OperationWithAllocRequest : public VM_CollectForAllocation {
-protected:
- bool _pause_succeeded;
- AllocationContext_t _allocation_context;
-
-public:
- VM_G1OperationWithAllocRequest(uint gc_count_before,
- size_t word_size,
- GCCause::Cause gc_cause)
- : VM_CollectForAllocation(word_size, gc_count_before, gc_cause),
- _pause_succeeded(false) {}
- bool pause_succeeded() { return _pause_succeeded; }
- void set_allocation_context(AllocationContext_t context) { _allocation_context = context; }
- AllocationContext_t allocation_context() { return _allocation_context; }
-};
class VM_G1CollectFull: public VM_GC_Operation {
public:
@@ -62,41 +44,35 @@ public:
virtual VMOp_Type type() const { return VMOp_G1CollectFull; }
virtual void doit();
virtual const char* name() const {
- return "full garbage-first collection";
+ return "G1 Full collection";
}
};
-class VM_G1CollectForAllocation: public VM_G1OperationWithAllocRequest {
-public:
- VM_G1CollectForAllocation(uint gc_count_before,
- size_t word_size);
- virtual VMOp_Type type() const { return VMOp_G1CollectForAllocation; }
- virtual void doit();
- virtual const char* name() const {
- return "garbage-first collection to satisfy allocation";
- }
-};
-
-class VM_G1IncCollectionPause: public VM_G1OperationWithAllocRequest {
+class VM_G1CollectForAllocation: public VM_CollectForAllocation {
private:
+ bool _pause_succeeded;
+ AllocationContext_t _allocation_context;
+
bool _should_initiate_conc_mark;
bool _should_retry_gc;
double _target_pause_time_ms;
uint _old_marking_cycles_completed_before;
public:
- VM_G1IncCollectionPause(uint gc_count_before,
- size_t word_size,
- bool should_initiate_conc_mark,
- double target_pause_time_ms,
- GCCause::Cause gc_cause);
- virtual VMOp_Type type() const { return VMOp_G1IncCollectionPause; }
+ VM_G1CollectForAllocation(size_t word_size,
+ uint gc_count_before,
+ GCCause::Cause gc_cause,
+ bool should_initiate_conc_mark,
+ double target_pause_time_ms,
+ AllocationContext_t allocation_context);
+ virtual VMOp_Type type() const { return VMOp_G1CollectForAllocation; }
virtual bool doit_prologue();
virtual void doit();
virtual void doit_epilogue();
virtual const char* name() const {
- return "garbage-first incremental collection pause";
+ return "G1 collect for allocation";
}
bool should_retry_gc() const { return _should_retry_gc; }
+ bool pause_succeeded() { return _pause_succeeded; }
};
// Concurrent GC stop-the-world operations such as remark and cleanup;
diff --git a/src/hotspot/share/gc/shared/barrierSet.hpp b/src/hotspot/share/gc/shared/barrierSet.hpp
index 63eeca7f8f3..7e5b93364e4 100644
--- a/src/hotspot/share/gc/shared/barrierSet.hpp
+++ b/src/hotspot/share/gc/shared/barrierSet.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -147,9 +147,8 @@ public:
// 3) Provide specializations for BarrierSet::GetName and BarrierSet::GetType.
template
class AccessBarrier: protected RawAccessBarrier {
- protected:
+ private:
typedef RawAccessBarrier Raw;
- typedef typename BarrierSetT::template AccessBarrier CRTPAccessBarrier;
public:
// Primitive heap accesses. These accessors get resolved when
diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp
index d322cfd33af..2f84d45aa29 100644
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp
@@ -804,7 +804,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:
@@ -822,6 +822,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;
diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
index 78ebe926c2a..23ed193ae0d 100644
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1433,6 +1433,7 @@ C2V_VMENTRY(jobject, getNextStackFrame, (JNIEnv*, jobject compilerToVM, jobject
Deoptimization::reassign_fields(fst.current(), fst.register_map(), scope->objects(), realloc_failures, false);
GrowableArray* local_values = scope->locals();
+ assert(local_values != NULL, "NULL locals");
typeArrayOop array_oop = oopFactory::new_boolArray(local_values->length(), CHECK_NULL);
typeArrayHandle array(THREAD, array_oop);
for (int i = 0; i < local_values->length(); i++) {
@@ -1660,7 +1661,6 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame
GrowableArray* scopeLocals = cvf->scope()->locals();
StackValueCollection* locals = cvf->locals();
-
if (locals != NULL) {
for (int i2 = 0; i2 < locals->size(); i2++) {
StackValue* var = locals->at(i2);
@@ -1671,6 +1671,27 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame
}
}
}
+
+ GrowableArray* scopeExpressions = cvf->scope()->expressions();
+ StackValueCollection* expressions = cvf->expressions();
+ if (expressions != NULL) {
+ for (int i2 = 0; i2 < expressions->size(); i2++) {
+ StackValue* var = expressions->at(i2);
+ if (var->type() == T_OBJECT && scopeExpressions->at(i2)->is_object()) {
+ jvalue val;
+ val.l = (jobject) expressions->at(i2)->get_obj()();
+ cvf->update_stack(T_OBJECT, i2, val);
+ }
+ }
+ }
+
+ GrowableArray* scopeMonitors = cvf->scope()->monitors();
+ GrowableArray* monitors = cvf->monitors();
+ if (monitors != NULL) {
+ for (int i2 = 0; i2 < monitors->length(); i2++) {
+ cvf->update_monitor(i2, monitors->at(i2));
+ }
+ }
}
// all locals are materialized by now
diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp
index cf5953f9a72..eca9635ec87 100644
--- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp
+++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -351,7 +351,7 @@ class name : AllStatic {
static type name() { \
assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \
InstanceKlass* ik = klassName::klass(); \
- address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \
+ address addr = ik->static_field_addr(_##name##_offset); \
oop result = HeapAccess<>::oop_load((HeapWord*)addr); \
return type(result); \
} \
@@ -359,7 +359,7 @@ class name : AllStatic {
assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \
assert(klassName::klass() != NULL, "Class not yet loaded: " #klassName); \
InstanceKlass* ik = klassName::klass(); \
- address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \
+ address addr = ik->static_field_addr(_##name##_offset); \
HeapAccess<>::oop_store((HeapWord*)addr, x); \
}
#define STATIC_PRIMITIVE_FIELD(klassName, name, jtypename) \
@@ -367,13 +367,13 @@ class name : AllStatic {
static jtypename name() { \
assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \
InstanceKlass* ik = klassName::klass(); \
- address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \
+ address addr = ik->static_field_addr(_##name##_offset); \
return HeapAccess<>::load((jtypename*)addr); \
} \
static void set_##name(jtypename x) { \
assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \
InstanceKlass* ik = klassName::klass(); \
- address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \
+ address addr = ik->static_field_addr(_##name##_offset); \
HeapAccess<>::store((jtypename*)addr, x); \
}
diff --git a/src/hotspot/share/oops/access.hpp b/src/hotspot/share/oops/access.hpp
index 106919d9e8a..7a1842f8a25 100644
--- a/src/hotspot/share/oops/access.hpp
+++ b/src/hotspot/share/oops/access.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -342,7 +342,7 @@ class Access: public AllStatic {
template
static void verify_primitive_decorators() {
const DecoratorSet primitive_decorators = (AS_DECORATOR_MASK ^ AS_NO_KEEPALIVE) | IN_HEAP |
- IN_HEAP_ARRAY | MO_DECORATOR_MASK;
+ IN_HEAP_ARRAY;
verify_decorators();
}
@@ -350,7 +350,7 @@ class Access: public AllStatic {
static void verify_oop_decorators() {
const DecoratorSet oop_decorators = AS_DECORATOR_MASK | IN_DECORATOR_MASK |
(ON_DECORATOR_MASK ^ ON_UNKNOWN_OOP_REF) | // no unknown oop refs outside of the heap
- OOP_DECORATOR_MASK | MO_DECORATOR_MASK;
+ OOP_DECORATOR_MASK;
verify_decorators();
}
@@ -358,8 +358,7 @@ class Access: public AllStatic {
static void verify_heap_oop_decorators() {
const DecoratorSet heap_oop_decorators = AS_DECORATOR_MASK | ON_DECORATOR_MASK |
OOP_DECORATOR_MASK | (IN_DECORATOR_MASK ^
- (IN_ROOT ^ IN_CONCURRENT_ROOT)) | // no root accesses in the heap
- MO_DECORATOR_MASK;
+ (IN_ROOT | IN_CONCURRENT_ROOT)); // no root accesses in the heap
verify_decorators();
}
diff --git a/src/hotspot/share/oops/access.inline.hpp b/src/hotspot/share/oops/access.inline.hpp
index 36f709f08f5..aeadfbf58cd 100644
--- a/src/hotspot/share/oops/access.inline.hpp
+++ b/src/hotspot/share/oops/access.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,11 +491,12 @@ namespace AccessInternal {
// not possible.
struct PreRuntimeDispatch: AllStatic {
template
- static bool can_hardwire_raw() {
- return !HasDecorator::value || // primitive access
- !HasDecorator::value || // don't care about compressed oops (oop* address)
- HasDecorator::value; // we can infer we use compressed oops (narrowOop* address)
- }
+ struct CanHardwireRaw: public IntegralConstant<
+ bool,
+ !HasDecorator::value || // primitive access
+ !HasDecorator::value || // don't care about compressed oops (oop* address)
+ HasDecorator::value> // we can infer we use compressed oops (narrowOop* address)
+ {};
static const DecoratorSet convert_compressed_oops = INTERNAL_RT_USE_COMPRESSED_OOPS | INTERNAL_CONVERT_COMPRESSED_OOP;
@@ -507,16 +508,21 @@ namespace AccessInternal {
template
inline static typename EnableIf<
- HasDecorator::value>::type
+ HasDecorator::value && CanHardwireRaw::value>::type
store(void* addr, T value) {
typedef RawAccessBarrier Raw;
- if (can_hardwire_raw()) {
- if (HasDecorator::value) {
- Raw::oop_store(addr, value);
- } else {
- Raw::store(addr, value);
- }
- } else if (UseCompressedOops) {
+ if (HasDecorator::value) {
+ Raw::oop_store(addr, value);
+ } else {
+ Raw::store(addr, value);
+ }
+ }
+
+ template
+ inline static typename EnableIf<
+ HasDecorator::value && !CanHardwireRaw::value>::type
+ store(void* addr, T value) {
+ if (UseCompressedOops) {
const DecoratorSet expanded_decorators = decorators | convert_compressed_oops;
PreRuntimeDispatch::store(addr, value);
} else {
@@ -558,16 +564,21 @@ namespace AccessInternal {
template
inline static typename EnableIf<
- HasDecorator::value, T>::type
+ HasDecorator::value && CanHardwireRaw::value, T>::type
load(void* addr) {
typedef RawAccessBarrier Raw;
- if (can_hardwire_raw()) {
- if (HasDecorator::value) {
- return Raw::template oop_load(addr);
- } else {
- return Raw::template load(addr);
- }
- } else if (UseCompressedOops) {
+ if (HasDecorator::value) {
+ return Raw::template oop_load(addr);
+ } else {
+ return Raw::template load(addr);
+ }
+ }
+
+ template
+ inline static typename EnableIf<
+ HasDecorator::value && !CanHardwireRaw::value, T>::type
+ load(void* addr) {
+ if (UseCompressedOops) {
const DecoratorSet expanded_decorators = decorators | convert_compressed_oops;
return PreRuntimeDispatch::load(addr);
} else {
@@ -609,16 +620,21 @@ namespace AccessInternal {
template
inline static typename EnableIf<
- HasDecorator::value, T>::type
+ HasDecorator::value && CanHardwireRaw::value, T>::type
atomic_cmpxchg(T new_value, void* addr, T compare_value) {
typedef RawAccessBarrier Raw;
- if (can_hardwire_raw()) {
- if (HasDecorator::value) {
- return Raw::oop_atomic_cmpxchg(new_value, addr, compare_value);
- } else {
- return Raw::atomic_cmpxchg(new_value, addr, compare_value);
- }
- } else if (UseCompressedOops) {
+ if (HasDecorator::value) {
+ return Raw::oop_atomic_cmpxchg(new_value, addr, compare_value);
+ } else {
+ return Raw::atomic_cmpxchg(new_value, addr, compare_value);
+ }
+ }
+
+ template
+ inline static typename EnableIf<
+ HasDecorator::value && !CanHardwireRaw::value, T>::type
+ atomic_cmpxchg(T new_value, void* addr, T compare_value) {
+ if (UseCompressedOops) {
const DecoratorSet expanded_decorators = decorators | convert_compressed_oops;
return PreRuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value);
} else {
@@ -661,16 +677,21 @@ namespace AccessInternal {
template
inline static typename EnableIf<
- HasDecorator::value, T>::type
+ HasDecorator::value && CanHardwireRaw::value, T>::type
atomic_xchg(T new_value, void* addr) {
typedef RawAccessBarrier Raw;
- if (can_hardwire_raw()) {
- if (HasDecorator::value) {
- return Raw::oop_atomic_xchg(new_value, addr);
- } else {
- return Raw::atomic_xchg(new_value, addr);
- }
- } else if (UseCompressedOops) {
+ if (HasDecorator::value) {
+ return Raw::oop_atomic_xchg(new_value, addr);
+ } else {
+ return Raw::atomic_xchg(new_value, addr);
+ }
+ }
+
+ template
+ inline static typename EnableIf<
+ HasDecorator::value && !CanHardwireRaw::value, T>::type
+ atomic_xchg(T new_value, void* addr) {
+ if (UseCompressedOops) {
const DecoratorSet expanded_decorators = decorators | convert_compressed_oops;
return PreRuntimeDispatch::atomic_xchg(new_value, addr);
} else {
@@ -797,6 +818,13 @@ namespace AccessInternal {
PreRuntimeDispatch::store(addr, value);
}
+ template
+ inline void store_reduce_types(narrowOop* addr, narrowOop value) {
+ const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP |
+ INTERNAL_RT_USE_COMPRESSED_OOPS;
+ PreRuntimeDispatch::store(addr, value);
+ }
+
template
inline void store_reduce_types(HeapWord* addr, oop value) {
const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP;
@@ -816,7 +844,16 @@ namespace AccessInternal {
}
template
- inline oop atomic_cmpxchg_reduce_types(oop new_value, HeapWord* addr, oop compare_value) {
+ inline narrowOop atomic_cmpxchg_reduce_types(narrowOop new_value, narrowOop* addr, narrowOop compare_value) {
+ const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP |
+ INTERNAL_RT_USE_COMPRESSED_OOPS;
+ return PreRuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value);
+ }
+
+ template
+ inline oop atomic_cmpxchg_reduce_types(oop new_value,
+ HeapWord* addr,
+ oop compare_value) {
const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP;
return PreRuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value);
}
@@ -834,6 +871,13 @@ namespace AccessInternal {
return PreRuntimeDispatch::atomic_xchg(new_value, addr);
}
+ template
+ inline narrowOop atomic_xchg_reduce_types(narrowOop new_value, narrowOop* addr) {
+ const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP |
+ INTERNAL_RT_USE_COMPRESSED_OOPS;
+ return PreRuntimeDispatch::atomic_xchg(new_value, addr);
+ }
+
template
inline oop atomic_xchg_reduce_types(oop new_value, HeapWord* addr) {
const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP;
@@ -846,9 +890,10 @@ namespace AccessInternal {
}
template
- inline oop load_reduce_types(narrowOop* addr) {
- const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP | INTERNAL_RT_USE_COMPRESSED_OOPS;
- return PreRuntimeDispatch::load(addr);
+ inline typename OopOrNarrowOop::type load_reduce_types(narrowOop* addr) {
+ const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP |
+ INTERNAL_RT_USE_COMPRESSED_OOPS;
+ return PreRuntimeDispatch::load::type>(addr);
}
template
diff --git a/src/hotspot/share/oops/accessBackend.hpp b/src/hotspot/share/oops/accessBackend.hpp
index d5829376560..cd37c9f8855 100644
--- a/src/hotspot/share/oops/accessBackend.hpp
+++ b/src/hotspot/share/oops/accessBackend.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* 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 "metaprogramming/conditional.hpp"
#include "metaprogramming/enableIf.hpp"
#include "metaprogramming/integralConstant.hpp"
+#include "metaprogramming/isSame.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
@@ -54,11 +55,11 @@ namespace AccessInternal {
BARRIER_CLONE
};
- template
+ template
struct MustConvertCompressedOop: public IntegralConstant::value &&
- HasDecorator::value &&
- HasDecorator::value> {};
+ IsSame::type, narrowOop>::value &&
+ IsSame::value> {};
// This metafunction returns an appropriate oop type if the value is oop-like
// and otherwise returns the same type T.
@@ -172,13 +173,13 @@ protected:
// Only encode if INTERNAL_VALUE_IS_OOP
template
static inline typename EnableIf<
- AccessInternal::MustConvertCompressedOop::value,
+ AccessInternal::MustConvertCompressedOop::value,
typename HeapOopType::type>::type
encode_internal(T value);
template
static inline typename EnableIf<
- !AccessInternal::MustConvertCompressedOop::value, T>::type
+ !AccessInternal::MustConvertCompressedOop::value, T>::type
encode_internal(T value) {
return value;
}
@@ -192,12 +193,12 @@ protected:
// Only decode if INTERNAL_VALUE_IS_OOP
template
static inline typename EnableIf<
- AccessInternal::MustConvertCompressedOop::value, T>::type
+ AccessInternal::MustConvertCompressedOop::value, T>::type
decode_internal(typename HeapOopType::type value);
template
static inline typename EnableIf<
- !AccessInternal::MustConvertCompressedOop::value, T>::type
+ !AccessInternal::MustConvertCompressedOop::value, T>::type
decode_internal(T value) {
return value;
}
diff --git a/src/hotspot/share/oops/accessBackend.inline.hpp b/src/hotspot/share/oops/accessBackend.inline.hpp
index 1d7890271ce..4ba8f506ef7 100644
--- a/src/hotspot/share/oops/accessBackend.inline.hpp
+++ b/src/hotspot/share/oops/accessBackend.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
template
template
inline typename EnableIf<
- AccessInternal::MustConvertCompressedOop::value, T>::type
+ AccessInternal::MustConvertCompressedOop::value, T>::type
RawAccessBarrier::decode_internal(typename HeapOopType::type value) {
if (HasDecorator::value) {
return oopDesc::decode_heap_oop_not_null(value);
@@ -44,7 +44,7 @@ RawAccessBarrier::decode_internal(typename HeapOopType:
template
template
inline typename EnableIf<
- AccessInternal::MustConvertCompressedOop::value,
+ AccessInternal::MustConvertCompressedOop::value,
typename HeapOopType::type>::type
RawAccessBarrier::encode_internal(T value) {
if (HasDecorator::value) {
diff --git a/src/hotspot/share/oops/compiledICHolder.cpp b/src/hotspot/share/oops/compiledICHolder.cpp
index 55397d06c10..19f44adab81 100644
--- a/src/hotspot/share/oops/compiledICHolder.cpp
+++ b/src/hotspot/share/oops/compiledICHolder.cpp
@@ -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");
}
diff --git a/src/hotspot/share/oops/compiledICHolder.hpp b/src/hotspot/share/oops/compiledICHolder.hpp
index c3e899fde88..af4a38a9f33 100644
--- a/src/hotspot/share/oops/compiledICHolder.hpp
+++ b/src/hotspot/share/oops/compiledICHolder.hpp
@@ -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 {
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);
diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp
index 8dc75922419..b947b4aa26c 100644
--- a/src/hotspot/share/oops/constantPool.hpp
+++ b/src/hotspot/share/oops/constantPool.hpp
@@ -25,6 +25,7 @@
#ifndef SHARE_VM_OOPS_CONSTANTPOOLOOP_HPP
#define SHARE_VM_OOPS_CONSTANTPOOLOOP_HPP
+#include "memory/allocation.inline.hpp"
#include "oops/arrayOop.hpp"
#include "oops/cpCache.hpp"
#include "oops/objArrayOop.hpp"
@@ -1021,7 +1022,7 @@ class SymbolHashMap: public CHeapObj {
delete(cur);
}
}
- delete _buckets;
+ FREE_C_HEAP_ARRAY(SymbolHashMapBucket, _buckets);
}
}; // End SymbolHashMap class
diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp
index 661428651f1..9c30d2ff64c 100644
--- a/src/hotspot/share/oops/cpCache.cpp
+++ b/src/hotspot/share/oops/cpCache.cpp
@@ -278,14 +278,16 @@ void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, const
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,
+ Klass* 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());
@@ -514,10 +516,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()) {
@@ -526,63 +541,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) {
@@ -599,10 +586,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)) {
diff --git a/src/hotspot/share/oops/cpCache.hpp b/src/hotspot/share/oops/cpCache.hpp
index 16670229ec0..c8a1b8fb51a 100644
--- a/src/hotspot/share/oops/cpCache.hpp
+++ b/src/hotspot/share/oops/cpCache.hpp
@@ -249,6 +249,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
void set_itable_call(
Bytecodes::Code invoke_code, // the bytecode used; must be invokeinterface
+ Klass* referenced_klass, // the referenced klass in the InterfaceMethodref
const methodHandle& method, // the resolved interface method
int itable_index // index into itable for the method
);
@@ -352,6 +353,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; }
intx flags_ord() const { return (intx)OrderAccess::load_acquire(&_flags); }
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); }
@@ -387,7 +389,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);
diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
index 4888d180e13..201f2988186 100644
--- a/src/hotspot/share/oops/instanceKlass.cpp
+++ b/src/hotspot/share/oops/instanceKlass.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2265,7 +2265,8 @@ void InstanceKlass::set_source_debug_extension(const char* array, int length) {
}
address InstanceKlass::static_field_addr(int offset) {
- return (address)(offset + InstanceMirrorKlass::offset_of_static_fields() + cast_from_oop(java_mirror()));
+ assert(offset >= InstanceMirrorKlass::offset_of_static_fields(), "has already been adjusted");
+ return (address)(offset + cast_from_oop(java_mirror()));
}
@@ -3421,6 +3422,15 @@ void JNIid::verify(Klass* holder) {
}
}
+oop InstanceKlass::klass_holder_phantom() {
+ oop* addr;
+ if (is_anonymous()) {
+ addr = _java_mirror.ptr_raw();
+ } else {
+ addr = &class_loader_data()->_class_loader;
+ }
+ return RootAccess::oop_load(addr);
+}
#ifdef ASSERT
void InstanceKlass::set_init_state(ClassState state) {
diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp
index 15a6b69bcc2..58656736cdf 100644
--- a/src/hotspot/share/oops/instanceKlass.hpp
+++ b/src/hotspot/share/oops/instanceKlass.hpp
@@ -609,9 +609,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;
}
}
@@ -623,6 +625,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;
}
@@ -640,6 +645,11 @@ class InstanceKlass: public Klass {
return is_anonymous() ? java_mirror() : class_loader();
}
+ // Load the klass_holder as a phantom. This is useful when a weak Klass
+ // pointer has been "peeked" and then must be kept alive before it may
+ // be used safely.
+ oop klass_holder_phantom();
+
bool is_contended() const {
return (_misc_flags & _misc_is_contended) != 0;
}
diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp
index a718ccd3e96..6cbf97878ed 100644
--- a/src/hotspot/share/oops/klassVtable.cpp
+++ b/src/hotspot/share/oops/klassVtable.cpp
@@ -1200,7 +1200,6 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
Array* methods = InstanceKlass::cast(interf)->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)->class_loader());
int ime_count = method_count_for_interface(interf);
@@ -1369,8 +1368,10 @@ void visit_all_interfaces(Array* 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);
}
}
diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp
index 6866b833fdd..424752dd03e 100644
--- a/src/hotspot/share/oops/method.hpp
+++ b/src/hotspot/share/oops/method.hpp
@@ -698,6 +698,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); }
diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp
index 0e9384c6291..9f7f0c0a0ea 100644
--- a/src/hotspot/share/oops/oop.hpp
+++ b/src/hotspot/share/oops/oop.hpp
@@ -28,6 +28,7 @@
#include "gc/shared/specialized_oop_closures.hpp"
#include "memory/iterator.hpp"
#include "memory/memRegion.hpp"
+#include "oops/access.hpp"
#include "oops/metadata.hpp"
#include "utilities/macros.hpp"
@@ -178,6 +179,8 @@ class oopDesc {
static inline void encode_store_heap_oop(oop* p, oop v);
// Access to fields in a instanceOop through these methods.
+ template
+ oop obj_field_access(int offset) const;
oop obj_field(int offset) const;
void obj_field_put(int offset, oop value);
void obj_field_put_raw(int offset, oop value);
diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp
index a8b8d37f345..6b28c4ddb1b 100644
--- a/src/hotspot/share/oops/oop.inline.hpp
+++ b/src/hotspot/share/oops/oop.inline.hpp
@@ -326,7 +326,10 @@ void oopDesc::encode_store_heap_oop(narrowOop* p, oop v) {
*p = encode_heap_oop(v);
}
+template
+inline oop oopDesc::obj_field_access(int offset) const { return HeapAccess::oop_load_at(as_oop(), offset); }
inline oop oopDesc::obj_field(int offset) const { return HeapAccess<>::oop_load_at(as_oop(), offset); }
+
inline void oopDesc::obj_field_put(int offset, oop value) { HeapAccess<>::oop_store_at(as_oop(), offset, value); }
inline jbyte oopDesc::byte_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); }
diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp
index 7def4ee721e..d77f451ae0a 100644
--- a/src/hotspot/share/opto/callnode.cpp
+++ b/src/hotspot/share/opto/callnode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -772,7 +772,7 @@ bool CallNode::may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) {
ciKlass* boxing_klass = t_oop->klass();
if (is_CallStaticJava() && as_CallStaticJava()->is_boxing_method()) {
// Skip unrelated boxing methods.
- Node* proj = proj_out(TypeFunc::Parms);
+ Node* proj = proj_out_or_null(TypeFunc::Parms);
if ((proj == NULL) || (phase->type(proj)->is_instptr()->klass() != boxing_klass)) {
return false;
}
@@ -784,7 +784,7 @@ bool CallNode::may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) {
}
// May modify (by reflection) if an boxing object is passed
// as argument or returned.
- Node* proj = returns_pointer() ? proj_out(TypeFunc::Parms) : NULL;
+ Node* proj = returns_pointer() ? proj_out_or_null(TypeFunc::Parms) : NULL;
if (proj != NULL) {
const TypeInstPtr* inst_t = phase->type(proj)->isa_instptr();
if ((inst_t != NULL) && (!inst_t->klass_is_exact() ||
@@ -824,7 +824,7 @@ bool CallNode::has_non_debug_use(Node *n) {
Node *CallNode::result_cast() {
Node *cast = NULL;
- Node *p = proj_out(TypeFunc::Parms);
+ Node *p = proj_out_or_null(TypeFunc::Parms);
if (p == NULL)
return NULL;
@@ -1378,13 +1378,13 @@ Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
PhaseIterGVN *igvn = phase->is_IterGVN();
// Unreachable fall through path (negative array length),
// the allocation can only throw so disconnect it.
- Node* proj = proj_out(TypeFunc::Control);
+ Node* proj = proj_out_or_null(TypeFunc::Control);
Node* catchproj = NULL;
if (proj != NULL) {
for (DUIterator_Fast imax, i = proj->fast_outs(imax); i < imax; i++) {
Node *cn = proj->fast_out(i);
if (cn->is_Catch()) {
- catchproj = cn->as_Multi()->proj_out(CatchProjNode::fall_through_index);
+ catchproj = cn->as_Multi()->proj_out_or_null(CatchProjNode::fall_through_index);
break;
}
}
@@ -1442,7 +1442,7 @@ Node *AllocateArrayNode::make_ideal_length(const TypeOopPtr* oop_type, PhaseTran
// Create a cast which is control dependent on the initialization to
// propagate the fact that the array length must be positive.
length = new CastIINode(length, narrow_length_type);
- length->set_req(0, initialization()->proj_out(0));
+ length->set_req(0, initialization()->proj_out_or_null(0));
}
}
diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp
index e2269104bf7..eec31934e4e 100644
--- a/src/hotspot/share/opto/cfgnode.cpp
+++ b/src/hotspot/share/opto/cfgnode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2373,7 +2373,7 @@ Node *NeverBranchNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (can_reshape && !in(0)->is_Loop()) {
// Dead code elimination can sometimes delete this projection so
// if it's not there, there's nothing to do.
- Node* fallthru = proj_out(0);
+ Node* fallthru = proj_out_or_null(0);
if (fallthru != NULL) {
phase->is_IterGVN()->replace_node(fallthru, in(0));
}
diff --git a/src/hotspot/share/opto/divnode.hpp b/src/hotspot/share/opto/divnode.hpp
index b1bf06e6750..b0b1263027d 100644
--- a/src/hotspot/share/opto/divnode.hpp
+++ b/src/hotspot/share/opto/divnode.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -154,8 +154,8 @@ public:
virtual bool is_CFG() const { return false; }
virtual uint ideal_reg() const { return NotAMachineReg; }
- ProjNode* div_proj() { return proj_out(div_proj_num); }
- ProjNode* mod_proj() { return proj_out(mod_proj_num); }
+ ProjNode* div_proj() { return proj_out_or_null(div_proj_num); }
+ ProjNode* mod_proj() { return proj_out_or_null(mod_proj_num); }
};
//------------------------------DivModINode---------------------------------------
diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp
index c635e60361d..f6e1078172c 100644
--- a/src/hotspot/share/opto/escape.cpp
+++ b/src/hotspot/share/opto/escape.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -366,7 +366,7 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de
delayed_worklist->push(n);
// Check if a call returns an object.
if ((n->as_Call()->returns_pointer() &&
- n->as_Call()->proj_out(TypeFunc::Parms) != NULL) ||
+ n->as_Call()->proj_out_or_null(TypeFunc::Parms) != NULL) ||
(n->is_CallStaticJava() &&
n->as_CallStaticJava()->is_boxing_method())) {
add_call_node(n->as_Call());
@@ -2674,7 +2674,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
PhaseGVN* igvn = _igvn;
const TypeOopPtr *toop = C->get_adr_type(alias_idx)->isa_oopptr();
bool is_instance = (toop != NULL) && toop->is_known_instance();
- Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
+ Node *start_mem = C->start()->proj_out_or_null(TypeFunc::Memory);
Node *prev = NULL;
Node *result = orig_mem;
while (prev != result) {
@@ -3028,7 +3028,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist,
// An allocation may have an Initialize which has raw stores. Scan
// the users of the raw allocation result and push AddP users
// on alloc_worklist.
- Node *raw_result = alloc->proj_out(TypeFunc::Parms);
+ Node *raw_result = alloc->proj_out_or_null(TypeFunc::Parms);
assert (raw_result != NULL, "must have an allocation result");
for (DUIterator_Fast imax, i = raw_result->fast_outs(imax); i < imax; i++) {
Node *use = raw_result->fast_out(i);
@@ -3219,7 +3219,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist,
// we don't need to do anything, but the users must be pushed
} else if (n->is_MemBar()) { // Initialize, MemBar nodes
// we don't need to do anything, but the users must be pushed
- n = n->as_MemBar()->proj_out(TypeFunc::Memory);
+ n = n->as_MemBar()->proj_out_or_null(TypeFunc::Memory);
if (n == NULL)
continue;
} else if (n->Opcode() == Op_StrCompressedCopy ||
diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp
index 207897c7a60..fad539c2fd9 100644
--- a/src/hotspot/share/opto/graphKit.cpp
+++ b/src/hotspot/share/opto/graphKit.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -3754,7 +3754,7 @@ AllocateNode* InitializeNode::allocation() {
// Trace Allocate -> Proj[Parm] -> Initialize
InitializeNode* AllocateNode::initialization() {
- ProjNode* rawoop = proj_out(AllocateNode::RawAddress);
+ ProjNode* rawoop = proj_out_or_null(AllocateNode::RawAddress);
if (rawoop == NULL) return NULL;
for (DUIterator_Fast imax, i = rawoop->fast_outs(imax); i < imax; i++) {
Node* init = rawoop->fast_out(i);
diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp
index 3437dfed372..2bbec0406f3 100644
--- a/src/hotspot/share/opto/ifnode.cpp
+++ b/src/hotspot/share/opto/ifnode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -505,7 +505,7 @@ ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) {
// Flip 1: If (Bool[<] CmpU(l, LoadRange)) ...
// Flip 2: If (Bool[<=] CmpU(LoadRange, l)) ...
- ProjNode* iftrap = proj_out(flip_test == 2 ? true : false);
+ ProjNode* iftrap = proj_out_or_null(flip_test == 2 ? true : false);
return iftrap;
}
@@ -1195,14 +1195,17 @@ bool IfNode::is_null_check(ProjNode* proj, PhaseIterGVN* igvn) {
// Check that the If that is in between the 2 integer comparisons has
// no side effect
bool IfNode::is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn) {
- if (proj != NULL &&
- proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) &&
- proj->outcnt() <= 2) {
+ if (proj == NULL) {
+ return false;
+ }
+ CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none);
+ if (unc != NULL && proj->outcnt() <= 2) {
if (proj->outcnt() == 1 ||
// Allow simple null check from LoadRange
(is_cmp_with_loadrange(proj) && is_null_check(proj, igvn))) {
CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none);
CallStaticJavaNode* dom_unc = proj->in(0)->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none);
+ assert(dom_unc != NULL, "is_uncommon_trap_if_pattern returned NULL");
// reroute_side_effect_free_unc changes the state of this
// uncommon trap to restart execution at the previous
@@ -1471,7 +1474,7 @@ Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN *igvn) {
// be skipped. For example, range check predicate has two checks
// for lower and upper bounds.
ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj();
- if ((unc_proj != NULL) && (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL)) {
+ if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL) {
prev_dom = idom;
}
diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp
index 24ae05c2a01..f7bb9341adf 100644
--- a/src/hotspot/share/opto/library_call.cpp
+++ b/src/hotspot/share/opto/library_call.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1495,7 +1495,7 @@ bool LibraryCallKit::inline_string_copy(bool compress) {
// escape analysis can go from the MemBarStoreStoreNode to the
// AllocateNode and eliminate the MemBarStoreStoreNode if possible
// based on the escape status of the AllocateNode.
- insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out(AllocateNode::RawAddress));
+ insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out_or_null(AllocateNode::RawAddress));
}
if (compress) {
set_result(_gvn.transform(count));
@@ -1589,7 +1589,7 @@ bool LibraryCallKit::inline_string_toBytesU() {
// escape analysis can go from the MemBarStoreStoreNode to the
// AllocateNode and eliminate the MemBarStoreStoreNode if possible
// based on the escape status of the AllocateNode.
- insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out(AllocateNode::RawAddress));
+ insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out_or_null(AllocateNode::RawAddress));
} else {
insert_mem_bar(Op_MemBarCPUOrder);
}
@@ -1675,7 +1675,7 @@ bool LibraryCallKit::inline_string_getCharsU() {
// escape analysis can go from the MemBarStoreStoreNode to the
// AllocateNode and eliminate the MemBarStoreStoreNode if possible
// based on the escape status of the AllocateNode.
- insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out(AllocateNode::RawAddress));
+ insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out_or_null(AllocateNode::RawAddress));
} else {
insert_mem_bar(Op_MemBarCPUOrder);
}
@@ -4722,7 +4722,7 @@ void LibraryCallKit::copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, b
// escape analysis can go from the MemBarStoreStoreNode to the
// AllocateNode and eliminate the MemBarStoreStoreNode if possible
// based on the escape status of the AllocateNode.
- insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out(AllocateNode::RawAddress));
+ insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out_or_null(AllocateNode::RawAddress));
} else {
insert_mem_bar(Op_MemBarCPUOrder);
}
@@ -5031,7 +5031,7 @@ void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, No
Node *mem = reset_memory();
set_all_memory(mem);
alloc->set_req(TypeFunc::Memory, mem);
- set_control(init->proj_out(TypeFunc::Control));
+ set_control(init->proj_out_or_null(TypeFunc::Control));
set_i_o(callprojs.fallthrough_ioproj);
// Update memory as done in GraphKit::set_output_for_allocation()
@@ -5042,8 +5042,8 @@ void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, No
}
const TypePtr* telemref = ary_type->add_offset(Type::OffsetBot);
int elemidx = C->get_alias_index(telemref);
- set_memory(init->proj_out(TypeFunc::Memory), Compile::AliasIdxRaw);
- set_memory(init->proj_out(TypeFunc::Memory), elemidx);
+ set_memory(init->proj_out_or_null(TypeFunc::Memory), Compile::AliasIdxRaw);
+ set_memory(init->proj_out_or_null(TypeFunc::Memory), elemidx);
Node* allocx = _gvn.transform(alloc);
assert(allocx == alloc, "where has the allocation gone?");
@@ -5360,7 +5360,7 @@ LibraryCallKit::tightly_coupled_allocation(Node* ptr,
// to finish initializing the allocated object.
if ((ctl->is_IfFalse() || ctl->is_IfTrue()) && ctl->in(0)->is_If()) {
IfNode* iff = ctl->in(0)->as_If();
- Node* not_ctl = iff->proj_out(1 - ctl->as_Proj()->_con);
+ Node* not_ctl = iff->proj_out_or_null(1 - ctl->as_Proj()->_con);
assert(not_ctl != NULL && not_ctl != ctl, "found alternate");
if (slow_region != NULL && slow_region->find_edge(not_ctl) >= 1) {
ctl = iff->in(0); // This test feeds the known slow_region.
diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp
index 28a270ef4c4..c25edf8b499 100644
--- a/src/hotspot/share/opto/loopTransform.cpp
+++ b/src/hotspot/share/opto/loopTransform.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1017,7 +1017,6 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_
CountedLoopNode *main_head = loop->_head->as_CountedLoop();
assert( main_head->is_normal_loop(), "" );
CountedLoopEndNode *main_end = main_head->loopexit();
- guarantee(main_end != NULL, "no loop exit node");
assert( main_end->outcnt() == 2, "1 true, 1 false path only" );
Node *pre_header= main_head->in(LoopNode::EntryControl);
@@ -1243,7 +1242,6 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old
// Find common pieces of the loop being guarded with pre & post loops
CountedLoopNode *main_head = loop->_head->as_CountedLoop();
CountedLoopEndNode *main_end = main_head->loopexit();
- guarantee(main_end != NULL, "no loop exit node");
// diagnostic to show loop end is not properly formed
assert(main_end->outcnt() == 2, "1 true, 1 false path only");
@@ -1293,7 +1291,6 @@ void PhaseIdealLoop::insert_scalar_rced_post_loop(IdealLoopTree *loop, Node_List
// Find common pieces of the loop being guarded with pre & post loops
CountedLoopNode *main_head = loop->_head->as_CountedLoop();
CountedLoopEndNode *main_end = main_head->loopexit();
- guarantee(main_end != NULL, "no loop exit node");
// diagnostic to show loop end is not properly formed
assert(main_end->outcnt() == 2, "1 true, 1 false path only");
@@ -1427,7 +1424,6 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad
assert(LoopUnrollLimit, "");
CountedLoopNode *loop_head = loop->_head->as_CountedLoop();
CountedLoopEndNode *loop_end = loop_head->loopexit();
- assert(loop_end, "");
#ifndef PRODUCT
if (PrintOpto && VerifyLoopOptimizations) {
tty->print("Unrolling ");
@@ -2972,7 +2968,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
}
store = n;
store_value = value;
- } else if (n->is_If() && n != head->loopexit()) {
+ } else if (n->is_If() && n != head->loopexit_or_null()) {
msg = "extra control flow";
msg_node = n;
}
@@ -3114,7 +3110,6 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
ok.set(store->in(MemNode::Memory)->_idx);
CountedLoopEndNode* loop_exit = head->loopexit();
- guarantee(loop_exit != NULL, "no loop exit node");
// Loop structure is ok
ok.set(head->_idx);
@@ -3204,7 +3199,7 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) {
return false;
}
- Node* exit = head->loopexit()->proj_out(0);
+ Node* exit = head->loopexit()->proj_out_or_null(0);
if (exit == NULL) {
return false;
}
@@ -3280,8 +3275,8 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) {
call->init_req(TypeFunc::Control, head->init_control());
call->init_req(TypeFunc::I_O, C->top()); // Does no I/O.
call->init_req(TypeFunc::Memory, mem_phi->in(LoopNode::EntryControl));
- call->init_req(TypeFunc::ReturnAdr, C->start()->proj_out(TypeFunc::ReturnAdr));
- call->init_req(TypeFunc::FramePtr, C->start()->proj_out(TypeFunc::FramePtr));
+ call->init_req(TypeFunc::ReturnAdr, C->start()->proj_out_or_null(TypeFunc::ReturnAdr));
+ call->init_req(TypeFunc::FramePtr, C->start()->proj_out_or_null(TypeFunc::FramePtr));
_igvn.register_new_node_with_optimizer(call);
result_ctrl = new ProjNode(call,TypeFunc::Control);
_igvn.register_new_node_with_optimizer(result_ctrl);
diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp
index 1c0ada42512..59ab59de1df 100644
--- a/src/hotspot/share/opto/loopnode.cpp
+++ b/src/hotspot/share/opto/loopnode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -68,11 +68,11 @@ void LoopNode::dump_spec(outputStream *st) const {
bool LoopNode::is_valid_counted_loop() const {
if (is_CountedLoop()) {
CountedLoopNode* l = as_CountedLoop();
- CountedLoopEndNode* le = l->loopexit();
+ CountedLoopEndNode* le = l->loopexit_or_null();
if (le != NULL &&
- le->proj_out(1 /* true */) == l->in(LoopNode::LoopBackControl)) {
+ le->proj_out_or_null(1 /* true */) == l->in(LoopNode::LoopBackControl)) {
Node* phi = l->phi();
- Node* exit = le->proj_out(0 /* false */);
+ Node* exit = le->proj_out_or_null(0 /* false */);
if (exit != NULL && exit->Opcode() == Op_IfFalse &&
phi != NULL && phi->is_Phi() &&
phi->in(LoopNode::LoopBackControl) == l->incr() &&
@@ -793,7 +793,7 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*& loop) {
#ifdef ASSERT
assert(l->is_valid_counted_loop(), "counted loop shape is messed up");
- assert(l == loop->_head && l->phi() == phi && l->loopexit() == lex, "" );
+ assert(l == loop->_head && l->phi() == phi && l->loopexit_or_null() == lex, "" );
#endif
#ifndef PRODUCT
if (TraceLoopOpts) {
@@ -917,7 +917,7 @@ void LoopNode::verify_strip_mined(int expect_skeleton) const {
}
}
CountedLoopEndNode* cle = inner_out->in(0)->as_CountedLoopEnd();
- assert(cle == inner->loopexit(), "mismatch");
+ assert(cle == inner->loopexit_or_null(), "mismatch");
bool has_skeleton = outer_le->in(1)->bottom_type()->singleton() && outer_le->in(1)->bottom_type()->is_int()->get_con() == 0;
if (has_skeleton) {
assert(expect_skeleton == 1 || expect_skeleton == -1, "unexpected skeleton node");
@@ -1216,7 +1216,7 @@ IfFalseNode* OuterStripMinedLoopNode::outer_loop_exit() const {
if (le == NULL) {
return NULL;
}
- Node* c = le->proj_out(false);
+ Node* c = le->proj_out_or_null(false);
if (c == NULL) {
return NULL;
}
diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp
index 7e615de7e29..6c245365d25 100644
--- a/src/hotspot/share/opto/loopnode.hpp
+++ b/src/hotspot/share/opto/loopnode.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -215,6 +215,7 @@ public:
Node *init_control() const { return in(EntryControl); }
Node *back_control() const { return in(LoopBackControl); }
+ CountedLoopEndNode *loopexit_or_null() const;
CountedLoopEndNode *loopexit() const;
Node *init_trip() const;
Node *stride() const;
@@ -342,7 +343,7 @@ public:
return NULL;
}
Node *ln = iv_phi->in(0);
- if (ln->is_CountedLoop() && ln->as_CountedLoop()->loopexit() == this) {
+ if (ln->is_CountedLoop() && ln->as_CountedLoop()->loopexit_or_null() == this) {
return (CountedLoopNode*)ln;
}
return NULL;
@@ -354,7 +355,7 @@ public:
};
-inline CountedLoopEndNode *CountedLoopNode::loopexit() const {
+inline CountedLoopEndNode *CountedLoopNode::loopexit_or_null() const {
Node *bc = back_control();
if( bc == NULL ) return NULL;
Node *le = bc->in(0);
@@ -362,13 +363,18 @@ inline CountedLoopEndNode *CountedLoopNode::loopexit() const {
return NULL;
return (CountedLoopEndNode*)le;
}
-inline Node *CountedLoopNode::init_trip() const { return loopexit() ? loopexit()->init_trip() : NULL; }
-inline Node *CountedLoopNode::stride() const { return loopexit() ? loopexit()->stride() : NULL; }
-inline int CountedLoopNode::stride_con() const { return loopexit() ? loopexit()->stride_con() : 0; }
-inline bool CountedLoopNode::stride_is_con() const { return loopexit() && loopexit()->stride_is_con(); }
-inline Node *CountedLoopNode::limit() const { return loopexit() ? loopexit()->limit() : NULL; }
-inline Node *CountedLoopNode::incr() const { return loopexit() ? loopexit()->incr() : NULL; }
-inline Node *CountedLoopNode::phi() const { return loopexit() ? loopexit()->phi() : NULL; }
+inline CountedLoopEndNode *CountedLoopNode::loopexit() const {
+ CountedLoopEndNode* cle = loopexit_or_null();
+ assert(cle != NULL, "loopexit is NULL");
+ return cle;
+}
+inline Node *CountedLoopNode::init_trip() const { return loopexit_or_null() ? loopexit()->init_trip() : NULL; }
+inline Node *CountedLoopNode::stride() const { return loopexit_or_null() ? loopexit()->stride() : NULL; }
+inline int CountedLoopNode::stride_con() const { return loopexit_or_null() ? loopexit()->stride_con() : 0; }
+inline bool CountedLoopNode::stride_is_con() const { return loopexit_or_null() && loopexit()->stride_is_con(); }
+inline Node *CountedLoopNode::limit() const { return loopexit_or_null() ? loopexit()->limit() : NULL; }
+inline Node *CountedLoopNode::incr() const { return loopexit_or_null() ? loopexit()->incr() : NULL; }
+inline Node *CountedLoopNode::phi() const { return loopexit_or_null() ? loopexit()->phi() : NULL; }
//------------------------------LoopLimitNode-----------------------------
// Counted Loop limit node which represents exact final iterator value:
diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp
index d7a46ada7cd..bcdc58ecf51 100644
--- a/src/hotspot/share/opto/loopopts.cpp
+++ b/src/hotspot/share/opto/loopopts.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -239,7 +239,7 @@ void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff, bool flip, bool exc
// Make control-dependent data Nodes on the live path (path that will remain
// once the dominated IF is removed) become control-dependent on the
// dominating projection.
- Node* dp = iff->as_If()->proj_out(pop == Op_IfTrue);
+ Node* dp = iff->as_If()->proj_out_or_null(pop == Op_IfTrue);
// Loop predicates may have depending checks which should not
// be skipped. For example, range check predicate has two checks
@@ -1731,7 +1731,7 @@ void PhaseIdealLoop::clone_outer_loop(LoopNode* head, CloneLoopMode mode, IdealL
Node* sfpt = cl->outer_safepoint();
CountedLoopEndNode* cle = cl->loopexit();
CountedLoopNode* new_cl = old_new[cl->_idx]->as_CountedLoop();
- CountedLoopEndNode* new_cle = new_cl->as_CountedLoop()->loopexit();
+ CountedLoopEndNode* new_cle = new_cl->as_CountedLoop()->loopexit_or_null();
Node* cle_out = cle->proj_out(false);
Node* new_sfpt = NULL;
@@ -1956,7 +1956,7 @@ void PhaseIdealLoop::clone_loop( IdealLoopTree *loop, Node_List &old_new, int dd
if (head->is_strip_mined() && mode != IgnoreStripMined) {
CountedLoopNode* cl = head->as_CountedLoop();
CountedLoopEndNode* cle = cl->loopexit();
- Node* cle_out = cle->proj_out(false);
+ Node* cle_out = cle->proj_out_or_null(false);
if (use == cle_out) {
IfNode* le = cl->outer_loop_end();
use = le->proj_out(false);
diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp
index 8e8737f65c6..a221fe6bf8a 100644
--- a/src/hotspot/share/opto/macro.cpp
+++ b/src/hotspot/share/opto/macro.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -496,7 +496,7 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
if (level <= 0) {
return NULL; // Give up: phi tree too deep
}
- Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
+ Node *start_mem = C->start()->proj_out_or_null(TypeFunc::Memory);
Node *alloc_mem = alloc->in(TypeFunc::Memory);
uint length = mem->req();
@@ -576,7 +576,7 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, Node *sfpt_ctl, BasicType
int alias_idx = C->get_alias_index(adr_t);
int offset = adr_t->offset();
- Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
+ Node *start_mem = C->start()->proj_out_or_null(TypeFunc::Memory);
Node *alloc_ctrl = alloc->in(TypeFunc::Control);
Node *alloc_mem = alloc->in(TypeFunc::Memory);
Arena *a = Thread::current()->resource_area();
@@ -974,8 +974,8 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray proj_out(TypeFunc::Control);
- Node* mem_proj = n->proj_out(TypeFunc::Memory);
+ Node* ctl_proj = n->proj_out_or_null(TypeFunc::Control);
+ Node* mem_proj = n->proj_out_or_null(TypeFunc::Memory);
if (ctl_proj != NULL) {
igvn.replace_node(ctl_proj, n->in(0));
}
@@ -1086,12 +1086,12 @@ void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc) {
// Eliminate Initialize node.
InitializeNode *init = use->as_Initialize();
assert(init->outcnt() <= 2, "only a control and memory projection expected");
- Node *ctrl_proj = init->proj_out(TypeFunc::Control);
+ Node *ctrl_proj = init->proj_out_or_null(TypeFunc::Control);
if (ctrl_proj != NULL) {
assert(init->in(TypeFunc::Control) == _fallthroughcatchproj, "allocation control projection");
_igvn.replace_node(ctrl_proj, _fallthroughcatchproj);
}
- Node *mem_proj = init->proj_out(TypeFunc::Memory);
+ Node *mem_proj = init->proj_out_or_null(TypeFunc::Memory);
if (mem_proj != NULL) {
Node *mem = init->in(TypeFunc::Memory);
#ifdef ASSERT
@@ -1198,7 +1198,7 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) {
bool PhaseMacroExpand::eliminate_boxing_node(CallStaticJavaNode *boxing) {
// EA should remove all uses of non-escaping boxing node.
- if (!C->eliminate_boxing() || boxing->proj_out(TypeFunc::Parms) != NULL) {
+ if (!C->eliminate_boxing() || boxing->proj_out_or_null(TypeFunc::Parms) != NULL) {
return false;
}
@@ -1580,8 +1580,8 @@ void PhaseMacroExpand::expand_allocate_common(
// before the InitializeNode happen before the storestore
// barrier.
- Node* init_ctrl = init->proj_out(TypeFunc::Control);
- Node* init_mem = init->proj_out(TypeFunc::Memory);
+ Node* init_ctrl = init->proj_out_or_null(TypeFunc::Control);
+ Node* init_mem = init->proj_out_or_null(TypeFunc::Memory);
MemBarNode* mb = MemBarNode::make(C, Op_MemBarStoreStore, Compile::AliasIdxBot);
transform_later(mb);
diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp
index 77a9d68f88b..0fc4b41f9e2 100644
--- a/src/hotspot/share/opto/memnode.cpp
+++ b/src/hotspot/share/opto/memnode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -136,7 +136,7 @@ Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypeOopPtr *t_oo
if (!(is_instance || is_boxed_value_load))
return mchain; // don't try to optimize non-instance types
uint instance_id = t_oop->instance_id();
- Node *start_mem = phase->C->start()->proj_out(TypeFunc::Memory);
+ Node *start_mem = phase->C->start()->proj_out_or_null(TypeFunc::Memory);
Node *prev = NULL;
Node *result = mchain;
while (prev != result) {
diff --git a/src/hotspot/share/opto/multnode.cpp b/src/hotspot/share/opto/multnode.cpp
index 56fad9183b1..389ef5fd165 100644
--- a/src/hotspot/share/opto/multnode.cpp
+++ b/src/hotspot/share/opto/multnode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,8 +43,8 @@ const RegMask &MultiNode::out_RegMask() const {
Node *MultiNode::match( const ProjNode *proj, const Matcher *m ) { return proj->clone(); }
//------------------------------proj_out---------------------------------------
-// Get a named projection
-ProjNode* MultiNode::proj_out(uint which_proj) const {
+// Get a named projection or null if not found
+ProjNode* MultiNode::proj_out_or_null(uint which_proj) const {
assert((Opcode() != Op_If && Opcode() != Op_RangeCheck) || which_proj == (uint)true || which_proj == (uint)false, "must be 1 or 0");
assert((Opcode() != Op_If && Opcode() != Op_RangeCheck) || outcnt() == 2, "bad if #1");
for( DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++ ) {
@@ -63,6 +63,13 @@ ProjNode* MultiNode::proj_out(uint which_proj) const {
return NULL;
}
+// Get a named projection
+ProjNode* MultiNode::proj_out(uint which_proj) const {
+ ProjNode* p = proj_out_or_null(which_proj);
+ assert(p != NULL, "named projection %u not found", which_proj);
+ return p;
+}
+
//=============================================================================
//------------------------------ProjNode---------------------------------------
uint ProjNode::hash() const {
@@ -214,8 +221,6 @@ CallStaticJavaNode* ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptR
}
ProjNode* other_proj = iff->proj_out(1-_con);
- if (other_proj == NULL) // Should never happen, but make Parfait happy.
- return NULL;
CallStaticJavaNode* call = other_proj->is_uncommon_trap_proj(reason);
if (call != NULL) {
assert(reason == Deoptimization::Reason_none ||
diff --git a/src/hotspot/share/opto/multnode.hpp b/src/hotspot/share/opto/multnode.hpp
index ec32fea977b..95b8e71fa01 100644
--- a/src/hotspot/share/opto/multnode.hpp
+++ b/src/hotspot/share/opto/multnode.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,6 +47,7 @@ public:
virtual Node *match( const ProjNode *proj, const Matcher *m );
virtual uint ideal_reg() const { return NotAMachineReg; }
ProjNode* proj_out(uint which_proj) const; // Get a named projection
+ ProjNode* proj_out_or_null(uint which_proj) const;
};
diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp
index e10f866b35c..b9dd8012fdc 100644
--- a/src/hotspot/share/opto/phaseX.cpp
+++ b/src/hotspot/share/opto/phaseX.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1524,7 +1524,7 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) {
// receiver to know when to enable the regular fall-through path
// in addition to the NullPtrException path.
if (use->is_CallDynamicJava() && n == use->in(TypeFunc::Parms)) {
- Node* p = use->as_CallDynamicJava()->proj_out(TypeFunc::Control);
+ Node* p = use->as_CallDynamicJava()->proj_out_or_null(TypeFunc::Control);
if (p != NULL) {
add_users_to_worklist0(p);
}
@@ -1617,12 +1617,12 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) {
if (use_op == Op_Allocate || use_op == Op_AllocateArray) {
InitializeNode* init = use->as_Allocate()->initialization();
if (init != NULL) {
- Node* imem = init->proj_out(TypeFunc::Memory);
+ Node* imem = init->proj_out_or_null(TypeFunc::Memory);
if (imem != NULL) add_users_to_worklist0(imem);
}
}
if (use_op == Op_Initialize) {
- Node* imem = use->as_Initialize()->proj_out(TypeFunc::Memory);
+ Node* imem = use->as_Initialize()->proj_out_or_null(TypeFunc::Memory);
if (imem != NULL) add_users_to_worklist0(imem);
}
// Loading the java mirror from a klass oop requires two loads and the type
diff --git a/src/hotspot/share/opto/stringopts.cpp b/src/hotspot/share/opto/stringopts.cpp
index 889353dabfe..4afbc961108 100644
--- a/src/hotspot/share/opto/stringopts.cpp
+++ b/src/hotspot/share/opto/stringopts.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -362,11 +362,11 @@ void StringConcat::eliminate_initialize(InitializeNode* init) {
// Eliminate Initialize node.
assert(init->outcnt() <= 2, "only a control and memory projection expected");
assert(init->req() <= InitializeNode::RawStores, "no pending inits");
- Node *ctrl_proj = init->proj_out(TypeFunc::Control);
+ Node *ctrl_proj = init->proj_out_or_null(TypeFunc::Control);
if (ctrl_proj != NULL) {
C->gvn_replace_by(ctrl_proj, init->in(TypeFunc::Control));
}
- Node *mem_proj = init->proj_out(TypeFunc::Memory);
+ Node *mem_proj = init->proj_out_or_null(TypeFunc::Memory);
if (mem_proj != NULL) {
Node *mem = init->in(TypeFunc::Memory);
C->gvn_replace_by(mem_proj, mem);
@@ -891,7 +891,7 @@ bool StringConcat::validate_control_flow() {
ctrl_path.push(cn);
ctrl_path.push(cn->proj_out(0));
ctrl_path.push(cn->proj_out(0)->unique_out());
- Node* catchproj = cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0);
+ Node* catchproj = cn->proj_out(0)->unique_out()->as_Catch()->proj_out_or_null(0);
if (catchproj != NULL) {
ctrl_path.push(catchproj);
}
@@ -1035,13 +1035,13 @@ bool StringConcat::validate_control_flow() {
// by calls in the region.
_stringopts->_visited.Clear();
Node_List worklist;
- Node* final_result = _end->proj_out(TypeFunc::Parms);
+ Node* final_result = _end->proj_out_or_null(TypeFunc::Parms);
for (uint i = 0; i < _control.size(); i++) {
CallNode* cnode = _control.at(i)->isa_Call();
if (cnode != NULL) {
_stringopts->_visited.test_set(cnode->_idx);
}
- Node* result = cnode != NULL ? cnode->proj_out(TypeFunc::Parms) : NULL;
+ Node* result = cnode != NULL ? cnode->proj_out_or_null(TypeFunc::Parms) : NULL;
if (result != NULL && result != final_result) {
worklist.push(result);
}
diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp
index 25ffb67f017..ef129dcbca5 100644
--- a/src/hotspot/share/opto/superword.cpp
+++ b/src/hotspot/share/opto/superword.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -190,7 +190,7 @@ void SuperWord::unrolling_analysis(int &local_loop_unroll_factor) {
int *ignored_loop_nodes = NEW_RESOURCE_ARRAY(int, ignored_size);
Node_Stack nstack((int)ignored_size);
CountedLoopNode *cl = lpt()->_head->as_CountedLoop();
- Node *cl_exit = cl->loopexit();
+ Node *cl_exit = cl->loopexit_or_null();
int rpo_idx = _post_block.length();
assert(rpo_idx == 0, "post loop block is empty");
diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp
index 06d0f91a6b1..a843717d302 100644
--- a/src/hotspot/share/prims/jni.cpp
+++ b/src/hotspot/share/prims/jni.cpp
@@ -2820,7 +2820,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) { \
@@ -2870,7 +2870,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) { \
@@ -3106,7 +3106,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) {
@@ -3132,7 +3132,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
diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp
index 6ea720a1e44..78272c45e4d 100644
--- a/src/hotspot/share/prims/jvmtiTagMap.cpp
+++ b/src/hotspot/share/prims/jvmtiTagMap.cpp
@@ -30,6 +30,7 @@
#include "code/codeCache.hpp"
#include "jvmtifiles/jvmtiEnv.hpp"
#include "memory/resourceArea.hpp"
+#include "oops/access.inline.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.inline.hpp"
@@ -52,10 +53,6 @@
#include "runtime/vm_operations.hpp"
#include "services/serviceUtil.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1SATBCardTableModRefBS.hpp"
-#include "gc/parallel/parallelScavengeHeap.hpp"
-#endif // INCLUDE_ALL_GCS
// JvmtiTagHashmapEntry
//
@@ -78,22 +75,31 @@ class JvmtiTagHashmapEntry : public CHeapObj {
}
// constructor
- JvmtiTagHashmapEntry(oop object, jlong tag) { init(object, tag); }
+ JvmtiTagHashmapEntry(oop object, jlong tag) { init(object, tag); }
public:
// accessor methods
- inline oop object() const { return _object; }
- inline oop* object_addr() { return &_object; }
- inline jlong tag() const { return _tag; }
+ inline oop* object_addr() { return &_object; }
+ inline oop object() { return RootAccess::oop_load(object_addr()); }
+ // Peek at the object without keeping it alive. The returned object must be
+ // kept alive using a normal access if it leaks out of a thread transition from VM.
+ inline oop object_peek() {
+ return RootAccess::oop_load(object_addr());
+ }
+ inline jlong tag() const { return _tag; }
inline void set_tag(jlong tag) {
assert(tag != 0, "can't be zero");
_tag = tag;
}
- inline JvmtiTagHashmapEntry* next() const { return _next; }
- inline void set_next(JvmtiTagHashmapEntry* next) { _next = next; }
+ inline bool equals(oop object) {
+ return object == object_peek();
+ }
+
+ inline JvmtiTagHashmapEntry* next() const { return _next; }
+ inline void set_next(JvmtiTagHashmapEntry* next) { _next = next; }
};
@@ -211,7 +217,7 @@ class JvmtiTagHashmap : public CHeapObj {
JvmtiTagHashmapEntry* entry = _table[i];
while (entry != NULL) {
JvmtiTagHashmapEntry* next = entry->next();
- oop key = entry->object();
+ oop key = entry->object_peek();
assert(key != NULL, "jni weak reference cleared!!");
unsigned int h = hash(key, new_size);
JvmtiTagHashmapEntry* anchor = new_table[h];
@@ -304,7 +310,7 @@ class JvmtiTagHashmap : public CHeapObj {
unsigned int h = hash(key);
JvmtiTagHashmapEntry* entry = _table[h];
while (entry != NULL) {
- if (entry->object() == key) {
+ if (entry->equals(key)) {
return entry;
}
entry = entry->next();
@@ -345,7 +351,7 @@ class JvmtiTagHashmap : public CHeapObj {
JvmtiTagHashmapEntry* entry = _table[h];
JvmtiTagHashmapEntry* prev = NULL;
while (entry != NULL) {
- if (key == entry->object()) {
+ if (entry->equals(key)) {
break;
}
prev = entry;
@@ -1535,16 +1541,12 @@ class TagObjectCollector : public JvmtiTagHashmapEntryClosure {
void do_entry(JvmtiTagHashmapEntry* entry) {
for (int i=0; i<_tag_count; i++) {
if (_tags[i] == entry->tag()) {
+ // The reference in this tag map could be the only (implicitly weak)
+ // reference to that object. If we hand it out, we need to keep it live wrt
+ // SATB marking similar to other j.l.ref.Reference referents. This is
+ // achieved by using a phantom load in the object() accessor.
oop o = entry->object();
assert(o != NULL && Universe::heap()->is_in_reserved(o), "sanity check");
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- // The reference in this tag map could be the only (implicitly weak)
- // reference to that object. If we hand it out, we need to keep it live wrt
- // SATB marking similar to other j.l.ref.Reference referents.
- G1SATBCardTableModRefBS::enqueue(o);
- }
-#endif
jobject ref = JNIHandles::make_local(JavaThread::current(), o);
_object_results->append(ref);
_tag_results->append((uint64_t)entry->tag());
@@ -3363,10 +3365,8 @@ void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) {
while (entry != NULL) {
JvmtiTagHashmapEntry* next = entry->next();
- oop* obj = entry->object_addr();
-
// has object been GC'ed
- if (!is_alive->do_object_b(entry->object())) {
+ if (!is_alive->do_object_b(entry->object_peek())) {
// grab the tag
jlong tag = entry->tag();
guarantee(tag != 0, "checking");
@@ -3384,7 +3384,7 @@ void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) {
++freed;
} else {
f->do_oop(entry->object_addr());
- oop new_oop = entry->object();
+ oop new_oop = entry->object_peek();
// if the object has moved then re-hash it and move its
// entry to its new location.
@@ -3418,7 +3418,7 @@ void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) {
// Re-add all the entries which were kept aside
while (delayed_add != NULL) {
JvmtiTagHashmapEntry* next = delayed_add->next();
- unsigned int pos = JvmtiTagHashmap::hash(delayed_add->object(), size);
+ unsigned int pos = JvmtiTagHashmap::hash(delayed_add->object_peek(), size);
delayed_add->set_next(table[pos]);
table[pos] = delayed_add;
delayed_add = next;
diff --git a/src/hotspot/share/prims/resolvedMethodTable.cpp b/src/hotspot/share/prims/resolvedMethodTable.cpp
index 095fbb942c3..40cb4f85678 100644
--- a/src/hotspot/share/prims/resolvedMethodTable.cpp
+++ b/src/hotspot/share/prims/resolvedMethodTable.cpp
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "gc/shared/gcLocker.hpp"
#include "memory/allocation.hpp"
+#include "oops/access.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/method.hpp"
#include "oops/symbol.hpp"
@@ -33,24 +34,39 @@
#include "runtime/mutexLocker.hpp"
#include "utilities/hashtable.inline.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1SATBCardTableModRefBS.hpp"
-#endif
+oop ResolvedMethodEntry::object() {
+ return RootAccess::oop_load(literal_addr());
+}
+
+oop ResolvedMethodEntry::object_no_keepalive() {
+ // The AS_NO_KEEPALIVE peeks at the oop without keeping it alive.
+ // This is dangerous in general but is okay if the loaded oop does
+ // not leak out past a thread transition where a safepoint can happen.
+ // A subsequent oop_load without AS_NO_KEEPALIVE (the object() accessor)
+ // keeps the oop alive before doing so.
+ return RootAccess::oop_load(literal_addr());
+}
+
ResolvedMethodTable::ResolvedMethodTable()
: Hashtable(_table_size, sizeof(ResolvedMethodEntry)) { }
oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
if (p->hash() == hash) {
- oop target = p->literal();
+
+ // Peek the object to check if it is the right target.
+ oop target = p->object_no_keepalive();
+
// The method is in the table as a target already
if (java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) {
ResourceMark rm;
log_debug(membername, table) ("ResolvedMethod entry found for %s index %d",
method->name_and_sig_as_C_string(), index);
- return target;
+ // The object() accessor makes sure the target object is kept alive before
+ // leaking out.
+ return p->object();
}
}
}
@@ -70,18 +86,6 @@ oop ResolvedMethodTable::lookup(Method* method) {
return lookup(index, hash, method);
}
-// Tell the GC that this oop was looked up in the table
-static void ensure_oop_alive(oop mname) {
- // A lookup in the ResolvedMethodTable could return an object that was previously
- // considered dead. The SATB part of G1 needs to get notified about this
- // potential resurrection, otherwise the marking might not find the object.
-#if INCLUDE_ALL_GCS
- if (UseG1GC && mname != NULL) {
- G1SATBCardTableModRefBS::enqueue(mname);
- }
-#endif
-}
-
oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
assert_locked_or_safepoint(ResolvedMethodTable_lock);
@@ -91,7 +95,6 @@ oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
// One was added while aquiring the lock
oop entry = lookup(index, hash, method);
if (entry != NULL) {
- ensure_oop_alive(entry);
return entry;
}
@@ -100,14 +103,13 @@ oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
ResourceMark rm;
log_debug(membername, table) ("ResolvedMethod entry added for %s index %d",
method->name_and_sig_as_C_string(), index);
- return p->literal();
+ return rmethod_name;
}
ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
oop ResolvedMethodTable::find_method(Method* method) {
oop entry = _the_table->lookup(method);
- ensure_oop_alive(entry);
return entry;
}
@@ -147,12 +149,12 @@ void ResolvedMethodTable::unlink(BoolObjectClosure* is_alive) {
ResolvedMethodEntry* entry = _the_table->bucket(i);
while (entry != NULL) {
_oops_counted++;
- if (is_alive->do_object_b(entry->literal())) {
+ if (is_alive->do_object_b(entry->object_no_keepalive())) {
p = entry->next_addr();
} else {
_oops_removed++;
if (log_is_enabled(Debug, membername, table)) {
- Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(entry->literal());
+ Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(entry->object_no_keepalive());
ResourceMark rm;
log_debug(membername, table) ("ResolvedMethod entry removed for %s index %d",
m->name_and_sig_as_C_string(), i);
@@ -185,7 +187,7 @@ void ResolvedMethodTable::print() {
ResolvedMethodEntry* entry = bucket(i);
while (entry != NULL) {
tty->print("%d : ", i);
- oop rmethod_name = entry->literal();
+ oop rmethod_name = entry->object_no_keepalive();
rmethod_name->print();
Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name);
m->print();
@@ -203,8 +205,7 @@ void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) {
for (int i = 0; i < _the_table->table_size(); ++i) {
ResolvedMethodEntry* entry = _the_table->bucket(i);
while (entry != NULL) {
-
- oop mem_name = entry->literal();
+ oop mem_name = entry->object_no_keepalive();
Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
if (old_method->is_old()) {
diff --git a/src/hotspot/share/prims/resolvedMethodTable.hpp b/src/hotspot/share/prims/resolvedMethodTable.hpp
index 122040b5132..ba863fc3590 100644
--- a/src/hotspot/share/prims/resolvedMethodTable.hpp
+++ b/src/hotspot/share/prims/resolvedMethodTable.hpp
@@ -44,6 +44,9 @@ class ResolvedMethodEntry : public HashtableEntry {
return (ResolvedMethodEntry**)HashtableEntry::next_addr();
}
+ oop object();
+ oop object_no_keepalive();
+
void print_on(outputStream* st) const;
};
diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp
index 5804af9fdbd..7decb80ccde 100644
--- a/src/hotspot/share/runtime/arguments.cpp
+++ b/src/hotspot/share/runtime/arguments.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -63,7 +63,11 @@
#endif
// Note: This is a special bug reporting site for the JVM
-#define DEFAULT_VENDOR_URL_BUG "http://bugreport.java.com/bugreport/crash.jsp"
+#ifdef VENDOR_URL_VM_BUG
+# define DEFAULT_VENDOR_URL_BUG VENDOR_URL_VM_BUG
+#else
+# define DEFAULT_VENDOR_URL_BUG "http://bugreport.java.com/bugreport/crash.jsp"
+#endif
#define DEFAULT_JAVA_LAUNCHER "generic"
char* Arguments::_jvm_flags_file = NULL;
@@ -523,6 +527,7 @@ static SpecialFlag const special_jvm_flags[] = {
{ "ConvertSleepToYield", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) },
{ "ConvertYieldToSleep", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) },
{ "MinSleepInterval", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) },
+ { "CheckAssertionStatusDirectives",JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) },
{ "PermSize", JDK_Version::undefined(), JDK_Version::jdk(8), JDK_Version::undefined() },
{ "MaxPermSize", JDK_Version::undefined(), JDK_Version::jdk(8), JDK_Version::undefined() },
{ "SharedReadWriteSize", JDK_Version::undefined(), JDK_Version::jdk(10), JDK_Version::undefined() },
diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
index ad4b27a3b0b..6f17cd18bfe 100644
--- a/src/hotspot/share/runtime/globals.hpp
+++ b/src/hotspot/share/runtime/globals.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -893,9 +893,6 @@ public:
develop(bool, TraceJavaAssertions, false, \
"Trace java language assertions") \
\
- notproduct(bool, CheckAssertionStatusDirectives, false, \
- "Temporary - see javaClasses.cpp") \
- \
notproduct(bool, PrintMallocFree, false, \
"Trace calls to C heap malloc/free allocation") \
\
diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp
index ff31ac9da77..d995a2fbf10 100644
--- a/src/hotspot/share/runtime/init.cpp
+++ b/src/hotspot/share/runtime/init.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -131,6 +131,7 @@ jint init_globals() {
InterfaceSupport_init();
SharedRuntime::generate_stubs();
universe2_init(); // dependent on codeCache_init and stubRoutines_init1
+ javaClasses_init();// must happen after vtable initialization, before referenceProcessor_init
referenceProcessor_init();
jni_handles_init();
#if INCLUDE_VM_STRUCTS
@@ -150,7 +151,6 @@ jint init_globals() {
if (!universe_post_init()) {
return JNI_ERR;
}
- javaClasses_init(); // must happen after vtable initialization
stubRoutines_init2(); // note: StubRoutines need 2-phase init
MethodHandles::generate_adapters();
diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp
index 83b24f574ed..8dc6735af28 100644
--- a/src/hotspot/share/runtime/os.hpp
+++ b/src/hotspot/share/runtime/os.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -778,7 +778,6 @@ class os: AllStatic {
static void* signal(int signal_number, void* handler);
static void signal_raise(int signal_number);
static int signal_wait();
- static int signal_lookup();
static void* user_handler();
static void terminate_signal_thread();
static int sigexitnum_pd();
diff --git a/src/hotspot/share/runtime/vframe_hp.cpp b/src/hotspot/share/runtime/vframe_hp.cpp
index 77c4e6d31a3..eeab33f651e 100644
--- a/src/hotspot/share/runtime/vframe_hp.cpp
+++ b/src/hotspot/share/runtime/vframe_hp.cpp
@@ -57,65 +57,23 @@ StackValueCollection* compiledVFrame::locals() const {
// There is one scv_list entry for every JVM stack state in use.
int length = scv_list->length();
StackValueCollection* result = new StackValueCollection(length);
- // In rare instances set_locals may have occurred in which case
- // there are local values that are not described by the ScopeValue anymore
- GrowableArray* deferred = NULL;
+ for (int i = 0; i < length; i++) {
+ result->add(create_stack_value(scv_list->at(i)));
+ }
+
+ // Replace the original values with any stores that have been
+ // performed through compiledVFrame::update_locals.
GrowableArray* list = thread()->deferred_locals();
if (list != NULL ) {
// In real life this never happens or is typically a single element search
for (int i = 0; i < list->length(); i++) {
- if (list->at(i)->matches((vframe*)this)) {
- deferred = list->at(i)->locals();
+ if (list->at(i)->matches(this)) {
+ list->at(i)->update_locals(result);
break;
}
}
}
- for( int i = 0; i < length; i++ ) {
- result->add( create_stack_value(scv_list->at(i)) );
- }
-
- // Replace specified locals with any deferred writes that are present
- if (deferred != NULL) {
- for ( int l = 0; l < deferred->length() ; l ++) {
- jvmtiDeferredLocalVariable* val = deferred->at(l);
- switch (val->type()) {
- case T_BOOLEAN:
- result->set_int_at(val->index(), val->value().z);
- break;
- case T_CHAR:
- result->set_int_at(val->index(), val->value().c);
- break;
- case T_FLOAT:
- result->set_float_at(val->index(), val->value().f);
- break;
- case T_DOUBLE:
- result->set_double_at(val->index(), val->value().d);
- break;
- case T_BYTE:
- result->set_int_at(val->index(), val->value().b);
- break;
- case T_SHORT:
- result->set_int_at(val->index(), val->value().s);
- break;
- case T_INT:
- result->set_int_at(val->index(), val->value().i);
- break;
- case T_LONG:
- result->set_long_at(val->index(), val->value().j);
- break;
- case T_OBJECT:
- {
- Handle obj(Thread::current(), (oop)val->value().l);
- result->set_obj_at(val->index(), obj);
- }
- break;
- default:
- ShouldNotReachHere();
- }
- }
- }
-
return result;
}
@@ -126,29 +84,32 @@ void compiledVFrame::set_locals(StackValueCollection* values) const {
}
void compiledVFrame::update_local(BasicType type, int index, jvalue value) {
+ assert(index >= 0 && index < method()->max_locals(), "out of bounds");
+ update_deferred_value(type, index, value);
+}
-#ifdef ASSERT
+void compiledVFrame::update_stack(BasicType type, int index, jvalue value) {
+ assert(index >= 0 && index < method()->max_stack(), "out of bounds");
+ update_deferred_value(type, index + method()->max_locals(), value);
+}
+void compiledVFrame::update_monitor(int index, MonitorInfo* val) {
+ assert(index >= 0, "out of bounds");
+ jvalue value;
+ value.l = (jobject) val->owner();
+ update_deferred_value(T_OBJECT, index + method()->max_locals() + method()->max_stack(), value);
+}
+
+void compiledVFrame::update_deferred_value(BasicType type, int index, jvalue value) {
assert(fr().is_deoptimized_frame(), "frame must be scheduled for deoptimization");
-#endif /* ASSERT */
GrowableArray* deferred = thread()->deferred_locals();
+ jvmtiDeferredLocalVariableSet* locals = NULL;
if (deferred != NULL ) {
// See if this vframe has already had locals with deferred writes
- int f;
- for ( f = 0 ; f < deferred->length() ; f++ ) {
+ for (int f = 0; f < deferred->length(); f++ ) {
if (deferred->at(f)->matches(this)) {
- // Matching, vframe now see if the local already had deferred write
- GrowableArray* locals = deferred->at(f)->locals();
- int l;
- for (l = 0 ; l < locals->length() ; l++ ) {
- if (locals->at(l)->index() == index) {
- locals->at(l)->set_value(value);
- return;
- }
- }
- // No matching local already present. Push a new value onto the deferred collection
- locals->push(new jvmtiDeferredLocalVariable(index, type, value));
- return;
+ locals = deferred->at(f);
+ break;
}
}
// No matching vframe must push a new vframe
@@ -158,9 +119,12 @@ void compiledVFrame::update_local(BasicType type, int index, jvalue value) {
deferred = new(ResourceObj::C_HEAP, mtCompiler) GrowableArray (1, true);
thread()->set_deferred_locals(deferred);
}
- deferred->push(new jvmtiDeferredLocalVariableSet(method(), bci(), fr().id(), vframe_id()));
- assert(deferred->top()->id() == fr().id(), "Huh? Must match");
- deferred->top()->set_local_at(index, type, value);
+ if (locals == NULL) {
+ locals = new jvmtiDeferredLocalVariableSet(method(), bci(), fr().id(), vframe_id());
+ deferred->push(locals);
+ assert(locals->id() == fr().id(), "Huh? Must match");
+ }
+ locals->set_value_at(index, type, value);
}
StackValueCollection* compiledVFrame::expressions() const {
@@ -173,8 +137,22 @@ StackValueCollection* compiledVFrame::expressions() const {
// There is one scv_list entry for every JVM stack state in use.
int length = scv_list->length();
StackValueCollection* result = new StackValueCollection(length);
- for( int i = 0; i < length; i++ )
- result->add( create_stack_value(scv_list->at(i)) );
+ for (int i = 0; i < length; i++) {
+ result->add(create_stack_value(scv_list->at(i)));
+ }
+
+ // Replace the original values with any stores that have been
+ // performed through compiledVFrame::update_stack.
+ GrowableArray* list = thread()->deferred_locals();
+ if (list != NULL ) {
+ // In real life this never happens or is typically a single element search
+ for (int i = 0; i < list->length(); i++) {
+ if (list->at(i)->matches(this)) {
+ list->at(i)->update_stack(result);
+ break;
+ }
+ }
+ }
return result;
}
@@ -236,6 +214,20 @@ GrowableArray* compiledVFrame::monitors() const {
mv->eliminated(), false));
}
}
+
+ // Replace the original values with any stores that have been
+ // performed through compiledVFrame::update_monitors.
+ GrowableArray* list = thread()->deferred_locals();
+ if (list != NULL ) {
+ // In real life this never happens or is typically a single element search
+ for (int i = 0; i < list->length(); i++) {
+ if (list->at(i)->matches(this)) {
+ list->at(i)->update_monitors(result);
+ break;
+ }
+ }
+ }
+
return result;
}
@@ -332,14 +324,14 @@ jvmtiDeferredLocalVariableSet::jvmtiDeferredLocalVariableSet(Method* method, int
}
jvmtiDeferredLocalVariableSet::~jvmtiDeferredLocalVariableSet() {
- for (int i = 0; i < _locals->length() ; i++ ) {
+ for (int i = 0; i < _locals->length(); i++ ) {
delete _locals->at(i);
}
// Free growableArray and c heap for elements
delete _locals;
}
-bool jvmtiDeferredLocalVariableSet::matches(vframe* vf) {
+bool jvmtiDeferredLocalVariableSet::matches(const vframe* vf) {
if (!vf->is_compiled_frame()) return false;
compiledVFrame* cvf = (compiledVFrame*)vf;
if (cvf->fr().id() == id() && cvf->vframe_id() == vframe_id()) {
@@ -349,24 +341,93 @@ bool jvmtiDeferredLocalVariableSet::matches(vframe* vf) {
return false;
}
-void jvmtiDeferredLocalVariableSet::set_local_at(int idx, BasicType type, jvalue val) {
- int i;
- for ( i = 0 ; i < locals()->length() ; i++ ) {
- if ( locals()->at(i)->index() == idx) {
- assert(locals()->at(i)->type() == type, "Wrong type");
- locals()->at(i)->set_value(val);
+void jvmtiDeferredLocalVariableSet::set_value_at(int idx, BasicType type, jvalue val) {
+ for (int i = 0; i < _locals->length(); i++) {
+ if (_locals->at(i)->index() == idx) {
+ assert(_locals->at(i)->type() == type, "Wrong type");
+ _locals->at(i)->set_value(val);
return;
}
}
- locals()->push(new jvmtiDeferredLocalVariable(idx, type, val));
+ _locals->push(new jvmtiDeferredLocalVariable(idx, type, val));
}
+void jvmtiDeferredLocalVariableSet::update_value(StackValueCollection* locals, BasicType type, int index, jvalue value) {
+ switch (type) {
+ case T_BOOLEAN:
+ locals->set_int_at(index, value.z);
+ break;
+ case T_CHAR:
+ locals->set_int_at(index, value.c);
+ break;
+ case T_FLOAT:
+ locals->set_float_at(index, value.f);
+ break;
+ case T_DOUBLE:
+ locals->set_double_at(index, value.d);
+ break;
+ case T_BYTE:
+ locals->set_int_at(index, value.b);
+ break;
+ case T_SHORT:
+ locals->set_int_at(index, value.s);
+ break;
+ case T_INT:
+ locals->set_int_at(index, value.i);
+ break;
+ case T_LONG:
+ locals->set_long_at(index, value.j);
+ break;
+ case T_OBJECT:
+ {
+ Handle obj(Thread::current(), (oop)value.l);
+ locals->set_obj_at(index, obj);
+ }
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+}
+
+void jvmtiDeferredLocalVariableSet::update_locals(StackValueCollection* locals) {
+ for (int l = 0; l < _locals->length(); l ++) {
+ jvmtiDeferredLocalVariable* val = _locals->at(l);
+ if (val->index() >= 0 && val->index() < method()->max_locals()) {
+ update_value(locals, val->type(), val->index(), val->value());
+ }
+ }
+}
+
+
+void jvmtiDeferredLocalVariableSet::update_stack(StackValueCollection* expressions) {
+ for (int l = 0; l < _locals->length(); l ++) {
+ jvmtiDeferredLocalVariable* val = _locals->at(l);
+ if (val->index() >= method()->max_locals() && val->index() < method()->max_locals() + method()->max_stack()) {
+ update_value(expressions, val->type(), val->index() - method()->max_locals(), val->value());
+ }
+ }
+}
+
+
+void jvmtiDeferredLocalVariableSet::update_monitors(GrowableArray* monitors) {
+ for (int l = 0; l < _locals->length(); l ++) {
+ jvmtiDeferredLocalVariable* val = _locals->at(l);
+ if (val->index() >= method()->max_locals() + method()->max_stack()) {
+ int lock_index = val->index() - (method()->max_locals() + method()->max_stack());
+ MonitorInfo* info = monitors->at(lock_index);
+ MonitorInfo* new_info = new MonitorInfo((oopDesc*)val->value().l, info->lock(), info->eliminated(), info->owner_is_scalar_replaced());
+ monitors->at_put(lock_index, new_info);
+ }
+ }
+}
+
+
void jvmtiDeferredLocalVariableSet::oops_do(OopClosure* f) {
// The Method* is on the stack so a live activation keeps it alive
// either by mirror in interpreter or code in compiled code.
- for ( int i = 0; i < locals()->length(); i++ ) {
- if ( locals()->at(i)->type() == T_OBJECT) {
- f->do_oop(locals()->at(i)->oop_addr());
+ for (int i = 0; i < _locals->length(); i++) {
+ if (_locals->at(i)->type() == T_OBJECT) {
+ f->do_oop(_locals->at(i)->oop_addr());
}
}
}
diff --git a/src/hotspot/share/runtime/vframe_hp.hpp b/src/hotspot/share/runtime/vframe_hp.hpp
index e7f4a9b55ff..ab7db10549e 100644
--- a/src/hotspot/share/runtime/vframe_hp.hpp
+++ b/src/hotspot/share/runtime/vframe_hp.hpp
@@ -51,6 +51,8 @@ class compiledVFrame: public javaVFrame {
return (compiledVFrame*) vf;
}
+ void update_deferred_value(BasicType type, int index, jvalue value);
+
public:
// Constructors
compiledVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread, CompiledMethod* nm);
@@ -58,6 +60,12 @@ class compiledVFrame: public javaVFrame {
// Update a local in a compiled frame. Update happens when deopt occurs
void update_local(BasicType type, int index, jvalue value);
+ // Update an expression stack value in a compiled frame. Update happens when deopt occurs
+ void update_stack(BasicType type, int index, jvalue value);
+
+ // Update a lock value in a compiled frame. Update happens when deopt occurs
+ void update_monitor(int index, MonitorInfo* value);
+
// Returns the active nmethod
CompiledMethod* code() const;
@@ -91,6 +99,8 @@ class compiledVFrame: public javaVFrame {
class jvmtiDeferredLocalVariable;
class jvmtiDeferredLocalVariableSet : public CHeapObj {
+ friend class compiledVFrame;
+
private:
Method* _method;
@@ -99,17 +109,23 @@ private:
int _vframe_id;
GrowableArray* _locals;
+ void update_value(StackValueCollection* locals, BasicType type, int index, jvalue value);
+
+ void set_value_at(int idx, BasicType typ, jvalue val);
+
public:
// JVM state
Method* method() const { return _method; }
int bci() const { return _bci; }
intptr_t* id() const { return _id; }
int vframe_id() const { return _vframe_id; }
- GrowableArray* locals() const { return _locals; }
- void set_local_at(int idx, BasicType typ, jvalue val);
+
+ void update_locals(StackValueCollection* locals);
+ void update_stack(StackValueCollection* locals);
+ void update_monitors(GrowableArray* monitors);
// Does the vframe match this jvmtiDeferredLocalVariableSet
- bool matches(vframe* vf);
+ bool matches(const vframe* vf);
// GC
void oops_do(OopClosure* f);
diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp
index 28b5259c892..c613aa0b074 100644
--- a/src/hotspot/share/runtime/vmStructs.cpp
+++ b/src/hotspot/share/runtime/vmStructs.cpp
@@ -233,7 +233,7 @@ typedef PaddedEnd PaddedObjectMonitor;
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*) \
nonstatic_field(ConstantPool, _cache, ConstantPoolCache*) \
diff --git a/src/hotspot/share/runtime/vm_operations.hpp b/src/hotspot/share/runtime/vm_operations.hpp
index 145337a8d01..3d81e71aefd 100644
--- a/src/hotspot/share/runtime/vm_operations.hpp
+++ b/src/hotspot/share/runtime/vm_operations.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -67,9 +67,8 @@
template(CGC_Operation) \
template(CMS_Initial_Mark) \
template(CMS_Final_Remark) \
- template(G1CollectFull) \
template(G1CollectForAllocation) \
- template(G1IncCollectionPause) \
+ template(G1CollectFull) \
template(HandshakeOneThread) \
template(HandshakeAllThreads) \
template(HandshakeFallback) \
diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp
index 8d127605e13..9d1e7ded38d 100644
--- a/src/hotspot/share/utilities/vmError.cpp
+++ b/src/hotspot/share/utilities/vmError.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -243,11 +243,12 @@ void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, char* bu
RegisterMap map((JavaThread*)t, false); // No update
fr = fr.sender(&map);
} else {
+ // is_first_C_frame() does only simple checks for frame pointer,
+ // it will pass if java compiled code has a pointer in EBP.
+ if (os::is_first_C_frame(&fr)) break;
fr = os::get_sender_for_C_frame(&fr);
}
} else {
- // is_first_C_frame() does only simple checks for frame pointer,
- // it will pass if java compiled code has a pointer in EBP.
if (os::is_first_C_frame(&fr)) break;
fr = os::get_sender_for_C_frame(&fr);
}
diff --git a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
index c213b126b6e..9df3e3c9562 100644
--- a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
+++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
@@ -439,6 +439,11 @@ JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyDa
goto errOut;
}
passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
+
+ // clear the password and release
+ memset(passwordChars, 0, passwordLen);
+ (*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
+ JNI_ABORT);
}
}
@@ -527,8 +532,19 @@ JNF_COCOA_ENTER(env);
if (passwordObj) {
passwordLen = (*env)->GetArrayLength(env, passwordObj);
- passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
- passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
+
+ if (passwordLen > 0) {
+ passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
+ if (passwordChars == NULL) {
+ goto errOut;
+ }
+ passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
+
+ // clear the password and release
+ memset(passwordChars, 0, passwordLen);
+ (*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
+ JNI_ABORT);
+ }
}
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java
index 7fd898fe594..7e032058f30 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java
@@ -25,6 +25,7 @@
package com.sun.crypto.provider;
+import java.lang.ref.Reference;
import java.security.MessageDigest;
import java.security.KeyRep;
import java.security.InvalidKeyException;
@@ -86,7 +87,12 @@ final class DESKey implements SecretKey {
public byte[] getEncoded() {
// Return a copy of the key, rather than a reference,
// so that the key data cannot be modified from outside
- return this.key.clone();
+
+ // The key is zeroized by finalize()
+ // The reachability fence ensures finalize() isn't called early
+ byte[] result = key.clone();
+ Reference.reachabilityFence(this);
+ return result;
}
public String getAlgorithm() {
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java
index a618b71f05b..89970c467df 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java
@@ -25,6 +25,7 @@
package com.sun.crypto.provider;
+import java.lang.ref.Reference;
import java.security.MessageDigest;
import java.security.KeyRep;
import java.security.InvalidKeyException;
@@ -86,7 +87,11 @@ final class DESedeKey implements SecretKey {
}
public byte[] getEncoded() {
- return this.key.clone();
+ // The key is zeroized by finalize()
+ // The reachability fence ensures finalize() isn't called early
+ byte[] result = key.clone();
+ Reference.reachabilityFence(this);
+ return result;
}
public String getAlgorithm() {
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java
index 6a2f298fe6e..201d47ca7fb 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, 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
@@ -28,11 +28,13 @@ package com.sun.crypto.provider;
import java.util.*;
import java.lang.*;
import java.math.BigInteger;
+import java.security.AccessController;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.security.PrivilegedAction;
import java.security.ProviderException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
@@ -60,6 +62,17 @@ extends KeyAgreementSpi {
private BigInteger x = BigInteger.ZERO; // the private value
private BigInteger y = BigInteger.ZERO;
+ private static class AllowKDF {
+
+ private static final boolean VALUE = getValue();
+
+ private static boolean getValue() {
+ return AccessController.doPrivileged(
+ (PrivilegedAction)
+ () -> Boolean.getBoolean("jdk.crypto.KeyAgreement.legacyKDF"));
+ }
+ }
+
/**
* Empty constructor
*/
@@ -367,6 +380,14 @@ extends KeyAgreementSpi {
if (algorithm == null) {
throw new NoSuchAlgorithmException("null algorithm");
}
+
+ if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") &&
+ !AllowKDF.VALUE) {
+
+ throw new NoSuchAlgorithmException("Unsupported secret key "
+ + "algorithm: " + algorithm);
+ }
+
byte[] secret = engineGenerateSecret();
if (algorithm.equalsIgnoreCase("DES")) {
// DES
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java b/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java
index 011fb954963..ec5451101ee 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java
@@ -25,6 +25,7 @@
package com.sun.crypto.provider;
+import java.lang.ref.Reference;
import java.security.MessageDigest;
import java.security.KeyRep;
import java.security.spec.InvalidKeySpecException;
@@ -80,7 +81,11 @@ final class PBEKey implements SecretKey {
}
public byte[] getEncoded() {
- return this.key.clone();
+ // The key is zeroized by finalize()
+ // The reachability fence ensures finalize() isn't called early
+ byte[] result = key.clone();
+ Reference.reachabilityFence(this);
+ return result;
}
public String getAlgorithm() {
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
index bc9a7f88c8c..59e65cd9014 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
@@ -26,6 +26,7 @@
package com.sun.crypto.provider;
import java.io.ObjectStreamException;
+import java.lang.ref.Reference;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
@@ -208,7 +209,11 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
}
public byte[] getEncoded() {
- return key.clone();
+ // The key is zeroized by finalize()
+ // The reachability fence ensures finalize() isn't called early
+ byte[] result = key.clone();
+ Reference.reachabilityFence(this);
+ return result;
}
public String getAlgorithm() {
@@ -220,7 +225,11 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
}
public char[] getPassword() {
- return passwd.clone();
+ // The password is zeroized by finalize()
+ // The reachability fence ensures finalize() isn't called early
+ char[] result = passwd.clone();
+ Reference.reachabilityFence(this);
+ return result;
}
public byte[] getSalt() {
diff --git a/src/java.base/share/classes/java/lang/Runtime.java b/src/java.base/share/classes/java/lang/Runtime.java
index d09c1a28b93..c2bb813ed5c 100644
--- a/src/java.base/share/classes/java/lang/Runtime.java
+++ b/src/java.base/share/classes/java/lang/Runtime.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1099,16 +1099,23 @@ public class Runtime {
m.group(VersionPattern.OPT_GROUP));
// empty '+'
- if ((m.group(VersionPattern.PLUS_GROUP) != null)
- && !build.isPresent()) {
- if (optional.isPresent()) {
- if (pre.isPresent())
- throw new IllegalArgumentException("'+' found with"
- + " pre-release and optional components:'" + s
- + "'");
+ if (!build.isPresent()) {
+ if (m.group(VersionPattern.PLUS_GROUP) != null) {
+ if (optional.isPresent()) {
+ if (pre.isPresent())
+ throw new IllegalArgumentException("'+' found with"
+ + " pre-release and optional components:'" + s
+ + "'");
+ } else {
+ throw new IllegalArgumentException("'+' found with neither"
+ + " build or optional components: '" + s + "'");
+ }
} else {
- throw new IllegalArgumentException("'+' found with neither"
- + " build or optional components: '" + s + "'");
+ if (optional.isPresent() && !pre.isPresent()) {
+ throw new IllegalArgumentException("optional component"
+ + " must be preceeded by a pre-release component"
+ + " or '+': '" + s + "'");
+ }
}
}
return new Version(List.of(version), pre, build, optional);
diff --git a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
index 3c83d56d259..696222940d7 100644
--- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
+++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
@@ -80,13 +80,20 @@ class DirectMethodHandle extends MethodHandle {
mtype = mtype.insertParameterTypes(0, receiver);
}
if (!member.isField()) {
- if (refKind == REF_invokeSpecial) {
- member = member.asSpecial();
- LambdaForm lform = preparedLambdaForm(member);
- return new Special(mtype, lform, member);
- } else {
- LambdaForm lform = preparedLambdaForm(member);
- return new DirectMethodHandle(mtype, lform, member);
+ switch (refKind) {
+ case REF_invokeSpecial: {
+ member = member.asSpecial();
+ LambdaForm lform = preparedLambdaForm(member);
+ return new Special(mtype, lform, member);
+ }
+ case REF_invokeInterface: {
+ LambdaForm lform = preparedLambdaForm(member);
+ return new Interface(mtype, lform, member, receiver);
+ }
+ default: {
+ LambdaForm lform = preparedLambdaForm(member);
+ return new DirectMethodHandle(mtype, lform, member);
+ }
}
} else {
LambdaForm lform = preparedFieldLambdaForm(member);
@@ -190,6 +197,7 @@ class DirectMethodHandle extends MethodHandle {
static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
boolean needsInit = (which == LF_INVSTATIC_INIT);
boolean doesAlloc = (which == LF_NEWINVSPECIAL);
+ boolean needsReceiverCheck = (which == LF_INVINTERFACE);
String linkerName;
LambdaForm.Kind kind;
switch (which) {
@@ -219,6 +227,7 @@ class DirectMethodHandle extends MethodHandle {
int nameCursor = ARG_LIMIT;
final int NEW_OBJ = (doesAlloc ? nameCursor++ : -1);
final int GET_MEMBER = nameCursor++;
+ final int CHECK_RECEIVER = (needsReceiverCheck ? nameCursor++ : -1);
final int LINKER_CALL = nameCursor++;
Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
assert(names.length == nameCursor);
@@ -233,6 +242,10 @@ class DirectMethodHandle extends MethodHandle {
}
assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
+ if (needsReceiverCheck) {
+ names[CHECK_RECEIVER] = new Name(getFunction(NF_checkReceiver), names[DMH_THIS], names[ARG_BASE]);
+ outArgs[0] = names[CHECK_RECEIVER];
+ }
assert(outArgs[outArgs.length-1] == names[GET_MEMBER]); // look, shifted args!
int result = LAST_RESULT;
if (doesAlloc) {
@@ -376,6 +389,29 @@ class DirectMethodHandle extends MethodHandle {
}
}
+ /** This subclass represents invokeinterface instructions. */
+ static class Interface extends DirectMethodHandle {
+ private final Class> refc;
+ private Interface(MethodType mtype, LambdaForm form, MemberName member, Class> refc) {
+ super(mtype, form, member);
+ assert refc.isInterface() : refc;
+ this.refc = refc;
+ }
+ @Override
+ MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+ return new Interface(mt, lf, member, refc);
+ }
+
+ Object checkReceiver(Object recv) {
+ if (!refc.isInstance(recv)) {
+ String msg = String.format("Class %s does not implement the requested interface %s",
+ recv.getClass().getName(), refc.getName());
+ throw new IncompatibleClassChangeError(msg);
+ }
+ return recv;
+ }
+ }
+
/** This subclass handles constructor references. */
static class Constructor extends DirectMethodHandle {
final MemberName initMethod;
@@ -738,7 +774,8 @@ class DirectMethodHandle extends MethodHandle {
NF_allocateInstance = 8,
NF_constructorMethod = 9,
NF_UNSAFE = 10,
- NF_LIMIT = 11;
+ NF_checkReceiver = 11,
+ NF_LIMIT = 12;
private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
@@ -785,6 +822,11 @@ class DirectMethodHandle extends MethodHandle {
return new NamedFunction(
MemberName.getFactory()
.resolveOrFail(REF_getField, member, DirectMethodHandle.class, NoSuchMethodException.class));
+ case NF_checkReceiver:
+ member = new MemberName(Interface.class, "checkReceiver", OBJ_OBJ_TYPE, REF_invokeVirtual);
+ return new NamedFunction(
+ MemberName.getFactory()
+ .resolveOrFail(REF_invokeVirtual, member, Interface.class, NoSuchMethodException.class));
default:
throw newInternalError("Unknown function: " + func);
}
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
index bad45f6e336..f100ab2913c 100644
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
@@ -3766,6 +3766,7 @@ assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c"));
* specified in the elements of the {@code filters} array.
* The first element of the filter array corresponds to the {@code pos}
* argument of the target, and so on in sequence.
+ * The filter functions are invoked in left to right order.
*
* Null arguments in the array are treated as identity functions,
* and the corresponding arguments left unchanged.
@@ -3836,11 +3837,12 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
filterArgumentsCheckArity(target, pos, filters);
MethodHandle adapter = target;
- int curPos = pos-1; // pre-incremented
- for (MethodHandle filter : filters) {
- curPos += 1;
+ // process filters in reverse order so that the invocation of
+ // the resulting adapter will invoke the filters in left-to-right order
+ for (int i = filters.length - 1; i >= 0; --i) {
+ MethodHandle filter = filters[i];
if (filter == null) continue; // ignore null elements of filters
- adapter = filterArgument(adapter, curPos, filter);
+ adapter = filterArgument(adapter, pos + i, filter);
}
return adapter;
}
diff --git a/src/java.base/share/classes/java/util/ResourceBundle.java b/src/java.base/share/classes/java/util/ResourceBundle.java
index e902b3e45e8..324edafc4a6 100644
--- a/src/java.base/share/classes/java/util/ResourceBundle.java
+++ b/src/java.base/share/classes/java/util/ResourceBundle.java
@@ -591,7 +591,7 @@ public abstract class ResourceBundle {
*/
private static ClassLoader getLoaderForControl(Module module) {
ClassLoader loader = getLoader(module);
- return loader == null ? ClassLoader.getSystemClassLoader() : loader;
+ return loader == null ? ClassLoader.getPlatformClassLoader() : loader;
}
/**
diff --git a/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java b/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java
index 557ce73a7a3..03f77879b2c 100644
--- a/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java
+++ b/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java
@@ -1608,4 +1608,30 @@ public class ArrayBlockingQueue extends AbstractQueue
}
}
+ /**
+ * Deserializes this queue and then checks some invariants.
+ *
+ * @param s the input stream
+ * @throws ClassNotFoundException if the class of a serialized object
+ * could not be found
+ * @throws java.io.InvalidObjectException if invariants are violated
+ * @throws java.io.IOException if an I/O error occurs
+ */
+ private void readObject(java.io.ObjectInputStream s)
+ throws java.io.IOException, ClassNotFoundException {
+
+ // Read in items array and various fields
+ s.defaultReadObject();
+
+ // Check invariants over count and index fields. Note that
+ // if putIndex==takeIndex, count can be either 0 or items.length.
+ if (items.length == 0 ||
+ takeIndex < 0 || takeIndex >= items.length ||
+ putIndex < 0 || putIndex >= items.length ||
+ count < 0 || count > items.length ||
+ Math.floorMod(putIndex - takeIndex, items.length) !=
+ Math.floorMod(count, items.length)) {
+ throw new java.io.InvalidObjectException("invariants violated");
+ }
+ }
}
diff --git a/src/java.base/share/classes/java/util/stream/DoublePipeline.java b/src/java.base/share/classes/java/util/stream/DoublePipeline.java
index 199a3d37f6a..29f80a6f5c9 100644
--- a/src/java.base/share/classes/java/util/stream/DoublePipeline.java
+++ b/src/java.base/share/classes/java/util/stream/DoublePipeline.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -40,7 +40,6 @@ import java.util.function.DoubleToIntFunction;
import java.util.function.DoubleToLongFunction;
import java.util.function.DoubleUnaryOperator;
import java.util.function.IntFunction;
-import java.util.function.LongPredicate;
import java.util.function.ObjDoubleConsumer;
import java.util.function.Supplier;
@@ -265,6 +264,12 @@ abstract class DoublePipeline
@Override
Sink opWrapSink(int flags, Sink |
|