--- a/.hgtags-top-repo Wed Jan 13 15:16:06 2010 -0800
+++ b/.hgtags-top-repo Wed Jul 05 17:04:53 2017 +0200
@@ -52,3 +52,4 @@
d1516b9f23954b29b8e76e6f4efc467c08c78133 jdk7-b75
c8b63075403d53a208104a8a6ea5072c1cb66aab jdk7-b76
1f17ca8353babb13f4908c1f87d11508232518c8 jdk7-b77
+ab4ae8f4514693a9fe17ca2fec0239d8f8450d2c jdk7-b78
--- a/hotspot/.hgtags Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/.hgtags Wed Jul 05 17:04:53 2017 +0200
@@ -52,3 +52,4 @@
d8dd291a362acb656026a9c0a9da48501505a1e7 jdk7-b75
9174bb32e934965288121f75394874eeb1fcb649 jdk7-b76
455105fc81d941482f8f8056afaa7aa0949c9300 jdk7-b77
+e703499b4b51e3af756ae77c3d5e8b3058a14e4e jdk7-b78
--- a/hotspot/make/hotspot_version Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/hotspot_version Wed Jul 05 17:04:53 2017 +0200
@@ -35,7 +35,7 @@
HS_MAJOR_VER=17
HS_MINOR_VER=0
-HS_BUILD_NUMBER=05
+HS_BUILD_NUMBER=06
JDK_MAJOR_VER=1
JDK_MINOR_VER=7
--- a/hotspot/make/linux/makefiles/debug.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/linux/makefiles/debug.make Wed Jul 05 17:04:53 2017 +0200
@@ -38,7 +38,7 @@
"Please use 'make jvmg' to build debug JVM. \n" \
"----------------------------------------------------------------------\n")
-G_SUFFIX =
+G_SUFFIX = _g
VERSION = debug
SYSDEFS += -DASSERT -DDEBUG
PICFLAGS = DEFAULT
--- a/hotspot/make/linux/makefiles/fastdebug.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/linux/makefiles/fastdebug.make Wed Jul 05 17:04:53 2017 +0200
@@ -58,7 +58,7 @@
# Linker mapfile
MAPFILE = $(GAMMADIR)/make/linux/makefiles/mapfile-vers-debug
-G_SUFFIX =
+G_SUFFIX = _g
VERSION = optimized
SYSDEFS += -DASSERT -DFASTDEBUG
PICFLAGS = DEFAULT
--- a/hotspot/make/linux/makefiles/jsig.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/linux/makefiles/jsig.make Wed Jul 05 17:04:53 2017 +0200
@@ -25,9 +25,12 @@
# Rules to build signal interposition library, used by vm.make
# libjsig[_g].so: signal interposition library
-JSIG = jsig$(G_SUFFIX)
+JSIG = jsig
LIBJSIG = lib$(JSIG).so
+JSIG_G = $(JSIG)$(G_SUFFIX)
+LIBJSIG_G = lib$(JSIG_G).so
+
JSIGSRCDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/vm
DEST_JSIG = $(JDK_LIBDIR)/$(LIBJSIG)
@@ -50,6 +53,7 @@
@echo Making signal interposition lib...
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \
$(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) -o $@ $< -ldl
+ $(QUIETLY) [ -f $(LIBJSIG_G) ] || { ln -s $@ $(LIBJSIG_G); }
install_jsig: $(LIBJSIG)
@echo "Copying $(LIBJSIG) to $(DEST_JSIG)"
--- a/hotspot/make/linux/makefiles/jvmg.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/linux/makefiles/jvmg.make Wed Jul 05 17:04:53 2017 +0200
@@ -35,7 +35,7 @@
# Linker mapfile
MAPFILE = $(GAMMADIR)/make/linux/makefiles/mapfile-vers-debug
-G_SUFFIX =
+G_SUFFIX = _g
VERSION = debug
SYSDEFS += -DASSERT -DDEBUG
PICFLAGS = DEFAULT
--- a/hotspot/make/linux/makefiles/launcher.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/linux/makefiles/launcher.make Wed Jul 05 17:04:53 2017 +0200
@@ -25,7 +25,9 @@
# Rules to build gamma launcher, used by vm.make
# gamma[_g]: launcher
-LAUNCHER = gamma$(G_SUFFIX)
+
+LAUNCHER = gamma
+LAUNCHER_G = $(LAUNCHER)$(G_SUFFIX)
LAUNCHERDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/launcher
LAUNCHERFLAGS = $(ARCHFLAG) \
@@ -70,4 +72,5 @@
$(LINK_LAUNCHER/PRE_HOOK) \
$(LINK_LAUNCHER) $(LFLAGS_LAUNCHER) -o $@ $(LAUNCHER.o) $(LIBS_LAUNCHER); \
$(LINK_LAUNCHER/POST_HOOK) \
+ [ -f $(LAUNCHER_G) ] || { ln -s $@ $(LAUNCHER_G); }; \
}
--- a/hotspot/make/linux/makefiles/saproc.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/linux/makefiles/saproc.make Wed Jul 05 17:04:53 2017 +0200
@@ -25,9 +25,13 @@
# Rules to build serviceability agent library, used by vm.make
# libsaproc[_g].so: serviceability agent
-SAPROC = saproc$(G_SUFFIX)
+
+SAPROC = saproc
LIBSAPROC = lib$(SAPROC).so
+SAPROC_G = $(SAPROC)$(G_SUFFIX)
+LIBSAPROC_G = lib$(SAPROC_G).so
+
AGENT_DIR = $(GAMMADIR)/agent
SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family)
@@ -75,6 +79,7 @@
$(SA_DEBUG_CFLAGS) \
-o $@ \
-lthread_db
+ $(QUIETLY) [ -f $(LIBSAPROC_G) ] || { ln -s $@ $(LIBSAPROC_G); }
install_saproc: checkAndBuildSA
$(QUIETLY) if [ -e $(LIBSAPROC) ] ; then \
--- a/hotspot/make/linux/makefiles/vm.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/linux/makefiles/vm.make Wed Jul 05 17:04:53 2017 +0200
@@ -113,8 +113,9 @@
#----------------------------------------------------------------------
# JVM
-JVM = jvm$(G_SUFFIX)
-LIBJVM = lib$(JVM).so
+JVM = jvm
+LIBJVM = lib$(JVM).so
+LIBJVM_G = lib$(JVM)$(G_SUFFIX).so
JVM_OBJ_FILES = $(Obj_Files)
@@ -201,6 +202,7 @@
$(LFLAGS_VM) -o $@ $(LIBJVM.o) $(LIBS_VM); \
$(LINK_LIB.CC/POST_HOOK) \
rm -f $@.1; ln -s $@ $@.1; \
+ [ -f $(LIBJVM_G) ] || { ln -s $@ $(LIBJVM_G); ln -s $@.1 $(LIBJVM_G).1; }; \
if [ -x /usr/sbin/selinuxenabled ] ; then \
/usr/sbin/selinuxenabled; \
if [ $$? = 0 ] ; then \
--- a/hotspot/make/solaris/makefiles/debug.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/solaris/makefiles/debug.make Wed Jul 05 17:04:53 2017 +0200
@@ -54,7 +54,7 @@
"Please use 'gnumake jvmg' to build debug JVM. \n" \
"-------------------------------------------------------------------------\n")
-G_SUFFIX =
+G_SUFFIX = _g
VERSION = debug
SYSDEFS += -DASSERT -DDEBUG
PICFLAGS = DEFAULT
--- a/hotspot/make/solaris/makefiles/dtrace.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/solaris/makefiles/dtrace.make Wed Jul 05 17:04:53 2017 +0200
@@ -24,8 +24,8 @@
# Rules to build jvm_db/dtrace, used by vm.make
-# we build libjvm_dtrace/libjvm_db/dtrace for COMPILER1 and COMPILER2
-# but not for CORE configuration
+# We build libjvm_dtrace/libjvm_db/dtrace for COMPILER1 and COMPILER2
+# but not for CORE or KERNEL configurations.
ifneq ("${TYPE}", "CORE")
ifneq ("${TYPE}", "KERNEL")
@@ -37,12 +37,13 @@
else
-
JVM_DB = libjvm_db
-LIBJVM_DB = libjvm$(G_SUFFIX)_db.so
+LIBJVM_DB = libjvm_db.so
+LIBJVM_DB_G = libjvm$(G_SUFFIX)_db.so
JVM_DTRACE = jvm_dtrace
-LIBJVM_DTRACE = libjvm$(G_SUFFIX)_dtrace.so
+LIBJVM_DTRACE = libjvm_dtrace.so
+LIBJVM_DTRACE_G = libjvm$(G_SUFFIX)_dtrace.so
JVMOFFS = JvmOffsets
JVMOFFS.o = $(JVMOFFS).o
@@ -77,7 +78,7 @@
LFLAGS_JVM_DTRACE += -D_REENTRANT $(PICFLAG)
else
LFLAGS_JVM_DB += -mt $(PICFLAG) -xnolib
-LFLAGS_JVM_DTRACE += -mt $(PICFLAG) -xnolib
+LFLAGS_JVM_DTRACE += -mt $(PICFLAG) -xnolib -ldl
endif
ISA = $(subst i386,i486,$(shell isainfo -n))
@@ -86,18 +87,24 @@
ifneq ("${ISA}","${BUILDARCH}")
XLIBJVM_DB = 64/$(LIBJVM_DB)
+XLIBJVM_DB_G = 64/$(LIBJVM_DB_G)
XLIBJVM_DTRACE = 64/$(LIBJVM_DTRACE)
+XLIBJVM_DTRACE_G = 64/$(LIBJVM_DTRACE_G)
$(XLIBJVM_DB): $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE)
@echo Making $@
$(QUIETLY) mkdir -p 64/ ; \
$(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. -I$(GENERATED) \
$(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc
+ [ -f $(XLIBJVM_DB_G) ] || { ln -s $(LIBJVM_DB) $(XLIBJVM_DB_G); }
+
$(XLIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE)
@echo Making $@
$(QUIETLY) mkdir -p 64/ ; \
$(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. \
$(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor
+ [ -f $(XLIBJVM_DTRACE_G) ] || { ln -s $(LIBJVM_DTRACE) $(XLIBJVM_DTRACE_G); }
+
endif # ifneq ("${ISA}","${BUILDARCH}")
ifdef USE_GCC
@@ -142,11 +149,13 @@
@echo Making $@
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. -I$(GENERATED) \
$(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc
+ [ -f $(LIBJVM_DB_G) ] || { ln -s $@ $(LIBJVM_DB_G); }
$(LIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(XLIBJVM_DTRACE) $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE)
@echo Making $@
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. \
$(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor
+ [ -f $(LIBJVM_DTRACE_G) ] || { ln -s $@ $(LIBJVM_DTRACE_G); }
$(DTRACE).d: $(DTRACE_SRCDIR)/hotspot.d $(DTRACE_SRCDIR)/hotspot_jni.d \
$(DTRACE_SRCDIR)/hs_private.d $(DTRACE_SRCDIR)/jhelper.d
--- a/hotspot/make/solaris/makefiles/fastdebug.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/solaris/makefiles/fastdebug.make Wed Jul 05 17:04:53 2017 +0200
@@ -90,7 +90,6 @@
# for this method for now. (fix this when dtrace bug 6258412 is fixed)
OPT_CFLAGS/ciEnv.o = $(OPT_CFLAGS) -xinline=no%__1cFciEnvbFpost_compiled_method_load_event6MpnHnmethod__v_
-
# (OPT_CFLAGS/SLOWER is also available, to alter compilation of buggy files)
# If you set HOTSPARC_GENERIC=yes, you disable all OPT_CFLAGS settings
@@ -115,8 +114,7 @@
# and mustn't be otherwise.
MAPFILE_DTRACE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-$(TYPE)
-
-G_SUFFIX =
+G_SUFFIX = _g
VERSION = optimized
SYSDEFS += -DASSERT -DFASTDEBUG -DCHECK_UNHANDLED_OOPS
PICFLAGS = DEFAULT
--- a/hotspot/make/solaris/makefiles/jsig.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/solaris/makefiles/jsig.make Wed Jul 05 17:04:53 2017 +0200
@@ -25,8 +25,11 @@
# Rules to build signal interposition library, used by vm.make
# libjsig[_g].so: signal interposition library
-JSIG = jsig$(G_SUFFIX)
-LIBJSIG = lib$(JSIG).so
+JSIG = jsig
+LIBJSIG = lib$(JSIG).so
+
+JSIG_G = $(JSIG)$(G_SUFFIX)
+LIBJSIG_G = lib$(JSIG_G).so
JSIGSRCDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/vm
@@ -46,6 +49,7 @@
@echo Making signal interposition lib...
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \
$(LFLAGS_JSIG) -o $@ $< -ldl
+ [ -f $(LIBJSIG_G) ] || { ln -s $@ $(LIBJSIG_G); }
install_jsig: $(LIBJSIG)
@echo "Copying $(LIBJSIG) to $(DEST_JSIG)"
--- a/hotspot/make/solaris/makefiles/jvmg.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/solaris/makefiles/jvmg.make Wed Jul 05 17:04:53 2017 +0200
@@ -51,7 +51,7 @@
# and mustn't be otherwise.
MAPFILE_DTRACE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-$(TYPE)
-G_SUFFIX =
+G_SUFFIX = _g
VERSION = debug
SYSDEFS += -DASSERT -DDEBUG
PICFLAGS = DEFAULT
--- a/hotspot/make/solaris/makefiles/launcher.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/solaris/makefiles/launcher.make Wed Jul 05 17:04:53 2017 +0200
@@ -25,7 +25,8 @@
# Rules to build gamma launcher, used by vm.make
# gamma[_g]: launcher
-LAUNCHER = gamma$(G_SUFFIX)
+LAUNCHER = gamma
+LAUNCHER_G = $(LAUNCHER)$(G_SUFFIX)
LAUNCHERDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/launcher
LAUNCHERFLAGS = $(ARCHFLAG) \
@@ -88,5 +89,6 @@
$(LINK_LAUNCHER/PRE_HOOK) \
$(LINK_LAUNCHER) $(LFLAGS_LAUNCHER) -o $@ $(LAUNCHER.o) $(LIBS_LAUNCHER); \
$(LINK_LAUNCHER/POST_HOOK) \
+ [ -f $(LAUNCHER_G) ] || { ln -s $@ $(LAUNCHER_G); }; \
;; \
esac
--- a/hotspot/make/solaris/makefiles/saproc.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/solaris/makefiles/saproc.make Wed Jul 05 17:04:53 2017 +0200
@@ -25,9 +25,13 @@
# Rules to build serviceability agent library, used by vm.make
# libsaproc[_g].so: serviceability agent
-SAPROC = saproc$(G_SUFFIX)
+
+SAPROC = saproc
LIBSAPROC = lib$(SAPROC).so
+SAPROC_G = $(SAPROC)$(G_SUFFIX)
+LIBSAPROC_G = lib$(SAPROC_G).so
+
AGENT_DIR = $(GAMMADIR)/agent
SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family)/proc
@@ -69,6 +73,7 @@
$(SA_LFLAGS) \
-o $@ \
-ldl -ldemangle -lthread -lc
+ [ -f $(LIBSAPROC_G) ] || { ln -s $@ $(LIBSAPROC_G); }
install_saproc: checkAndBuildSA
$(QUIETLY) if [ -f $(LIBSAPROC) ] ; then \
--- a/hotspot/make/solaris/makefiles/sparcWorks.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/solaris/makefiles/sparcWorks.make Wed Jul 05 17:04:53 2017 +0200
@@ -281,8 +281,6 @@
OPT_CFLAGS=-xO4 $(EXTRA_OPT_CFLAGS)
endif
-CFLAGS += $(GAMMADIR)/src/os_cpu/solaris_sparc/vm/solaris_sparc.il
-
endif # sparc
ifeq ("${Platform_arch_model}", "x86_32")
@@ -293,13 +291,14 @@
# [phh] Is this still true for 6.1?
OPT_CFLAGS+=-xO3
-CFLAGS += $(GAMMADIR)/src/os_cpu/solaris_x86/vm/solaris_x86_32.il
-
endif # 32bit x86
# no more exceptions
CFLAGS/NOEX=-noex
+# Inline functions
+CFLAGS += $(GAMMADIR)/src/os_cpu/solaris_${Platform_arch}/vm/solaris_${Platform_arch_model}.il
+
# Reduce code bloat by reverting back to 5.0 behavior for static initializers
CFLAGS += -Qoption ccfe -one_static_init
@@ -312,6 +311,15 @@
PICFLAG/BETTER = $(PICFLAG/DEFAULT)
PICFLAG/BYFILE = $(PICFLAG/$@)$(PICFLAG/DEFAULT$(PICFLAG/$@))
+# Use $(MAPFLAG:FILENAME=real_file_name) to specify a map file.
+MAPFLAG = -M FILENAME
+
+# Use $(SONAMEFLAG:SONAME=soname) to specify the intrinsic name of a shared obj
+SONAMEFLAG = -h SONAME
+
+# Build shared library
+SHARED_FLAG = -G
+
# Would be better if these weren't needed, since we link with CC, but
# at present removing them causes run-time errors
LFLAGS += -library=Crun
--- a/hotspot/make/solaris/makefiles/vm.make Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/make/solaris/makefiles/vm.make Wed Jul 05 17:04:53 2017 +0200
@@ -108,11 +108,16 @@
# older libm before libCrun, just to make sure it's found and used first.
LIBS += -lsocket -lsched -ldl $(LIBM) -lCrun -lthread -ldoor -lc
else
+ifeq ($(COMPILER_REV_NUMERIC), 502)
+# SC6.1 has it's own libm.so: specifying anything else provokes a name conflict.
+LIBS += -ldl -lthread -lsocket -lm -lsched -ldoor
+else
LIBS += -ldl -lthread -lsocket $(LIBM) -lsched -ldoor
-endif
+endif # 502
+endif # 505
else
LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc
-endif
+endif # sparcWorks
# By default, link the *.o into the library, not the executable.
LINK_INTO$(LINK_INTO) = LIBJVM
@@ -126,8 +131,9 @@
#----------------------------------------------------------------------
# JVM
-JVM = jvm$(G_SUFFIX)
-LIBJVM = lib$(JVM).so
+JVM = jvm
+LIBJVM = lib$(JVM).so
+LIBJVM_G = lib$(JVM)$(G_SUFFIX).so
JVM_OBJ_FILES = $(Obj_Files) $(DTRACE_OBJS)
@@ -173,11 +179,12 @@
-sbfast|-xsbfast) \
;; \
*) \
- echo Linking vm...; \
- $(LINK_LIB.CC/PRE_HOOK) \
- $(LINK_VM) $(LFLAGS_VM) -o $@ $(LIBJVM.o) $(LIBS_VM); \
- $(LINK_LIB.CC/POST_HOOK) \
- rm -f $@.1; ln -s $@ $@.1; \
+ echo Linking vm...; \
+ $(LINK_LIB.CC/PRE_HOOK) \
+ $(LINK_VM) $(LFLAGS_VM) -o $@ $(LIBJVM.o) $(LIBS_VM); \
+ $(LINK_LIB.CC/POST_HOOK) \
+ rm -f $@.1; ln -s $@ $@.1; \
+ [ -f $(LIBJVM_G) ] || { ln -s $@ $(LIBJVM_G); ln -s $@.1 $(LIBJVM_G).1; }; \
;; \
esac
--- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -189,14 +189,17 @@
Register OSR_buf = osrBufferPointer()->as_register();
{ assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below");
int monitor_offset = BytesPerWord * method()->max_locals() +
- (BasicObjectLock::size() * BytesPerWord) * (number_of_locks - 1);
+ (2 * BytesPerWord) * (number_of_locks - 1);
+ // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in
+ // the OSR buffer using 2 word entries: first the lock and then
+ // the oop.
for (int i = 0; i < number_of_locks; i++) {
- int slot_offset = monitor_offset - ((i * BasicObjectLock::size()) * BytesPerWord);
+ int slot_offset = monitor_offset - ((i * 2) * BytesPerWord);
#ifdef ASSERT
// verify the interpreter's monitor has a non-null object
{
Label L;
- __ ld_ptr(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes(), O7);
+ __ ld_ptr(OSR_buf, slot_offset + 1*BytesPerWord, O7);
__ cmp(G0, O7);
__ br(Assembler::notEqual, false, Assembler::pt, L);
__ delayed()->nop();
@@ -205,9 +208,9 @@
}
#endif // ASSERT
// Copy the lock field into the compiled activation.
- __ ld_ptr(OSR_buf, slot_offset + BasicObjectLock::lock_offset_in_bytes(), O7);
+ __ ld_ptr(OSR_buf, slot_offset + 0, O7);
__ st_ptr(O7, frame_map()->address_for_monitor_lock(i));
- __ ld_ptr(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes(), O7);
+ __ ld_ptr(OSR_buf, slot_offset + 1*BytesPerWord, O7);
__ st_ptr(O7, frame_map()->address_for_monitor_object(i));
}
}
@@ -953,9 +956,11 @@
} else {
#ifdef _LP64
assert(base != to_reg->as_register_lo(), "can't handle this");
+ assert(O7 != to_reg->as_register_lo(), "can't handle this");
__ ld(base, offset + hi_word_offset_in_bytes, to_reg->as_register_lo());
+ __ lduw(base, offset + lo_word_offset_in_bytes, O7); // in case O7 is base or offset, use it last
__ sllx(to_reg->as_register_lo(), 32, to_reg->as_register_lo());
- __ ld(base, offset + lo_word_offset_in_bytes, to_reg->as_register_lo());
+ __ or3(to_reg->as_register_lo(), O7, to_reg->as_register_lo());
#else
if (base == to_reg->as_register_lo()) {
__ ld(base, offset + hi_word_offset_in_bytes, to_reg->as_register_hi());
@@ -976,8 +981,8 @@
FloatRegister reg = to_reg->as_double_reg();
// split unaligned loads
if (unaligned || PatchALot) {
- __ ldf(FloatRegisterImpl::S, base, offset + BytesPerWord, reg->successor());
- __ ldf(FloatRegisterImpl::S, base, offset, reg);
+ __ ldf(FloatRegisterImpl::S, base, offset + 4, reg->successor());
+ __ ldf(FloatRegisterImpl::S, base, offset, reg);
} else {
__ ldf(FloatRegisterImpl::D, base, offset, to_reg->as_double_reg());
}
@@ -2200,6 +2205,7 @@
Register len = O2;
__ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr);
+ LP64_ONLY(__ sra(src_pos, 0, src_pos);) //higher 32bits must be null
if (shift == 0) {
__ add(src_ptr, src_pos, src_ptr);
} else {
@@ -2208,6 +2214,7 @@
}
__ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr);
+ LP64_ONLY(__ sra(dst_pos, 0, dst_pos);) //higher 32bits must be null
if (shift == 0) {
__ add(dst_ptr, dst_pos, dst_ptr);
} else {
--- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -144,17 +144,17 @@
if (index->is_register()) {
// apply the shift and accumulate the displacement
if (shift > 0) {
- LIR_Opr tmp = new_register(T_INT);
+ LIR_Opr tmp = new_pointer_register();
__ shift_left(index, shift, tmp);
index = tmp;
}
if (disp != 0) {
- LIR_Opr tmp = new_register(T_INT);
+ LIR_Opr tmp = new_pointer_register();
if (Assembler::is_simm13(disp)) {
- __ add(tmp, LIR_OprFact::intConst(disp), tmp);
+ __ add(tmp, LIR_OprFact::intptrConst(disp), tmp);
index = tmp;
} else {
- __ move(LIR_OprFact::intConst(disp), tmp);
+ __ move(LIR_OprFact::intptrConst(disp), tmp);
__ add(tmp, index, tmp);
index = tmp;
}
@@ -162,8 +162,8 @@
}
} else if (disp != 0 && !Assembler::is_simm13(disp)) {
// index is illegal so replace it with the displacement loaded into a register
- index = new_register(T_INT);
- __ move(LIR_OprFact::intConst(disp), index);
+ index = new_pointer_register();
+ __ move(LIR_OprFact::intptrConst(disp), index);
disp = 0;
}
--- a/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -22,10 +22,9 @@
*
*/
-//
// Sets the default values for platform dependent flags used by the client compiler.
// (see c1_globals.hpp)
-//
+
#ifndef TIERED
define_pd_global(bool, BackgroundCompilation, true );
define_pd_global(bool, CICompileOSR, true );
@@ -48,27 +47,24 @@
define_pd_global(bool, UseTLAB, true );
define_pd_global(bool, ProfileInterpreter, false);
define_pd_global(intx, FreqInlineSize, 325 );
-define_pd_global(intx, NewRatio, 8 ); // Design center runs on 1.3.1
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, PermSize, 12*M );
-define_pd_global(uintx, MaxPermSize, 64*M );
-define_pd_global(bool, NeverActAsServerClassMachine, true);
+define_pd_global(uintx,PermSize, 12*M );
+define_pd_global(uintx,MaxPermSize, 64*M );
+define_pd_global(bool, NeverActAsServerClassMachine, true );
define_pd_global(intx, NewSizeThreadIncrease, 16*K );
-define_pd_global(uintx, DefaultMaxRAM, 1*G);
+define_pd_global(uint64_t,MaxRAM, 1ULL*G);
define_pd_global(intx, InitialCodeCacheSize, 160*K);
-#endif // TIERED
+#endif // !TIERED
define_pd_global(bool, UseTypeProfile, false);
define_pd_global(bool, RoundFPResults, false);
-
-define_pd_global(bool, LIRFillDelaySlots, true);
+define_pd_global(bool, LIRFillDelaySlots, true );
define_pd_global(bool, OptimizeSinglePrecision, false);
-define_pd_global(bool, CSEArrayLength, true);
+define_pd_global(bool, CSEArrayLength, true );
define_pd_global(bool, TwoOperandLIRForm, false);
-
-define_pd_global(intx, SafepointPollOffset, 0);
+define_pd_global(intx, SafepointPollOffset, 0 );
--- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -59,7 +59,6 @@
define_pd_global(intx, FreqInlineSize, 175);
define_pd_global(intx, INTPRESSURE, 48); // large register set
define_pd_global(intx, InteriorEntryAlignment, 16); // = CodeEntryAlignment
-define_pd_global(intx, NewRatio, 2);
define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K));
// The default setting 16/16 seems to work best.
// (For _228_jack 16/16 is 2% better than 4/4, 16/4, 32/32, 32/16, or 16/32.)
@@ -83,25 +82,25 @@
// sequence of instructions to load a 64 bit pointer.
//
// InitialCodeCacheSize derived from specjbb2000 run.
-define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize
-define_pd_global(intx, ReservedCodeCacheSize, 48*M);
-define_pd_global(intx, CodeCacheExpansionSize, 64*K);
+define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize
+define_pd_global(intx, ReservedCodeCacheSize, 48*M);
+define_pd_global(intx, CodeCacheExpansionSize, 64*K);
// Ergonomics related flags
-define_pd_global(uintx, DefaultMaxRAM, 32*G);
+define_pd_global(uint64_t,MaxRAM, 128ULL*G);
#else
// InitialCodeCacheSize derived from specjbb2000 run.
-define_pd_global(intx, InitialCodeCacheSize, 1536*K); // Integral multiple of CodeCacheExpansionSize
-define_pd_global(intx, ReservedCodeCacheSize, 32*M);
-define_pd_global(intx, CodeCacheExpansionSize, 32*K);
+define_pd_global(intx, InitialCodeCacheSize, 1536*K); // Integral multiple of CodeCacheExpansionSize
+define_pd_global(intx, ReservedCodeCacheSize, 32*M);
+define_pd_global(intx, CodeCacheExpansionSize, 32*K);
// Ergonomics related flags
-define_pd_global(uintx, DefaultMaxRAM, 1*G);
+define_pd_global(uint64_t,MaxRAM, 4ULL*G);
#endif
-define_pd_global(uintx,CodeCacheMinBlockLength, 4);
+define_pd_global(uintx,CodeCacheMinBlockLength, 4);
// Heap related flags
-define_pd_global(uintx, PermSize, ScaleForWordSize(16*M));
-define_pd_global(uintx, MaxPermSize, ScaleForWordSize(64*M));
+define_pd_global(uintx,PermSize, ScaleForWordSize(16*M));
+define_pd_global(uintx,MaxPermSize, ScaleForWordSize(64*M));
// Ergonomics related flags
define_pd_global(bool, NeverActAsServerClassMachine, false);
--- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -22,10 +22,8 @@
*
*/
-//
// Sets the default values for platform dependent flags used by the runtime system.
// (see globals.hpp)
-//
// For sparc we do not do call backs when a thread is in the interpreter, because the
// interpreter dispatch needs at least two instructions - first to load the dispatch address
@@ -41,26 +39,23 @@
define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks
define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast
-define_pd_global(intx, CodeEntryAlignment, 32);
-define_pd_global(uintx, TLABSize, 0);
-define_pd_global(uintx, NewSize, ScaleForWordSize((2048 * K) + (2 * (64 * K))));
-define_pd_global(intx, SurvivorRatio, 8);
-define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC
-define_pd_global(intx, InlineSmallCode, 1500);
+define_pd_global(intx, CodeEntryAlignment, 32);
+define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC
+define_pd_global(intx, InlineSmallCode, 1500);
#ifdef _LP64
// Stack slots are 2X larger in LP64 than in the 32 bit VM.
-define_pd_global(intx, ThreadStackSize, 1024);
-define_pd_global(intx, VMThreadStackSize, 1024);
+define_pd_global(intx, ThreadStackSize, 1024);
+define_pd_global(intx, VMThreadStackSize, 1024);
#else
-define_pd_global(intx, ThreadStackSize, 512);
-define_pd_global(intx, VMThreadStackSize, 512);
+define_pd_global(intx, ThreadStackSize, 512);
+define_pd_global(intx, VMThreadStackSize, 512);
#endif
define_pd_global(intx, StackYellowPages, 2);
define_pd_global(intx, StackRedPages, 1);
define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+1));
-define_pd_global(intx, PreInflateSpin, 40); // Determined by running design center
+define_pd_global(intx, PreInflateSpin, 40); // Determined by running design center
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);
--- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -150,8 +150,7 @@
}
-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, bool unbox) {
- assert(!unbox, "NYI");//6815692//
+address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) {
address compiled_entry = __ pc();
Label cont;
--- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -2251,6 +2251,7 @@
emit_byte(0x9D);
}
+#ifndef _LP64 // no 32bit push/pop on amd64
void Assembler::popl(Address dst) {
// NOTE: this will adjust stack by 8byte on 64bits
InstructionMark im(this);
@@ -2258,6 +2259,7 @@
emit_byte(0x8F);
emit_operand(rax, dst);
}
+#endif
void Assembler::prefetch_prefix(Address src) {
prefix(src);
@@ -2428,6 +2430,7 @@
emit_byte(0x9C);
}
+#ifndef _LP64 // no 32bit push/pop on amd64
void Assembler::pushl(Address src) {
// Note this will push 64bit on 64bit
InstructionMark im(this);
@@ -2435,6 +2438,7 @@
emit_byte(0xFF);
emit_operand(rsi, src);
}
+#endif
void Assembler::pxor(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
@@ -5591,7 +5595,12 @@
}
void MacroAssembler::andpd(XMMRegister dst, AddressLiteral src) {
- andpd(dst, as_Address(src));
+ if (reachable(src)) {
+ andpd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ andpd(dst, Address(rscratch1, 0));
+ }
}
void MacroAssembler::andptr(Register dst, int32_t imm32) {
@@ -6078,11 +6087,21 @@
}
void MacroAssembler::comisd(XMMRegister dst, AddressLiteral src) {
- comisd(dst, as_Address(src));
+ if (reachable(src)) {
+ comisd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ comisd(dst, Address(rscratch1, 0));
+ }
}
void MacroAssembler::comiss(XMMRegister dst, AddressLiteral src) {
- comiss(dst, as_Address(src));
+ if (reachable(src)) {
+ comiss(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ comiss(dst, Address(rscratch1, 0));
+ }
}
@@ -7647,7 +7666,7 @@
#ifdef ASSERT
Label L;
- testl(tmp, tmp);
+ testptr(tmp, tmp);
jccb(Assembler::notZero, L);
hlt();
bind(L);
--- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -1244,7 +1244,9 @@
void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8);
void pcmpestri(XMMRegister xmm1, Address src, int imm8);
+#ifndef _LP64 // no 32bit push/pop on amd64
void popl(Address dst);
+#endif
#ifdef _LP64
void popq(Address dst);
@@ -1285,7 +1287,9 @@
// Interleave Low Bytes
void punpcklbw(XMMRegister dst, XMMRegister src);
+#ifndef _LP64 // no 32bit push/pop on amd64
void pushl(Address src);
+#endif
void pushq(Address src);
--- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -301,22 +301,25 @@
Register OSR_buf = osrBufferPointer()->as_pointer_register();
{ assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below");
int monitor_offset = BytesPerWord * method()->max_locals() +
- (BasicObjectLock::size() * BytesPerWord) * (number_of_locks - 1);
+ (2 * BytesPerWord) * (number_of_locks - 1);
+ // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in
+ // the OSR buffer using 2 word entries: first the lock and then
+ // the oop.
for (int i = 0; i < number_of_locks; i++) {
- int slot_offset = monitor_offset - ((i * BasicObjectLock::size()) * BytesPerWord);
+ int slot_offset = monitor_offset - ((i * 2) * BytesPerWord);
#ifdef ASSERT
// verify the interpreter's monitor has a non-null object
{
Label L;
- __ cmpptr(Address(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD);
+ __ cmpptr(Address(OSR_buf, slot_offset + 1*BytesPerWord), (int32_t)NULL_WORD);
__ jcc(Assembler::notZero, L);
__ stop("locked object is NULL");
__ bind(L);
}
#endif
- __ movptr(rbx, Address(OSR_buf, slot_offset + BasicObjectLock::lock_offset_in_bytes()));
+ __ movptr(rbx, Address(OSR_buf, slot_offset + 0));
__ movptr(frame_map()->address_for_monitor_lock(i), rbx);
- __ movptr(rbx, Address(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes()));
+ __ movptr(rbx, Address(OSR_buf, slot_offset + 1*BytesPerWord));
__ movptr(frame_map()->address_for_monitor_object(i), rbx);
}
}
@@ -785,7 +788,13 @@
ShouldNotReachHere();
__ movoop(as_Address(addr, noreg), c->as_jobject());
} else {
+#ifdef _LP64
+ __ movoop(rscratch1, c->as_jobject());
+ null_check_here = code_offset();
+ __ movptr(as_Address_lo(addr), rscratch1);
+#else
__ movoop(as_Address(addr), c->as_jobject());
+#endif
}
}
break;
@@ -1118,8 +1127,14 @@
__ pushptr(frame_map()->address_for_slot(src ->single_stack_ix()));
__ popptr (frame_map()->address_for_slot(dest->single_stack_ix()));
} else {
+#ifndef _LP64
__ pushl(frame_map()->address_for_slot(src ->single_stack_ix()));
__ popl (frame_map()->address_for_slot(dest->single_stack_ix()));
+#else
+ //no pushl on 64bits
+ __ movl(rscratch1, frame_map()->address_for_slot(src ->single_stack_ix()));
+ __ movl(frame_map()->address_for_slot(dest->single_stack_ix()), rscratch1);
+#endif
}
} else if (src->is_double_stack()) {
@@ -3136,8 +3151,10 @@
#ifdef _LP64
assert_different_registers(c_rarg0, dst, dst_pos, length);
+ __ movl2ptr(src_pos, src_pos); //higher 32bits must be null
__ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
assert_different_registers(c_rarg1, length);
+ __ movl2ptr(dst_pos, dst_pos); //higher 32bits must be null
__ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
__ mov(c_rarg2, length);
--- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -755,8 +755,19 @@
}
LIR_Opr addr = new_pointer_register();
- __ move(obj.result(), addr);
- __ add(addr, offset.result(), addr);
+ LIR_Address* a;
+ if(offset.result()->is_constant()) {
+ a = new LIR_Address(obj.result(),
+ NOT_LP64(offset.result()->as_constant_ptr()->as_jint()) LP64_ONLY((int)offset.result()->as_constant_ptr()->as_jlong()),
+ as_BasicType(type));
+ } else {
+ a = new LIR_Address(obj.result(),
+ offset.result(),
+ LIR_Address::times_1,
+ 0,
+ as_BasicType(type));
+ }
+ __ leal(LIR_OprFact::address(a), addr);
if (type == objectType) { // Write-barrier needed for Object fields.
// Do the pre-write barrier, if any.
--- a/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -22,10 +22,8 @@
*
*/
-//
// Sets the default values for platform dependent flags used by the client compiler.
// (see c1_globals.hpp)
-//
#ifndef TIERED
define_pd_global(bool, BackgroundCompilation, true );
@@ -48,27 +46,24 @@
define_pd_global(intx, OnStackReplacePercentage, 933 );
define_pd_global(intx, FreqInlineSize, 325 );
-define_pd_global(intx, NewRatio, 12 );
define_pd_global(intx, NewSizeThreadIncrease, 4*K );
define_pd_global(intx, InitialCodeCacheSize, 160*K);
define_pd_global(intx, ReservedCodeCacheSize, 32*M );
define_pd_global(bool, ProfileInterpreter, false);
define_pd_global(intx, CodeCacheExpansionSize, 32*K );
define_pd_global(uintx,CodeCacheMinBlockLength, 1);
-define_pd_global(uintx, PermSize, 12*M );
-define_pd_global(uintx, MaxPermSize, 64*M );
-define_pd_global(bool, NeverActAsServerClassMachine, true);
-define_pd_global(uintx, DefaultMaxRAM, 1*G);
+define_pd_global(uintx,PermSize, 12*M );
+define_pd_global(uintx,MaxPermSize, 64*M );
+define_pd_global(bool, NeverActAsServerClassMachine, true );
+define_pd_global(uint64_t,MaxRAM, 1ULL*G);
define_pd_global(bool, CICompileOSR, true );
-#endif // TIERED
+#endif // !TIERED
define_pd_global(bool, UseTypeProfile, false);
define_pd_global(bool, RoundFPResults, true );
-
define_pd_global(bool, LIRFillDelaySlots, false);
-define_pd_global(bool, OptimizeSinglePrecision, true);
+define_pd_global(bool, OptimizeSinglePrecision, true );
define_pd_global(bool, CSEArrayLength, false);
-define_pd_global(bool, TwoOperandLIRForm, true);
+define_pd_global(bool, TwoOperandLIRForm, true );
-
-define_pd_global(intx, SafepointPollOffset, 256);
+define_pd_global(intx, SafepointPollOffset, 256 );
--- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -22,7 +22,6 @@
*
*/
-//
// Sets the default values for platform dependent flags used by the server compiler.
// (see c2_globals.hpp). Alpha-sorted.
@@ -46,8 +45,8 @@
define_pd_global(intx, CompileThreshold, 10000);
#endif // TIERED
define_pd_global(intx, Tier2CompileThreshold, 10000);
-define_pd_global(intx, Tier3CompileThreshold, 20000 );
-define_pd_global(intx, Tier4CompileThreshold, 40000 );
+define_pd_global(intx, Tier3CompileThreshold, 20000);
+define_pd_global(intx, Tier4CompileThreshold, 40000);
define_pd_global(intx, BackEdgeThreshold, 100000);
define_pd_global(intx, Tier2BackEdgeThreshold, 100000);
@@ -61,7 +60,6 @@
#ifdef AMD64
define_pd_global(intx, INTPRESSURE, 13);
define_pd_global(intx, InteriorEntryAlignment, 16);
-define_pd_global(intx, NewRatio, 2);
define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K));
define_pd_global(intx, LoopUnrollLimit, 60);
// InitialCodeCacheSize derived from specjbb2000 run.
@@ -69,19 +67,18 @@
define_pd_global(intx, CodeCacheExpansionSize, 64*K);
// Ergonomics related flags
-define_pd_global(uintx, DefaultMaxRAM, 32*G);
+define_pd_global(uint64_t,MaxRAM, 128ULL*G);
#else
define_pd_global(intx, INTPRESSURE, 6);
define_pd_global(intx, InteriorEntryAlignment, 4);
-define_pd_global(intx, NewRatio, 8); // Design center runs on 1.3.1
define_pd_global(intx, NewSizeThreadIncrease, 4*K);
-define_pd_global(intx, LoopUnrollLimit, 50); // Design center runs on 1.3.1
+define_pd_global(intx, LoopUnrollLimit, 50); // Design center runs on 1.3.1
// InitialCodeCacheSize derived from specjbb2000 run.
define_pd_global(intx, InitialCodeCacheSize, 2304*K); // Integral multiple of CodeCacheExpansionSize
define_pd_global(intx, CodeCacheExpansionSize, 32*K);
// Ergonomics related flags
-define_pd_global(uintx, DefaultMaxRAM, 1*G);
+define_pd_global(uint64_t,MaxRAM, 4ULL*G);
#endif // AMD64
define_pd_global(intx, OptoLoopAlignment, 16);
define_pd_global(intx, RegisterCostAreaRatio, 16000);
@@ -97,8 +94,8 @@
define_pd_global(uintx,CodeCacheMinBlockLength, 4);
// Heap related flags
-define_pd_global(uintx, PermSize, ScaleForWordSize(16*M));
-define_pd_global(uintx, MaxPermSize, ScaleForWordSize(64*M));
+define_pd_global(uintx,PermSize, ScaleForWordSize(16*M));
+define_pd_global(uintx,MaxPermSize, ScaleForWordSize(64*M));
// Ergonomics related flags
define_pd_global(bool, NeverActAsServerClassMachine, false);
--- a/hotspot/src/cpu/x86/vm/globals_x86.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -22,17 +22,16 @@
*
*/
-//
// Sets the default values for platform dependent flags used by the runtime system.
// (see globals.hpp)
-//
-define_pd_global(bool, ConvertSleepToYield, true);
-define_pd_global(bool, ShareVtableStubs, true);
-define_pd_global(bool, CountInterpCalls, true);
+define_pd_global(bool, ConvertSleepToYield, true);
+define_pd_global(bool, ShareVtableStubs, true);
+define_pd_global(bool, CountInterpCalls, true);
+define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this
-define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks
-define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast
+define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks
+define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast
// See 4827828 for this change. There is no globals_core_i486.hpp. I can't
// assign a different value for C2 without touching a number of files. Use
@@ -42,29 +41,24 @@
// the uep and the vep doesn't get real alignment but just slops on by
// only assured that the entry instruction meets the 5 byte size requirement.
#ifdef COMPILER2
-define_pd_global(intx, CodeEntryAlignment, 32);
+define_pd_global(intx, CodeEntryAlignment, 32);
#else
-define_pd_global(intx, CodeEntryAlignment, 16);
+define_pd_global(intx, CodeEntryAlignment, 16);
#endif // COMPILER2
+define_pd_global(intx, InlineFrequencyCount, 100);
+define_pd_global(intx, InlineSmallCode, 1000);
-define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this
-
-define_pd_global(uintx, TLABSize, 0);
+define_pd_global(intx, StackYellowPages, 2);
+define_pd_global(intx, StackRedPages, 1);
#ifdef AMD64
-define_pd_global(uintx, NewSize, ScaleForWordSize(2048 * K));
// Very large C++ stack frames using solaris-amd64 optimized builds
// due to lack of optimization caused by C++ compiler bugs
define_pd_global(intx, StackShadowPages, SOLARIS_ONLY(20) NOT_SOLARIS(6) DEBUG_ONLY(+2));
#else
-define_pd_global(uintx, NewSize, 1024 * K);
define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+1));
#endif // AMD64
-define_pd_global(intx, InlineFrequencyCount, 100);
-define_pd_global(intx, InlineSmallCode, 1000);
-define_pd_global(intx, PreInflateSpin, 10);
-define_pd_global(intx, StackYellowPages, 2);
-define_pd_global(intx, StackRedPages, 1);
+define_pd_global(intx, PreInflateSpin, 10);
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -196,6 +196,9 @@
} else {
assert(EnableInvokeDynamic, "giant index used only for EnableInvokeDynamic");
movl(reg, Address(rsi, bcp_offset));
+ // Check if the secondary index definition is still ~x, otherwise
+ // we have to change the following assembler code to calculate the
+ // plain index.
assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line");
notl(reg); // convert to plain index
}
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -185,12 +185,30 @@
}
+void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index,
+ int bcp_offset,
+ bool giant_index) {
+ assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
+ if (!giant_index) {
+ load_unsigned_short(index, Address(r13, bcp_offset));
+ } else {
+ assert(EnableInvokeDynamic, "giant index used only for EnableInvokeDynamic");
+ movl(index, Address(r13, bcp_offset));
+ // Check if the secondary index definition is still ~x, otherwise
+ // we have to change the following assembler code to calculate the
+ // plain index.
+ assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line");
+ notl(index); // convert to plain index
+ }
+}
+
+
void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache,
Register index,
- int bcp_offset) {
- assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
+ int bcp_offset,
+ bool giant_index) {
assert(cache != index, "must use different registers");
- load_unsigned_short(index, Address(r13, bcp_offset));
+ get_cache_index_at_bcp(index, bcp_offset, giant_index);
movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize));
assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below");
// convert from field index to ConstantPoolCacheEntry index
@@ -200,10 +218,10 @@
void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache,
Register tmp,
- int bcp_offset) {
- assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
+ int bcp_offset,
+ bool giant_index) {
assert(cache != tmp, "must use different register");
- load_unsigned_short(tmp, Address(r13, bcp_offset));
+ get_cache_index_at_bcp(tmp, bcp_offset, giant_index);
assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below");
// convert from field index to ConstantPoolCacheEntry index
// and from word offset to byte offset
@@ -1236,7 +1254,8 @@
void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
Register mdp,
- Register reg2) {
+ Register reg2,
+ bool receiver_can_be_null) {
if (ProfileInterpreter) {
Label profile_continue;
@@ -1246,8 +1265,15 @@
// We are making a call. Increment the count.
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
+ Label skip_receiver_profile;
+ if (receiver_can_be_null) {
+ testptr(receiver, receiver);
+ jcc(Assembler::zero, skip_receiver_profile);
+ }
+
// Record the receiver type.
record_klass_in_profile(receiver, mdp, reg2);
+ bind(skip_receiver_profile);
// The method data pointer needs to be updated to reflect the new target.
update_mdp_by_constant(mdp,
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -95,9 +95,10 @@
void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset);
void get_cache_and_index_at_bcp(Register cache, Register index,
- int bcp_offset);
+ int bcp_offset, bool giant_index = false);
void get_cache_entry_pointer_at_bcp(Register cache, Register tmp,
- int bcp_offset);
+ int bcp_offset, bool giant_index = false);
+ void get_cache_index_at_bcp(Register index, int bcp_offset, bool giant_index = false);
void pop_ptr(Register r = rax);
@@ -236,7 +237,8 @@
void profile_call(Register mdp);
void profile_final_call(Register mdp);
void profile_virtual_call(Register receiver, Register mdp,
- Register scratch2);
+ Register scratch2,
+ bool receiver_can_be_null = false);
void profile_ret(Register return_bci, Register mdp);
void profile_null_seen(Register mdp);
void profile_typecheck(Register mdp, Register klass, Register scratch);
--- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -277,12 +277,11 @@
address entry_point = __ pc();
// abstract method entry
- // remove return address. Not really needed, since exception
- // handling throws away expression stack
- __ pop(rbx);
- // adjust stack to what a normal return would do
- __ mov(rsp, r13);
+ // pop return address, reset last_sp to NULL
+ __ empty_expression_stack();
+ __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
+ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
// throw exception
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
@@ -300,7 +299,10 @@
if (!EnableMethodHandles) {
return generate_abstract_entry();
}
- return generate_abstract_entry(); //6815692//
+
+ address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm);
+
+ return entry_point;
}
--- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -448,7 +448,7 @@
rbx_index, Address::times_ptr,
base + vtableEntry::method_offset_in_bytes());
Register rbx_method = rbx_temp;
- __ movl(rbx_method, vtable_entry_addr);
+ __ movptr(rbx_method, vtable_entry_addr);
__ verify_oop(rbx_method);
__ jmp(rbx_method_fie);
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -2935,6 +2935,16 @@
// arraycopy stubs used by compilers
generate_arraycopy_stubs();
+
+ // generic method handle stubs
+ if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
+ for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
+ ek < MethodHandles::_EK_LIMIT;
+ ek = MethodHandles::EntryKind(1 + (int)ek)) {
+ StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
+ MethodHandles::generate_method_handle_stub(_masm, ek);
+ }
+ }
}
public:
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -155,15 +155,8 @@
}
-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, bool unbox) {
+address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) {
TosState incoming_state = state;
- if (EnableInvokeDynamic) {
- if (unbox) {
- incoming_state = atos;
- }
- } else {
- assert(!unbox, "old behavior");
- }
Label interpreter_entry;
address compiled_entry = __ pc();
@@ -216,46 +209,6 @@
__ restore_bcp();
__ restore_locals();
- Label L_fail;
-
- if (unbox && state != atos) {
- // cast and unbox
- BasicType type = as_BasicType(state);
- if (type == T_BYTE) type = T_BOOLEAN; // FIXME
- KlassHandle boxk = SystemDictionaryHandles::box_klass(type);
- __ mov32(rbx, ExternalAddress((address) boxk.raw_value()));
- __ testl(rax, rax);
- Label L_got_value, L_get_value;
- // convert nulls to zeroes (avoid NPEs here)
- if (!(type == T_FLOAT || type == T_DOUBLE)) {
- // if rax already contains zero bits, forge ahead
- __ jcc(Assembler::zero, L_got_value);
- } else {
- __ jcc(Assembler::notZero, L_get_value);
- __ fldz();
- __ jmp(L_got_value);
- }
- __ bind(L_get_value);
- __ cmp32(rbx, Address(rax, oopDesc::klass_offset_in_bytes()));
- __ jcc(Assembler::notEqual, L_fail);
- int offset = java_lang_boxing_object::value_offset_in_bytes(type);
- // Cf. TemplateTable::getfield_or_static
- switch (type) {
- case T_BYTE: // fall through:
- case T_BOOLEAN: __ load_signed_byte(rax, Address(rax, offset)); break;
- case T_CHAR: __ load_unsigned_short(rax, Address(rax, offset)); break;
- case T_SHORT: __ load_signed_short(rax, Address(rax, offset)); break;
- case T_INT: __ movl(rax, Address(rax, offset)); break;
- case T_FLOAT: __ fld_s(Address(rax, offset)); break;
- case T_DOUBLE: __ fld_d(Address(rax, offset)); break;
- // Access to java.lang.Double.value does not need to be atomic:
- case T_LONG: { __ movl(rdx, Address(rax, offset + 4));
- __ movl(rax, Address(rax, offset + 0)); } break;
- default: ShouldNotReachHere();
- }
- __ bind(L_got_value);
- }
-
Label L_got_cache, L_giant_index;
if (EnableInvokeDynamic) {
__ cmpb(Address(rsi, 0), Bytecodes::_invokedynamic);
@@ -263,32 +216,6 @@
}
__ get_cache_and_index_at_bcp(rbx, rcx, 1, false);
__ bind(L_got_cache);
- if (unbox && state == atos) {
- // insert a casting conversion, to keep verifier sane
- Label L_ok, L_ok_pops;
- __ testl(rax, rax);
- __ jcc(Assembler::zero, L_ok);
- __ push(rax); // save the object to check
- __ push(rbx); // save CP cache reference
- __ movl(rdx, Address(rax, oopDesc::klass_offset_in_bytes()));
- __ movl(rbx, Address(rbx, rcx,
- Address::times_4, constantPoolCacheOopDesc::base_offset() +
- ConstantPoolCacheEntry::f1_offset()));
- __ movl(rbx, Address(rbx, __ delayed_value(sun_dyn_CallSiteImpl::type_offset_in_bytes, rcx)));
- __ movl(rbx, Address(rbx, __ delayed_value(java_dyn_MethodType::rtype_offset_in_bytes, rcx)));
- __ movl(rax, Address(rbx, __ delayed_value(java_lang_Class::klass_offset_in_bytes, rcx)));
- __ check_klass_subtype(rdx, rax, rbx, L_ok_pops);
- __ pop(rcx); // pop and discard CP cache
- __ mov(rbx, rax); // target supertype into rbx for L_fail
- __ pop(rax); // failed object into rax for L_fail
- __ jmp(L_fail);
-
- __ bind(L_ok_pops);
- // restore pushed temp regs:
- __ pop(rbx);
- __ pop(rax);
- __ bind(L_ok);
- }
__ movl(rbx, Address(rbx, rcx,
Address::times_ptr, constantPoolCacheOopDesc::base_offset() +
ConstantPoolCacheEntry::flags_offset()));
@@ -301,14 +228,6 @@
__ bind(L_giant_index);
__ get_cache_and_index_at_bcp(rbx, rcx, 1, true);
__ jmp(L_got_cache);
-
- if (unbox) {
- __ bind(L_fail);
- __ push(rbx); // missed klass (required)
- __ push(rax); // bad object (actual)
- __ movptr(rdx, ExternalAddress((address) &Interpreter::_throw_WrongMethodType_entry));
- __ call(rdx);
- }
}
return entry;
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -100,21 +100,26 @@
return entry;
}
-// Arguments are: required type in rarg1, failing object (or NULL) in rarg2
+// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4.
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
address entry = __ pc();
__ pop(c_rarg2); // failing object is at TOS
__ pop(c_rarg1); // required type is at TOS+8
- // expression stack must be empty before entering the VM if an
- // exception happened
+ __ verify_oop(c_rarg1);
+ __ verify_oop(c_rarg2);
+
+ // Various method handle types use interpreter registers as temps.
+ __ restore_bcp();
+ __ restore_locals();
+
+ // Expression stack must be empty before entering the VM for an exception.
__ empty_expression_stack();
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
- InterpreterRuntime::
- throw_WrongMethodTypeException),
+ InterpreterRuntime::throw_WrongMethodTypeException),
// pass required type, failing object (or NULL)
c_rarg1, c_rarg2);
return entry;
@@ -166,8 +171,7 @@
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
- int step, bool unbox) {
- assert(!unbox, "NYI");//6815692//
+ int step) {
// amd64 doesn't need to do anything special about compiled returns
// to the interpreter so the code that exists on x86 to place a sentinel
@@ -183,15 +187,29 @@
__ restore_bcp();
__ restore_locals();
- __ get_cache_and_index_at_bcp(rbx, rcx, 1);
+ Label L_got_cache, L_giant_index;
+ if (EnableInvokeDynamic) {
+ __ cmpb(Address(r13, 0), Bytecodes::_invokedynamic);
+ __ jcc(Assembler::equal, L_giant_index);
+ }
+ __ get_cache_and_index_at_bcp(rbx, rcx, 1, false);
+ __ bind(L_got_cache);
__ movl(rbx, Address(rbx, rcx,
- Address::times_8,
+ Address::times_ptr,
in_bytes(constantPoolCacheOopDesc::base_offset()) +
3 * wordSize));
__ andl(rbx, 0xFF);
if (TaggedStackInterpreter) __ shll(rbx, 1); // 2 slots per parameter.
__ lea(rsp, Address(rsp, rbx, Address::times_8));
__ dispatch_next(state, step);
+
+ // out of the main line of code...
+ if (EnableInvokeDynamic) {
+ __ bind(L_giant_index);
+ __ get_cache_and_index_at_bcp(rbx, rcx, 1, true);
+ __ jmp(L_got_cache);
+ }
+
return entry;
}
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -2890,9 +2890,6 @@
void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) {
- bool is_invdyn_bootstrap = (byte_no < 0);
- if (is_invdyn_bootstrap) byte_no = -byte_no;
-
// determine flags
Bytecodes::Code code = bytecode();
const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
@@ -2907,8 +2904,6 @@
const Register flags = rdx;
assert_different_registers(method, index, recv, flags);
- assert(!is_invdyn_bootstrap || is_invokedynamic, "byte_no<0 hack only for invdyn");
-
// save 'interpreter return address'
__ save_bcp();
@@ -2944,9 +2939,7 @@
// load return address
{
address table_addr;
- if (is_invdyn_bootstrap)
- table_addr = (address)Interpreter::return_5_unbox_addrs_by_index_table();
- else if (is_invokeinterface || is_invokedynamic)
+ if (is_invokeinterface || is_invokedynamic)
table_addr = (address)Interpreter::return_5_addrs_by_index_table();
else
table_addr = (address)Interpreter::return_3_addrs_by_index_table();
@@ -3153,54 +3146,10 @@
__ profile_call(rsi);
}
- Label handle_unlinked_site;
- __ movptr(rcx, Address(rax, __ delayed_value(sun_dyn_CallSiteImpl::target_offset_in_bytes, rcx)));
- __ testptr(rcx, rcx);
- __ jcc(Assembler::zero, handle_unlinked_site);
-
+ __ movptr(rcx, Address(rax, __ delayed_value(java_dyn_CallSite::target_offset_in_bytes, rcx)));
+ __ null_check(rcx);
__ prepare_to_jump_from_interpreted();
__ jump_to_method_handle_entry(rcx, rdx);
-
- // Initial calls come here...
- __ bind(handle_unlinked_site);
- __ pop(rcx); // remove return address pushed by prepare_invoke
-
- // box stacked arguments into an array for the bootstrap method
- address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::bootstrap_invokedynamic);
- __ restore_bcp(); // rsi must be correct for call_VM
- __ call_VM(rax, entry, rax);
- __ movl(rdi, rax); // protect bootstrap MH from prepare_invoke
-
- // recompute return address
- __ restore_bcp(); // rsi must be correct for prepare_invoke
- prepare_invoke(rax, rbx, -byte_no); // smashes rcx, rdx
- // rax: CallSite object (f1)
- // rbx: unused (f2)
- // rdi: bootstrap MH
- // rdx: flags
-
- // now load up the arglist, which has been neatly boxed
- __ get_thread(rcx);
- __ movptr(rdx, Address(rcx, JavaThread::vm_result_2_offset()));
- __ movptr(Address(rcx, JavaThread::vm_result_2_offset()), NULL_WORD);
- __ verify_oop(rdx);
- // rdx = arglist
-
- // save SP now, before we add the bootstrap call to the stack
- // We must preserve a fiction that the original arguments are outgoing,
- // because the return sequence will reset the stack to this point
- // and then pop all those arguments. It seems error-prone to use
- // a different argument list size just for bootstrapping.
- __ prepare_to_jump_from_interpreted();
-
- // Now let's play adapter, pushing the real arguments on the stack.
- __ pop(rbx); // return PC
- __ push(rdi); // boot MH
- __ push(rax); // call site
- __ push(rdx); // arglist
- __ push(rbx); // return PC, again
- __ mov(rcx, rdi);
- __ jump_to_method_handle_entry(rcx, rdx);
}
//----------------------------------------------------------------------------------------------------
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -203,18 +203,15 @@
__ jcc(Assembler::notEqual, fast_patch);
__ get_method(scratch);
// Let breakpoint table handling rewrite to quicker bytecode
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::set_original_bytecode_at),
- scratch, r13, bc);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), scratch, r13, bc);
#ifndef ASSERT
__ jmpb(patch_done);
+#else
+ __ jmp(patch_done);
+#endif
__ bind(fast_patch);
}
-#else
- __ jmp(patch_done);
- __ bind(fast_patch);
- }
+#ifdef ASSERT
Label okay;
__ load_unsigned_byte(scratch, at_bcp(0));
__ cmpl(scratch, (int) Bytecodes::java_code(bytecode));
@@ -2054,26 +2051,28 @@
}
}
-void TemplateTable::resolve_cache_and_index(int byte_no,
- Register Rcache,
- Register index) {
+void TemplateTable::resolve_cache_and_index(int byte_no, Register Rcache, Register index) {
assert(byte_no == 1 || byte_no == 2, "byte_no out of range");
+ bool is_invokedynamic = (bytecode() == Bytecodes::_invokedynamic);
const Register temp = rbx;
assert_different_registers(Rcache, index, temp);
const int shift_count = (1 + byte_no) * BitsPerByte;
Label resolved;
- __ get_cache_and_index_at_bcp(Rcache, index, 1);
- __ movl(temp, Address(Rcache,
- index, Address::times_8,
- constantPoolCacheOopDesc::base_offset() +
- ConstantPoolCacheEntry::indices_offset()));
- __ shrl(temp, shift_count);
- // have we resolved this bytecode?
- __ andl(temp, 0xFF);
- __ cmpl(temp, (int) bytecode());
- __ jcc(Assembler::equal, resolved);
+ __ get_cache_and_index_at_bcp(Rcache, index, 1, is_invokedynamic);
+ if (is_invokedynamic) {
+ // we are resolved if the f1 field contains a non-null CallSite object
+ __ cmpptr(Address(Rcache, index, Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f1_offset()), (int32_t) NULL_WORD);
+ __ jcc(Assembler::notEqual, resolved);
+ } else {
+ __ movl(temp, Address(Rcache, index, Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::indices_offset()));
+ __ shrl(temp, shift_count);
+ // have we resolved this bytecode?
+ __ andl(temp, 0xFF);
+ __ cmpl(temp, (int) bytecode());
+ __ jcc(Assembler::equal, resolved);
+ }
// resolve first time through
address entry;
@@ -2090,6 +2089,9 @@
case Bytecodes::_invokeinterface:
entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke);
break;
+ case Bytecodes::_invokedynamic:
+ entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic);
+ break;
default:
ShouldNotReachHere();
break;
@@ -2098,7 +2100,7 @@
__ call_VM(noreg, entry, temp);
// Update registers with resolved info
- __ get_cache_and_index_at_bcp(Rcache, index, 1);
+ __ get_cache_and_index_at_bcp(Rcache, index, 1, is_invokedynamic);
__ bind(resolved);
}
@@ -2832,15 +2834,14 @@
ShouldNotReachHere();
}
-void TemplateTable::prepare_invoke(Register method,
- Register index,
- int byte_no,
- Bytecodes::Code code) {
+void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) {
// determine flags
+ Bytecodes::Code code = bytecode();
const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
+ const bool is_invokedynamic = code == Bytecodes::_invokedynamic;
const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
const bool is_invokespecial = code == Bytecodes::_invokespecial;
- const bool load_receiver = code != Bytecodes::_invokestatic;
+ const bool load_receiver = (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic);
const bool receiver_null_check = is_invokespecial;
const bool save_flags = is_invokeinterface || is_invokevirtual;
// setup registers & access constant pool cache
@@ -2858,9 +2859,13 @@
__ movl(recv, flags);
__ andl(recv, 0xFF);
if (TaggedStackInterpreter) __ shll(recv, 1); // index*2
- __ movptr(recv, Address(rsp, recv, Address::times_8,
- -Interpreter::expr_offset_in_bytes(1)));
- __ verify_oop(recv);
+ Address recv_addr(rsp, recv, Address::times_8, -Interpreter::expr_offset_in_bytes(1));
+ if (is_invokedynamic) {
+ __ lea(recv, recv_addr);
+ } else {
+ __ movptr(recv, recv_addr);
+ __ verify_oop(recv);
+ }
}
// do null check if needed
@@ -2878,10 +2883,14 @@
ConstantPoolCacheEntry::verify_tosBits();
// load return address
{
- ExternalAddress return_5((address)Interpreter::return_5_addrs_by_index_table());
- ExternalAddress return_3((address)Interpreter::return_3_addrs_by_index_table());
- __ lea(rscratch1, (is_invokeinterface ? return_5 : return_3));
- __ movptr(flags, Address(rscratch1, flags, Address::times_8));
+ address table_addr;
+ if (is_invokeinterface || is_invokedynamic)
+ table_addr = (address)Interpreter::return_5_addrs_by_index_table();
+ else
+ table_addr = (address)Interpreter::return_3_addrs_by_index_table();
+ ExternalAddress table(table_addr);
+ __ lea(rscratch1, table);
+ __ movptr(flags, Address(rscratch1, flags, Address::times_ptr));
}
// push return address
@@ -2947,7 +2956,7 @@
void TemplateTable::invokevirtual(int byte_no) {
transition(vtos, vtos);
- prepare_invoke(rbx, noreg, byte_no, bytecode());
+ prepare_invoke(rbx, noreg, byte_no);
// rbx: index
// rcx: receiver
@@ -2959,7 +2968,7 @@
void TemplateTable::invokespecial(int byte_no) {
transition(vtos, vtos);
- prepare_invoke(rbx, noreg, byte_no, bytecode());
+ prepare_invoke(rbx, noreg, byte_no);
// do the call
__ verify_oop(rbx);
__ profile_call(rax);
@@ -2969,7 +2978,7 @@
void TemplateTable::invokestatic(int byte_no) {
transition(vtos, vtos);
- prepare_invoke(rbx, noreg, byte_no, bytecode());
+ prepare_invoke(rbx, noreg, byte_no);
// do the call
__ verify_oop(rbx);
__ profile_call(rax);
@@ -2983,7 +2992,7 @@
void TemplateTable::invokeinterface(int byte_no) {
transition(vtos, vtos);
- prepare_invoke(rax, rbx, byte_no, bytecode());
+ prepare_invoke(rax, rbx, byte_no);
// rax: Interface
// rbx: index
@@ -3072,7 +3081,24 @@
return;
}
- __ stop("invokedynamic NYI");//6815692//
+ prepare_invoke(rax, rbx, byte_no);
+
+ // rax: CallSite object (f1)
+ // rbx: unused (f2)
+ // rcx: receiver address
+ // rdx: flags (unused)
+
+ if (ProfileInterpreter) {
+ Label L;
+ // %%% should make a type profile for any invokedynamic that takes a ref argument
+ // profile this call
+ __ profile_call(r13);
+ }
+
+ __ movptr(rcx, Address(rax, __ delayed_value(java_dyn_CallSite::target_offset_in_bytes, rcx)));
+ __ null_check(rcx);
+ __ prepare_to_jump_from_interpreted();
+ __ jump_to_method_handle_entry(rcx, rdx);
}
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -22,8 +22,7 @@
*
*/
- static void prepare_invoke(Register method, Register index, int byte_no,
- Bytecodes::Code code);
+ static void prepare_invoke(Register method, Register index, int byte_no);
static void invokevirtual_helper(Register index, Register recv,
Register flags);
static void volatile_barrier(Assembler::Membar_mask_bits order_constraint);
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -255,6 +255,8 @@
if (!VM_Version::supports_sse2()) {
vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported");
}
+ // in 64 bit the use of SSE2 is the minimum
+ if (UseSSE < 2) UseSSE = 2;
#endif
// If the OS doesn't support SSE, we can't use this feature even if the HW does
--- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -204,6 +204,20 @@
goto unwind_and_return;
}
+ // Update the invocation counter
+ if ((UseCompiler || CountCompiledCalls) && !method->is_synchronized()) {
+ thread->set_do_not_unlock();
+ InvocationCounter *counter = method->invocation_counter();
+ counter->increment();
+ if (counter->reached_InvocationLimit()) {
+ CALL_VM_NOCHECK(
+ InterpreterRuntime::frequency_counter_overflow(thread, NULL));
+ if (HAS_PENDING_EXCEPTION)
+ goto unwind_and_return;
+ }
+ thread->clr_do_not_unlock();
+ }
+
// Lock if necessary
BasicObjectLock *monitor;
monitor = NULL;
--- a/hotspot/src/cpu/zero/vm/frame_zero.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/zero/vm/frame_zero.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -36,11 +36,8 @@
return zeroframe()->is_interpreter_frame();
}
-bool frame::is_fake_stub_frame() const {
- return zeroframe()->is_fake_stub_frame();
-}
-
frame frame::sender_for_entry_frame(RegisterMap *map) const {
+ assert(zeroframe()->is_entry_frame(), "wrong type of frame");
assert(map != NULL, "map must be set");
assert(!entry_frame_is_first(), "next Java fp must be non zero");
assert(entry_frame_call_wrapper()->anchor()->last_Java_sp() == sender_sp(),
@@ -50,15 +47,10 @@
return frame(sender_sp(), sp() + 1);
}
-frame frame::sender_for_interpreter_frame(RegisterMap *map) const {
- return frame(sender_sp(), sp() + 1);
-}
-
-frame frame::sender_for_compiled_frame(RegisterMap *map) const {
- return frame(sender_sp(), sp() + 1);
-}
-
-frame frame::sender_for_fake_stub_frame(RegisterMap *map) const {
+frame frame::sender_for_nonentry_frame(RegisterMap *map) const {
+ assert(zeroframe()->is_interpreter_frame() ||
+ zeroframe()->is_shark_frame() ||
+ zeroframe()->is_fake_stub_frame(), "wrong type of frame");
return frame(sender_sp(), sp() + 1);
}
@@ -69,17 +61,8 @@
if (is_entry_frame())
return sender_for_entry_frame(map);
-
- if (is_interpreted_frame())
- return sender_for_interpreter_frame(map);
-
- if (is_compiled_frame())
- return sender_for_compiled_frame(map);
-
- if (is_fake_stub_frame())
- return sender_for_fake_stub_frame(map);
-
- ShouldNotReachHere();
+ else
+ return sender_for_nonentry_frame(map);
}
#ifdef CC_INTERP
--- a/hotspot/src/cpu/zero/vm/frame_zero.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/zero/vm/frame_zero.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -65,10 +65,7 @@
}
public:
- bool is_fake_stub_frame() const;
-
- public:
- frame sender_for_fake_stub_frame(RegisterMap* map) const;
+ frame sender_for_nonentry_frame(RegisterMap* map) const;
public:
void zero_print_on_error(int index,
--- a/hotspot/src/cpu/zero/vm/globals_zero.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/zero/vm/globals_zero.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -23,10 +23,8 @@
*
*/
-//
// Set the default values for platform dependent flags used by the
// runtime system. See globals.hpp for details of what they do.
-//
define_pd_global(bool, ConvertSleepToYield, true);
define_pd_global(bool, ShareVtableStubs, true);
@@ -37,14 +35,7 @@
define_pd_global(bool, UncommonNullCast, true);
define_pd_global(intx, CodeEntryAlignment, 32);
-define_pd_global(uintx, TLABSize, 0);
-#ifdef _LP64
-define_pd_global(uintx, NewSize, ScaleForWordSize(2048 * K));
-#else
-define_pd_global(uintx, NewSize, ScaleForWordSize(1024 * K));
-#endif // _LP64
define_pd_global(intx, InlineFrequencyCount, 100);
-define_pd_global(intx, InlineSmallCode, 1000);
define_pd_global(intx, PreInflateSpin, 10);
define_pd_global(intx, StackYellowPages, 2);
--- a/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1,6 +1,6 @@
/*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
- * Copyright 2007, 2008 Red Hat, Inc.
+ * Copyright 2007, 2008, 2009 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -61,7 +61,14 @@
BasicType *in_sig_bt,
VMRegPair *in_regs,
BasicType ret_type) {
+#ifdef SHARK
+ return SharkCompiler::compiler()->generate_native_wrapper(masm,
+ method,
+ in_sig_bt,
+ ret_type);
+#else
ShouldNotCallThis();
+#endif // SHARK
}
int Deoptimization::last_frame_adjust(int callee_parameters,
--- a/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -1,6 +1,6 @@
/*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
- * Copyright 2008 Red Hat, Inc.
+ * Copyright 2008, 2009 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,7 @@
// | ... |
class SharkFrame : public ZeroFrame {
- friend class SharkFunction;
+ friend class SharkStack;
private:
SharkFrame() : ZeroFrame() {
--- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -223,8 +223,8 @@
"environment on Linux when /proc filesystem is not mounted.";
void os::Linux::initialize_system_info() {
- _processor_count = sysconf(_SC_NPROCESSORS_CONF);
- if (_processor_count == 1) {
+ set_processor_count(sysconf(_SC_NPROCESSORS_CONF));
+ if (processor_count() == 1) {
pid_t pid = os::Linux::gettid();
char fname[32];
jio_snprintf(fname, sizeof(fname), "/proc/%d", pid);
@@ -236,7 +236,7 @@
}
}
_physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE);
- assert(_processor_count > 0, "linux error");
+ assert(processor_count() > 0, "linux error");
}
void os::init_system_properties_values() {
@@ -4683,6 +4683,7 @@
// Return immediately if a permit is available.
if (_counter > 0) {
_counter = 0 ;
+ OrderAccess::fence();
return ;
}
@@ -4725,6 +4726,7 @@
_counter = 0;
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
+ OrderAccess::fence();
return;
}
@@ -4765,6 +4767,7 @@
jt->java_suspend_self();
}
+ OrderAccess::fence();
}
void Parker::unpark() {
--- a/hotspot/src/os/solaris/dtrace/libjvm_db.c Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/os/solaris/dtrace/libjvm_db.c Wed Jul 05 17:04:53 2017 +0200
@@ -937,54 +937,56 @@
return err;
}
-static int
-scopeDesc_chain(Nmethod_t *N)
-{
+static int scopeDesc_chain(Nmethod_t *N) {
int32_t decode_offset = 0;
int32_t err;
- if (debug > 2)
- fprintf(stderr, "\t scopeDesc_chain: BEGIN\n");
+ if (debug > 2) {
+ fprintf(stderr, "\t scopeDesc_chain: BEGIN\n");
+ }
err = ps_pread(N->J->P, N->pc_desc + OFFSET_PcDesc_scope_decode_offset,
&decode_offset, SZ32);
CHECK_FAIL(err);
while (decode_offset > 0) {
- if (debug > 2)
- fprintf(stderr, "\t scopeDesc_chain: decode_offset: %#x\n", decode_offset);
+ Vframe_t *vf = &N->vframes[N->vf_cnt];
- Vframe_t *vf = &N->vframes[N->vf_cnt];
+ if (debug > 2) {
+ fprintf(stderr, "\t scopeDesc_chain: decode_offset: %#x\n", decode_offset);
+ }
+
+ err = scope_desc_at(N, decode_offset, vf);
+ CHECK_FAIL(err);
- err = scope_desc_at(N, decode_offset, vf);
- CHECK_FAIL(err);
+ if (vf->methodIdx > N->oops_len) {
+ fprintf(stderr, "\t scopeDesc_chain: (methodIdx > oops_len) !\n");
+ return -1;
+ }
+ err = read_pointer(N->J, N->nm + N->oops_beg + (vf->methodIdx-1)*POINTER_SIZE,
+ &vf->methodOop);
+ CHECK_FAIL(err);
- if (vf->methodIdx > N->oops_len) {
- fprintf(stderr, "\t scopeDesc_chain: (methodIdx > oops_len) !\n");
- return -1;
- }
- err = read_pointer(N->J, N->nm + N->oops_beg + (vf->methodIdx-1)*POINTER_SIZE,
- &vf->methodOop);
+ if (vf->methodOop) {
+ N->vf_cnt++;
+ err = line_number_from_bci(N->J, vf);
CHECK_FAIL(err);
-
- if (vf->methodOop) {
- N->vf_cnt++;
- err = line_number_from_bci(N->J, vf);
- CHECK_FAIL(err);
- if (debug > 2) {
- fprintf(stderr, "\t scopeDesc_chain: methodOop: %#8llx, line: %ld\n",
- vf->methodOop, vf->line);
- }
+ if (debug > 2) {
+ fprintf(stderr, "\t scopeDesc_chain: methodOop: %#8llx, line: %ld\n",
+ vf->methodOop, vf->line);
}
- decode_offset = vf->sender_decode_offset;
+ }
+ decode_offset = vf->sender_decode_offset;
}
- if (debug > 2)
- fprintf(stderr, "\t scopeDesc_chain: END \n\n");
+ if (debug > 2) {
+ fprintf(stderr, "\t scopeDesc_chain: END \n\n");
+ }
return PS_OK;
fail:
- if (debug)
- fprintf(stderr, "\t scopeDesc_chain: FAIL \n\n");
+ if (debug) {
+ fprintf(stderr, "\t scopeDesc_chain: FAIL \n\n");
+ }
return err;
}
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -457,7 +457,7 @@
void os::Solaris::initialize_system_info() {
- _processor_count = sysconf(_SC_NPROCESSORS_CONF);
+ set_processor_count(sysconf(_SC_NPROCESSORS_CONF));
_processors_online = sysconf (_SC_NPROCESSORS_ONLN);
_physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE);
}
@@ -5803,6 +5803,7 @@
// Return immediately if a permit is available.
if (_counter > 0) {
_counter = 0 ;
+ OrderAccess::fence();
return ;
}
@@ -5846,6 +5847,7 @@
_counter = 0;
status = os::Solaris::mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
+ OrderAccess::fence();
return;
}
@@ -5892,6 +5894,7 @@
jt->java_suspend_self();
}
+ OrderAccess::fence();
}
void Parker::unpark() {
--- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -3150,7 +3150,7 @@
_vm_allocation_granularity = si.dwAllocationGranularity;
_processor_type = si.dwProcessorType;
_processor_level = si.wProcessorLevel;
- _processor_count = si.dwNumberOfProcessors;
+ set_processor_count(si.dwNumberOfProcessors);
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
--- a/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -22,10 +22,9 @@
*
*/
-//
// Sets the default values for platform dependent flags used by the runtime system.
// (see globals.hpp)
-//
+
define_pd_global(bool, DontYieldALot, false);
#ifdef AMD64
define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default
@@ -39,11 +38,10 @@
#endif // AMD64
define_pd_global(intx, CompilerThreadStackSize, 0);
-define_pd_global(intx, SurvivorRatio, 8);
-define_pd_global(uintx, JVMInvokeMethodSlack, 8192);
+define_pd_global(uintx,JVMInvokeMethodSlack, 8192);
// Only used on 64 bit platforms
-define_pd_global(uintx, HeapBaseMinAddress, 2*G);
+define_pd_global(uintx,HeapBaseMinAddress, 2*G);
// Only used on 64 bit Windows platforms
define_pd_global(bool, UseVectoredExceptions, false);
--- a/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -22,31 +22,25 @@
*
*/
-//
// Sets the default values for platform dependent flags used by the runtime system.
// (see globals.hpp)
-//
+
define_pd_global(bool, DontYieldALot, true); // Determined in the design center
#ifdef AMD64
define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default
define_pd_global(intx, VMThreadStackSize, 1024);
-define_pd_global(intx, SurvivorRatio, 6);
-define_pd_global(uintx, JVMInvokeMethodSlack, 8*K);
+define_pd_global(uintx,JVMInvokeMethodSlack, 8*K);
#else
-// UseStackBanging is not pd
-// define_pd_global(bool, UseStackBanging, true);
-
// ThreadStackSize 320 allows TaggedStackInterpreter and a couple of test cases
// to run while keeping the number of threads that can be created high.
define_pd_global(intx, ThreadStackSize, 320);
define_pd_global(intx, VMThreadStackSize, 512);
-define_pd_global(intx, SurvivorRatio, 8);
-define_pd_global(uintx, JVMInvokeMethodSlack, 10*K);
+define_pd_global(uintx,JVMInvokeMethodSlack, 10*K);
#endif // AMD64
define_pd_global(intx, CompilerThreadStackSize, 0);
// Only used on 64 bit platforms
-define_pd_global(uintx, HeapBaseMinAddress, 256*M);
+define_pd_global(uintx,HeapBaseMinAddress, 256*M);
// Only used on 64 bit Windows platforms
define_pd_global(bool, UseVectoredExceptions, false);
--- a/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -22,10 +22,9 @@
*
*/
-//
// Sets the default values for platform dependent flags used by the runtime system.
// (see globals.hpp)
-//
+
define_pd_global(bool, DontYieldALot, false);
// Default stack size on Windows is determined by the executable (java.exe
@@ -35,8 +34,6 @@
define_pd_global(intx, ThreadStackSize, 0); // 0 => use system default
define_pd_global(intx, VMThreadStackSize, 0); // 0 => use system default
-define_pd_global(intx, SurvivorRatio, 8);
-
#ifdef ASSERT
define_pd_global(intx, CompilerThreadStackSize, 1024);
#else
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -365,7 +365,7 @@
if (_next_loop_index < 31) _next_loop_index++;
} else {
// block already marked as loop header
- assert(is_power_of_2(_loop_map.at(block->block_id())), "exactly one bit must be set");
+ assert(is_power_of_2((unsigned int)_loop_map.at(block->block_id())), "exactly one bit must be set");
}
}
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1855,12 +1855,26 @@
addr = new LIR_Address(base_op, index_op->as_jint(), dst_type);
} else {
#ifdef X86
+#ifdef _LP64
+ if (!index_op->is_illegal() && index_op->type() == T_INT) {
+ LIR_Opr tmp = new_pointer_register();
+ __ convert(Bytecodes::_i2l, index_op, tmp);
+ index_op = tmp;
+ }
+#endif
addr = new LIR_Address(base_op, index_op, LIR_Address::Scale(log2_scale), 0, dst_type);
#else
if (index_op->is_illegal() || log2_scale == 0) {
+#ifdef _LP64
+ if (!index_op->is_illegal() && index_op->type() == T_INT) {
+ LIR_Opr tmp = new_pointer_register();
+ __ convert(Bytecodes::_i2l, index_op, tmp);
+ index_op = tmp;
+ }
+#endif
addr = new LIR_Address(base_op, index_op, dst_type);
} else {
- LIR_Opr tmp = new_register(T_INT);
+ LIR_Opr tmp = new_pointer_register();
__ shift_left(index_op, log2_scale, tmp);
addr = new LIR_Address(base_op, tmp, dst_type);
}
@@ -1915,10 +1929,25 @@
LIR_Opr index_op = idx.result();
if (log2_scale != 0) {
// temporary fix (platform dependent code without shift on Intel would be better)
- index_op = new_register(T_INT);
- __ move(idx.result(), index_op);
+ index_op = new_pointer_register();
+#ifdef _LP64
+ if(idx.result()->type() == T_INT) {
+ __ convert(Bytecodes::_i2l, idx.result(), index_op);
+ } else {
+#endif
+ __ move(idx.result(), index_op);
+#ifdef _LP64
+ }
+#endif
__ shift_left(index_op, log2_scale, index_op);
}
+#ifdef _LP64
+ else if(!index_op->is_illegal() && index_op->type() == T_INT) {
+ LIR_Opr tmp = new_pointer_register();
+ __ convert(Bytecodes::_i2l, index_op, tmp);
+ index_op = tmp;
+ }
+#endif
LIR_Address* addr = new LIR_Address(base_op, index_op, x->basic_type());
__ move(value.result(), addr);
--- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -2464,6 +2464,10 @@
case T_LONG: // fall through
case T_DOUBLE: {
+#ifdef _LP64
+ scope_values->append(&_int_0_scope_value);
+ scope_values->append(new ConstantLongValue(c->as_jlong_bits()));
+#else
if (hi_word_offset_in_bytes > lo_word_offset_in_bytes) {
scope_values->append(new ConstantIntValue(c->as_jint_hi_bits()));
scope_values->append(new ConstantIntValue(c->as_jint_lo_bits()));
@@ -2471,7 +2475,7 @@
scope_values->append(new ConstantIntValue(c->as_jint_lo_bits()));
scope_values->append(new ConstantIntValue(c->as_jint_hi_bits()));
}
-
+#endif
return 2;
}
@@ -2503,17 +2507,18 @@
} else if (opr->is_single_cpu()) {
bool is_oop = opr->is_oop_register();
int cache_idx = opr->cpu_regnr() * 2 + (is_oop ? 1 : 0);
+ Location::Type int_loc_type = NOT_LP64(Location::normal) LP64_ONLY(Location::int_in_long);
ScopeValue* sv = _scope_value_cache.at(cache_idx);
if (sv == NULL) {
- Location::Type loc_type = is_oop ? Location::oop : Location::normal;
+ Location::Type loc_type = is_oop ? Location::oop : int_loc_type;
VMReg rname = frame_map()->regname(opr);
sv = new LocationValue(Location::new_reg_loc(loc_type, rname));
_scope_value_cache.at_put(cache_idx, sv);
}
// check if cached value is correct
- DEBUG_ONLY(assert_equal(sv, new LocationValue(Location::new_reg_loc(is_oop ? Location::oop : Location::normal, frame_map()->regname(opr)))));
+ DEBUG_ONLY(assert_equal(sv, new LocationValue(Location::new_reg_loc(is_oop ? Location::oop : int_loc_type, frame_map()->regname(opr)))));
scope_values->append(sv);
return 1;
--- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -61,9 +61,11 @@
BCEscapeAnalyzer* _parent;
int _level;
+ public:
class ArgumentMap;
class StateInfo;
+ private:
// helper functions
bool is_argument(int i) { return i >= 0 && i < _arg_size; }
--- a/hotspot/src/share/vm/ci/ciEnv.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -46,6 +46,9 @@
ciInstanceKlass* ciEnv::_Thread;
ciInstanceKlass* ciEnv::_OutOfMemoryError;
ciInstanceKlass* ciEnv::_String;
+ciInstanceKlass* ciEnv::_StringBuffer;
+ciInstanceKlass* ciEnv::_StringBuilder;
+ciInstanceKlass* ciEnv::_Integer;
ciSymbol* ciEnv::_unloaded_cisymbol = NULL;
ciInstanceKlass* ciEnv::_unloaded_ciinstance_klass = NULL;
@@ -110,6 +113,8 @@
_ArrayIndexOutOfBoundsException_instance = NULL;
_ArrayStoreException_instance = NULL;
_ClassCastException_instance = NULL;
+ _the_null_string = NULL;
+ _the_min_jint_string = NULL;
}
ciEnv::ciEnv(Arena* arena) {
@@ -163,6 +168,8 @@
_ArrayIndexOutOfBoundsException_instance = NULL;
_ArrayStoreException_instance = NULL;
_ClassCastException_instance = NULL;
+ _the_null_string = NULL;
+ _the_min_jint_string = NULL;
}
ciEnv::~ciEnv() {
@@ -248,6 +255,22 @@
return _ClassCastException_instance;
}
+ciInstance* ciEnv::the_null_string() {
+ if (_the_null_string == NULL) {
+ VM_ENTRY_MARK;
+ _the_null_string = get_object(Universe::the_null_string())->as_instance();
+ }
+ return _the_null_string;
+}
+
+ciInstance* ciEnv::the_min_jint_string() {
+ if (_the_min_jint_string == NULL) {
+ VM_ENTRY_MARK;
+ _the_min_jint_string = get_object(Universe::the_min_jint_string())->as_instance();
+ }
+ return _the_min_jint_string;
+}
+
// ------------------------------------------------------------------
// ciEnv::get_method_from_handle
ciMethod* ciEnv::get_method_from_handle(jobject method) {
@@ -690,10 +713,8 @@
ciInstanceKlass* declared_holder = get_instance_klass_for_declared_method_holder(holder);
// Get the method's name and signature.
- int nt_index = cpool->name_and_type_ref_index_at(index);
- int sig_index = cpool->signature_ref_index_at(nt_index);
symbolOop name_sym = cpool->name_ref_at(index);
- symbolOop sig_sym = cpool->symbol_at(sig_index);
+ symbolOop sig_sym = cpool->signature_ref_at(index);
if (holder_is_accessible) { // Our declared holder is loaded.
instanceKlass* lookup = declared_holder->get_instanceKlass();
--- a/hotspot/src/share/vm/ci/ciEnv.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/ci/ciEnv.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -82,6 +82,9 @@
static ciInstanceKlass* _Thread;
static ciInstanceKlass* _OutOfMemoryError;
static ciInstanceKlass* _String;
+ static ciInstanceKlass* _StringBuffer;
+ static ciInstanceKlass* _StringBuilder;
+ static ciInstanceKlass* _Integer;
static ciSymbol* _unloaded_cisymbol;
static ciInstanceKlass* _unloaded_ciinstance_klass;
@@ -97,6 +100,9 @@
ciInstance* _ArrayStoreException_instance;
ciInstance* _ClassCastException_instance;
+ ciInstance* _the_null_string; // The Java string "null"
+ ciInstance* _the_min_jint_string; // The Java string "-2147483648"
+
// Look up a klass by name from a particular class loader (the accessor's).
// If require_local, result must be defined in that class loader, or NULL.
// If !require_local, a result from remote class loader may be reported,
@@ -310,6 +316,15 @@
ciInstanceKlass* String_klass() {
return _String;
}
+ ciInstanceKlass* StringBuilder_klass() {
+ return _StringBuilder;
+ }
+ ciInstanceKlass* StringBuffer_klass() {
+ return _StringBuffer;
+ }
+ ciInstanceKlass* Integer_klass() {
+ return _Integer;
+ }
ciInstance* NullPointerException_instance() {
assert(_NullPointerException_instance != NULL, "initialization problem");
return _NullPointerException_instance;
@@ -324,6 +339,9 @@
ciInstance* ArrayStoreException_instance();
ciInstance* ClassCastException_instance();
+ ciInstance* the_null_string();
+ ciInstance* the_min_jint_string();
+
static ciSymbol* unloaded_cisymbol() {
return _unloaded_cisymbol;
}
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -341,6 +341,20 @@
}
// ------------------------------------------------------------------
+// ciInstanceKlass::get_field_by_name
+ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static) {
+ VM_ENTRY_MARK;
+ instanceKlass* k = get_instanceKlass();
+ fieldDescriptor fd;
+ klassOop def = k->find_field(name->get_symbolOop(), signature->get_symbolOop(), is_static, &fd);
+ if (def == NULL) {
+ return NULL;
+ }
+ ciField* field = new (CURRENT_THREAD_ENV->arena()) ciField(&fd);
+ return field;
+}
+
+// ------------------------------------------------------------------
// ciInstanceKlass::non_static_fields.
class NonStaticFieldFiller: public FieldClosure {
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -148,6 +148,7 @@
ciInstanceKlass* get_canonical_holder(int offset);
ciField* get_field_by_offset(int field_offset, bool is_static);
+ ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static);
GrowableArray<ciField*>* non_static_fields();
--- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -168,6 +168,15 @@
ciEnv::_String =
get(SystemDictionary::string_klass())
->as_instance_klass();
+ ciEnv::_StringBuffer =
+ get(SystemDictionary::stringBuffer_klass())
+ ->as_instance_klass();
+ ciEnv::_StringBuilder =
+ get(SystemDictionary::StringBuilder_klass())
+ ->as_instance_klass();
+ ciEnv::_Integer =
+ get(SystemDictionary::int_klass())
+ ->as_instance_klass();
for (int len = -1; len != _ci_objects->length(); ) {
len = _ci_objects->length();
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -2511,23 +2511,12 @@
fac_ptr->nonstatic_byte_count -= 1;
(*fields_ptr)->ushort_at_put(i + instanceKlass::signature_index_offset,
word_sig_index);
- if (wordSize == jintSize) {
- fac_ptr->nonstatic_word_count += 1;
- } else {
- fac_ptr->nonstatic_double_count += 1;
- }
-
- FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i+4);
+ fac_ptr->nonstatic_word_count += 1;
+
+ FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i + instanceKlass::low_offset);
assert(atype == NONSTATIC_BYTE, "");
FieldAllocationType new_atype = NONSTATIC_WORD;
- if (wordSize > jintSize) {
- if (Universe::field_type_should_be_aligned(T_LONG)) {
- atype = NONSTATIC_ALIGNED_DOUBLE;
- } else {
- atype = NONSTATIC_DOUBLE;
- }
- }
- (*fields_ptr)->ushort_at_put(i+4, new_atype);
+ (*fields_ptr)->ushort_at_put(i + instanceKlass::low_offset, new_atype);
found_vmentry = true;
break;
@@ -3085,7 +3074,7 @@
int len = fields->length();
for (int i = 0; i < len; i += instanceKlass::next_offset) {
int real_offset;
- FieldAllocationType atype = (FieldAllocationType) fields->ushort_at(i+4);
+ FieldAllocationType atype = (FieldAllocationType) fields->ushort_at(i + instanceKlass::low_offset);
switch (atype) {
case STATIC_OOP:
real_offset = next_static_oop_offset;
@@ -3173,8 +3162,8 @@
default:
ShouldNotReachHere();
}
- fields->short_at_put(i+4, extract_low_short_from_int(real_offset) );
- fields->short_at_put(i+5, extract_high_short_from_int(real_offset) );
+ fields->short_at_put(i + instanceKlass::low_offset, extract_low_short_from_int(real_offset));
+ fields->short_at_put(i + instanceKlass::high_offset, extract_high_short_from_int(real_offset));
}
// Size of instances
@@ -3766,8 +3755,9 @@
}
bool ClassFileParser::is_supported_version(u2 major, u2 minor) {
- u2 max_version = JDK_Version::is_gte_jdk17x_version() ?
- JAVA_MAX_SUPPORTED_VERSION : JAVA_6_VERSION;
+ u2 max_version =
+ JDK_Version::is_gte_jdk17x_version() ? JAVA_MAX_SUPPORTED_VERSION :
+ (JDK_Version::is_gte_jdk16x_version() ? JAVA_6_VERSION : JAVA_1_5_VERSION);
return (major >= JAVA_MIN_SUPPORTED_VERSION) &&
(major <= max_version) &&
((major != max_version) ||
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1124,8 +1124,7 @@
if (_dirty && _methods != NULL) {
BarrierSet* bs = Universe::heap()->barrier_set();
assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt");
- bs->write_ref_array(MemRegion((HeapWord*)_methods->base(),
- _methods->array_size()));
+ bs->write_ref_array((HeapWord*)_methods->base(), _methods->length());
_dirty = false;
}
}
@@ -2430,15 +2429,15 @@
}
-// Support for sun_dyn_CallSiteImpl
-
-int sun_dyn_CallSiteImpl::_type_offset;
-int sun_dyn_CallSiteImpl::_target_offset;
-int sun_dyn_CallSiteImpl::_vmmethod_offset;
-
-void sun_dyn_CallSiteImpl::compute_offsets() {
+// Support for java_dyn_CallSite
+
+int java_dyn_CallSite::_type_offset;
+int java_dyn_CallSite::_target_offset;
+int java_dyn_CallSite::_vmmethod_offset;
+
+void java_dyn_CallSite::compute_offsets() {
if (!EnableInvokeDynamic) return;
- klassOop k = SystemDictionary::CallSiteImpl_klass();
+ klassOop k = SystemDictionary::CallSite_klass();
if (k != NULL) {
compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true);
compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_dyn_MethodHandle_signature(), true);
@@ -2446,23 +2445,23 @@
}
}
-oop sun_dyn_CallSiteImpl::type(oop site) {
+oop java_dyn_CallSite::type(oop site) {
return site->obj_field(_type_offset);
}
-oop sun_dyn_CallSiteImpl::target(oop site) {
+oop java_dyn_CallSite::target(oop site) {
return site->obj_field(_target_offset);
}
-void sun_dyn_CallSiteImpl::set_target(oop site, oop target) {
+void java_dyn_CallSite::set_target(oop site, oop target) {
site->obj_field_put(_target_offset, target);
}
-oop sun_dyn_CallSiteImpl::vmmethod(oop site) {
+oop java_dyn_CallSite::vmmethod(oop site) {
return site->obj_field(_vmmethod_offset);
}
-void sun_dyn_CallSiteImpl::set_vmmethod(oop site, oop ref) {
+void java_dyn_CallSite::set_vmmethod(oop site, oop ref) {
site->obj_field_put(_vmmethod_offset, ref);
}
@@ -2811,7 +2810,7 @@
java_dyn_MethodTypeForm::compute_offsets();
}
if (EnableInvokeDynamic) {
- sun_dyn_CallSiteImpl::compute_offsets();
+ java_dyn_CallSite::compute_offsets();
}
java_security_AccessControlContext::compute_offsets();
// Initialize reflection classes. The layouts of these classes
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -1061,9 +1061,9 @@
};
-// Interface to sun.dyn.CallSiteImpl objects
+// Interface to java.dyn.CallSite objects
-class sun_dyn_CallSiteImpl: AllStatic {
+class java_dyn_CallSite: AllStatic {
friend class JavaClasses;
private:
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -99,6 +99,15 @@
return java_lang_Class::parallelCapable(class_loader());
}
// ----------------------------------------------------------------------------
+// ParallelDefineClass flag does not apply to bootclass loader
+bool SystemDictionary::is_parallelDefine(Handle class_loader) {
+ if (class_loader.is_null()) return false;
+ if (AllowParallelDefineClass && java_lang_Class::parallelCapable(class_loader())) {
+ return true;
+ }
+ return false;
+}
+// ----------------------------------------------------------------------------
// Resolving of classes
// Forwards to resolve_or_null
@@ -724,13 +733,13 @@
// Do actual loading
k = load_instance_class(name, class_loader, THREAD);
- // For UnsyncloadClass and AllowParallelDefineClass only:
+ // For UnsyncloadClass only
// If they got a linkageError, check if a parallel class load succeeded.
// If it did, then for bytecode resolution the specification requires
// that we return the same result we did for the other thread, i.e. the
// successfully loaded instanceKlass
// Should not get here for classloaders that support parallelism
- // with the new cleaner mechanism
+ // with the new cleaner mechanism, even with AllowParallelDefineClass
// Bootstrap goes through here to allow for an extra guarantee check
if (UnsyncloadClass || (class_loader.is_null())) {
if (k.is_null() && HAS_PENDING_EXCEPTION
@@ -1483,14 +1492,17 @@
}
// Support parallel classloading
-// Initial implementation for bootstrap classloader
-// For custom class loaders that support parallel classloading,
+// All parallel class loaders, including bootstrap classloader
+// lock a placeholder entry for this class/class_loader pair
+// to allow parallel defines of different classes for this class loader
// With AllowParallelDefine flag==true, in case they do not synchronize around
// FindLoadedClass/DefineClass, calls, we check for parallel
// loading for them, wait if a defineClass is in progress
// and return the initial requestor's results
+// This flag does not apply to the bootstrap classloader.
// With AllowParallelDefine flag==false, call through to define_instance_class
// which will throw LinkageError: duplicate class definition.
+// False is the requested default.
// For better performance, the class loaders should synchronize
// findClass(), i.e. FindLoadedClass/DefineClassIfAbsent or they
// potentially waste time reading and parsing the bytestream.
@@ -1511,9 +1523,11 @@
{
MutexLocker mu(SystemDictionary_lock, THREAD);
// First check if class already defined
- klassOop check = find_class(d_index, d_hash, name_h, class_loader);
- if (check != NULL) {
- return(instanceKlassHandle(THREAD, check));
+ if (UnsyncloadClass || (is_parallelDefine(class_loader))) {
+ klassOop check = find_class(d_index, d_hash, name_h, class_loader);
+ if (check != NULL) {
+ return(instanceKlassHandle(THREAD, check));
+ }
}
// Acquire define token for this class/classloader
@@ -1529,7 +1543,7 @@
// Only special cases allow parallel defines and can use other thread's results
// Other cases fall through, and may run into duplicate defines
// caught by finding an entry in the SystemDictionary
- if ((UnsyncloadClass || AllowParallelDefineClass) && (probe->instanceKlass() != NULL)) {
+ if ((UnsyncloadClass || is_parallelDefine(class_loader)) && (probe->instanceKlass() != NULL)) {
probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS);
placeholders()->find_and_remove(p_index, p_hash, name_h, class_loader, THREAD);
SystemDictionary_lock->notify_all();
@@ -1973,7 +1987,7 @@
WKID indy_group_end = WK_KLASS_ENUM_NAME(Dynamic_klass);
initialize_wk_klasses_until(indy_group_start, scan, CHECK);
if (EnableInvokeDynamic) {
- initialize_wk_klasses_through(indy_group_start, scan, CHECK);
+ initialize_wk_klasses_through(indy_group_end, scan, CHECK);
}
if (_well_known_klasses[indy_group_start] == NULL) {
// Skip the rest of the dynamic typing classes, if Linkage is not loaded.
@@ -2404,7 +2418,7 @@
methodHandle mh_invdyn,
TRAPS) {
Handle empty;
- // call sun.dyn.CallSiteImpl::makeSite(caller, name, mtype, cmid, cbci)
+ // call java.dyn.CallSite::makeSite(caller, name, mtype, cmid, cbci)
oop name_str_oop = StringTable::intern(name(), CHECK_(empty)); // not a handle!
JavaCallArguments args(Handle(THREAD, caller->java_mirror()));
args.push_oop(name_str_oop);
@@ -2413,17 +2427,19 @@
args.push_int(caller_bci);
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result,
- SystemDictionary::CallSiteImpl_klass(),
+ SystemDictionary::CallSite_klass(),
vmSymbols::makeSite_name(), vmSymbols::makeSite_signature(),
&args, CHECK_(empty));
oop call_site_oop = (oop) result.get_jobject();
assert(call_site_oop->is_oop()
- /*&& sun_dyn_CallSiteImpl::is_instance(call_site_oop)*/, "must be sane");
- sun_dyn_CallSiteImpl::set_vmmethod(call_site_oop, mh_invdyn());
+ /*&& java_dyn_CallSite::is_instance(call_site_oop)*/, "must be sane");
+ java_dyn_CallSite::set_vmmethod(call_site_oop, mh_invdyn());
if (TraceMethodHandles) {
+#ifndef PRODUCT
tty->print_cr("Linked invokedynamic bci=%d site="INTPTR_FORMAT":", caller_bci, call_site_oop);
call_site_oop->print();
tty->cr();
+#endif //PRODUCT
}
return call_site_oop;
}
@@ -2436,9 +2452,17 @@
instanceKlassHandle ik(THREAD, caller());
- if (ik->bootstrap_method() != NULL) {
- return Handle(THREAD, ik->bootstrap_method());
+ oop boot_method_oop = ik->bootstrap_method();
+ if (boot_method_oop != NULL) {
+ if (TraceMethodHandles) {
+ tty->print_cr("bootstrap method for "PTR_FORMAT" cached as "PTR_FORMAT":", ik(), boot_method_oop);
+ }
+ NOT_PRODUCT(if (!boot_method_oop->is_oop()) { tty->print_cr("*** boot MH of "PTR_FORMAT" = "PTR_FORMAT, ik(), boot_method_oop); ik()->print(); });
+ assert(boot_method_oop->is_oop()
+ && java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane");
+ return Handle(THREAD, boot_method_oop);
}
+ boot_method_oop = NULL; // GC safety
// call java.dyn.Linkage::findBootstrapMethod(caller, sbk)
JavaCallArguments args(Handle(THREAD, ik->java_mirror()));
@@ -2452,9 +2476,18 @@
vmSymbols::findBootstrapMethod_name(),
vmSymbols::findBootstrapMethod_signature(),
&args, CHECK_(empty));
- oop boot_method_oop = (oop) result.get_jobject();
+ boot_method_oop = (oop) result.get_jobject();
if (boot_method_oop != NULL) {
+ if (TraceMethodHandles) {
+#ifndef PRODUCT
+ tty->print_cr("--------");
+ tty->print_cr("bootstrap method for "PTR_FORMAT" computed as "PTR_FORMAT":", ik(), boot_method_oop);
+ ik()->print();
+ boot_method_oop->print();
+ tty->print_cr("========");
+#endif //PRODUCT
+ }
assert(boot_method_oop->is_oop()
&& java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane");
// probably no race conditions, but let's be careful:
@@ -2463,6 +2496,14 @@
else
boot_method_oop = ik->bootstrap_method();
} else {
+ if (TraceMethodHandles) {
+#ifndef PRODUCT
+ tty->print_cr("--------");
+ tty->print_cr("bootstrap method for "PTR_FORMAT" computed as NULL:", ik());
+ ik()->print();
+ tty->print_cr("========");
+#endif //PRODUCT
+ }
boot_method_oop = ik->bootstrap_method();
}
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -144,13 +144,13 @@
template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \
template(Linkage_klass, java_dyn_Linkage, Opt) \
template(CallSite_klass, java_dyn_CallSite, Opt) \
- template(CallSiteImpl_klass, sun_dyn_CallSiteImpl, Opt) \
template(Dynamic_klass, java_dyn_Dynamic, Opt) \
/* Note: MethodHandle must be first, and Dynamic last in group */ \
\
template(vector_klass, java_util_Vector, Pre) \
template(hashtable_klass, java_util_Hashtable, Pre) \
template(stringBuffer_klass, java_lang_StringBuffer, Pre) \
+ template(StringBuilder_klass, java_lang_StringBuilder, Pre) \
\
/* It's NULL in non-1.4 JDKs. */ \
template(stackTraceElement_klass, java_lang_StackTraceElement, Opt) \
@@ -578,6 +578,7 @@
static Handle compute_loader_lock_object(Handle class_loader, TRAPS);
static void check_loader_lock_contention(Handle loader_lock, TRAPS);
static bool is_parallelCapable(Handle class_loader);
+ static bool is_parallelDefine(Handle class_loader);
static klassOop find_shared_class(symbolHandle class_name);
--- a/hotspot/src/share/vm/classfile/verifier.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1903,17 +1903,8 @@
verify_cp_type(index, cp, types, CHECK_VERIFY(this));
// Get method name and signature
- symbolHandle method_name;
- symbolHandle method_sig;
- if (opcode == Bytecodes::_invokedynamic) {
- int name_index = cp->name_ref_index_at(index);
- int sig_index = cp->signature_ref_index_at(index);
- method_name = symbolHandle(THREAD, cp->symbol_at(name_index));
- method_sig = symbolHandle(THREAD, cp->symbol_at(sig_index));
- } else {
- method_name = symbolHandle(THREAD, cp->name_ref_at(index));
- method_sig = symbolHandle(THREAD, cp->signature_ref_at(index));
- }
+ symbolHandle method_name(THREAD, cp->name_ref_at(index));
+ symbolHandle method_sig(THREAD, cp->signature_ref_at(index));
if (!SignatureVerifier::is_valid_method_signature(method_sig)) {
class_format_error(
--- a/hotspot/src/share/vm/classfile/vmSymbols.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -303,6 +303,11 @@
const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED;
return (flags & (req | neg)) == req;
}
+inline bool match_F_Y(jshort flags) {
+ const int req = JVM_ACC_SYNCHRONIZED;
+ const int neg = JVM_ACC_STATIC;
+ return (flags & (req | neg)) == req;
+}
inline bool match_F_RN(jshort flags) {
const int req = JVM_ACC_NATIVE;
const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED;
@@ -361,6 +366,7 @@
const char* sname = vmSymbols::name_for(signature_for(id));
const char* fname = "";
switch (flags_for(id)) {
+ case F_Y: fname = "synchronized "; break;
case F_RN: fname = "native "; break;
case F_SN: fname = "native static "; break;
case F_S: fname = "static "; break;
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -84,6 +84,7 @@
template(java_lang_reflect_Field, "java/lang/reflect/Field") \
template(java_lang_reflect_Array, "java/lang/reflect/Array") \
template(java_lang_StringBuffer, "java/lang/StringBuffer") \
+ template(java_lang_StringBuilder, "java/lang/StringBuilder") \
template(java_lang_CharSequence, "java/lang/CharSequence") \
template(java_security_AccessControlContext, "java/security/AccessControlContext") \
template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \
@@ -104,6 +105,7 @@
template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \
template(sun_jkernel_DownloadManager, "sun/jkernel/DownloadManager") \
template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \
+ template(setBootClassLoaderHook_name, "setBootClassLoaderHook") \
\
/* class file format tags */ \
template(tag_source_file, "SourceFile") \
@@ -233,10 +235,9 @@
template(sun_dyn_AdapterMethodHandle, "sun/dyn/AdapterMethodHandle") \
template(sun_dyn_BoundMethodHandle, "sun/dyn/BoundMethodHandle") \
template(sun_dyn_DirectMethodHandle, "sun/dyn/DirectMethodHandle") \
- template(sun_dyn_CallSiteImpl, "sun/dyn/CallSiteImpl") \
template(makeImpl_name, "makeImpl") /*MethodType::makeImpl*/ \
template(makeImpl_signature, "(Ljava/lang/Class;[Ljava/lang/Class;ZZ)Ljava/dyn/MethodType;") \
- template(makeSite_name, "makeSite") /*CallSiteImpl::makeImpl*/ \
+ template(makeSite_name, "makeSite") /*CallSite::makeSite*/ \
template(makeSite_signature, "(Ljava/lang/Class;Ljava/lang/String;Ljava/dyn/MethodType;II)Ljava/dyn/CallSite;") \
template(findBootstrapMethod_name, "findBootstrapMethod") \
template(findBootstrapMethod_signature, "(Ljava/lang/Class;Ljava/lang/Class;)Ljava/dyn/MethodHandle;") \
@@ -335,6 +336,7 @@
template(ptypes_name, "ptypes") \
template(form_name, "form") \
template(erasedType_name, "erasedType") \
+ template(append_name, "append") \
\
/* non-intrinsic name/signature pairs: */ \
template(register_method_name, "register") \
@@ -416,6 +418,13 @@
template(string_signature, "Ljava/lang/String;") \
template(reference_signature, "Ljava/lang/ref/Reference;") \
template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \
+ template(String_StringBuilder_signature, "(Ljava/lang/String;)Ljava/lang/StringBuilder;") \
+ template(int_StringBuilder_signature, "(I)Ljava/lang/StringBuilder;") \
+ template(char_StringBuilder_signature, "(C)Ljava/lang/StringBuilder;") \
+ template(String_StringBuffer_signature, "(Ljava/lang/String;)Ljava/lang/StringBuffer;") \
+ template(int_StringBuffer_signature, "(I)Ljava/lang/StringBuffer;") \
+ template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \
+ template(int_String_signature, "(I)Ljava/lang/String;") \
/* signature symbols needed by intrinsics */ \
VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \
\
@@ -815,10 +824,34 @@
/*the compiler does have special inlining code for these; bytecode inline is just fine */ \
\
do_intrinsic(_fillInStackTrace, java_lang_Throwable, fillInStackTrace_name, void_throwable_signature, F_RNY) \
- \
- do_intrinsic(_Object_init, java_lang_Object, object_initializer_name, void_method_signature, F_R) \
- /* (symbol object_initializer_name defined above) */ \
- \
+ \
+ do_intrinsic(_StringBuilder_void, java_lang_StringBuilder, object_initializer_name, void_method_signature, F_R) \
+ do_intrinsic(_StringBuilder_int, java_lang_StringBuilder, object_initializer_name, int_void_signature, F_R) \
+ do_intrinsic(_StringBuilder_String, java_lang_StringBuilder, object_initializer_name, string_void_signature, F_R) \
+ \
+ do_intrinsic(_StringBuilder_append_char, java_lang_StringBuilder, append_name, char_StringBuilder_signature, F_R) \
+ do_intrinsic(_StringBuilder_append_int, java_lang_StringBuilder, append_name, int_StringBuilder_signature, F_R) \
+ do_intrinsic(_StringBuilder_append_String, java_lang_StringBuilder, append_name, String_StringBuilder_signature, F_R) \
+ \
+ do_intrinsic(_StringBuilder_toString, java_lang_StringBuilder, toString_name, void_string_signature, F_R) \
+ \
+ do_intrinsic(_StringBuffer_void, java_lang_StringBuffer, object_initializer_name, void_method_signature, F_R) \
+ do_intrinsic(_StringBuffer_int, java_lang_StringBuffer, object_initializer_name, int_void_signature, F_R) \
+ do_intrinsic(_StringBuffer_String, java_lang_StringBuffer, object_initializer_name, string_void_signature, F_R) \
+ \
+ do_intrinsic(_StringBuffer_append_char, java_lang_StringBuffer, append_name, char_StringBuffer_signature, F_Y) \
+ do_intrinsic(_StringBuffer_append_int, java_lang_StringBuffer, append_name, int_StringBuffer_signature, F_Y) \
+ do_intrinsic(_StringBuffer_append_String, java_lang_StringBuffer, append_name, String_StringBuffer_signature, F_Y) \
+ \
+ do_intrinsic(_StringBuffer_toString, java_lang_StringBuffer, toString_name, void_string_signature, F_Y) \
+ \
+ do_intrinsic(_Integer_toString, java_lang_Integer, toString_name, int_String_signature, F_S) \
+ \
+ do_intrinsic(_String_String, java_lang_String, object_initializer_name, string_void_signature, F_R) \
+ \
+ do_intrinsic(_Object_init, java_lang_Object, object_initializer_name, void_method_signature, F_R) \
+ /* (symbol object_initializer_name defined above) */ \
+ \
do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \
/* (symbols invoke_name and invoke_signature defined above) */ \
\
@@ -946,11 +979,12 @@
enum Flags {
// AccessFlags syndromes relevant to intrinsics.
F_none = 0,
- F_R, // !static !synchronized (R="regular")
- F_S, // static !synchronized
- F_RN, // !static native !synchronized
- F_SN, // static native !synchronized
- F_RNY // !static native synchronized
+ F_R, // !static ?native !synchronized (R="regular")
+ F_S, // static ?native !synchronized
+ F_Y, // !static ?native synchronized
+ F_RN, // !static native !synchronized
+ F_SN, // static native !synchronized
+ F_RNY // !static native synchronized
};
public:
--- a/hotspot/src/share/vm/code/dependencies.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/code/dependencies.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1528,19 +1528,23 @@
int nsup = 0, nint = 0;
for (ContextStream str(*this); str.next(); ) {
klassOop k = str.klass();
- switch (str._change_type) {
+ switch (str.change_type()) {
case Change_new_type:
tty->print_cr(" dependee = %s", instanceKlass::cast(k)->external_name());
break;
case Change_new_sub:
- if (!WizardMode)
- ++nsup;
- else tty->print_cr(" context super = %s", instanceKlass::cast(k)->external_name());
+ if (!WizardMode) {
+ ++nsup;
+ } else {
+ tty->print_cr(" context super = %s", instanceKlass::cast(k)->external_name());
+ }
break;
case Change_new_impl:
- if (!WizardMode)
- ++nint;
- else tty->print_cr(" context interface = %s", instanceKlass::cast(k)->external_name());
+ if (!WizardMode) {
+ ++nint;
+ } else {
+ tty->print_cr(" context interface = %s", instanceKlass::cast(k)->external_name());
+ }
break;
}
}
--- a/hotspot/src/share/vm/code/dependencies.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/code/dependencies.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -470,7 +470,7 @@
// super types can be context types for a relevant dependency, which the
// new type could invalidate.
class DepChange : public StackObj {
- private:
+ public:
enum ChangeType {
NO_CHANGE = 0, // an uninvolved klass
Change_new_type, // a newly loaded type
@@ -480,6 +480,7 @@
Start_Klass = CHANGE_LIMIT // internal indicator for ContextStream
};
+ private:
// each change set is rooted in exactly one new type (at present):
KlassHandle _new_type;
@@ -510,15 +511,15 @@
// }
class ContextStream : public StackObj {
private:
- DepChange& _changes;
+ DepChange& _changes;
friend class DepChange;
// iteration variables:
- ChangeType _change_type;
- klassOop _klass;
- objArrayOop _ti_base; // i.e., transitive_interfaces
- int _ti_index;
- int _ti_limit;
+ ChangeType _change_type;
+ klassOop _klass;
+ objArrayOop _ti_base; // i.e., transitive_interfaces
+ int _ti_index;
+ int _ti_limit;
// start at the beginning:
void start() {
@@ -530,11 +531,11 @@
_ti_limit = 0;
}
+ public:
ContextStream(DepChange& changes)
: _changes(changes)
{ start(); }
- public:
ContextStream(DepChange& changes, No_Safepoint_Verifier& nsv)
: _changes(changes)
// the nsv argument makes it safe to hold oops like _klass
@@ -542,6 +543,7 @@
bool next();
+ ChangeType change_type() { return _change_type; }
klassOop klass() { return _klass; }
};
friend class DepChange::ContextStream;
--- a/hotspot/src/share/vm/code/nmethod.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -414,9 +414,8 @@
}
const char* nmethod::compile_kind() const {
- if (method() == NULL) return "unloaded";
- if (is_native_method()) return "c2n";
if (is_osr_method()) return "osr";
+ if (method() != NULL && is_native_method()) return "c2n";
return NULL;
}
@@ -1127,6 +1126,9 @@
}
flags.state = unloaded;
+ // Log the unloading.
+ log_state_change();
+
// The methodOop is gone at this point
assert(_method == NULL, "Tautology");
@@ -1137,8 +1139,6 @@
void nmethod::invalidate_osr_method() {
assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod");
- if (_entry_bci != InvalidOSREntryBci)
- inc_decompile_count();
// Remove from list of active nmethods
if (method() != NULL)
instanceKlass::cast(method()->method_holder())->remove_osr_nmethod(this);
@@ -1146,59 +1146,63 @@
_entry_bci = InvalidOSREntryBci;
}
-void nmethod::log_state_change(int state) const {
+void nmethod::log_state_change() const {
if (LogCompilation) {
if (xtty != NULL) {
ttyLocker ttyl; // keep the following output all in one block
- xtty->begin_elem("make_not_entrant %sthread='" UINTX_FORMAT "'",
- (state == zombie ? "zombie='1' " : ""),
- os::current_thread_id());
+ if (flags.state == unloaded) {
+ xtty->begin_elem("make_unloaded thread='" UINTX_FORMAT "'",
+ os::current_thread_id());
+ } else {
+ xtty->begin_elem("make_not_entrant thread='" UINTX_FORMAT "'%s",
+ os::current_thread_id(),
+ (flags.state == zombie ? " zombie='1'" : ""));
+ }
log_identity(xtty);
xtty->stamp();
xtty->end_elem();
}
}
- if (PrintCompilation) {
- print_on(tty, state == zombie ? "made zombie " : "made not entrant ");
+ if (PrintCompilation && flags.state != unloaded) {
+ print_on(tty, flags.state == zombie ? "made zombie " : "made not entrant ");
tty->cr();
}
}
// Common functionality for both make_not_entrant and make_zombie
-void nmethod::make_not_entrant_or_zombie(int state) {
+bool nmethod::make_not_entrant_or_zombie(int state) {
assert(state == zombie || state == not_entrant, "must be zombie or not_entrant");
- // Code for an on-stack-replacement nmethod is removed when a class gets unloaded.
- // They never become zombie/non-entrant, so the nmethod sweeper will never remove
- // them. Instead the entry_bci is set to InvalidOSREntryBci, so the osr nmethod
- // will never be used anymore. That the nmethods only gets removed when class unloading
- // happens, make life much simpler, since the nmethods are not just going to disappear
- // out of the blue.
- if (is_osr_method()) {
- if (osr_entry_bci() != InvalidOSREntryBci) {
- // only log this once
- log_state_change(state);
- }
- invalidate_osr_method();
- return;
+ // If the method is already zombie there is nothing to do
+ if (is_zombie()) {
+ return false;
}
- // If the method is already zombie or set to the state we want, nothing to do
- if (is_zombie() || (state == not_entrant && is_not_entrant())) {
- return;
- }
-
- log_state_change(state);
-
// Make sure the nmethod is not flushed in case of a safepoint in code below.
nmethodLocker nml(this);
{
+ // invalidate osr nmethod before acquiring the patching lock since
+ // they both acquire leaf locks and we don't want a deadlock.
+ // This logic is equivalent to the logic below for patching the
+ // verified entry point of regular methods.
+ if (is_osr_method()) {
+ // this effectively makes the osr nmethod not entrant
+ invalidate_osr_method();
+ }
+
// Enter critical section. Does not block for safepoint.
MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag);
+
+ if (flags.state == state) {
+ // another thread already performed this transition so nothing
+ // to do, but return false to indicate this.
+ return false;
+ }
+
// The caller can be calling the method statically or through an inline
// cache call.
- if (!is_not_entrant()) {
+ if (!is_osr_method() && !is_not_entrant()) {
NativeJump::patch_verified_entry(entry_point(), verified_entry_point(),
SharedRuntime::get_handle_wrong_method_stub());
assert (NativeJump::instruction_size == nmethod::_zombie_instruction_size, "");
@@ -1217,6 +1221,10 @@
// Change state
flags.state = state;
+
+ // Log the transition once
+ log_state_change();
+
} // leave critical region under Patching_lock
if (state == not_entrant) {
@@ -1240,7 +1248,6 @@
// It's a true state change, so mark the method as decompiled.
inc_decompile_count();
-
// zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event
// and it hasn't already been reported for this nmethod then report it now.
// (the event may have been reported earilier if the GC marked it for unloading).
@@ -1268,7 +1275,7 @@
// Check whether method got unloaded at a safepoint before this,
// if so we can skip the flushing steps below
- if (method() == NULL) return;
+ if (method() == NULL) return true;
// Remove nmethod from method.
// We need to check if both the _code and _from_compiled_code_entry_point
@@ -1282,6 +1289,8 @@
HandleMark hm;
method()->clear_code();
}
+
+ return true;
}
--- a/hotspot/src/share/vm/code/nmethod.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/code/nmethod.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -252,7 +252,9 @@
void* operator new(size_t size, int nmethod_size);
const char* reloc_string_for(u_char* begin, u_char* end);
- void make_not_entrant_or_zombie(int state);
+ // Returns true if this thread changed the state of the nmethod or
+ // false if another thread performed the transition.
+ bool make_not_entrant_or_zombie(int state);
void inc_decompile_count();
// used to check that writes to nmFlags are done consistently.
@@ -375,10 +377,12 @@
bool is_zombie() const { return flags.state == zombie; }
bool is_unloaded() const { return flags.state == unloaded; }
- // Make the nmethod non entrant. The nmethod will continue to be alive.
- // It is used when an uncommon trap happens.
- void make_not_entrant() { make_not_entrant_or_zombie(not_entrant); }
- void make_zombie() { make_not_entrant_or_zombie(zombie); }
+ // Make the nmethod non entrant. The nmethod will continue to be
+ // alive. It is used when an uncommon trap happens. Returns true
+ // if this thread changed the state of the nmethod or false if
+ // another thread performed the transition.
+ bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); }
+ bool make_zombie() { return make_not_entrant_or_zombie(zombie); }
// used by jvmti to track if the unload event has been reported
bool unload_reported() { return _unload_reported; }
@@ -563,7 +567,7 @@
// Logging
void log_identity(xmlStream* log) const;
void log_new_nmethod() const;
- void log_state_change(int state) const;
+ void log_state_change() const;
// Prints a comment for one native instruction (reloc info, pc desc)
void print_code_comment_on(outputStream* st, int column, address begin, address end);
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -709,7 +709,8 @@
// Support for parallelizing survivor space rescan
if (CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) {
- size_t max_plab_samples = MaxNewSize/((SurvivorRatio+2)*MinTLABSize);
+ size_t max_plab_samples = cp->max_gen0_size()/
+ ((SurvivorRatio+2)*MinTLABSize);
_survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads);
_survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples);
_cursor = NEW_C_HEAP_ARRAY(size_t, ParallelGCThreads);
--- a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -351,9 +351,16 @@
CollectionSetChooser::printSortedHeapRegions() {
gclog_or_tty->print_cr("Printing %d Heap Regions sorted by amount of known garbage",
_numMarkedRegions);
+
+ DEBUG_ONLY(int marked_count = 0;)
for (int i = 0; i < _markedRegions.length(); i++) {
- printHeapRegion(_markedRegions.at(i));
+ HeapRegion* r = _markedRegions.at(i);
+ if (r != NULL) {
+ printHeapRegion(r);
+ DEBUG_ONLY(marked_count++;)
+ }
}
+ assert(marked_count == _numMarkedRegions, "must be");
gclog_or_tty->print_cr("Done sorted heap region print");
}
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -42,28 +42,49 @@
_n_periods(0),
_threads(NULL), _n_threads(0)
{
- if (G1ConcRefine) {
- _n_threads = (int)thread_num();
- if (_n_threads > 0) {
- _threads = NEW_C_HEAP_ARRAY(ConcurrentG1RefineThread*, _n_threads);
- int worker_id_offset = (int)DirtyCardQueueSet::num_par_ids();
- ConcurrentG1RefineThread *next = NULL;
- for (int i = _n_threads - 1; i >= 0; i--) {
- ConcurrentG1RefineThread* t = new ConcurrentG1RefineThread(this, next, worker_id_offset, i);
- assert(t != NULL, "Conc refine should have been created");
- assert(t->cg1r() == this, "Conc refine thread should refer to this");
- _threads[i] = t;
- next = t;
- }
- }
+
+ // Ergomonically select initial concurrent refinement parameters
+ if (FLAG_IS_DEFAULT(G1ConcRefineGreenZone)) {
+ FLAG_SET_DEFAULT(G1ConcRefineGreenZone, MAX2<int>(ParallelGCThreads, 1));
+ }
+ set_green_zone(G1ConcRefineGreenZone);
+
+ if (FLAG_IS_DEFAULT(G1ConcRefineYellowZone)) {
+ FLAG_SET_DEFAULT(G1ConcRefineYellowZone, green_zone() * 3);
+ }
+ set_yellow_zone(MAX2<int>(G1ConcRefineYellowZone, green_zone()));
+
+ if (FLAG_IS_DEFAULT(G1ConcRefineRedZone)) {
+ FLAG_SET_DEFAULT(G1ConcRefineRedZone, yellow_zone() * 2);
+ }
+ set_red_zone(MAX2<int>(G1ConcRefineRedZone, yellow_zone()));
+ _n_worker_threads = thread_num();
+ // We need one extra thread to do the young gen rset size sampling.
+ _n_threads = _n_worker_threads + 1;
+ reset_threshold_step();
+
+ _threads = NEW_C_HEAP_ARRAY(ConcurrentG1RefineThread*, _n_threads);
+ int worker_id_offset = (int)DirtyCardQueueSet::num_par_ids();
+ ConcurrentG1RefineThread *next = NULL;
+ for (int i = _n_threads - 1; i >= 0; i--) {
+ ConcurrentG1RefineThread* t = new ConcurrentG1RefineThread(this, next, worker_id_offset, i);
+ assert(t != NULL, "Conc refine should have been created");
+ assert(t->cg1r() == this, "Conc refine thread should refer to this");
+ _threads[i] = t;
+ next = t;
}
}
-size_t ConcurrentG1Refine::thread_num() {
- if (G1ConcRefine) {
- return (G1ParallelRSetThreads > 0) ? G1ParallelRSetThreads : ParallelGCThreads;
+void ConcurrentG1Refine::reset_threshold_step() {
+ if (FLAG_IS_DEFAULT(G1ConcRefineThresholdStep)) {
+ _thread_threshold_step = (yellow_zone() - green_zone()) / (worker_thread_num() + 1);
+ } else {
+ _thread_threshold_step = G1ConcRefineThresholdStep;
}
- return 0;
+}
+
+int ConcurrentG1Refine::thread_num() {
+ return MAX2<int>((G1ParallelRSetThreads > 0) ? G1ParallelRSetThreads : ParallelGCThreads, 1);
}
void ConcurrentG1Refine::init() {
@@ -123,6 +144,15 @@
}
}
+void ConcurrentG1Refine::reinitialize_threads() {
+ reset_threshold_step();
+ if (_threads != NULL) {
+ for (int i = 0; i < _n_threads; i++) {
+ _threads[i]->initialize();
+ }
+ }
+}
+
ConcurrentG1Refine::~ConcurrentG1Refine() {
if (G1ConcRSLogCacheSize > 0) {
assert(_card_counts != NULL, "Logic");
@@ -384,4 +414,3 @@
st->cr();
}
}
-
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -29,6 +29,31 @@
class ConcurrentG1Refine: public CHeapObj {
ConcurrentG1RefineThread** _threads;
int _n_threads;
+ int _n_worker_threads;
+ /*
+ * The value of the update buffer queue length falls into one of 3 zones:
+ * green, yellow, red. If the value is in [0, green) nothing is
+ * done, the buffers are left unprocessed to enable the caching effect of the
+ * dirtied cards. In the yellow zone [green, yellow) the concurrent refinement
+ * threads are gradually activated. In [yellow, red) all threads are
+ * running. If the length becomes red (max queue length) the mutators start
+ * processing the buffers.
+ *
+ * There are some interesting cases (with G1AdaptiveConcRefine turned off):
+ * 1) green = yellow = red = 0. In this case the mutator will process all
+ * buffers. Except for those that are created by the deferred updates
+ * machinery during a collection.
+ * 2) green = 0. Means no caching. Can be a good way to minimize the
+ * amount of time spent updating rsets during a collection.
+ */
+ int _green_zone;
+ int _yellow_zone;
+ int _red_zone;
+
+ int _thread_threshold_step;
+
+ // Reset the threshold step value based of the current zone boundaries.
+ void reset_threshold_step();
// The cache for card refinement.
bool _use_cache;
@@ -147,6 +172,8 @@
void init(); // Accomplish some initialization that has to wait.
void stop();
+ void reinitialize_threads();
+
// Iterate over the conc refine threads
void threads_do(ThreadClosure *tc);
@@ -178,7 +205,20 @@
void clear_and_record_card_counts();
- static size_t thread_num();
+ static int thread_num();
void print_worker_threads_on(outputStream* st) const;
+
+ void set_green_zone(int x) { _green_zone = x; }
+ void set_yellow_zone(int x) { _yellow_zone = x; }
+ void set_red_zone(int x) { _red_zone = x; }
+
+ int green_zone() const { return _green_zone; }
+ int yellow_zone() const { return _yellow_zone; }
+ int red_zone() const { return _red_zone; }
+
+ int total_thread_num() const { return _n_threads; }
+ int worker_thread_num() const { return _n_worker_threads; }
+
+ int thread_threshold_step() const { return _thread_threshold_step; }
};
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -25,10 +25,6 @@
#include "incls/_precompiled.incl"
#include "incls/_concurrentG1RefineThread.cpp.incl"
-// ======= Concurrent Mark Thread ========
-
-// The CM thread is created when the G1 garbage collector is used
-
ConcurrentG1RefineThread::
ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next,
int worker_id_offset, int worker_id) :
@@ -37,19 +33,42 @@
_worker_id(worker_id),
_active(false),
_next(next),
+ _monitor(NULL),
_cg1r(cg1r),
- _vtime_accum(0.0),
- _interval_ms(5.0)
+ _vtime_accum(0.0)
{
+
+ // Each thread has its own monitor. The i-th thread is responsible for signalling
+ // to thread i+1 if the number of buffers in the queue exceeds a threashold for this
+ // thread. Monitors are also used to wake up the threads during termination.
+ // The 0th worker in notified by mutator threads and has a special monitor.
+ // The last worker is used for young gen rset size sampling.
+ if (worker_id > 0) {
+ _monitor = new Monitor(Mutex::nonleaf, "Refinement monitor", true);
+ } else {
+ _monitor = DirtyCardQ_CBL_mon;
+ }
+ initialize();
create_and_start();
}
+void ConcurrentG1RefineThread::initialize() {
+ if (_worker_id < cg1r()->worker_thread_num()) {
+ // Current thread activation threshold
+ _threshold = MIN2<int>(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(),
+ cg1r()->yellow_zone());
+ // A thread deactivates once the number of buffer reached a deactivation threshold
+ _deactivation_threshold = MAX2<int>(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone());
+ } else {
+ set_active(true);
+ }
+}
+
void ConcurrentG1RefineThread::sample_young_list_rs_lengths() {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1CollectorPolicy* g1p = g1h->g1_policy();
if (g1p->adaptive_young_list_length()) {
int regions_visited = 0;
-
g1h->young_list_rs_length_sampling_init();
while (g1h->young_list_rs_length_sampling_more()) {
g1h->young_list_rs_length_sampling_next();
@@ -70,99 +89,121 @@
}
}
-void ConcurrentG1RefineThread::run() {
- initialize_in_thread();
+void ConcurrentG1RefineThread::run_young_rs_sampling() {
+ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
_vtime_start = os::elapsedVTime();
- wait_for_universe_init();
+ while(!_should_terminate) {
+ _sts.join();
+ sample_young_list_rs_lengths();
+ _sts.leave();
- while (!_should_terminate) {
- DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
- // Wait for completed log buffers to exist.
- {
- MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag);
- while (((_worker_id == 0 && !dcqs.process_completed_buffers()) ||
- (_worker_id > 0 && !is_active())) &&
- !_should_terminate) {
- DirtyCardQ_CBL_mon->wait(Mutex::_no_safepoint_check_flag);
- }
- }
-
- if (_should_terminate) {
- return;
+ if (os::supports_vtime()) {
+ _vtime_accum = (os::elapsedVTime() - _vtime_start);
+ } else {
+ _vtime_accum = 0.0;
}
- // Now we take them off (this doesn't hold locks while it applies
- // closures.) (If we did a full collection, then we'll do a full
- // traversal.
- _sts.join();
- int n_logs = 0;
- int lower_limit = 0;
- double start_vtime_sec; // only used when G1SmoothConcRefine is on
- int prev_buffer_num; // only used when G1SmoothConcRefine is on
- // This thread activation threshold
- int threshold = G1UpdateBufferQueueProcessingThreshold * _worker_id;
- // Next thread activation threshold
- int next_threshold = threshold + G1UpdateBufferQueueProcessingThreshold;
- int deactivation_threshold = MAX2<int>(threshold - G1UpdateBufferQueueProcessingThreshold / 2, 0);
+ MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
+ if (_should_terminate) {
+ break;
+ }
+ _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefineServiceInterval);
+ }
+}
- if (G1SmoothConcRefine) {
- lower_limit = 0;
- start_vtime_sec = os::elapsedVTime();
- prev_buffer_num = (int) dcqs.completed_buffers_num();
- } else {
- lower_limit = G1UpdateBufferQueueProcessingThreshold / 4; // For now.
+void ConcurrentG1RefineThread::wait_for_completed_buffers() {
+ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
+ while (!_should_terminate && !is_active()) {
+ _monitor->wait(Mutex::_no_safepoint_check_flag);
+ }
+}
+
+bool ConcurrentG1RefineThread::is_active() {
+ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ return _worker_id > 0 ? _active : dcqs.process_completed_buffers();
+}
+
+void ConcurrentG1RefineThread::activate() {
+ MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
+ if (_worker_id > 0) {
+ if (G1TraceConcurrentRefinement) {
+ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d",
+ _worker_id, _threshold, (int)dcqs.completed_buffers_num());
}
- while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, lower_limit)) {
- double end_vtime_sec;
- double elapsed_vtime_sec;
- int elapsed_vtime_ms;
- int curr_buffer_num = (int) dcqs.completed_buffers_num();
+ set_active(true);
+ } else {
+ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ dcqs.set_process_completed(true);
+ }
+ _monitor->notify();
+}
- if (G1SmoothConcRefine) {
- end_vtime_sec = os::elapsedVTime();
- elapsed_vtime_sec = end_vtime_sec - start_vtime_sec;
- elapsed_vtime_ms = (int) (elapsed_vtime_sec * 1000.0);
+void ConcurrentG1RefineThread::deactivate() {
+ MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
+ if (_worker_id > 0) {
+ if (G1TraceConcurrentRefinement) {
+ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d",
+ _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num());
+ }
+ set_active(false);
+ } else {
+ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ dcqs.set_process_completed(false);
+ }
+}
+
+void ConcurrentG1RefineThread::run() {
+ initialize_in_thread();
+ wait_for_universe_init();
- if (curr_buffer_num > prev_buffer_num ||
- curr_buffer_num > next_threshold) {
- decreaseInterval(elapsed_vtime_ms);
- } else if (curr_buffer_num < prev_buffer_num) {
- increaseInterval(elapsed_vtime_ms);
- }
+ if (_worker_id >= cg1r()->worker_thread_num()) {
+ run_young_rs_sampling();
+ terminate();
+ }
+
+ _vtime_start = os::elapsedVTime();
+ while (!_should_terminate) {
+ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+
+ // Wait for work
+ wait_for_completed_buffers();
+
+ if (_should_terminate) {
+ break;
+ }
+
+ _sts.join();
+
+ do {
+ int curr_buffer_num = (int)dcqs.completed_buffers_num();
+ // If the number of the buffers falls down into the yellow zone,
+ // that means that the transition period after the evacuation pause has ended.
+ if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) {
+ dcqs.set_completed_queue_padding(0);
}
- if (_worker_id == 0) {
- sample_young_list_rs_lengths();
- } else if (curr_buffer_num < deactivation_threshold) {
+
+ if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) {
// If the number of the buffer has fallen below our threshold
// we should deactivate. The predecessor will reactivate this
// thread should the number of the buffers cross the threshold again.
- MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag);
deactivate();
- if (G1TraceConcurrentRefinement) {
- gclog_or_tty->print_cr("G1-Refine-deactivated worker %d", _worker_id);
- }
break;
}
// Check if we need to activate the next thread.
- if (curr_buffer_num > next_threshold && _next != NULL && !_next->is_active()) {
- MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag);
+ if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) {
_next->activate();
- DirtyCardQ_CBL_mon->notify_all();
- if (G1TraceConcurrentRefinement) {
- gclog_or_tty->print_cr("G1-Refine-activated worker %d", _next->_worker_id);
- }
}
+ } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone()));
- if (G1SmoothConcRefine) {
- prev_buffer_num = curr_buffer_num;
- _sts.leave();
- os::sleep(Thread::current(), (jlong) _interval_ms, false);
- _sts.join();
- start_vtime_sec = os::elapsedVTime();
- }
- n_logs++;
+ // We can exit the loop above while being active if there was a yield request.
+ if (is_active()) {
+ deactivate();
}
+
_sts.leave();
if (os::supports_vtime()) {
@@ -172,7 +213,6 @@
}
}
assert(_should_terminate, "just checking");
-
terminate();
}
@@ -191,8 +231,8 @@
}
{
- MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag);
- DirtyCardQ_CBL_mon->notify_all();
+ MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
+ _monitor->notify();
}
{
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -40,42 +40,36 @@
// when the number of the rset update buffer crosses a certain threshold. A successor
// would self-deactivate when the number of the buffers falls below the threshold.
bool _active;
- ConcurrentG1RefineThread * _next;
- public:
- virtual void run();
-
- bool is_active() { return _active; }
- void activate() { _active = true; }
- void deactivate() { _active = false; }
-
- private:
- ConcurrentG1Refine* _cg1r;
-
- double _interval_ms;
+ ConcurrentG1RefineThread* _next;
+ Monitor* _monitor;
+ ConcurrentG1Refine* _cg1r;
- void decreaseInterval(int processing_time_ms) {
- double min_interval_ms = (double) processing_time_ms;
- _interval_ms = 0.8 * _interval_ms;
- if (_interval_ms < min_interval_ms)
- _interval_ms = min_interval_ms;
- }
- void increaseInterval(int processing_time_ms) {
- double max_interval_ms = 9.0 * (double) processing_time_ms;
- _interval_ms = 1.1 * _interval_ms;
- if (max_interval_ms > 0 && _interval_ms > max_interval_ms)
- _interval_ms = max_interval_ms;
- }
+ int _thread_threshold_step;
+ // This thread activation threshold
+ int _threshold;
+ // This thread deactivation threshold
+ int _deactivation_threshold;
- void sleepBeforeNextCycle();
+ void sample_young_list_rs_lengths();
+ void run_young_rs_sampling();
+ void wait_for_completed_buffers();
+
+ void set_active(bool x) { _active = x; }
+ bool is_active();
+ void activate();
+ void deactivate();
// For use by G1CollectedHeap, which is a friend.
static SuspendibleThreadSet* sts() { return &_sts; }
- public:
+public:
+ virtual void run();
// Constructor
ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread* next,
int worker_id_offset, int worker_id);
+ void initialize();
+
// Printing
void print() const;
void print_on(outputStream* st) const;
@@ -83,13 +77,10 @@
// Total virtual time so far.
double vtime_accum() { return _vtime_accum; }
- ConcurrentG1Refine* cg1r() { return _cg1r; }
-
- void sample_young_list_rs_lengths();
+ ConcurrentG1Refine* cg1r() { return _cg1r; }
// Yield for GC
- void yield();
-
+ void yield();
// shutdown
void stop();
};
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -760,7 +760,6 @@
rp->setup_policy(false); // snapshot the soft ref policy to be used in this cycle
SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
- satb_mq_set.set_process_completed_threshold(G1SATBProcessCompletedThreshold);
satb_mq_set.set_active_all_threads(true);
// update_g1_committed() will be called at the end of an evac pause
--- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -61,8 +61,8 @@
#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
#endif // _MSC_VER
-DirtyCardQueueSet::DirtyCardQueueSet() :
- PtrQueueSet(true /*notify_when_complete*/),
+DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) :
+ PtrQueueSet(notify_when_complete),
_closure(NULL),
_shared_dirty_card_queue(this, true /*perm*/),
_free_ids(NULL),
@@ -77,12 +77,12 @@
}
void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
+ int process_completed_threshold,
int max_completed_queue,
Mutex* lock, PtrQueueSet* fl_owner) {
- PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue, fl_owner);
+ PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold,
+ max_completed_queue, fl_owner);
set_buffer_size(G1UpdateBufferSize);
- set_process_completed_threshold(G1UpdateBufferQueueProcessingThreshold);
-
_shared_dirty_card_queue.set_lock(lock);
_free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon);
}
@@ -154,9 +154,10 @@
return b;
}
-DirtyCardQueueSet::CompletedBufferNode*
-DirtyCardQueueSet::get_completed_buffer_lock(int stop_at) {
- CompletedBufferNode* nd = NULL;
+
+BufferNode*
+DirtyCardQueueSet::get_completed_buffer(int stop_at) {
+ BufferNode* nd = NULL;
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
if ((int)_n_completed_buffers <= stop_at) {
@@ -166,53 +167,31 @@
if (_completed_buffers_head != NULL) {
nd = _completed_buffers_head;
- _completed_buffers_head = nd->next;
+ _completed_buffers_head = nd->next();
if (_completed_buffers_head == NULL)
_completed_buffers_tail = NULL;
_n_completed_buffers--;
+ assert(_n_completed_buffers >= 0, "Invariant");
}
debug_only(assert_completed_buffer_list_len_correct_locked());
return nd;
}
-// We only do this in contexts where there is no concurrent enqueueing.
-DirtyCardQueueSet::CompletedBufferNode*
-DirtyCardQueueSet::get_completed_buffer_CAS() {
- CompletedBufferNode* nd = _completed_buffers_head;
-
- while (nd != NULL) {
- CompletedBufferNode* next = nd->next;
- CompletedBufferNode* result =
- (CompletedBufferNode*)Atomic::cmpxchg_ptr(next,
- &_completed_buffers_head,
- nd);
- if (result == nd) {
- return result;
- } else {
- nd = _completed_buffers_head;
- }
- }
- assert(_completed_buffers_head == NULL, "Loop post");
- _completed_buffers_tail = NULL;
- return NULL;
-}
-
bool DirtyCardQueueSet::
apply_closure_to_completed_buffer_helper(int worker_i,
- CompletedBufferNode* nd) {
+ BufferNode* nd) {
if (nd != NULL) {
+ void **buf = BufferNode::make_buffer_from_node(nd);
+ size_t index = nd->index();
bool b =
- DirtyCardQueue::apply_closure_to_buffer(_closure, nd->buf,
- nd->index, _sz,
+ DirtyCardQueue::apply_closure_to_buffer(_closure, buf,
+ index, _sz,
true, worker_i);
- void** buf = nd->buf;
- size_t index = nd->index;
- delete nd;
if (b) {
deallocate_buffer(buf);
return true; // In normal case, go on to next buffer.
} else {
- enqueue_complete_buffer(buf, index, true);
+ enqueue_complete_buffer(buf, index);
return false;
}
} else {
@@ -222,40 +201,36 @@
bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i,
int stop_at,
- bool with_CAS)
+ bool during_pause)
{
- CompletedBufferNode* nd = NULL;
- if (with_CAS) {
- guarantee(stop_at == 0, "Precondition");
- nd = get_completed_buffer_CAS();
- } else {
- nd = get_completed_buffer_lock(stop_at);
- }
+ assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause");
+ BufferNode* nd = get_completed_buffer(stop_at);
bool res = apply_closure_to_completed_buffer_helper(worker_i, nd);
if (res) Atomic::inc(&_processed_buffers_rs_thread);
return res;
}
void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() {
- CompletedBufferNode* nd = _completed_buffers_head;
+ BufferNode* nd = _completed_buffers_head;
while (nd != NULL) {
bool b =
- DirtyCardQueue::apply_closure_to_buffer(_closure, nd->buf, 0, _sz,
- false);
+ DirtyCardQueue::apply_closure_to_buffer(_closure,
+ BufferNode::make_buffer_from_node(nd),
+ 0, _sz, false);
guarantee(b, "Should not stop early.");
- nd = nd->next;
+ nd = nd->next();
}
}
void DirtyCardQueueSet::abandon_logs() {
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
- CompletedBufferNode* buffers_to_delete = NULL;
+ BufferNode* buffers_to_delete = NULL;
{
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
while (_completed_buffers_head != NULL) {
- CompletedBufferNode* nd = _completed_buffers_head;
- _completed_buffers_head = nd->next;
- nd->next = buffers_to_delete;
+ BufferNode* nd = _completed_buffers_head;
+ _completed_buffers_head = nd->next();
+ nd->set_next(buffers_to_delete);
buffers_to_delete = nd;
}
_n_completed_buffers = 0;
@@ -263,10 +238,9 @@
debug_only(assert_completed_buffer_list_len_correct_locked());
}
while (buffers_to_delete != NULL) {
- CompletedBufferNode* nd = buffers_to_delete;
- buffers_to_delete = nd->next;
- deallocate_buffer(nd->buf);
- delete nd;
+ BufferNode* nd = buffers_to_delete;
+ buffers_to_delete = nd->next();
+ deallocate_buffer(BufferNode::make_buffer_from_node(nd));
}
// Since abandon is done only at safepoints, we can safely manipulate
// these queues.
--- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -84,11 +84,12 @@
jint _processed_buffers_rs_thread;
public:
- DirtyCardQueueSet();
+ DirtyCardQueueSet(bool notify_when_complete = true);
void initialize(Monitor* cbl_mon, Mutex* fl_lock,
- int max_completed_queue = 0,
- Mutex* lock = NULL, PtrQueueSet* fl_owner = NULL);
+ int process_completed_threshold,
+ int max_completed_queue,
+ Mutex* lock, PtrQueueSet* fl_owner = NULL);
// The number of parallel ids that can be claimed to allow collector or
// mutator threads to do card-processing work.
@@ -120,12 +121,13 @@
// is returned to the completed buffer set, and this call returns false.
bool apply_closure_to_completed_buffer(int worker_i = 0,
int stop_at = 0,
- bool with_CAS = false);
+ bool during_pause = false);
+
bool apply_closure_to_completed_buffer_helper(int worker_i,
- CompletedBufferNode* nd);
+ BufferNode* nd);
- CompletedBufferNode* get_completed_buffer_CAS();
- CompletedBufferNode* get_completed_buffer_lock(int stop_at);
+ BufferNode* get_completed_buffer(int stop_at);
+
// Applies the current closure to all completed buffers,
// non-consumptively.
void apply_closure_to_all_completed_buffers();
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -928,6 +928,8 @@
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
TraceTime t(full ? "Full GC (System.gc())" : "Full GC", PrintGC, true, gclog_or_tty);
+ TraceMemoryManagerStats tms(true /* fullGC */);
+
double start = os::elapsedTime();
g1_policy()->record_full_collection_start();
@@ -1001,6 +1003,8 @@
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
+ MemoryService::track_memory_usage();
+
if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
gclog_or_tty->print(" VerifyAfterGC:");
@@ -1371,6 +1375,7 @@
G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
SharedHeap(policy_),
_g1_policy(policy_),
+ _dirty_card_queue_set(false),
_ref_processor(NULL),
_process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)),
_bot_shared(NULL),
@@ -1456,8 +1461,6 @@
Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap");
Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap");
- // We allocate this in any case, but only do no work if the command line
- // param is off.
_cg1r = new ConcurrentG1Refine();
// Reserve the maximum.
@@ -1590,18 +1593,20 @@
JavaThread::satb_mark_queue_set().initialize(SATB_Q_CBL_mon,
SATB_Q_FL_lock,
- 0,
+ G1SATBProcessCompletedThreshold,
Shared_SATB_Q_lock);
JavaThread::dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
DirtyCardQ_FL_lock,
- G1UpdateBufferQueueMaxLength,
+ concurrent_g1_refine()->yellow_zone(),
+ concurrent_g1_refine()->red_zone(),
Shared_DirtyCardQ_lock);
if (G1DeferredRSUpdate) {
dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
DirtyCardQ_FL_lock,
- 0,
+ -1, // never trigger processing
+ -1, // no limit on length
Shared_DirtyCardQ_lock,
&JavaThread::dirty_card_queue_set());
}
@@ -1732,13 +1737,6 @@
return car->free();
}
-void G1CollectedHeap::collect(GCCause::Cause cause) {
- // The caller doesn't have the Heap_lock
- assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock");
- MutexLocker ml(Heap_lock);
- collect_locked(cause);
-}
-
void G1CollectedHeap::collect_as_vm_thread(GCCause::Cause cause) {
assert(Thread::current()->is_VM_thread(), "Precondition#1");
assert(Heap_lock->is_locked(), "Precondition#2");
@@ -1755,17 +1753,31 @@
}
}
-
-void G1CollectedHeap::collect_locked(GCCause::Cause cause) {
- // Don't want to do a GC until cleanup is completed.
- wait_for_cleanup_complete();
-
- // Read the GC count while holding the Heap_lock
- int gc_count_before = SharedHeap::heap()->total_collections();
+void G1CollectedHeap::collect(GCCause::Cause cause) {
+ // The caller doesn't have the Heap_lock
+ assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock");
+
+ int gc_count_before;
{
- MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back
- VM_G1CollectFull op(gc_count_before, cause);
- VMThread::execute(&op);
+ MutexLocker ml(Heap_lock);
+ // Read the GC count while holding the Heap_lock
+ gc_count_before = SharedHeap::heap()->total_collections();
+
+ // Don't want to do a GC until cleanup is completed.
+ wait_for_cleanup_complete();
+ } // We give up heap lock; VMThread::execute gets it back below
+ switch (cause) {
+ case GCCause::_scavenge_alot: {
+ // Do an incremental pause, which might sometimes be abandoned.
+ VM_G1IncCollectionPause op(gc_count_before, cause);
+ VMThread::execute(&op);
+ break;
+ }
+ default: {
+ // In all other cases, we currently do a full gc.
+ VM_G1CollectFull op(gc_count_before, cause);
+ VMThread::execute(&op);
+ }
}
}
@@ -2119,7 +2131,7 @@
}
size_t G1CollectedHeap::max_capacity() const {
- return _g1_committed.byte_size();
+ return g1_reserved_obj_bytes();
}
jlong G1CollectedHeap::millis_since_last_gc() {
@@ -2638,6 +2650,8 @@
}
{
+ ResourceMark rm;
+
char verbose_str[128];
sprintf(verbose_str, "GC pause ");
if (g1_policy()->in_young_gc_mode()) {
@@ -2649,8 +2663,6 @@
if (g1_policy()->should_initiate_conc_mark())
strcat(verbose_str, " (initial-mark)");
- GCCauseSetter x(this, GCCause::_g1_inc_collection_pause);
-
// if PrintGCDetails is on, we'll print long statistics information
// in the collector policy code, so let's not print this as the output
// is messy if we do.
@@ -2658,7 +2670,8 @@
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
TraceTime t(verbose_str, PrintGC && !PrintGCDetails, true, gclog_or_tty);
- ResourceMark rm;
+ TraceMemoryManagerStats tms(false /* fullGC */);
+
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
assert(Thread::current() == VMThread::vm_thread(), "should be in vm thread");
guarantee(!is_gc_active(), "collection is not reentrant");
@@ -2802,6 +2815,22 @@
_young_list->reset_auxilary_lists();
}
} else {
+ if (_in_cset_fast_test != NULL) {
+ assert(_in_cset_fast_test_base != NULL, "Since _in_cset_fast_test isn't");
+ FREE_C_HEAP_ARRAY(bool, _in_cset_fast_test_base);
+ // this is more for peace of mind; we're nulling them here and
+ // we're expecting them to be null at the beginning of the next GC
+ _in_cset_fast_test = NULL;
+ _in_cset_fast_test_base = NULL;
+ }
+ // This looks confusing, because the DPT should really be empty
+ // at this point -- since we have not done any collection work,
+ // there should not be any derived pointers in the table to update;
+ // however, there is some additional state in the DPT which is
+ // reset at the end of the (null) "gc" here via the following call.
+ // A better approach might be to split off that state resetting work
+ // into a separate method that asserts that the DPT is empty and call
+ // that here. That is deferred for now.
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
}
@@ -2838,6 +2867,8 @@
assert(regions_accounted_for(), "Region leakage.");
+ MemoryService::track_memory_usage();
+
if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
gclog_or_tty->print(" VerifyAfterGC:");
@@ -4209,10 +4240,11 @@
RedirtyLoggedCardTableEntryFastClosure redirty;
dirty_card_queue_set().set_closure(&redirty);
dirty_card_queue_set().apply_closure_to_all_completed_buffers();
- JavaThread::dirty_card_queue_set().merge_bufferlists(&dirty_card_queue_set());
+
+ DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set();
+ dcq.merge_bufferlists(&dirty_card_queue_set());
assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
}
-
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -692,7 +692,7 @@
// Reserved (g1 only; super method includes perm), capacity and the used
// portion in bytes.
- size_t g1_reserved_obj_bytes() { return _g1_reserved.byte_size(); }
+ size_t g1_reserved_obj_bytes() const { return _g1_reserved.byte_size(); }
virtual size_t capacity() const;
virtual size_t used() const;
// This should be called when we're not holding the heap lock. The
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1516,8 +1516,30 @@
(end_time_sec - _recent_prev_end_times_for_all_gcs_sec->oldest()) * 1000.0;
update_recent_gc_times(end_time_sec, elapsed_ms);
_recent_avg_pause_time_ratio = _recent_gc_times_ms->sum()/interval_ms;
- // using 1.01 to account for floating point inaccuracies
- assert(recent_avg_pause_time_ratio() < 1.01, "All GC?");
+ if (recent_avg_pause_time_ratio() < 0.0 ||
+ (recent_avg_pause_time_ratio() - 1.0 > 0.0)) {
+#ifndef PRODUCT
+ // Dump info to allow post-facto debugging
+ gclog_or_tty->print_cr("recent_avg_pause_time_ratio() out of bounds");
+ gclog_or_tty->print_cr("-------------------------------------------");
+ gclog_or_tty->print_cr("Recent GC Times (ms):");
+ _recent_gc_times_ms->dump();
+ gclog_or_tty->print_cr("(End Time=%3.3f) Recent GC End Times (s):", end_time_sec);
+ _recent_prev_end_times_for_all_gcs_sec->dump();
+ gclog_or_tty->print_cr("GC = %3.3f, Interval = %3.3f, Ratio = %3.3f",
+ _recent_gc_times_ms->sum(), interval_ms, recent_avg_pause_time_ratio());
+ // In debug mode, terminate the JVM if the user wants to debug at this point.
+ assert(!G1FailOnFPError, "Debugging data for CR 6898948 has been dumped above");
+#endif // !PRODUCT
+ // Clip ratio between 0.0 and 1.0, and continue. This will be fixed in
+ // CR 6902692 by redoing the manner in which the ratio is incrementally computed.
+ if (_recent_avg_pause_time_ratio < 0.0) {
+ _recent_avg_pause_time_ratio = 0.0;
+ } else {
+ assert(_recent_avg_pause_time_ratio - 1.0 > 0.0, "Ctl-point invariant");
+ _recent_avg_pause_time_ratio = 1.0;
+ }
+ }
}
if (G1PolicyVerbose > 1) {
@@ -1892,6 +1914,10 @@
calculate_young_list_min_length();
calculate_young_list_target_config();
+ // Note that _mmu_tracker->max_gc_time() returns the time in seconds.
+ double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSUpdatePauseFractionPercent / 100.0;
+ adjust_concurrent_refinement(update_rs_time, update_rs_processed_buffers, update_rs_time_goal_ms);
+
// </NEW PREDICTION>
_target_pause_time_ms = -1.0;
@@ -1899,6 +1925,47 @@
// <NEW PREDICTION>
+void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time,
+ double update_rs_processed_buffers,
+ double goal_ms) {
+ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ ConcurrentG1Refine *cg1r = G1CollectedHeap::heap()->concurrent_g1_refine();
+
+ if (G1AdaptiveConcRefine) {
+ const int k_gy = 3, k_gr = 6;
+ const double inc_k = 1.1, dec_k = 0.9;
+
+ int g = cg1r->green_zone();
+ if (update_rs_time > goal_ms) {
+ g = (int)(g * dec_k); // Can become 0, that's OK. That would mean a mutator-only processing.
+ } else {
+ if (update_rs_time < goal_ms && update_rs_processed_buffers > g) {
+ g = (int)MAX2(g * inc_k, g + 1.0);
+ }
+ }
+ // Change the refinement threads params
+ cg1r->set_green_zone(g);
+ cg1r->set_yellow_zone(g * k_gy);
+ cg1r->set_red_zone(g * k_gr);
+ cg1r->reinitialize_threads();
+
+ int processing_threshold_delta = MAX2((int)(cg1r->green_zone() * sigma()), 1);
+ int processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta,
+ cg1r->yellow_zone());
+ // Change the barrier params
+ dcqs.set_process_completed_threshold(processing_threshold);
+ dcqs.set_max_completed_queue(cg1r->red_zone());
+ }
+
+ int curr_queue_size = dcqs.completed_buffers_num();
+ if (curr_queue_size >= cg1r->yellow_zone()) {
+ dcqs.set_completed_queue_padding(curr_queue_size);
+ } else {
+ dcqs.set_completed_queue_padding(0);
+ }
+ dcqs.notify_if_necessary();
+}
+
double
G1CollectorPolicy::
predict_young_collection_elapsed_time_ms(size_t adjustment) {
@@ -2825,8 +2892,15 @@
double non_young_start_time_sec;
start_recording_regions();
- guarantee(_target_pause_time_ms > -1.0,
+ guarantee(_target_pause_time_ms > -1.0
+ NOT_PRODUCT(|| Universe::heap()->gc_cause() == GCCause::_scavenge_alot),
"_target_pause_time_ms should have been set!");
+#ifndef PRODUCT
+ if (_target_pause_time_ms <= -1.0) {
+ assert(ScavengeALot && Universe::heap()->gc_cause() == GCCause::_scavenge_alot, "Error");
+ _target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0;
+ }
+#endif
assert(_collection_set == NULL, "Precondition");
double base_time_ms = predict_base_elapsed_time_ms(_pending_cards);
@@ -2972,7 +3046,3 @@
G1CollectorPolicy::record_collection_pause_end(abandoned);
assert(assertMarkedBytesDataOK(), "Marked regions not OK at pause end.");
}
-
-// Local Variables: ***
-// c-indentation-style: gnu ***
-// End: ***
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -316,6 +316,10 @@
bool verify_young_ages(HeapRegion* head, SurvRateGroup *surv_rate_group);
#endif // PRODUCT
+ void adjust_concurrent_refinement(double update_rs_time,
+ double update_rs_processed_buffers,
+ double goal_ms);
+
protected:
double _pause_time_target_ms;
double _recorded_young_cset_choice_time_ms;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -86,12 +86,22 @@
// increase the array size (:-)
// remove the oldest entry (this might allow more GC time for
// the time slice than what's allowed)
- // concolidate the two entries with the minimum gap between them
- // (this mighte allow less GC time than what's allowed)
- guarantee(0, "array full, currently we can't recover");
+ // consolidate the two entries with the minimum gap between them
+ // (this might allow less GC time than what's allowed)
+ guarantee(NOT_PRODUCT(ScavengeALot ||) G1ForgetfulMMUTracker,
+ "array full, currently we can't recover unless +G1ForgetfulMMUTracker");
+ // In the case where ScavengeALot is true, such overflow is not
+ // uncommon; in such cases, we can, without much loss of precision
+ // or performance (we are GC'ing most of the time anyway!),
+ // simply overwrite the oldest entry in the tracker: this
+ // is also the behaviour when G1ForgetfulMMUTracker is enabled.
+ _head_index = trim_index(_head_index + 1);
+ assert(_head_index == _tail_index, "Because we have a full circular buffer");
+ _tail_index = trim_index(_tail_index + 1);
+ } else {
+ _head_index = trim_index(_head_index + 1);
+ ++_no_entries;
}
- _head_index = trim_index(_head_index + 1);
- ++_no_entries;
_array[_head_index] = G1MMUTrackerQueueElem(start, end);
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -99,7 +99,10 @@
// The array is of fixed size and I don't think we'll need more than
// two or three entries with the current behaviour of G1 pauses.
// If the array is full, an easy fix is to look for the pauses with
- // the shortest gap between them and concolidate them.
+ // the shortest gap between them and consolidate them.
+ // For now, we have taken the expedient alternative of forgetting
+ // the oldest entry in the event that +G1ForgetfulMMUTracker, thus
+ // potentially violating MMU specs for some time thereafter.
G1MMUTrackerQueueElem _array[QueueLength];
int _head_index;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -85,7 +85,7 @@
diagnostic(bool, G1SummarizeZFStats, false, \
"Summarize zero-filling info") \
\
- develop(bool, G1TraceConcurrentRefinement, false, \
+ diagnostic(bool, G1TraceConcurrentRefinement, false, \
"Trace G1 concurrent refinement") \
\
product(intx, G1MarkStackSize, 2 * 1024 * 1024, \
@@ -94,19 +94,6 @@
product(intx, G1MarkRegionStackSize, 1024 * 1024, \
"Size of the region stack for concurrent marking.") \
\
- develop(bool, G1ConcRefine, true, \
- "If true, run concurrent rem set refinement for G1") \
- \
- develop(intx, G1ConcRefineTargTraversals, 4, \
- "Number of concurrent refinement we try to achieve") \
- \
- develop(intx, G1ConcRefineInitialDelta, 4, \
- "Number of heap regions of alloc ahead of starting collection " \
- "pause to start concurrent refinement (initially)") \
- \
- develop(bool, G1SmoothConcRefine, true, \
- "Attempts to smooth out the overhead of concurrent refinement") \
- \
develop(bool, G1ConcZeroFill, true, \
"If true, run concurrent zero-filling thread") \
\
@@ -178,13 +165,38 @@
product(intx, G1UpdateBufferSize, 256, \
"Size of an update buffer") \
\
- product(intx, G1UpdateBufferQueueProcessingThreshold, 5, \
+ product(intx, G1ConcRefineYellowZone, 0, \
"Number of enqueued update buffers that will " \
- "trigger concurrent processing") \
+ "trigger concurrent processing. Will be selected ergonomically " \
+ "by default.") \
+ \
+ product(intx, G1ConcRefineRedZone, 0, \
+ "Maximum number of enqueued update buffers before mutator " \
+ "threads start processing new ones instead of enqueueing them. " \
+ "Will be selected ergonomically by default. Zero will disable " \
+ "concurrent processing.") \
+ \
+ product(intx, G1ConcRefineGreenZone, 0, \
+ "The number of update buffers that are left in the queue by the " \
+ "concurrent processing threads. Will be selected ergonomically " \
+ "by default.") \
\
- product(intx, G1UpdateBufferQueueMaxLength, 30, \
- "Maximum number of enqueued update buffers before mutator " \
- "threads start processing new ones instead of enqueueing them") \
+ product(intx, G1ConcRefineServiceInterval, 300, \
+ "The last concurrent refinement thread wakes up every " \
+ "specified number of milliseconds to do miscellaneous work.") \
+ \
+ product(intx, G1ConcRefineThresholdStep, 0, \
+ "Each time the rset update queue increases by this amount " \
+ "activate the next refinement thread if available. " \
+ "Will be selected ergonomically by default.") \
+ \
+ product(intx, G1RSUpdatePauseFractionPercent, 10, \
+ "A target percentage of time that is allowed to be spend on " \
+ "process RS update buffers during the collection pause.") \
+ \
+ product(bool, G1AdaptiveConcRefine, true, \
+ "Select green, yellow and red zones adaptively to meet the " \
+ "the pause requirements.") \
\
develop(intx, G1ConcRSLogCacheSize, 10, \
"Log base 2 of the length of conc RS hot-card cache.") \
@@ -242,6 +254,10 @@
product(bool, G1UseSurvivorSpaces, true, \
"When true, use survivor space.") \
\
+ develop(bool, G1FailOnFPError, false, \
+ "When set, G1 will fail when it encounters an FP 'error', " \
+ "so as to allow debugging") \
+ \
develop(bool, G1FixedTenuringThreshold, false, \
"When set, G1 will not adjust the tenuring threshold") \
\
@@ -252,6 +268,9 @@
"If non-0 is the size of the G1 survivor space, " \
"otherwise SurvivorRatio is used to determine the size") \
\
+ product(bool, G1ForgetfulMMUTracker, false, \
+ "If the MMU tracker's memory is full, forget the oldest entry") \
+ \
product(uintx, G1HeapRegionSize, 0, \
"Size of the G1 regions.") \
\
--- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -64,8 +64,8 @@
while (_index == 0) {
handle_zero_index();
}
+
assert(_index > 0, "postcondition");
-
_index -= oopSize;
_buf[byte_index_to_index((int)_index)] = ptr;
assert(0 <= _index && _index <= _sz, "Invariant.");
@@ -99,94 +99,110 @@
assert(_sz > 0, "Didn't set a buffer size.");
MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
if (_fl_owner->_buf_free_list != NULL) {
- void** res = _fl_owner->_buf_free_list;
- _fl_owner->_buf_free_list = (void**)_fl_owner->_buf_free_list[0];
+ void** res = BufferNode::make_buffer_from_node(_fl_owner->_buf_free_list);
+ _fl_owner->_buf_free_list = _fl_owner->_buf_free_list->next();
_fl_owner->_buf_free_list_sz--;
- // Just override the next pointer with NULL, just in case we scan this part
- // of the buffer.
- res[0] = NULL;
return res;
} else {
- return NEW_C_HEAP_ARRAY(void*, _sz);
+ // Allocate space for the BufferNode in front of the buffer.
+ char *b = NEW_C_HEAP_ARRAY(char, _sz + BufferNode::aligned_size());
+ return BufferNode::make_buffer_from_block(b);
}
}
void PtrQueueSet::deallocate_buffer(void** buf) {
assert(_sz > 0, "Didn't set a buffer size.");
MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
- buf[0] = (void*)_fl_owner->_buf_free_list;
- _fl_owner->_buf_free_list = buf;
+ BufferNode *node = BufferNode::make_node_from_buffer(buf);
+ node->set_next(_fl_owner->_buf_free_list);
+ _fl_owner->_buf_free_list = node;
_fl_owner->_buf_free_list_sz++;
}
void PtrQueueSet::reduce_free_list() {
+ assert(_fl_owner == this, "Free list reduction is allowed only for the owner");
// For now we'll adopt the strategy of deleting half.
MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag);
size_t n = _buf_free_list_sz / 2;
while (n > 0) {
assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong.");
- void** head = _buf_free_list;
- _buf_free_list = (void**)_buf_free_list[0];
- FREE_C_HEAP_ARRAY(void*,head);
+ void* b = BufferNode::make_block_from_node(_buf_free_list);
+ _buf_free_list = _buf_free_list->next();
+ FREE_C_HEAP_ARRAY(char, b);
+ _buf_free_list_sz --;
n--;
}
}
-void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index, bool ignore_max_completed) {
- // I use explicit locking here because there's a bailout in the middle.
- _cbl_mon->lock_without_safepoint_check();
-
- Thread* thread = Thread::current();
- assert( ignore_max_completed ||
- thread->is_Java_thread() ||
- SafepointSynchronize::is_at_safepoint(),
- "invariant" );
- ignore_max_completed = ignore_max_completed || !thread->is_Java_thread();
+void PtrQueue::handle_zero_index() {
+ assert(0 == _index, "Precondition.");
+ // This thread records the full buffer and allocates a new one (while
+ // holding the lock if there is one).
+ if (_buf != NULL) {
+ if (_lock) {
+ locking_enqueue_completed_buffer(_buf);
+ } else {
+ if (qset()->process_or_enqueue_complete_buffer(_buf)) {
+ // Recycle the buffer. No allocation.
+ _sz = qset()->buffer_size();
+ _index = _sz;
+ return;
+ }
+ }
+ }
+ // Reallocate the buffer
+ _buf = qset()->allocate_buffer();
+ _sz = qset()->buffer_size();
+ _index = _sz;
+ assert(0 <= _index && _index <= _sz, "Invariant.");
+}
- if (!ignore_max_completed && _max_completed_queue > 0 &&
- _n_completed_buffers >= (size_t) _max_completed_queue) {
- _cbl_mon->unlock();
- bool b = mut_process_buffer(buf);
- if (b) {
- deallocate_buffer(buf);
- return;
+bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) {
+ if (Thread::current()->is_Java_thread()) {
+ // We don't lock. It is fine to be epsilon-precise here.
+ if (_max_completed_queue == 0 || _max_completed_queue > 0 &&
+ _n_completed_buffers >= _max_completed_queue + _completed_queue_padding) {
+ bool b = mut_process_buffer(buf);
+ if (b) {
+ // True here means that the buffer hasn't been deallocated and the caller may reuse it.
+ return true;
+ }
}
+ }
+ // The buffer will be enqueued. The caller will have to get a new one.
+ enqueue_complete_buffer(buf);
+ return false;
+}
- // Otherwise, go ahead and enqueue the buffer. Must reaquire the lock.
- _cbl_mon->lock_without_safepoint_check();
- }
-
- // Here we still hold the _cbl_mon.
- CompletedBufferNode* cbn = new CompletedBufferNode;
- cbn->buf = buf;
- cbn->next = NULL;
- cbn->index = index;
+void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) {
+ MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
+ BufferNode* cbn = BufferNode::new_from_buffer(buf);
+ cbn->set_index(index);
if (_completed_buffers_tail == NULL) {
assert(_completed_buffers_head == NULL, "Well-formedness");
_completed_buffers_head = cbn;
_completed_buffers_tail = cbn;
} else {
- _completed_buffers_tail->next = cbn;
+ _completed_buffers_tail->set_next(cbn);
_completed_buffers_tail = cbn;
}
_n_completed_buffers++;
- if (!_process_completed &&
+ if (!_process_completed && _process_completed_threshold >= 0 &&
_n_completed_buffers >= _process_completed_threshold) {
_process_completed = true;
if (_notify_when_complete)
- _cbl_mon->notify_all();
+ _cbl_mon->notify();
}
debug_only(assert_completed_buffer_list_len_correct_locked());
- _cbl_mon->unlock();
}
int PtrQueueSet::completed_buffers_list_length() {
int n = 0;
- CompletedBufferNode* cbn = _completed_buffers_head;
+ BufferNode* cbn = _completed_buffers_head;
while (cbn != NULL) {
n++;
- cbn = cbn->next;
+ cbn = cbn->next();
}
return n;
}
@@ -197,7 +213,7 @@
}
void PtrQueueSet::assert_completed_buffer_list_len_correct_locked() {
- guarantee((size_t)completed_buffers_list_length() == _n_completed_buffers,
+ guarantee(completed_buffers_list_length() == _n_completed_buffers,
"Completed buffer length is wrong.");
}
@@ -206,12 +222,8 @@
_sz = sz * oopSize;
}
-void PtrQueueSet::set_process_completed_threshold(size_t sz) {
- _process_completed_threshold = sz;
-}
-
-// Merge lists of buffers. Notify waiting threads if the length of the list
-// exceeds threshold. The source queue is emptied as a result. The queues
+// Merge lists of buffers. Notify the processing threads.
+// The source queue is emptied as a result. The queues
// must share the monitor.
void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) {
assert(_cbl_mon == src->_cbl_mon, "Should share the same lock");
@@ -223,7 +235,7 @@
} else {
assert(_completed_buffers_head != NULL, "Well formedness");
if (src->_completed_buffers_head != NULL) {
- _completed_buffers_tail->next = src->_completed_buffers_head;
+ _completed_buffers_tail->set_next(src->_completed_buffers_head);
_completed_buffers_tail = src->_completed_buffers_tail;
}
}
@@ -236,31 +248,13 @@
assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL ||
_completed_buffers_head != NULL && _completed_buffers_tail != NULL,
"Sanity");
-
- if (!_process_completed &&
- _n_completed_buffers >= _process_completed_threshold) {
- _process_completed = true;
- if (_notify_when_complete)
- _cbl_mon->notify_all();
- }
}
-// Merge free lists of the two queues. The free list of the source
-// queue is emptied as a result. The queues must share the same
-// mutex that guards free lists.
-void PtrQueueSet::merge_freelists(PtrQueueSet* src) {
- assert(_fl_lock == src->_fl_lock, "Should share the same lock");
- MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag);
- if (_buf_free_list != NULL) {
- void **p = _buf_free_list;
- while (*p != NULL) {
- p = (void**)*p;
- }
- *p = src->_buf_free_list;
- } else {
- _buf_free_list = src->_buf_free_list;
+void PtrQueueSet::notify_if_necessary() {
+ MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
+ if (_n_completed_buffers >= _process_completed_threshold || _max_completed_queue == 0) {
+ _process_completed = true;
+ if (_notify_when_complete)
+ _cbl_mon->notify();
}
- _buf_free_list_sz += src->_buf_free_list_sz;
- src->_buf_free_list = NULL;
- src->_buf_free_list_sz = 0;
}
--- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -27,8 +27,10 @@
// the addresses of modified old-generation objects. This type supports
// this operation.
+// The definition of placement operator new(size_t, void*) in the <new>.
+#include <new>
+
class PtrQueueSet;
-
class PtrQueue VALUE_OBJ_CLASS_SPEC {
protected:
@@ -77,7 +79,7 @@
else enqueue_known_active(ptr);
}
- inline void handle_zero_index();
+ void handle_zero_index();
void locking_enqueue_completed_buffer(void** buf);
void enqueue_known_active(void* ptr);
@@ -126,34 +128,65 @@
};
+class BufferNode {
+ size_t _index;
+ BufferNode* _next;
+public:
+ BufferNode() : _index(0), _next(NULL) { }
+ BufferNode* next() const { return _next; }
+ void set_next(BufferNode* n) { _next = n; }
+ size_t index() const { return _index; }
+ void set_index(size_t i) { _index = i; }
+
+ // Align the size of the structure to the size of the pointer
+ static size_t aligned_size() {
+ static const size_t alignment = round_to(sizeof(BufferNode), sizeof(void*));
+ return alignment;
+ }
+
+ // BufferNode is allocated before the buffer.
+ // The chunk of memory that holds both of them is a block.
+
+ // Produce a new BufferNode given a buffer.
+ static BufferNode* new_from_buffer(void** buf) {
+ return new (make_block_from_buffer(buf)) BufferNode;
+ }
+
+ // The following are the required conversion routines:
+ static BufferNode* make_node_from_buffer(void** buf) {
+ return (BufferNode*)make_block_from_buffer(buf);
+ }
+ static void** make_buffer_from_node(BufferNode *node) {
+ return make_buffer_from_block(node);
+ }
+ static void* make_block_from_node(BufferNode *node) {
+ return (void*)node;
+ }
+ static void** make_buffer_from_block(void* p) {
+ return (void**)((char*)p + aligned_size());
+ }
+ static void* make_block_from_buffer(void** p) {
+ return (void*)((char*)p - aligned_size());
+ }
+};
+
// A PtrQueueSet represents resources common to a set of pointer queues.
// In particular, the individual queues allocate buffers from this shared
// set, and return completed buffers to the set.
// All these variables are are protected by the TLOQ_CBL_mon. XXX ???
class PtrQueueSet VALUE_OBJ_CLASS_SPEC {
-
protected:
-
- class CompletedBufferNode: public CHeapObj {
- public:
- void** buf;
- size_t index;
- CompletedBufferNode* next;
- CompletedBufferNode() : buf(NULL),
- index(0), next(NULL){ }
- };
-
Monitor* _cbl_mon; // Protects the fields below.
- CompletedBufferNode* _completed_buffers_head;
- CompletedBufferNode* _completed_buffers_tail;
- size_t _n_completed_buffers;
- size_t _process_completed_threshold;
+ BufferNode* _completed_buffers_head;
+ BufferNode* _completed_buffers_tail;
+ int _n_completed_buffers;
+ int _process_completed_threshold;
volatile bool _process_completed;
// This (and the interpretation of the first element as a "next"
// pointer) are protected by the TLOQ_FL_lock.
Mutex* _fl_lock;
- void** _buf_free_list;
+ BufferNode* _buf_free_list;
size_t _buf_free_list_sz;
// Queue set can share a freelist. The _fl_owner variable
// specifies the owner. It is set to "this" by default.
@@ -170,6 +203,7 @@
// Maximum number of elements allowed on completed queue: after that,
// enqueuer does the work itself. Zero indicates no maximum.
int _max_completed_queue;
+ int _completed_queue_padding;
int completed_buffers_list_length();
void assert_completed_buffer_list_len_correct_locked();
@@ -191,9 +225,12 @@
// Because of init-order concerns, we can't pass these as constructor
// arguments.
void initialize(Monitor* cbl_mon, Mutex* fl_lock,
- int max_completed_queue = 0,
+ int process_completed_threshold,
+ int max_completed_queue,
PtrQueueSet *fl_owner = NULL) {
_max_completed_queue = max_completed_queue;
+ _process_completed_threshold = process_completed_threshold;
+ _completed_queue_padding = 0;
assert(cbl_mon != NULL && fl_lock != NULL, "Init order issue?");
_cbl_mon = cbl_mon;
_fl_lock = fl_lock;
@@ -208,14 +245,17 @@
void deallocate_buffer(void** buf);
// Declares that "buf" is a complete buffer.
- void enqueue_complete_buffer(void** buf, size_t index = 0,
- bool ignore_max_completed = false);
+ void enqueue_complete_buffer(void** buf, size_t index = 0);
+
+ // To be invoked by the mutator.
+ bool process_or_enqueue_complete_buffer(void** buf);
bool completed_buffers_exist_dirty() {
return _n_completed_buffers > 0;
}
bool process_completed_buffers() { return _process_completed; }
+ void set_process_completed(bool x) { _process_completed = x; }
bool active() { return _all_active; }
@@ -226,15 +266,24 @@
// Get the buffer size.
size_t buffer_size() { return _sz; }
- // Set the number of completed buffers that triggers log processing.
- void set_process_completed_threshold(size_t sz);
+ // Get/Set the number of completed buffers that triggers log processing.
+ void set_process_completed_threshold(int sz) { _process_completed_threshold = sz; }
+ int process_completed_threshold() const { return _process_completed_threshold; }
// Must only be called at a safe point. Indicates that the buffer free
// list size may be reduced, if that is deemed desirable.
void reduce_free_list();
- size_t completed_buffers_num() { return _n_completed_buffers; }
+ int completed_buffers_num() { return _n_completed_buffers; }
void merge_bufferlists(PtrQueueSet* src);
- void merge_freelists(PtrQueueSet* src);
+
+ void set_max_completed_queue(int m) { _max_completed_queue = m; }
+ int max_completed_queue() { return _max_completed_queue; }
+
+ void set_completed_queue_padding(int padding) { _completed_queue_padding = padding; }
+ int completed_queue_padding() { return _completed_queue_padding; }
+
+ // Notify the consumer if the number of buffers crossed the threshold
+ void notify_if_necessary();
};
--- a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -67,9 +67,9 @@
{}
void SATBMarkQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
- int max_completed_queue,
+ int process_completed_threshold,
Mutex* lock) {
- PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue);
+ PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold, -1);
_shared_satb_queue.set_lock(lock);
if (ParallelGCThreads > 0) {
_par_closures = NEW_C_HEAP_ARRAY(ObjectClosure*, ParallelGCThreads);
@@ -122,12 +122,12 @@
bool SATBMarkQueueSet::apply_closure_to_completed_buffer_work(bool par,
int worker) {
- CompletedBufferNode* nd = NULL;
+ BufferNode* nd = NULL;
{
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
if (_completed_buffers_head != NULL) {
nd = _completed_buffers_head;
- _completed_buffers_head = nd->next;
+ _completed_buffers_head = nd->next();
if (_completed_buffers_head == NULL) _completed_buffers_tail = NULL;
_n_completed_buffers--;
if (_n_completed_buffers == 0) _process_completed = false;
@@ -135,9 +135,9 @@
}
ObjectClosure* cl = (par ? _par_closures[worker] : _closure);
if (nd != NULL) {
- ObjPtrQueue::apply_closure_to_buffer(cl, nd->buf, 0, _sz);
- deallocate_buffer(nd->buf);
- delete nd;
+ void **buf = BufferNode::make_buffer_from_node(nd);
+ ObjPtrQueue::apply_closure_to_buffer(cl, buf, 0, _sz);
+ deallocate_buffer(buf);
return true;
} else {
return false;
@@ -145,13 +145,13 @@
}
void SATBMarkQueueSet::abandon_partial_marking() {
- CompletedBufferNode* buffers_to_delete = NULL;
+ BufferNode* buffers_to_delete = NULL;
{
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
while (_completed_buffers_head != NULL) {
- CompletedBufferNode* nd = _completed_buffers_head;
- _completed_buffers_head = nd->next;
- nd->next = buffers_to_delete;
+ BufferNode* nd = _completed_buffers_head;
+ _completed_buffers_head = nd->next();
+ nd->set_next(buffers_to_delete);
buffers_to_delete = nd;
}
_completed_buffers_tail = NULL;
@@ -159,10 +159,9 @@
DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked());
}
while (buffers_to_delete != NULL) {
- CompletedBufferNode* nd = buffers_to_delete;
- buffers_to_delete = nd->next;
- deallocate_buffer(nd->buf);
- delete nd;
+ BufferNode* nd = buffers_to_delete;
+ buffers_to_delete = nd->next();
+ deallocate_buffer(BufferNode::make_buffer_from_node(nd));
}
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
// So we can safely manipulate these queues.
--- a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -60,8 +60,8 @@
SATBMarkQueueSet();
void initialize(Monitor* cbl_mon, Mutex* fl_lock,
- int max_completed_queue = 0,
- Mutex* lock = NULL);
+ int process_completed_threshold,
+ Mutex* lock);
static void handle_zero_index_for_thread(JavaThread* t);
--- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -42,7 +42,7 @@
void VM_G1IncCollectionPause::doit() {
JvmtiGCForAllocationMarker jgcm;
G1CollectedHeap* g1h = G1CollectedHeap::heap();
- GCCauseSetter x(g1h, GCCause::_g1_inc_collection_pause);
+ GCCauseSetter x(g1h, _gc_cause);
g1h->do_collection_pause_at_safepoint();
}
--- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -68,8 +68,9 @@
class VM_G1IncCollectionPause: public VM_GC_Operation {
public:
- VM_G1IncCollectionPause(int gc_count_before) :
- VM_GC_Operation(gc_count_before) {}
+ VM_G1IncCollectionPause(int gc_count_before,
+ GCCause::Cause gc_cause = GCCause::_g1_inc_collection_pause) :
+ VM_GC_Operation(gc_count_before) { _gc_cause = gc_cause; }
virtual VMOp_Type type() const { return VMOp_G1IncCollectionPause; }
virtual void doit();
virtual const char* name() const {
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 Wed Jul 05 17:04:53 2017 +0200
@@ -109,7 +109,6 @@
dirtyCardQueue.cpp dirtyCardQueue.hpp
dirtyCardQueue.cpp heapRegionRemSet.hpp
dirtyCardQueue.cpp mutexLocker.hpp
-dirtyCardQueue.cpp ptrQueue.inline.hpp
dirtyCardQueue.cpp safepoint.hpp
dirtyCardQueue.cpp thread.hpp
dirtyCardQueue.cpp thread_<os_family>.inline.hpp
@@ -222,6 +221,15 @@
g1MarkSweep.hpp timer.hpp
g1MarkSweep.hpp universe.hpp
+g1MemoryPool.cpp heapRegion.hpp
+g1MemoryPool.cpp g1CollectedHeap.inline.hpp
+g1MemoryPool.cpp g1CollectedHeap.hpp
+g1MemoryPool.cpp g1CollectorPolicy.hpp
+g1MemoryPool.cpp g1MemoryPool.hpp
+
+g1MemoryPool.hpp memoryUsage.hpp
+g1MemoryPool.hpp memoryPool.hpp
+
g1OopClosures.inline.hpp concurrentMark.hpp
g1OopClosures.inline.hpp g1OopClosures.hpp
g1OopClosures.inline.hpp g1CollectedHeap.hpp
@@ -303,12 +311,13 @@
klass.hpp g1OopClosures.hpp
+memoryService.cpp g1MemoryPool.hpp
+
ptrQueue.cpp allocation.hpp
ptrQueue.cpp allocation.inline.hpp
ptrQueue.cpp mutex.hpp
ptrQueue.cpp mutexLocker.hpp
ptrQueue.cpp ptrQueue.hpp
-ptrQueue.cpp ptrQueue.inline.hpp
ptrQueue.cpp thread_<os_family>.inline.hpp
ptrQueue.hpp allocation.hpp
@@ -318,7 +327,6 @@
satbQueue.cpp allocation.inline.hpp
satbQueue.cpp mutexLocker.hpp
-satbQueue.cpp ptrQueue.inline.hpp
satbQueue.cpp satbQueue.hpp
satbQueue.cpp sharedHeap.hpp
satbQueue.cpp thread.hpp
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -51,7 +51,7 @@
cname = PerfDataManager::counter_name(name_space(), "oldCapacity");
_old_capacity = PerfDataManager::create_variable(SUN_GC, cname,
- PerfData::U_Bytes, (jlong) Arguments::initial_heap_size(), CHECK);
+ PerfData::U_Bytes, (jlong) InitialHeapSize, CHECK);
cname = PerfDataManager::counter_name(name_space(), "boundaryMoved");
_boundary_moved = PerfDataManager::create_variable(SUN_GC, cname,
--- a/hotspot/src/share/vm/includeDB_compiler2 Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/includeDB_compiler2 Wed Jul 05 17:04:53 2017 +0200
@@ -149,6 +149,7 @@
c2compiler.hpp abstractCompiler.hpp
callGenerator.cpp addnode.hpp
+callGenerator.cpp bcEscapeAnalyzer.hpp
callGenerator.cpp callGenerator.hpp
callGenerator.cpp callnode.hpp
callGenerator.cpp cfgnode.hpp
@@ -321,6 +322,7 @@
compile.cpp rootnode.hpp
compile.cpp runtime.hpp
compile.cpp signature.hpp
+compile.cpp stringopts.hpp
compile.cpp stubRoutines.hpp
compile.cpp systemDictionary.hpp
compile.cpp timer.hpp
@@ -476,12 +478,16 @@
graphKit.cpp runtime.hpp
graphKit.cpp sharedRuntime.hpp
+graphKit.hpp addnode.hpp
graphKit.hpp callnode.hpp
graphKit.hpp cfgnode.hpp
graphKit.hpp ciEnv.hpp
+graphKit.hpp divnode.hpp
graphKit.hpp compile.hpp
graphKit.hpp deoptimization.hpp
graphKit.hpp phaseX.hpp
+graphKit.hpp mulnode.hpp
+graphKit.hpp subnode.hpp
graphKit.hpp type.hpp
idealKit.cpp addnode.hpp
@@ -490,7 +496,10 @@
idealKit.cpp idealKit.hpp
idealKit.cpp runtime.hpp
+idealKit.hpp addnode.hpp
+idealKit.hpp cfgnode.hpp
idealKit.hpp connode.hpp
+idealKit.hpp divnode.hpp
idealKit.hpp mulnode.hpp
idealKit.hpp phaseX.hpp
idealKit.hpp subnode.hpp
@@ -641,6 +650,7 @@
macro.cpp callnode.hpp
macro.cpp cfgnode.hpp
macro.cpp compile.hpp
+macro.cpp compileLog.hpp
macro.cpp connode.hpp
macro.cpp locknode.hpp
macro.cpp loopnode.hpp
@@ -993,6 +1003,21 @@
split_if.cpp connode.hpp
split_if.cpp loopnode.hpp
+stringopts.hpp phaseX.hpp
+stringopts.hpp node.hpp
+
+stringopts.cpp addnode.hpp
+stringopts.cpp callnode.hpp
+stringopts.cpp callGenerator.hpp
+stringopts.cpp compileLog.hpp
+stringopts.cpp divnode.hpp
+stringopts.cpp idealKit.hpp
+stringopts.cpp graphKit.hpp
+stringopts.cpp rootnode.hpp
+stringopts.cpp runtime.hpp
+stringopts.cpp subnode.hpp
+stringopts.cpp stringopts.hpp
+
stubGenerator_<arch_model>.cpp runtime.hpp
stubRoutines.cpp runtime.hpp
--- a/hotspot/src/share/vm/includeDB_core Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/includeDB_core Wed Jul 05 17:04:53 2017 +0200
@@ -289,7 +289,7 @@
attachListener.hpp debug.hpp
attachListener.hpp ostream.hpp
-barrierSet.cpp barrierSet.hpp
+barrierSet.cpp barrierSet.inline.hpp
barrierSet.cpp collectedHeap.hpp
barrierSet.cpp universe.hpp
@@ -570,6 +570,7 @@
ciEnv.hpp dependencies.hpp
ciEnv.hpp exceptionHandlerTable.hpp
ciEnv.hpp oopMap.hpp
+ciEnv.hpp systemDictionary.hpp
ciEnv.hpp thread.hpp
ciExceptionHandler.cpp ciExceptionHandler.hpp
@@ -1291,6 +1292,7 @@
cpCacheOop.cpp markSweep.inline.hpp
cpCacheOop.cpp objArrayOop.hpp
cpCacheOop.cpp oop.inline.hpp
+cpCacheOop.cpp rewriter.hpp
cpCacheOop.cpp universe.inline.hpp
cpCacheOop.hpp allocation.hpp
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -281,7 +281,7 @@
#define DO_BACKEDGE_CHECKS(skip, branch_pc) \
if ((skip) <= 0) { \
- if (UseCompiler && UseLoopCounter) { \
+ if (UseLoopCounter) { \
bool do_OSR = UseOnStackReplacement; \
BACKEDGE_COUNT->increment(); \
if (do_OSR) do_OSR = BACKEDGE_COUNT->reached_InvocationLimit(); \
@@ -289,16 +289,12 @@
nmethod* osr_nmethod; \
OSR_REQUEST(osr_nmethod, branch_pc); \
if (osr_nmethod != NULL && osr_nmethod->osr_entry_bci() != InvalidOSREntryBci) { \
- intptr_t* buf; \
- CALL_VM(buf=SharedRuntime::OSR_migration_begin(THREAD), handle_exception); \
+ intptr_t* buf = SharedRuntime::OSR_migration_begin(THREAD); \
istate->set_msg(do_osr); \
istate->set_osr_buf((address)buf); \
istate->set_osr_entry(osr_nmethod->osr_entry()); \
return; \
} \
- } else { \
- INCR_INVOCATION_COUNT; \
- SAFEPOINT; \
} \
} /* UseCompiler ... */ \
INCR_INVOCATION_COUNT; \
@@ -1281,12 +1277,7 @@
jfloat f;
jdouble r;
f = STACK_FLOAT(-1);
-#ifdef IA64
- // IA64 gcc bug
- r = ( f == 0.0f ) ? (jdouble) f : (jdouble) f + ia64_double_zero;
-#else
r = (jdouble) f;
-#endif
MORE_STACK(-1); // POP
SET_STACK_DOUBLE(r, 1);
UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);
--- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -282,18 +282,21 @@
constantPoolOop constants = method()->constants();
constantTag tag = constants->tag_at(i);
+ int nt_index = -1;
+
switch (tag.value()) {
case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_Methodref:
case JVM_CONSTANT_Fieldref:
+ case JVM_CONSTANT_NameAndType:
break;
default:
st->print_cr(" bad tag=%d at %d", tag.value(), i);
return;
}
- symbolOop name = constants->name_ref_at(orig_i);
- symbolOop signature = constants->signature_ref_at(orig_i);
+ symbolOop name = constants->uncached_name_ref_at(i);
+ symbolOop signature = constants->uncached_signature_ref_at(i);
st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string());
}
--- a/hotspot/src/share/vm/interpreter/interpreter.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/interpreter.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -314,6 +314,20 @@
break;
}
+ case Bytecodes::_invokedynamic: {
+ Thread *thread = Thread::current();
+ ResourceMark rm(thread);
+ methodHandle mh(thread, method);
+ type = Bytecode_invoke_at(mh, bci)->result_type(thread);
+ // since the cache entry might not be initialized:
+ // (NOT needed for the old calling convension)
+ if (!is_top_frame) {
+ int index = Bytes::get_native_u4(bcp+1);
+ method->constants()->cache()->entry_at(index)->set_parameter_size(callee_parameters);
+ }
+ break;
+ }
+
case Bytecodes::_ldc :
type = constant_pool_type( method, *(bcp+1) );
break;
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -681,7 +681,7 @@
IRT_END
-// First time execution: Resolve symbols, create a permanent CallSiteImpl object.
+// First time execution: Resolve symbols, create a permanent CallSite object.
IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
ResourceMark rm(thread);
@@ -708,21 +708,16 @@
constantPoolHandle pool(thread, caller_method->constants());
pool->set_invokedynamic(); // mark header to flag active call sites
- int raw_index = four_byte_index(thread);
- assert(constantPoolCacheOopDesc::is_secondary_index(raw_index), "invokedynamic indexes marked specially");
-
- // there are two CPC entries that are of interest:
- int site_index = constantPoolCacheOopDesc::decode_secondary_index(raw_index);
- int main_index = pool->cache()->entry_at(site_index)->main_entry_index();
- // and there is one CP entry, a NameAndType:
- int nt_index = pool->map_instruction_operand_to_index(raw_index);
+ int site_index = four_byte_index(thread);
+ // there is a second CPC entries that is of interest; it caches signature info:
+ int main_index = pool->cache()->secondary_entry_at(site_index)->main_entry_index();
// first resolve the signature to a MH.invoke methodOop
if (!pool->cache()->entry_at(main_index)->is_resolved(bytecode)) {
JvmtiHideSingleStepping jhss(thread);
CallInfo info;
LinkResolver::resolve_invoke(info, Handle(), pool,
- raw_index, bytecode, CHECK);
+ site_index, bytecode, CHECK);
// The main entry corresponds to a JVM_CONSTANT_NameAndType, and serves
// as a common reference point for all invokedynamic call sites with
// that exact call descriptor. We will link it in the CP cache exactly
@@ -741,7 +736,7 @@
assert(mh_invdyn.not_null() && mh_invdyn->is_method() && mh_invdyn->is_method_handle_invoke(),
"correct result from LinkResolver::resolve_invokedynamic");
- symbolHandle call_site_name(THREAD, pool->nt_name_ref_at(nt_index));
+ symbolHandle call_site_name(THREAD, pool->name_ref_at(site_index));
Handle call_site
= SystemDictionary::make_dynamic_call_site(caller_method->method_holder(),
caller_method->method_idnum(),
@@ -753,61 +748,11 @@
// In the secondary entry, the f1 field is the call site, and the f2 (index)
// field is some data about the invoke site.
int extra_data = 0;
- pool->cache()->entry_at(site_index)->set_dynamic_call(call_site(), extra_data);
+ pool->cache()->secondary_entry_at(site_index)->set_dynamic_call(call_site(), extra_data);
}
IRT_END
-// Called on first time execution, and also whenever the CallSite.target is null.
-// FIXME: Do more of this in Java code.
-IRT_ENTRY(void, InterpreterRuntime::bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site)) {
- methodHandle mh_invdyn(thread, (methodOop) sun_dyn_CallSiteImpl::vmmethod(call_site));
- Handle mh_type(thread, mh_invdyn->method_handle_type());
- objArrayHandle mh_ptypes(thread, java_dyn_MethodType::ptypes(mh_type()));
-
- // squish the arguments down to a single array
- int nargs = mh_ptypes->length();
- objArrayHandle arg_array;
- {
- objArrayOop aaoop = oopFactory::new_objArray(SystemDictionary::object_klass(), nargs, CHECK);
- arg_array = objArrayHandle(thread, aaoop);
- }
- frame fr = thread->last_frame();
- assert(fr.interpreter_frame_bcp() != NULL, "sanity");
- int tos_offset = 0;
- for (int i = nargs; --i >= 0; ) {
- intptr_t* slot_addr = fr.interpreter_frame_tos_at(tos_offset++);
- oop ptype = mh_ptypes->obj_at(i);
- oop arg = NULL;
- if (!java_lang_Class::is_primitive(ptype)) {
- arg = *(oop*) slot_addr;
- } else {
- BasicType bt = java_lang_Class::primitive_type(ptype);
- assert(frame::interpreter_frame_expression_stack_direction() < 0, "else reconsider this code");
- jvalue value;
- Interpreter::get_jvalue_in_slot(slot_addr, bt, &value);
- tos_offset += type2size[bt]-1;
- arg = java_lang_boxing_object::create(bt, &value, CHECK);
- // FIXME: These boxing objects are not canonicalized under
- // the Java autoboxing rules. They should be...
- // The best approach would be to push the arglist creation into Java.
- // The JVM should use a lower-level interface to communicate argument lists.
- }
- arg_array->obj_at_put(i, arg);
- }
-
- // now find the bootstrap method
- oop bootstrap_mh_oop = instanceKlass::cast(fr.interpreter_frame_method()->method_holder())->bootstrap_method();
- assert(bootstrap_mh_oop != NULL, "resolve_invokedynamic ensures a BSM");
-
- // return the bootstrap method and argument array via vm_result/_2
- thread->set_vm_result(bootstrap_mh_oop);
- thread->set_vm_result_2(arg_array());
-}
-IRT_END
-
-
-
//------------------------------------------------------------------------------------------------------------------------
// Miscellaneous
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -91,7 +91,6 @@
// Calls
static void resolve_invoke (JavaThread* thread, Bytecodes::Code bytecode);
static void resolve_invokedynamic(JavaThread* thread);
- static void bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site);
// Breakpoints
static void _breakpoint(JavaThread* thread, methodOopDesc* method, address bcp);
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1015,11 +1015,8 @@
// This guy is reached from InterpreterRuntime::resolve_invokedynamic.
- assert(constantPoolCacheOopDesc::is_secondary_index(raw_index), "must be secondary index");
- int nt_index = pool->map_instruction_operand_to_index(raw_index);
-
// At this point, we only need the signature, and can ignore the name.
- symbolHandle method_signature(THREAD, pool->nt_signature_ref_at(nt_index));
+ symbolHandle method_signature(THREAD, pool->signature_ref_at(raw_index)); // raw_index works directly
symbolHandle method_name = vmSymbolHandles::invoke_name();
KlassHandle resolved_klass = SystemDictionaryHandles::MethodHandle_klass();
--- a/hotspot/src/share/vm/interpreter/rewriter.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/rewriter.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -48,16 +48,6 @@
}
-int Rewriter::add_extra_cp_cache_entry(int main_entry) {
- // Hack: We put it on the map as an encoded value.
- // The only place that consumes this is ConstantPoolCacheEntry::set_initial_state
- int encoded = constantPoolCacheOopDesc::encode_secondary_index(main_entry);
- int plain_secondary_index = _cp_cache_map.append(encoded);
- return constantPoolCacheOopDesc::encode_secondary_index(plain_secondary_index);
-}
-
-
-
// Creates a constant pool cache given a CPC map
// This creates the constant pool cache initially in a state
// that is unsafe for concurrent GC processing but sets it to
@@ -127,7 +117,7 @@
assert(p[-1] == Bytecodes::_invokedynamic, "");
int cp_index = Bytes::get_Java_u2(p);
int cpc = maybe_add_cp_cache_entry(cp_index); // add lazily
- int cpc2 = add_extra_cp_cache_entry(cpc);
+ int cpc2 = add_secondary_cp_cache_entry(cpc);
// Replace the trailing four bytes with a CPC index for the dynamic
// call site. Unlike other CPC entries, there is one per bytecode,
@@ -137,7 +127,7 @@
// all these entries. That is the main reason invokedynamic
// must have a five-byte instruction format. (Of course, other JVM
// implementations can use the bytes for other purposes.)
- Bytes::put_native_u4(p, cpc2);
+ Bytes::put_native_u4(p, constantPoolCacheOopDesc::encode_secondary_index(cpc2));
// Note: We use native_u4 format exclusively for 4-byte indexes.
}
--- a/hotspot/src/share/vm/interpreter/rewriter.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/rewriter.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -43,13 +43,18 @@
bool has_cp_cache(int i) { return (uint)i < (uint)_cp_map.length() && _cp_map[i] >= 0; }
int maybe_add_cp_cache_entry(int i) { return has_cp_cache(i) ? _cp_map[i] : add_cp_cache_entry(i); }
int add_cp_cache_entry(int cp_index) {
+ assert((cp_index & _secondary_entry_tag) == 0, "bad tag");
assert(_cp_map[cp_index] == -1, "not twice on same cp_index");
int cache_index = _cp_cache_map.append(cp_index);
_cp_map.at_put(cp_index, cache_index);
assert(cp_entry_to_cp_cache(cp_index) == cache_index, "");
return cache_index;
}
- int add_extra_cp_cache_entry(int main_entry);
+ int add_secondary_cp_cache_entry(int main_cpc_entry) {
+ assert(main_cpc_entry < _cp_cache_map.length(), "must be earlier CP cache entry");
+ int cache_index = _cp_cache_map.append(main_cpc_entry | _secondary_entry_tag);
+ return cache_index;
+ }
// All the work goes in here:
Rewriter(instanceKlassHandle klass, TRAPS);
@@ -65,4 +70,8 @@
public:
// Driver routine:
static void rewrite(instanceKlassHandle klass, TRAPS);
+
+ enum {
+ _secondary_entry_tag = nth_bit(30)
+ };
};
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -178,14 +178,12 @@
#endif // !PRODUCT
EntryPoint TemplateInterpreter::_return_entry[TemplateInterpreter::number_of_return_entries];
EntryPoint TemplateInterpreter::_earlyret_entry;
-EntryPoint TemplateInterpreter::_return_unbox_entry;
EntryPoint TemplateInterpreter::_deopt_entry [TemplateInterpreter::number_of_deopt_entries ];
EntryPoint TemplateInterpreter::_continuation_entry;
EntryPoint TemplateInterpreter::_safept_entry;
address TemplateInterpreter::_return_3_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
address TemplateInterpreter::_return_5_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
-address TemplateInterpreter::_return_5_unbox_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
DispatchTable TemplateInterpreter::_active_table;
DispatchTable TemplateInterpreter::_normal_table;
@@ -253,22 +251,6 @@
}
}
- if (EnableInvokeDynamic) {
- CodeletMark cm(_masm, "unboxing return entry points");
- Interpreter::_return_unbox_entry =
- EntryPoint(
- generate_return_unbox_entry_for(btos, 5),
- generate_return_unbox_entry_for(ctos, 5),
- generate_return_unbox_entry_for(stos, 5),
- generate_return_unbox_entry_for(atos, 5), // cast conversion
- generate_return_unbox_entry_for(itos, 5),
- generate_return_unbox_entry_for(ltos, 5),
- generate_return_unbox_entry_for(ftos, 5),
- generate_return_unbox_entry_for(dtos, 5),
- Interpreter::_return_entry[5].entry(vtos) // no unboxing for void
- );
- }
-
{ CodeletMark cm(_masm, "earlyret entry points");
Interpreter::_earlyret_entry =
EntryPoint(
@@ -319,8 +301,6 @@
int index = Interpreter::TosState_as_index(states[j]);
Interpreter::_return_3_addrs_by_index[index] = Interpreter::return_entry(states[j], 3);
Interpreter::_return_5_addrs_by_index[index] = Interpreter::return_entry(states[j], 5);
- if (EnableInvokeDynamic)
- Interpreter::_return_5_unbox_addrs_by_index[index] = Interpreter::return_unbox_entry(states[j], 5);
}
{ CodeletMark cm(_masm, "continuation entry points");
@@ -485,9 +465,11 @@
void TemplateInterpreterGenerator::set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) {
assert(t->is_valid(), "template must exist");
switch (t->tos_in()) {
- case btos: vep = __ pc(); __ pop(btos); bep = __ pc(); generate_and_dispatch(t); break;
- case ctos: vep = __ pc(); __ pop(ctos); sep = __ pc(); generate_and_dispatch(t); break;
- case stos: vep = __ pc(); __ pop(stos); sep = __ pc(); generate_and_dispatch(t); break;
+ case btos:
+ case ctos:
+ case stos:
+ ShouldNotReachHere(); // btos/ctos/stos should use itos.
+ break;
case atos: vep = __ pc(); __ pop(atos); aep = __ pc(); generate_and_dispatch(t); break;
case itos: vep = __ pc(); __ pop(itos); iep = __ pc(); generate_and_dispatch(t); break;
case ltos: vep = __ pc(); __ pop(ltos); lep = __ pc(); generate_and_dispatch(t); break;
@@ -547,18 +529,6 @@
}
-address TemplateInterpreter::return_unbox_entry(TosState state, int length) {
- assert(EnableInvokeDynamic, "");
- if (state == vtos) {
- // no unboxing to do, actually
- return return_entry(state, length);
- } else {
- assert(length == 5, "unboxing entries generated for invokedynamic only");
- return _return_unbox_entry.entry(state);
- }
-}
-
-
address TemplateInterpreter::deopt_entry(TosState state, int length) {
guarantee(0 <= length && length < Interpreter::number_of_deopt_entries, "illegal length");
return _deopt_entry[length].entry(state);
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -110,14 +110,12 @@
#endif // !PRODUCT
static EntryPoint _return_entry[number_of_return_entries]; // entry points to return to from a call
static EntryPoint _earlyret_entry; // entry point to return early from a call
- static EntryPoint _return_unbox_entry; // entry point to unbox a return value from a call
static EntryPoint _deopt_entry[number_of_deopt_entries]; // entry points to return to from a deoptimization
static EntryPoint _continuation_entry;
static EntryPoint _safept_entry;
static address _return_3_addrs_by_index[number_of_return_addrs]; // for invokevirtual return entries
static address _return_5_addrs_by_index[number_of_return_addrs]; // for invokeinterface return entries
- static address _return_5_unbox_addrs_by_index[number_of_return_addrs]; // for invokedynamic bootstrap methods
static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch)
static DispatchTable _normal_table; // the normal dispatch table (used to set the active table in normal mode)
@@ -159,12 +157,10 @@
// Support for invokes
static address* return_3_addrs_by_index_table() { return _return_3_addrs_by_index; }
static address* return_5_addrs_by_index_table() { return _return_5_addrs_by_index; }
- static address* return_5_unbox_addrs_by_index_table() { return _return_5_unbox_addrs_by_index; }
static int TosState_as_index(TosState state); // computes index into return_3_entry_by_index table
static address return_entry (TosState state, int length);
static address deopt_entry (TosState state, int length);
- static address return_unbox_entry(TosState state, int length);
// Safepoint support
static void notice_safepoints(); // stops the thread when reaching a safepoint
--- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -51,10 +51,7 @@
address generate_WrongMethodType_handler();
address generate_ArrayIndexOutOfBounds_handler(const char* name);
address generate_continuation_for(TosState state);
- address generate_return_entry_for(TosState state, int step, bool unbox = false);
- address generate_return_unbox_entry_for(TosState state, int step) {
- return generate_return_entry_for(state, step, true);
- }
+ address generate_return_entry_for(TosState state, int step);
address generate_earlyret_entry_for(TosState state);
address generate_deopt_entry_for(TosState state, int step);
address generate_safept_entry_for(TosState state, address runtime_entry);
--- a/hotspot/src/share/vm/memory/barrierSet.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/memory/barrierSet.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -41,11 +41,6 @@
// count is number of array elements being written
void BarrierSet::static_write_ref_array_post(HeapWord* start, size_t count) {
- assert(count <= (size_t)max_intx, "count too large");
- HeapWord* end = start + objArrayOopDesc::array_size((int)count);
-#if 0
- warning("Post:\t" INTPTR_FORMAT "[" SIZE_FORMAT "] : [" INTPTR_FORMAT","INTPTR_FORMAT")\t",
- start, count, start, end);
-#endif
- Universe::heap()->barrier_set()->write_ref_array_work(MemRegion(start, end));
+ // simply delegate to instance method
+ Universe::heap()->barrier_set()->write_ref_array(start, count);
}
--- a/hotspot/src/share/vm/memory/barrierSet.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/memory/barrierSet.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -121,17 +121,20 @@
virtual void read_ref_array(MemRegion mr) = 0;
virtual void read_prim_array(MemRegion mr) = 0;
+ // Below length is the # array elements being written
virtual void write_ref_array_pre( oop* dst, int length) {}
virtual void write_ref_array_pre(narrowOop* dst, int length) {}
+ // Below MemRegion mr is expected to be HeapWord-aligned
inline void write_ref_array(MemRegion mr);
+ // Below count is the # array elements being written, starting
+ // at the address "start", which may not necessarily be HeapWord-aligned
+ inline void write_ref_array(HeapWord* start, size_t count);
- // Static versions, suitable for calling from generated code.
+ // Static versions, suitable for calling from generated code;
+ // count is # array elements being written, starting with "start",
+ // which may not necessarily be HeapWord-aligned.
static void static_write_ref_array_pre(HeapWord* start, size_t count);
static void static_write_ref_array_post(HeapWord* start, size_t count);
- // Narrow oop versions of the above; count is # of array elements being written,
- // starting with "start", which is HeapWord-aligned.
- static void static_write_ref_array_pre_narrow(HeapWord* start, size_t count);
- static void static_write_ref_array_post_narrow(HeapWord* start, size_t count);
protected:
virtual void write_ref_array_work(MemRegion mr) = 0;
--- a/hotspot/src/share/vm/memory/barrierSet.inline.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/memory/barrierSet.inline.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -43,6 +43,8 @@
}
void BarrierSet::write_ref_array(MemRegion mr) {
+ assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start() , "Unaligned start");
+ assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" );
if (kind() == CardTableModRef) {
((CardTableModRefBS*)this)->inline_write_ref_array(mr);
} else {
@@ -50,6 +52,34 @@
}
}
+// count is number of array elements being written
+void BarrierSet::write_ref_array(HeapWord* start, size_t count) {
+ assert(count <= (size_t)max_intx, "count too large");
+ HeapWord* end = (HeapWord*)((char*)start + (count*heapOopSize));
+ // In the case of compressed oops, start and end may potentially be misaligned;
+ // so we need to conservatively align the first downward (this is not
+ // strictly necessary for current uses, but a case of good hygiene and,
+ // if you will, aesthetics) and the second upward (this is essential for
+ // current uses) to a HeapWord boundary, so we mark all cards overlapping
+ // this write. In the event that this evolves in the future to calling a
+ // logging barrier of narrow oop granularity, like the pre-barrier for G1
+ // (mentioned here merely by way of example), we will need to change this
+ // interface, much like the pre-barrier one above, so it is "exactly precise"
+ // (if i may be allowed the adverbial redundancy for emphasis) and does not
+ // include narrow oop slots not included in the original write interval.
+ HeapWord* aligned_start = (HeapWord*)align_size_down((uintptr_t)start, HeapWordSize);
+ HeapWord* aligned_end = (HeapWord*)align_size_up ((uintptr_t)end, HeapWordSize);
+ // If compressed oops were not being used, these should already be aligned
+ assert(UseCompressedOops || (aligned_start == start && aligned_end == end),
+ "Expected heap word alignment of start and end");
+#if 0
+ warning("Post:\t" INTPTR_FORMAT "[" SIZE_FORMAT "] : [" INTPTR_FORMAT","INTPTR_FORMAT")\t",
+ start, count, aligned_start, aligned_end);
+#endif
+ write_ref_array_work(MemRegion(aligned_start, aligned_end));
+}
+
+
void BarrierSet::write_region(MemRegion mr) {
if (kind() == CardTableModRef) {
((CardTableModRefBS*)this)->inline_write_region(mr);
--- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -511,6 +511,8 @@
}
void CardTableModRefBS::dirty_MemRegion(MemRegion mr) {
+ assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start");
+ assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" );
jbyte* cur = byte_for(mr.start());
jbyte* last = byte_after(mr.last());
while (cur < last) {
@@ -520,6 +522,8 @@
}
void CardTableModRefBS::invalidate(MemRegion mr, bool whole_heap) {
+ assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start");
+ assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" );
for (int i = 0; i < _cur_covered_regions; i++) {
MemRegion mri = mr.intersection(_covered[i]);
if (!mri.is_empty()) dirty_MemRegion(mri);
--- a/hotspot/src/share/vm/memory/collectorPolicy.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -55,7 +55,7 @@
void CollectorPolicy::initialize_size_info() {
// User inputs from -mx and ms are aligned
- set_initial_heap_byte_size(Arguments::initial_heap_size());
+ set_initial_heap_byte_size(InitialHeapSize);
if (initial_heap_byte_size() == 0) {
set_initial_heap_byte_size(NewSize + OldSize);
}
--- a/hotspot/src/share/vm/memory/heap.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/memory/heap.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -464,7 +464,7 @@
}
// Verify that freelist contains the right amount of free space
- guarantee(len == _free_segments, "wrong freelist");
+ // guarantee(len == _free_segments, "wrong freelist");
// Verify that the number of free blocks is not out of hand.
static int free_block_threshold = 10000;
@@ -479,5 +479,5 @@
for(HeapBlock *h = first_block(); h != NULL; h = next_block(h)) {
if (h->free()) count--;
}
- guarantee(count == 0, "missing free blocks");
+ // guarantee(count == 0, "missing free blocks");
}
--- a/hotspot/src/share/vm/memory/referenceProcessor.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/memory/referenceProcessor.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -299,8 +299,8 @@
template <class T>
-static bool enqueue_discovered_ref_helper(ReferenceProcessor* ref,
- AbstractRefProcTaskExecutor* task_executor) {
+bool enqueue_discovered_ref_helper(ReferenceProcessor* ref,
+ AbstractRefProcTaskExecutor* task_executor) {
// Remember old value of pending references list
T* pending_list_addr = (T*)java_lang_ref_Reference::pending_list_addr();
--- a/hotspot/src/share/vm/memory/sharedHeap.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/memory/sharedHeap.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -224,10 +224,6 @@
CodeBlobClosure* code_roots,
OopClosure* non_root_closure);
-
- // Like CollectedHeap::collect, but assume that the caller holds the Heap_lock.
- virtual void collect_locked(GCCause::Cause cause) = 0;
-
// The functions below are helper functions that a subclass of
// "SharedHeap" can use in the implementation of its virtual
// functions.
--- a/hotspot/src/share/vm/memory/universe.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/memory/universe.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -67,6 +67,8 @@
objArrayOop Universe::_the_empty_system_obj_array = NULL;
objArrayOop Universe::_the_empty_class_klass_array = NULL;
objArrayOop Universe::_the_array_interfaces_array = NULL;
+oop Universe::_the_null_string = NULL;
+oop Universe::_the_min_jint_string = NULL;
LatestMethodOopCache* Universe::_finalizer_register_cache = NULL;
LatestMethodOopCache* Universe::_loader_addClass_cache = NULL;
ActiveMethodOopsCache* Universe::_reflect_invoke_cache = NULL;
@@ -187,6 +189,8 @@
f->do_oop((oop*)&_the_empty_system_obj_array);
f->do_oop((oop*)&_the_empty_class_klass_array);
f->do_oop((oop*)&_the_array_interfaces_array);
+ f->do_oop((oop*)&_the_null_string);
+ f->do_oop((oop*)&_the_min_jint_string);
_finalizer_register_cache->oops_do(f);
_loader_addClass_cache->oops_do(f);
_reflect_invoke_cache->oops_do(f);
@@ -289,6 +293,9 @@
klassOop ok = SystemDictionary::object_klass();
+ _the_null_string = StringTable::intern("null", CHECK);
+ _the_min_jint_string = StringTable::intern("-2147483648", CHECK);
+
if (UseSharedSpaces) {
// Verify shared interfaces array.
assert(_the_array_interfaces_array->obj_at(0) ==
@@ -744,22 +751,22 @@
static const uint64_t OopEncodingHeapMax = NarrowOopHeapMax << LogMinObjAlignmentInBytes;
char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) {
+ size_t base = 0;
#ifdef _LP64
if (UseCompressedOops) {
assert(mode == UnscaledNarrowOop ||
mode == ZeroBasedNarrowOop ||
mode == HeapBasedNarrowOop, "mode is invalid");
+ const size_t total_size = heap_size + HeapBaseMinAddress;
// Return specified base for the first request.
if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) {
- return (char*)HeapBaseMinAddress;
- }
- const size_t total_size = heap_size + HeapBaseMinAddress;
- if (total_size <= OopEncodingHeapMax && (mode != HeapBasedNarrowOop)) {
+ base = HeapBaseMinAddress;
+ } else if (total_size <= OopEncodingHeapMax && (mode != HeapBasedNarrowOop)) {
if (total_size <= NarrowOopHeapMax && (mode == UnscaledNarrowOop) &&
(Universe::narrow_oop_shift() == 0)) {
// Use 32-bits oops without encoding and
// place heap's top on the 4Gb boundary
- return (char*)(NarrowOopHeapMax - heap_size);
+ base = (NarrowOopHeapMax - heap_size);
} else {
// Can't reserve with NarrowOopShift == 0
Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
@@ -768,16 +775,38 @@
// Use zero based compressed oops with encoding and
// place heap's top on the 32Gb boundary in case
// total_size > 4Gb or failed to reserve below 4Gb.
- return (char*)(OopEncodingHeapMax - heap_size);
+ base = (OopEncodingHeapMax - heap_size);
}
}
} else {
// Can't reserve below 32Gb.
Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
}
+ // Set narrow_oop_base and narrow_oop_use_implicit_null_checks
+ // used in ReservedHeapSpace() constructors.
+ // The final values will be set in initialize_heap() below.
+ if (base != 0 && (base + heap_size) <= OopEncodingHeapMax) {
+ // Use zero based compressed oops
+ Universe::set_narrow_oop_base(NULL);
+ // Don't need guard page for implicit checks in indexed
+ // addressing mode with zero based Compressed Oops.
+ Universe::set_narrow_oop_use_implicit_null_checks(true);
+ } else {
+ // Set to a non-NULL value so the ReservedSpace ctor computes
+ // the correct no-access prefix.
+ // The final value will be set in initialize_heap() below.
+ Universe::set_narrow_oop_base((address)NarrowOopHeapMax);
+#ifdef _WIN64
+ if (UseLargePages) {
+ // Cannot allocate guard pages for implicit checks in indexed
+ // addressing mode when large pages are specified on windows.
+ Universe::set_narrow_oop_use_implicit_null_checks(false);
+ }
+#endif // _WIN64
+ }
}
#endif
- return NULL; // also return NULL (don't care) for 32-bit VM
+ return (char*)base; // also return NULL (don't care) for 32-bit VM
}
jint Universe::initialize_heap() {
--- a/hotspot/src/share/vm/memory/universe.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/memory/universe.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -169,6 +169,8 @@
static objArrayOop _the_empty_system_obj_array; // Canonicalized system obj array
static objArrayOop _the_empty_class_klass_array; // Canonicalized obj array of type java.lang.Class
static objArrayOop _the_array_interfaces_array; // Canonicalized 2-array of cloneable & serializable klasses
+ static oop _the_null_string; // A cache of "null" as a Java string
+ static oop _the_min_jint_string; // A cache of "-2147483648" as a Java string
static LatestMethodOopCache* _finalizer_register_cache; // static method for registering finalizable objects
static LatestMethodOopCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector
static ActiveMethodOopsCache* _reflect_invoke_cache; // method for security checks
@@ -310,6 +312,8 @@
static objArrayOop the_empty_system_obj_array () { return _the_empty_system_obj_array; }
static objArrayOop the_empty_class_klass_array () { return _the_empty_class_klass_array; }
static objArrayOop the_array_interfaces_array() { return _the_array_interfaces_array; }
+ static oop the_null_string() { return _the_null_string; }
+ static oop the_min_jint_string() { return _the_min_jint_string; }
static methodOop finalizer_register_method() { return _finalizer_register_cache->get_methodOop(); }
static methodOop loader_addClass_method() { return _loader_addClass_cache->get_methodOop(); }
static ActiveMethodOopsCache* reflect_invoke_cache() { return _reflect_invoke_cache; }
--- a/hotspot/src/share/vm/oops/constantPoolOop.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -262,25 +262,48 @@
int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncached) {
- jint ref_index = field_or_method_at(which, uncached);
+ int i = which;
+ if (!uncached && cache() != NULL) {
+ if (constantPoolCacheOopDesc::is_secondary_index(which))
+ // Invokedynamic indexes are always processed in native order
+ // so there is no question of reading a native u2 in Java order here.
+ return cache()->main_entry_at(which)->constant_pool_index();
+ // change byte-ordering and go via cache
+ i = remap_instruction_operand_from_cache(which);
+ } else {
+ if (tag_at(which).is_name_and_type())
+ // invokedynamic index is a simple name-and-type
+ return which;
+ }
+ assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
+ jint ref_index = *int_at_addr(i);
return extract_high_short_from_int(ref_index);
}
int constantPoolOopDesc::impl_klass_ref_index_at(int which, bool uncached) {
- jint ref_index = field_or_method_at(which, uncached);
+ guarantee(!constantPoolCacheOopDesc::is_secondary_index(which),
+ "an invokedynamic instruction does not have a klass");
+ int i = which;
+ if (!uncached && cache() != NULL) {
+ // change byte-ordering and go via cache
+ i = remap_instruction_operand_from_cache(which);
+ }
+ assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
+ jint ref_index = *int_at_addr(i);
return extract_low_short_from_int(ref_index);
}
-int constantPoolOopDesc::map_instruction_operand_to_index(int operand) {
- if (constantPoolCacheOopDesc::is_secondary_index(operand)) {
- return cache()->main_entry_at(operand)->constant_pool_index();
- }
+int constantPoolOopDesc::remap_instruction_operand_from_cache(int operand) {
+ // Operand was fetched by a stream using get_Java_u2, yet was stored
+ // by Rewriter::rewrite_member_reference in native order.
+ // So now we have to fix the damage by swapping back to native order.
assert((int)(u2)operand == operand, "clean u2");
- int index = Bytes::swap_u2(operand);
- return cache()->entry_at(index)->constant_pool_index();
+ int cpc_index = Bytes::swap_u2(operand);
+ int member_index = cache()->entry_at(cpc_index)->constant_pool_index();
+ return member_index;
}
--- a/hotspot/src/share/vm/oops/constantPoolOop.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -342,12 +342,14 @@
}
// The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve,
- // name_and_type_ref_index_at) all expect constant pool indices
- // from the bytecodes to be passed in, which are actually potentially byte-swapped
- // or rewritten constant pool cache indices. They all call map_instruction_operand_to_index.
- int map_instruction_operand_to_index(int operand);
+ // name_and_type_ref_index_at) all expect to be passed indices obtained
+ // directly from the bytecode, and extracted according to java byte order.
+ // If the indices are meant to refer to fields or methods, they are
+ // actually potentially byte-swapped, rewritten constant pool cache indices.
+ // The routine remap_instruction_operand_from_cache manages the adjustment
+ // of these values back to constant pool indices.
- // There are also "uncached" versions which do not map the operand index; see below.
+ // There are also "uncached" versions which do not adjust the operand index; see below.
// Lookup for entries consisting of (klass_index, name_and_type index)
klassOop klass_ref_at(int which, TRAPS);
@@ -361,8 +363,6 @@
// Lookup for entries consisting of (name_index, signature_index)
int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt)
int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt)
- symbolOop nt_name_ref_at(int which_nt) { return symbol_at(name_ref_index_at(which_nt)); }
- symbolOop nt_signature_ref_at(int which_nt) { return symbol_at(signature_ref_index_at(which_nt)); }
BasicType basic_type_for_signature_at(int which);
@@ -425,18 +425,7 @@
int impl_klass_ref_index_at(int which, bool uncached);
int impl_name_and_type_ref_index_at(int which, bool uncached);
- // Takes either a constant pool cache index in possibly byte-swapped
- // byte order (which comes from the bytecodes after rewriting) or,
- // if "uncached" is true, a vanilla constant pool index
- jint field_or_method_at(int which, bool uncached) {
- int i = which;
- if (!uncached && cache() != NULL) {
- // change byte-ordering and go via cache
- i = map_instruction_operand_to_index(which);
- }
- assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
- return *int_at_addr(i);
- }
+ int remap_instruction_operand_from_cache(int operand);
// Used while constructing constant pool (only by ClassFileParser)
jint klass_index_at(int which) {
--- a/hotspot/src/share/vm/oops/cpCacheOop.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/cpCacheOop.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -28,21 +28,17 @@
// Implememtation of ConstantPoolCacheEntry
-void ConstantPoolCacheEntry::set_initial_state(int index) {
- if (constantPoolCacheOopDesc::is_secondary_index(index)) {
- // Hack: The rewriter is trying to say that this entry itself
- // will be a secondary entry.
- int main_index = constantPoolCacheOopDesc::decode_secondary_index(index);
- assert(0 <= main_index && main_index < 0x10000, "sanity check");
- _indices = (main_index << 16);
- assert(main_entry_index() == main_index, "");
- return;
- }
+void ConstantPoolCacheEntry::initialize_entry(int index) {
assert(0 < index && index < 0x10000, "sanity check");
_indices = index;
assert(constant_pool_index() == index, "");
}
+void ConstantPoolCacheEntry::initialize_secondary_entry(int main_index) {
+ assert(0 <= main_index && main_index < 0x10000, "sanity check");
+ _indices = (main_index << 16);
+ assert(main_entry_index() == main_index, "");
+}
int ConstantPoolCacheEntry::as_flags(TosState state, bool is_final,
bool is_vfinal, bool is_volatile,
@@ -223,10 +219,10 @@
void ConstantPoolCacheEntry::set_dynamic_call(Handle call_site, int extra_data) {
- methodOop method = (methodOop) sun_dyn_CallSiteImpl::vmmethod(call_site());
+ methodOop method = (methodOop) java_dyn_CallSite::vmmethod(call_site());
assert(method->is_method(), "must be initialized properly");
int param_size = method->size_of_parameters();
- assert(param_size > 1, "method argument size must include MH.this & initial dynamic receiver");
+ assert(param_size >= 1, "method argument size must include MH.this");
param_size -= 1; // do not count MH.this; it is not stacked for invokedynamic
if (Atomic::cmpxchg_ptr(call_site(), &_f1, NULL) == NULL) {
// racing threads might be trying to install their own favorites
@@ -439,7 +435,18 @@
void constantPoolCacheOopDesc::initialize(intArray& inverse_index_map) {
assert(inverse_index_map.length() == length(), "inverse index map must have same length as cache");
- for (int i = 0; i < length(); i++) entry_at(i)->set_initial_state(inverse_index_map[i]);
+ for (int i = 0; i < length(); i++) {
+ ConstantPoolCacheEntry* e = entry_at(i);
+ int original_index = inverse_index_map[i];
+ if ((original_index & Rewriter::_secondary_entry_tag) != 0) {
+ int main_index = (original_index - Rewriter::_secondary_entry_tag);
+ assert(!entry_at(main_index)->is_secondary_entry(), "valid main index");
+ e->initialize_secondary_entry(main_index);
+ } else {
+ e->initialize_entry(original_index);
+ }
+ assert(entry_at(i) == e, "sanity");
+ }
}
// RedefineClasses() API support:
--- a/hotspot/src/share/vm/oops/cpCacheOop.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -154,7 +154,8 @@
};
// Initialization
- void set_initial_state(int index); // sets entry to initial state
+ void initialize_entry(int original_index); // initialize primary entry
+ void initialize_secondary_entry(int main_index); // initialize secondary entry
void set_field( // sets entry to resolved field state
Bytecodes::Code get_code, // the bytecode used for reading the field
@@ -251,6 +252,7 @@
// Code generation support
static WordSize size() { return in_WordSize(sizeof(ConstantPoolCacheEntry) / HeapWordSize); }
+ static ByteSize size_in_bytes() { return in_ByteSize(sizeof(ConstantPoolCacheEntry)); }
static ByteSize indices_offset() { return byte_offset_of(ConstantPoolCacheEntry, _indices); }
static ByteSize f1_offset() { return byte_offset_of(ConstantPoolCacheEntry, _f1); }
static ByteSize f2_offset() { return byte_offset_of(ConstantPoolCacheEntry, _f2); }
@@ -321,6 +323,7 @@
ConstantPoolCacheEntry* base() const { return (ConstantPoolCacheEntry*)((address)this + in_bytes(base_offset())); }
friend class constantPoolCacheKlass;
+ friend class ConstantPoolCacheEntry;
public:
// Initialization
@@ -329,7 +332,8 @@
// Secondary indexes.
// They must look completely different from normal indexes.
// The main reason is that byte swapping is sometimes done on normal indexes.
- // Also, it is helpful for debugging to tell the two apart.
+ // Also, some of the CP accessors do different things for secondary indexes.
+ // Finally, it is helpful for debugging to tell the two apart.
static bool is_secondary_index(int i) { return (i < 0); }
static int decode_secondary_index(int i) { assert(is_secondary_index(i), ""); return ~i; }
static int encode_secondary_index(int i) { assert(!is_secondary_index(i), ""); return ~i; }
@@ -337,18 +341,35 @@
// Accessors
void set_constant_pool(constantPoolOop pool) { oop_store_without_check((oop*)&_constant_pool, (oop)pool); }
constantPoolOop constant_pool() const { return _constant_pool; }
- ConstantPoolCacheEntry* entry_at(int i) const { assert(0 <= i && i < length(), "index out of bounds"); return base() + i; }
+ // Fetches the entry at the given index.
+ // The entry may be either primary or secondary.
+ // In either case the index must not be encoded or byte-swapped in any way.
+ ConstantPoolCacheEntry* entry_at(int i) const {
+ assert(0 <= i && i < length(), "index out of bounds");
+ return base() + i;
+ }
+ // Fetches the secondary entry referred to by index.
+ // The index may be a secondary index, and must not be byte-swapped.
+ ConstantPoolCacheEntry* secondary_entry_at(int i) const {
+ int raw_index = i;
+ if (is_secondary_index(i)) { // correct these on the fly
+ raw_index = decode_secondary_index(i);
+ }
+ assert(entry_at(raw_index)->is_secondary_entry(), "not a secondary entry");
+ return entry_at(raw_index);
+ }
+ // Given a primary or secondary index, fetch the corresponding primary entry.
+ // Indirect through the secondary entry, if the index is encoded as a secondary index.
+ // The index must not be byte-swapped.
ConstantPoolCacheEntry* main_entry_at(int i) const {
- ConstantPoolCacheEntry* e;
+ int primary_index = i;
if (is_secondary_index(i)) {
// run through an extra level of indirection:
- i = decode_secondary_index(i);
- e = entry_at(i);
- i = e->main_entry_index();
+ int raw_index = decode_secondary_index(i);
+ primary_index = entry_at(raw_index)->main_entry_index();
}
- e = entry_at(i);
- assert(!e->is_secondary_entry(), "only one level of indirection");
- return e;
+ assert(!entry_at(primary_index)->is_secondary_entry(), "only one level of indirection");
+ return entry_at(primary_index);
}
// GC support
@@ -359,6 +380,12 @@
// Code generation
static ByteSize base_offset() { return in_ByteSize(sizeof(constantPoolCacheOopDesc)); }
+ static ByteSize entry_offset(int raw_index) {
+ int index = raw_index;
+ if (is_secondary_index(raw_index))
+ index = decode_secondary_index(raw_index);
+ return (base_offset() + ConstantPoolCacheEntry::size_in_bytes() * index);
+ }
// RedefineClasses() API support:
// If any entry of this constantPoolCache points to any of
--- a/hotspot/src/share/vm/oops/generateOopMap.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/generateOopMap.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1556,13 +1556,13 @@
case Bytecodes::_getfield: do_field(true, false, itr->get_index_big(), itr->bci()); break;
case Bytecodes::_putfield: do_field(false, false, itr->get_index_big(), itr->bci()); break;
- case Bytecodes::_invokevirtual:
- case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_big(), itr->bci()); break;
- case Bytecodes::_invokestatic: do_method(true, false, itr->get_index_big(), itr->bci()); break;
- case Bytecodes::_invokedynamic: do_method(false, true, itr->get_index_int(), itr->bci()); break;
- case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_big(), itr->bci()); break;
- case Bytecodes::_newarray:
- case Bytecodes::_anewarray: pp_new_ref(vCTS, itr->bci()); break;
+ case Bytecodes::_invokevirtual:
+ case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_big(), itr->bci()); break;
+ case Bytecodes::_invokestatic: do_method(true, false, itr->get_index_big(), itr->bci()); break;
+ case Bytecodes::_invokedynamic: do_method(true, false, itr->get_index_int(), itr->bci()); break;
+ case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_big(), itr->bci()); break;
+ case Bytecodes::_newarray:
+ case Bytecodes::_anewarray: pp_new_ref(vCTS, itr->bci()); break;
case Bytecodes::_checkcast: do_checkcast(); break;
case Bytecodes::_arraylength:
case Bytecodes::_instanceof: pp(rCTS, vCTS); break;
@@ -1900,11 +1900,9 @@
}
void GenerateOopMap::do_method(int is_static, int is_interface, int idx, int bci) {
- // Dig up signature for field in constant pool
- constantPoolOop cp = _method->constants();
- int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx);
- int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx); // @@@@@
- symbolOop signature = cp->symbol_at(signatureIdx);
+ // Dig up signature for field in constant pool
+ constantPoolOop cp = _method->constants();
+ symbolOop signature = cp->signature_ref_at(idx);
// Parse method signature
CellTypeState out[4];
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -2045,8 +2045,9 @@
// As we walk along, look for equalities between outer1 and class2.
// Eventually, the walks will terminate as outer1 stops
// at the top-level class around the original class.
- symbolOop ignore_name;
- klassOop next = outer1->compute_enclosing_class(ignore_name, CHECK_false);
+ bool ignore_inner_is_member;
+ klassOop next = outer1->compute_enclosing_class(&ignore_inner_is_member,
+ CHECK_false);
if (next == NULL) break;
if (next == class2()) return true;
outer1 = instanceKlassHandle(THREAD, next);
@@ -2055,8 +2056,9 @@
// Now do the same for class2.
instanceKlassHandle outer2 = class2;
for (;;) {
- symbolOop ignore_name;
- klassOop next = outer2->compute_enclosing_class(ignore_name, CHECK_false);
+ bool ignore_inner_is_member;
+ klassOop next = outer2->compute_enclosing_class(&ignore_inner_is_member,
+ CHECK_false);
if (next == NULL) break;
// Might as well check the new outer against all available values.
if (next == class1()) return true;
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -337,12 +337,12 @@
static bool is_same_class_package(oop class_loader1, symbolOop class_name1, oop class_loader2, symbolOop class_name2);
// find an enclosing class (defined where original code was, in jvm.cpp!)
- klassOop compute_enclosing_class(symbolOop& simple_name_result, TRAPS) {
+ klassOop compute_enclosing_class(bool* inner_is_member, TRAPS) {
instanceKlassHandle self(THREAD, this->as_klassOop());
- return compute_enclosing_class_impl(self, simple_name_result, THREAD);
+ return compute_enclosing_class_impl(self, inner_is_member, THREAD);
}
static klassOop compute_enclosing_class_impl(instanceKlassHandle self,
- symbolOop& simple_name_result, TRAPS);
+ bool* inner_is_member, TRAPS);
// tell if two classes have the same enclosing class (at package level)
bool is_same_package_member(klassOop class2, TRAPS) {
--- a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -317,6 +317,11 @@
pm->claim_or_forward_breadth(sg_addr);
}
+ oop* bsm_addr = ik->adr_bootstrap_method();
+ if (PSScavenge::should_scavenge(bsm_addr)) {
+ pm->claim_or_forward_breadth(bsm_addr);
+ }
+
klassKlass::oop_copy_contents(pm, obj);
}
@@ -345,6 +350,11 @@
pm->claim_or_forward_depth(sg_addr);
}
+ oop* bsm_addr = ik->adr_bootstrap_method();
+ if (PSScavenge::should_scavenge(bsm_addr)) {
+ pm->claim_or_forward_depth(bsm_addr);
+ }
+
klassKlass::oop_copy_contents(pm, obj);
}
--- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -78,9 +78,9 @@
#ifndef SERIALGC
template <class T>
-static void specialized_oop_follow_contents(instanceRefKlass* ref,
- ParCompactionManager* cm,
- oop obj) {
+void specialized_oop_follow_contents(instanceRefKlass* ref,
+ ParCompactionManager* cm,
+ oop obj) {
T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj);
T heap_oop = oopDesc::load_heap_oop(referent_addr);
debug_only(
--- a/hotspot/src/share/vm/oops/objArrayKlass.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -127,16 +127,14 @@
// pointer delta is scaled to number of elements (length field in
// objArrayOop) which we assume is 32 bit.
assert(pd == (size_t)(int)pd, "length field overflow");
- const size_t done_word_len = objArrayOopDesc::array_size((int)pd);
- bs->write_ref_array(MemRegion((HeapWord*)dst, done_word_len));
+ bs->write_ref_array((HeapWord*)dst, pd);
THROW(vmSymbols::java_lang_ArrayStoreException());
return;
}
}
}
}
- const size_t word_len = objArrayOopDesc::array_size(length);
- bs->write_ref_array(MemRegion((HeapWord*)dst, word_len));
+ bs->write_ref_array((HeapWord*)dst, length);
}
void objArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,
--- a/hotspot/src/share/vm/oops/objArrayOop.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/objArrayOop.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -37,6 +37,32 @@
return &((T*)base())[index];
}
+private:
+ // Give size of objArrayOop in HeapWords minus the header
+ static int array_size(int length) {
+ const int OopsPerHeapWord = HeapWordSize/heapOopSize;
+ assert(OopsPerHeapWord >= 1 && (HeapWordSize % heapOopSize == 0),
+ "Else the following (new) computation would be in error");
+#ifdef ASSERT
+ // The old code is left in for sanity-checking; it'll
+ // go away pretty soon. XXX
+ // Without UseCompressedOops, this is simply:
+ // oop->length() * HeapWordsPerOop;
+ // With narrowOops, HeapWordsPerOop is 1/2 or equal 0 as an integer.
+ // The oop elements are aligned up to wordSize
+ const int HeapWordsPerOop = heapOopSize/HeapWordSize;
+ int old_res;
+ if (HeapWordsPerOop > 0) {
+ old_res = length * HeapWordsPerOop;
+ } else {
+ old_res = align_size_up(length, OopsPerHeapWord)/OopsPerHeapWord;
+ }
+#endif // ASSERT
+ int res = ((uint)length + OopsPerHeapWord - 1)/OopsPerHeapWord;
+ assert(res == old_res, "Inconsistency between old and new.");
+ return res;
+ }
+
public:
// Returns the offset of the first element.
static int base_offset_in_bytes() {
@@ -67,27 +93,14 @@
// Sizing
static int header_size() { return arrayOopDesc::header_size(T_OBJECT); }
int object_size() { return object_size(length()); }
- int array_size() { return array_size(length()); }
static int object_size(int length) {
// This returns the object size in HeapWords.
- return align_object_size(header_size() + array_size(length));
- }
-
- // Give size of objArrayOop in HeapWords minus the header
- static int array_size(int length) {
- // Without UseCompressedOops, this is simply:
- // oop->length() * HeapWordsPerOop;
- // With narrowOops, HeapWordsPerOop is 1/2 or equal 0 as an integer.
- // The oop elements are aligned up to wordSize
- const int HeapWordsPerOop = heapOopSize/HeapWordSize;
- if (HeapWordsPerOop > 0) {
- return length * HeapWordsPerOop;
- } else {
- const int OopsPerHeapWord = HeapWordSize/heapOopSize;
- int word_len = align_size_up(length, OopsPerHeapWord)/OopsPerHeapWord;
- return word_len;
- }
+ uint asz = array_size(length);
+ uint osz = align_object_size(header_size() + asz);
+ assert(osz >= asz, "no overflow");
+ assert((int)osz > 0, "no overflow");
+ return (int)osz;
}
// special iterators for index ranges, returns size of object
--- a/hotspot/src/share/vm/oops/oop.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/oops/oop.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -30,13 +30,12 @@
// no virtual functions allowed
// store into oop with store check
-template <class T> void oop_store(T* p, oop v);
-template <class T> void oop_store(volatile T* p, oop v);
+template <class T> inline void oop_store(T* p, oop v);
+template <class T> inline void oop_store(volatile T* p, oop v);
// store into oop without store check
-template <class T> void oop_store_without_check(T* p, oop v);
-template <class T> void oop_store_without_check(volatile T* p, oop v);
-
+template <class T> inline void oop_store_without_check(T* p, oop v);
+template <class T> inline void oop_store_without_check(volatile T* p, oop v);
extern bool always_do_update_barrier;
--- a/hotspot/src/share/vm/opto/c2_globals.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/c2_globals.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -25,4 +25,4 @@
# include "incls/_precompiled.incl"
# include "incls/_c2_globals.cpp.incl"
-C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG)
+C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_EXPERIMENTAL_FLAG, MATERIALIZE_NOTPRODUCT_FLAG)
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -26,7 +26,7 @@
// Defines all globals flags used by the server compiler.
//
-#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \
+#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct) \
\
notproduct(intx, CompileZapFirst, 0, \
"If +ZapDeadCompiledLocals, " \
@@ -394,6 +394,12 @@
product(bool, UseOptoBiasInlining, true, \
"Generate biased locking code in C2 ideal graph") \
\
+ product(bool, OptimizeStringConcat, false, \
+ "Optimize the construction of Strings by StringBuilder") \
+ \
+ notproduct(bool, PrintOptimizeStringConcat, false, \
+ "Print information about transformations performed on Strings") \
+ \
product(intx, ValueSearchLimit, 1000, \
"Recursion limit in PhaseMacroExpand::value_from_mem_phi") \
\
@@ -413,4 +419,4 @@
product(bool, BlockLayoutRotateLoops, true, \
"Allow back branches to be fall throughs in the block layour") \
-C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG)
+C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG)
--- a/hotspot/src/share/vm/opto/callGenerator.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/callGenerator.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -98,12 +98,21 @@
//---------------------------DirectCallGenerator------------------------------
// Internal class which handles all out-of-line calls w/o receiver type checks.
class DirectCallGenerator : public CallGenerator {
-public:
- DirectCallGenerator(ciMethod* method)
- : CallGenerator(method)
+ private:
+ CallStaticJavaNode* _call_node;
+ // Force separate memory and I/O projections for the exceptional
+ // paths to facilitate late inlinig.
+ bool _separate_io_proj;
+
+ public:
+ DirectCallGenerator(ciMethod* method, bool separate_io_proj)
+ : CallGenerator(method),
+ _separate_io_proj(separate_io_proj)
{
}
virtual JVMState* generate(JVMState* jvms);
+
+ CallStaticJavaNode* call_node() const { return _call_node; }
};
JVMState* DirectCallGenerator::generate(JVMState* jvms) {
@@ -129,9 +138,10 @@
call->set_optimized_virtual(true);
}
kit.set_arguments_for_java_call(call);
- kit.set_edges_for_java_call(call);
- Node* ret = kit.set_results_for_java_call(call);
+ kit.set_edges_for_java_call(call, false, _separate_io_proj);
+ Node* ret = kit.set_results_for_java_call(call, _separate_io_proj);
kit.push_node(method()->return_type()->basic_type(), ret);
+ _call_node = call; // Save the call node in case we need it later
return kit.transfer_exceptions_into_jvms();
}
@@ -238,9 +248,9 @@
return new ParseGenerator(m, expected_uses, true);
}
-CallGenerator* CallGenerator::for_direct_call(ciMethod* m) {
+CallGenerator* CallGenerator::for_direct_call(ciMethod* m, bool separate_io_proj) {
assert(!m->is_abstract(), "for_direct_call mismatch");
- return new DirectCallGenerator(m);
+ return new DirectCallGenerator(m, separate_io_proj);
}
CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) {
@@ -248,6 +258,108 @@
return new VirtualCallGenerator(m, vtable_index);
}
+// Allow inlining decisions to be delayed
+class LateInlineCallGenerator : public DirectCallGenerator {
+ CallGenerator* _inline_cg;
+
+ public:
+ LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
+ DirectCallGenerator(method, true), _inline_cg(inline_cg) {}
+
+ virtual bool is_late_inline() const { return true; }
+
+ // Convert the CallStaticJava into an inline
+ virtual void do_late_inline();
+
+ JVMState* generate(JVMState* jvms) {
+ // Record that this call site should be revisited once the main
+ // parse is finished.
+ Compile::current()->add_late_inline(this);
+
+ // Emit the CallStaticJava and request separate projections so
+ // that the late inlining logic can distinguish between fall
+ // through and exceptional uses of the memory and io projections
+ // as is done for allocations and macro expansion.
+ return DirectCallGenerator::generate(jvms);
+ }
+
+};
+
+
+void LateInlineCallGenerator::do_late_inline() {
+ // Can't inline it
+ if (call_node() == NULL || call_node()->outcnt() == 0 ||
+ call_node()->in(0) == NULL || call_node()->in(0)->is_top())
+ return;
+
+ CallStaticJavaNode* call = call_node();
+
+ // Make a clone of the JVMState that appropriate to use for driving a parse
+ Compile* C = Compile::current();
+ JVMState* jvms = call->jvms()->clone_shallow(C);
+ uint size = call->req();
+ SafePointNode* map = new (C, size) SafePointNode(size, jvms);
+ for (uint i1 = 0; i1 < size; i1++) {
+ map->init_req(i1, call->in(i1));
+ }
+
+ // Make sure the state is a MergeMem for parsing.
+ if (!map->in(TypeFunc::Memory)->is_MergeMem()) {
+ map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory)));
+ }
+
+ // Make enough space for the expression stack and transfer the incoming arguments
+ int nargs = method()->arg_size();
+ jvms->set_map(map);
+ map->ensure_stack(jvms, jvms->method()->max_stack());
+ if (nargs > 0) {
+ for (int i1 = 0; i1 < nargs; i1++) {
+ map->set_req(i1 + jvms->argoff(), call->in(TypeFunc::Parms + i1));
+ }
+ }
+
+ CompileLog* log = C->log();
+ if (log != NULL) {
+ log->head("late_inline method='%d'", log->identify(method()));
+ JVMState* p = jvms;
+ while (p != NULL) {
+ log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
+ p = p->caller();
+ }
+ log->tail("late_inline");
+ }
+
+ // Setup default node notes to be picked up by the inlining
+ Node_Notes* old_nn = C->default_node_notes();
+ if (old_nn != NULL) {
+ Node_Notes* entry_nn = old_nn->clone(C);
+ entry_nn->set_jvms(jvms);
+ C->set_default_node_notes(entry_nn);
+ }
+
+ // Now perform the inling using the synthesized JVMState
+ JVMState* new_jvms = _inline_cg->generate(jvms);
+ if (new_jvms == NULL) return; // no change
+ if (C->failing()) return;
+
+ // Capture any exceptional control flow
+ GraphKit kit(new_jvms);
+
+ // Find the result object
+ Node* result = C->top();
+ int result_size = method()->return_type()->size();
+ if (result_size != 0 && !kit.stopped()) {
+ result = (result_size == 1) ? kit.pop() : kit.pop_pair();
+ }
+
+ kit.replace_call(call, result);
+}
+
+
+CallGenerator* CallGenerator::for_late_inline(ciMethod* method, CallGenerator* inline_cg) {
+ return new LateInlineCallGenerator(method, inline_cg);
+}
+
//---------------------------WarmCallGenerator--------------------------------
// Internal class which handles initial deferral of inlining decisions.
@@ -315,70 +427,7 @@
}
void WarmCallInfo::make_hot() {
- Compile* C = Compile::current();
- // Replace the callnode with something better.
- CallJavaNode* call = this->call()->as_CallJava();
- ciMethod* method = call->method();
- int nargs = method->arg_size();
- JVMState* jvms = call->jvms()->clone_shallow(C);
- uint size = TypeFunc::Parms + MAX2(2, nargs);
- SafePointNode* map = new (C, size) SafePointNode(size, jvms);
- for (uint i1 = 0; i1 < (uint)(TypeFunc::Parms + nargs); i1++) {
- map->init_req(i1, call->in(i1));
- }
- jvms->set_map(map);
- jvms->set_offsets(map->req());
- jvms->set_locoff(TypeFunc::Parms);
- jvms->set_stkoff(TypeFunc::Parms);
- GraphKit kit(jvms);
-
- JVMState* new_jvms = _hot_cg->generate(kit.jvms());
- if (new_jvms == NULL) return; // no change
- if (C->failing()) return;
-
- kit.set_jvms(new_jvms);
- Node* res = C->top();
- int res_size = method->return_type()->size();
- if (res_size != 0) {
- kit.inc_sp(-res_size);
- res = kit.argument(0);
- }
- GraphKit ekit(kit.combine_and_pop_all_exception_states()->jvms());
-
- // Replace the call:
- for (DUIterator i = call->outs(); call->has_out(i); i++) {
- Node* n = call->out(i);
- Node* nn = NULL; // replacement
- if (n->is_Proj()) {
- ProjNode* nproj = n->as_Proj();
- assert(nproj->_con < (uint)(TypeFunc::Parms + (res_size ? 1 : 0)), "sane proj");
- if (nproj->_con == TypeFunc::Parms) {
- nn = res;
- } else {
- nn = kit.map()->in(nproj->_con);
- }
- if (nproj->_con == TypeFunc::I_O) {
- for (DUIterator j = nproj->outs(); nproj->has_out(j); j++) {
- Node* e = nproj->out(j);
- if (e->Opcode() == Op_CreateEx) {
- e->replace_by(ekit.argument(0));
- } else if (e->Opcode() == Op_Catch) {
- for (DUIterator k = e->outs(); e->has_out(k); k++) {
- CatchProjNode* p = e->out(j)->as_CatchProj();
- if (p->is_handler_proj()) {
- p->replace_by(ekit.control());
- } else {
- p->replace_by(kit.control());
- }
- }
- }
- }
- }
- }
- NOT_PRODUCT(if (!nn) n->dump(2));
- assert(nn != NULL, "don't know what to do with this user");
- n->replace_by(nn);
- }
+ Unimplemented();
}
void WarmCallInfo::make_cold() {
--- a/hotspot/src/share/vm/opto/callGenerator.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/callGenerator.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -57,6 +57,13 @@
// is_trap: Does not return to the caller. (E.g., uncommon trap.)
virtual bool is_trap() const { return false; }
+ // is_late_inline: supports conversion of call into an inline
+ virtual bool is_late_inline() const { return false; }
+ // Replace the call with an inline version of the code
+ virtual void do_late_inline() { ShouldNotReachHere(); }
+
+ virtual CallStaticJavaNode* call_node() const { ShouldNotReachHere(); return NULL; }
+
// Note: It is possible for a CG to be both inline and virtual.
// (The hashCode intrinsic does a vtable check and an inlined fast path.)
@@ -92,9 +99,12 @@
static CallGenerator* for_osr(ciMethod* m, int osr_bci);
// How to generate vanilla out-of-line call sites:
- static CallGenerator* for_direct_call(ciMethod* m); // static, special
+ static CallGenerator* for_direct_call(ciMethod* m, bool separate_io_projs = false); // static, special
static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface
+ // How to generate a replace a direct call with an inline version
+ static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg);
+
// How to make a call but defer the decision whether to inline or not.
static CallGenerator* for_warm_call(WarmCallInfo* ci,
CallGenerator* if_cold,
--- a/hotspot/src/share/vm/opto/callnode.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/callnode.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -693,6 +693,84 @@
}
+void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj) {
+ projs->fallthrough_proj = NULL;
+ projs->fallthrough_catchproj = NULL;
+ projs->fallthrough_ioproj = NULL;
+ projs->catchall_ioproj = NULL;
+ projs->catchall_catchproj = NULL;
+ projs->fallthrough_memproj = NULL;
+ projs->catchall_memproj = NULL;
+ projs->resproj = NULL;
+ projs->exobj = NULL;
+
+ for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) {
+ ProjNode *pn = fast_out(i)->as_Proj();
+ if (pn->outcnt() == 0) continue;
+ switch (pn->_con) {
+ case TypeFunc::Control:
+ {
+ // For Control (fallthrough) and I_O (catch_all_index) we have CatchProj -> Catch -> Proj
+ projs->fallthrough_proj = pn;
+ DUIterator_Fast jmax, j = pn->fast_outs(jmax);
+ const Node *cn = pn->fast_out(j);
+ if (cn->is_Catch()) {
+ ProjNode *cpn = NULL;
+ for (DUIterator_Fast kmax, k = cn->fast_outs(kmax); k < kmax; k++) {
+ cpn = cn->fast_out(k)->as_Proj();
+ assert(cpn->is_CatchProj(), "must be a CatchProjNode");
+ if (cpn->_con == CatchProjNode::fall_through_index)
+ projs->fallthrough_catchproj = cpn;
+ else {
+ assert(cpn->_con == CatchProjNode::catch_all_index, "must be correct index.");
+ projs->catchall_catchproj = cpn;
+ }
+ }
+ }
+ break;
+ }
+ case TypeFunc::I_O:
+ if (pn->_is_io_use)
+ projs->catchall_ioproj = pn;
+ else
+ projs->fallthrough_ioproj = pn;
+ for (DUIterator j = pn->outs(); pn->has_out(j); j++) {
+ Node* e = pn->out(j);
+ if (e->Opcode() == Op_CreateEx && e->in(0)->is_CatchProj()) {
+ assert(projs->exobj == NULL, "only one");
+ projs->exobj = e;
+ }
+ }
+ break;
+ case TypeFunc::Memory:
+ if (pn->_is_io_use)
+ projs->catchall_memproj = pn;
+ else
+ projs->fallthrough_memproj = pn;
+ break;
+ case TypeFunc::Parms:
+ projs->resproj = pn;
+ break;
+ default:
+ assert(false, "unexpected projection from allocation node.");
+ }
+ }
+
+ // The resproj may not exist because the result couuld be ignored
+ // and the exception object may not exist if an exception handler
+ // swallows the exception but all the other must exist and be found.
+ assert(projs->fallthrough_proj != NULL, "must be found");
+ assert(projs->fallthrough_catchproj != NULL, "must be found");
+ assert(projs->fallthrough_memproj != NULL, "must be found");
+ assert(projs->fallthrough_ioproj != NULL, "must be found");
+ assert(projs->catchall_catchproj != NULL, "must be found");
+ if (separate_io_proj) {
+ assert(projs->catchall_memproj != NULL, "must be found");
+ assert(projs->catchall_ioproj != NULL, "must be found");
+ }
+}
+
+
//=============================================================================
uint CallJavaNode::size_of() const { return sizeof(*this); }
uint CallJavaNode::cmp( const Node &n ) const {
--- a/hotspot/src/share/vm/opto/callnode.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/callnode.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -470,6 +470,23 @@
#endif
};
+
+// Simple container for the outgoing projections of a call. Useful
+// for serious surgery on calls.
+class CallProjections : public StackObj {
+public:
+ Node* fallthrough_proj;
+ Node* fallthrough_catchproj;
+ Node* fallthrough_memproj;
+ Node* fallthrough_ioproj;
+ Node* catchall_catchproj;
+ Node* catchall_memproj;
+ Node* catchall_ioproj;
+ Node* resproj;
+ Node* exobj;
+};
+
+
//------------------------------CallNode---------------------------------------
// Call nodes now subsume the function of debug nodes at callsites, so they
// contain the functionality of a full scope chain of debug nodes.
@@ -521,6 +538,11 @@
// or returns NULL if there is no one.
Node *result_cast();
+ // Collect all the interesting edges from a call for use in
+ // replacing the call by something else. Used by macro expansion
+ // and the late inlining support.
+ void extract_projections(CallProjections* projs, bool separate_io_proj);
+
virtual uint match_edge(uint idx) const;
#ifndef PRODUCT
@@ -529,6 +551,7 @@
#endif
};
+
//------------------------------CallJavaNode-----------------------------------
// Make a static or dynamic subroutine call node using Java calling
// convention. (The "Java" calling convention is the compiler's calling
--- a/hotspot/src/share/vm/opto/compile.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/compile.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -224,6 +224,32 @@
}
+void Compile::gvn_replace_by(Node* n, Node* nn) {
+ for (DUIterator_Last imin, i = n->last_outs(imin); i >= imin; ) {
+ Node* use = n->last_out(i);
+ bool is_in_table = initial_gvn()->hash_delete(use);
+ uint uses_found = 0;
+ for (uint j = 0; j < use->len(); j++) {
+ if (use->in(j) == n) {
+ if (j < use->req())
+ use->set_req(j, nn);
+ else
+ use->set_prec(j, nn);
+ uses_found++;
+ }
+ }
+ if (is_in_table) {
+ // reinsert into table
+ initial_gvn()->hash_find_insert(use);
+ }
+ record_for_igvn(use);
+ i -= uses_found; // we deleted 1 or more copies of this edge
+ }
+}
+
+
+
+
// Identify all nodes that are reachable from below, useful.
// Use breadth-first pass that records state in a Unique_Node_List,
// recursive traversal is slower.
@@ -554,6 +580,28 @@
rethrow_exceptions(kit.transfer_exceptions_into_jvms());
}
+ if (!failing() && has_stringbuilder()) {
+ {
+ // remove useless nodes to make the usage analysis simpler
+ ResourceMark rm;
+ PhaseRemoveUseless pru(initial_gvn(), &for_igvn);
+ }
+
+ {
+ ResourceMark rm;
+ print_method("Before StringOpts", 3);
+ PhaseStringOpts pso(initial_gvn(), &for_igvn);
+ print_method("After StringOpts", 3);
+ }
+
+ // now inline anything that we skipped the first time around
+ while (_late_inlines.length() > 0) {
+ CallGenerator* cg = _late_inlines.pop();
+ cg->do_late_inline();
+ }
+ }
+ assert(_late_inlines.length() == 0, "should have been processed");
+
print_method("Before RemoveUseless", 3);
// Remove clutter produced by parsing.
@@ -820,6 +868,7 @@
_fixed_slots = 0;
set_has_split_ifs(false);
set_has_loops(has_method() && method()->has_loops()); // first approximation
+ set_has_stringbuilder(false);
_deopt_happens = true; // start out assuming the worst
_trap_can_recompile = false; // no traps emitted yet
_major_progress = true; // start out assuming good things will happen
@@ -1803,6 +1852,7 @@
!n->is_Phi() && // a few noisely useless nodes
!n->is_Proj() &&
!n->is_MachTemp() &&
+ !n->is_SafePointScalarObject() &&
!n->is_Catch() && // Would be nice to print exception table targets
!n->is_MergeMem() && // Not very interesting
!n->is_top() && // Debug info table constants
@@ -2240,6 +2290,30 @@
break;
}
+ case Op_Proj: {
+ if (OptimizeStringConcat) {
+ ProjNode* p = n->as_Proj();
+ if (p->_is_io_use) {
+ // Separate projections were used for the exception path which
+ // are normally removed by a late inline. If it wasn't inlined
+ // then they will hang around and should just be replaced with
+ // the original one.
+ Node* proj = NULL;
+ // Replace with just one
+ for (SimpleDUIterator i(p->in(0)); i.has_next(); i.next()) {
+ Node *use = i.get();
+ if (use->is_Proj() && p != use && use->as_Proj()->_con == p->_con) {
+ proj = use;
+ break;
+ }
+ }
+ assert(p != NULL, "must be found");
+ p->subsume_by(proj);
+ }
+ }
+ break;
+ }
+
case Op_Phi:
if (n->as_Phi()->bottom_type()->isa_narrowoop()) {
// The EncodeP optimization may create Phi with the same edges
--- a/hotspot/src/share/vm/opto/compile.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/compile.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -149,6 +149,7 @@
bool _has_loops; // True if the method _may_ have some loops
bool _has_split_ifs; // True if the method _may_ have some split-if
bool _has_unsafe_access; // True if the method _may_ produce faults in unsafe loads or stores.
+ bool _has_stringbuilder; // True StringBuffers or StringBuilders are allocated
uint _trap_hist[trapHistLength]; // Cumulative traps
bool _trap_can_recompile; // Have we emitted a recompiling trap?
uint _decompile_count; // Cumulative decompilation counts.
@@ -219,6 +220,9 @@
Unique_Node_List* _for_igvn; // Initial work-list for next round of Iterative GVN
WarmCallInfo* _warm_calls; // Sorted work-list for heat-based inlining.
+ GrowableArray<CallGenerator*> _late_inlines; // List of CallGenerators to be revisited after
+ // main parsing has finished.
+
// Matching, CFG layout, allocation, code generation
PhaseCFG* _cfg; // Results of CFG finding
bool _select_24_bit_instr; // We selected an instruction with a 24-bit result
@@ -298,6 +302,8 @@
void set_has_split_ifs(bool z) { _has_split_ifs = z; }
bool has_unsafe_access() const { return _has_unsafe_access; }
void set_has_unsafe_access(bool z) { _has_unsafe_access = z; }
+ bool has_stringbuilder() const { return _has_stringbuilder; }
+ void set_has_stringbuilder(bool z) { _has_stringbuilder = z; }
void set_trap_count(uint r, uint c) { assert(r < trapHistLength, "oob"); _trap_hist[r] = c; }
uint trap_count(uint r) const { assert(r < trapHistLength, "oob"); return _trap_hist[r]; }
bool trap_can_recompile() const { return _trap_can_recompile; }
@@ -475,6 +481,7 @@
// Decide how to build a call.
// The profile factor is a discount to apply to this site's interp. profile.
CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float profile_factor);
+ bool should_delay_inlining(ciMethod* call_method, JVMState* jvms);
// Report if there were too many traps at a current method and bci.
// Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded.
@@ -495,6 +502,11 @@
void set_initial_gvn(PhaseGVN *gvn) { _initial_gvn = gvn; }
void set_for_igvn(Unique_Node_List *for_igvn) { _for_igvn = for_igvn; }
+ // Replace n by nn using initial_gvn, calling hash_delete and
+ // record_for_igvn as needed.
+ void gvn_replace_by(Node* n, Node* nn);
+
+
void identify_useful_nodes(Unique_Node_List &useful);
void remove_useless_nodes (Unique_Node_List &useful);
@@ -502,6 +514,9 @@
void set_warm_calls(WarmCallInfo* l) { _warm_calls = l; }
WarmCallInfo* pop_warm_call();
+ // Record this CallGenerator for inlining at the end of parsing.
+ void add_late_inline(CallGenerator* cg) { _late_inlines.push(cg); }
+
// Matching, CFG layout, allocation, code generation
PhaseCFG* cfg() { return _cfg; }
bool select_24_bit_instr() const { return _select_24_bit_instr; }
--- a/hotspot/src/share/vm/opto/doCall.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/doCall.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -128,6 +128,12 @@
if (allow_inline) {
CallGenerator* cg = CallGenerator::for_inline(call_method, expected_uses);
+ if (require_inline && cg != NULL && should_delay_inlining(call_method, jvms)) {
+ // Delay the inlining of this method to give us the
+ // opportunity to perform some high level optimizations
+ // first.
+ return CallGenerator::for_late_inline(call_method, cg);
+ }
if (cg == NULL) {
// Fall through.
} else if (require_inline || !InlineWarmCalls) {
@@ -225,10 +231,63 @@
} else {
// Class Hierarchy Analysis or Type Profile reveals a unique target,
// or it is a static or special call.
- return CallGenerator::for_direct_call(call_method);
+ return CallGenerator::for_direct_call(call_method, should_delay_inlining(call_method, jvms));
}
}
+// Return true for methods that shouldn't be inlined early so that
+// they are easier to analyze and optimize as intrinsics.
+bool Compile::should_delay_inlining(ciMethod* call_method, JVMState* jvms) {
+ if (has_stringbuilder()) {
+
+ if ((call_method->holder() == C->env()->StringBuilder_klass() ||
+ call_method->holder() == C->env()->StringBuffer_klass()) &&
+ (jvms->method()->holder() == C->env()->StringBuilder_klass() ||
+ jvms->method()->holder() == C->env()->StringBuffer_klass())) {
+ // Delay SB calls only when called from non-SB code
+ return false;
+ }
+
+ switch (call_method->intrinsic_id()) {
+ case vmIntrinsics::_StringBuilder_void:
+ case vmIntrinsics::_StringBuilder_int:
+ case vmIntrinsics::_StringBuilder_String:
+ case vmIntrinsics::_StringBuilder_append_char:
+ case vmIntrinsics::_StringBuilder_append_int:
+ case vmIntrinsics::_StringBuilder_append_String:
+ case vmIntrinsics::_StringBuilder_toString:
+ case vmIntrinsics::_StringBuffer_void:
+ case vmIntrinsics::_StringBuffer_int:
+ case vmIntrinsics::_StringBuffer_String:
+ case vmIntrinsics::_StringBuffer_append_char:
+ case vmIntrinsics::_StringBuffer_append_int:
+ case vmIntrinsics::_StringBuffer_append_String:
+ case vmIntrinsics::_StringBuffer_toString:
+ case vmIntrinsics::_Integer_toString:
+ return true;
+
+ case vmIntrinsics::_String_String:
+ {
+ Node* receiver = jvms->map()->in(jvms->argoff() + 1);
+ if (receiver->is_Proj() && receiver->in(0)->is_CallStaticJava()) {
+ CallStaticJavaNode* csj = receiver->in(0)->as_CallStaticJava();
+ ciMethod* m = csj->method();
+ if (m != NULL &&
+ (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString ||
+ m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString))
+ // Delay String.<init>(new SB())
+ return true;
+ }
+ return false;
+ }
+
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
// uncommon-trap call-sites where callee is unloaded, uninitialized or will not link
bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* klass) {
--- a/hotspot/src/share/vm/opto/escape.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/escape.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -537,11 +537,13 @@
}
const TypeOopPtr *tinst = base_t->add_offset(t->offset())->is_oopptr();
- // Do NOT remove the next call: ensure an new alias index is allocated
- // for the instance type
+ // Do NOT remove the next line: ensure a new alias index is allocated
+ // for the instance type. Note: C++ will not remove it since the call
+ // has side effect.
int alias_idx = _compile->get_alias_index(tinst);
igvn->set_type(addp, tinst);
// record the allocation in the node map
+ assert(ptnode_adr(addp->_idx)->_node != NULL, "should be registered");
set_map(addp->_idx, get_map(base->_idx));
// Set addp's Base and Address to 'base'.
@@ -617,9 +619,14 @@
const TypePtr *atype = C->get_adr_type(alias_idx);
result = PhiNode::make(orig_phi->in(0), NULL, Type::MEMORY, atype);
C->copy_node_notes_to(result, orig_phi);
- set_map_phi(orig_phi->_idx, result);
igvn->set_type(result, result->bottom_type());
record_for_optimizer(result);
+
+ debug_only(Node* pn = ptnode_adr(orig_phi->_idx)->_node;)
+ assert(pn == NULL || pn == orig_phi, "wrong node");
+ set_map(orig_phi->_idx, result);
+ ptnode_adr(orig_phi->_idx)->_node = orig_phi;
+
new_created = true;
return result;
}
@@ -710,6 +717,81 @@
}
//
+// Move memory users to their memory slices.
+//
+void ConnectionGraph::move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phis, PhaseGVN *igvn) {
+ Compile* C = _compile;
+
+ const TypePtr* tp = igvn->type(n->in(MemNode::Address))->isa_ptr();
+ assert(tp != NULL, "ptr type");
+ int alias_idx = C->get_alias_index(tp);
+ int general_idx = C->get_general_index(alias_idx);
+
+ // Move users first
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+ Node* use = n->fast_out(i);
+ if (use->is_MergeMem()) {
+ MergeMemNode* mmem = use->as_MergeMem();
+ assert(n == mmem->memory_at(alias_idx), "should be on instance memory slice");
+ if (n != mmem->memory_at(general_idx) || alias_idx == general_idx) {
+ continue; // Nothing to do
+ }
+ // Replace previous general reference to mem node.
+ uint orig_uniq = C->unique();
+ Node* m = find_inst_mem(n, general_idx, orig_phis, igvn);
+ assert(orig_uniq == C->unique(), "no new nodes");
+ mmem->set_memory_at(general_idx, m);
+ --imax;
+ --i;
+ } else if (use->is_MemBar()) {
+ assert(!use->is_Initialize(), "initializing stores should not be moved");
+ if (use->req() > MemBarNode::Precedent &&
+ use->in(MemBarNode::Precedent) == n) {
+ // Don't move related membars.
+ record_for_optimizer(use);
+ continue;
+ }
+ tp = use->as_MemBar()->adr_type()->isa_ptr();
+ if (tp != NULL && C->get_alias_index(tp) == alias_idx ||
+ alias_idx == general_idx) {
+ continue; // Nothing to do
+ }
+ // Move to general memory slice.
+ uint orig_uniq = C->unique();
+ Node* m = find_inst_mem(n, general_idx, orig_phis, igvn);
+ assert(orig_uniq == C->unique(), "no new nodes");
+ igvn->hash_delete(use);
+ imax -= use->replace_edge(n, m);
+ igvn->hash_insert(use);
+ record_for_optimizer(use);
+ --i;
+#ifdef ASSERT
+ } else if (use->is_Mem()) {
+ if (use->Opcode() == Op_StoreCM && use->in(MemNode::OopStore) == n) {
+ // Don't move related cardmark.
+ continue;
+ }
+ // Memory nodes should have new memory input.
+ tp = igvn->type(use->in(MemNode::Address))->isa_ptr();
+ assert(tp != NULL, "ptr type");
+ int idx = C->get_alias_index(tp);
+ assert(get_map(use->_idx) != NULL || idx == alias_idx,
+ "Following memory nodes should have new memory input or be on the same memory slice");
+ } else if (use->is_Phi()) {
+ // Phi nodes should be split and moved already.
+ tp = use->as_Phi()->adr_type()->isa_ptr();
+ assert(tp != NULL, "ptr type");
+ int idx = C->get_alias_index(tp);
+ assert(idx == alias_idx, "Following Phi nodes should be on the same memory slice");
+ } else {
+ use->dump();
+ assert(false, "should not be here");
+#endif
+ }
+ }
+}
+
+//
// Search memory chain of "mem" to find a MemNode whose address
// is the specified alias index.
//
@@ -774,10 +856,18 @@
C->get_alias_index(result->as_Phi()->adr_type()) != alias_idx) {
Node *un = result->as_Phi()->unique_input(phase);
if (un != NULL) {
+ orig_phis.append_if_missing(result->as_Phi());
result = un;
} else {
break;
}
+ } else if (result->is_ClearArray()) {
+ if (!ClearArrayNode::step_through(&result, (uint)tinst->instance_id(), phase)) {
+ // Can not bypass initialization of the instance
+ // we are looking for.
+ break;
+ }
+ // Otherwise skip it (the call updated 'result' value).
} else if (result->Opcode() == Op_SCMemProj) {
assert(result->in(0)->is_LoadStore(), "sanity");
const Type *at = phase->type(result->in(0)->in(MemNode::Address));
@@ -807,7 +897,6 @@
return result;
}
-
//
// Convert the types of unescaped object to instance types where possible,
// propagate the new type information through the graph, and update memory
@@ -899,12 +988,13 @@
//
void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) {
GrowableArray<Node *> memnode_worklist;
- GrowableArray<Node *> mergemem_worklist;
GrowableArray<PhiNode *> orig_phis;
+
PhaseGVN *igvn = _compile->initial_gvn();
uint new_index_start = (uint) _compile->num_alias_types();
- VectorSet visited(Thread::current()->resource_area());
- VectorSet ptset(Thread::current()->resource_area());
+ Arena* arena = Thread::current()->resource_area();
+ VectorSet visited(arena);
+ VectorSet ptset(arena);
// Phase 1: Process possible allocations from alloc_worklist.
@@ -980,6 +1070,8 @@
// - non-escaping
// - eligible to be a unique type
// - not determined to be ineligible by escape analysis
+ assert(ptnode_adr(alloc->_idx)->_node != NULL &&
+ ptnode_adr(n->_idx)->_node != NULL, "should be registered");
set_map(alloc->_idx, n);
set_map(n->_idx, alloc);
const TypeOopPtr *t = igvn->type(n)->isa_oopptr();
@@ -1024,7 +1116,7 @@
alloc_worklist.append_if_missing(addp2);
}
alloc_worklist.append_if_missing(use);
- } else if (use->is_Initialize()) {
+ } else if (use->is_MemBar()) {
memnode_worklist.append_if_missing(use);
}
}
@@ -1034,10 +1126,12 @@
PointsTo(ptset, get_addp_base(n), igvn);
assert(ptset.Size() == 1, "AddP address is unique");
uint elem = ptset.getelem(); // Allocation node's index
- if (elem == _phantom_object)
+ if (elem == _phantom_object) {
+ assert(false, "escaped allocation");
continue; // Assume the value was set outside this method.
+ }
Node *base = get_map(elem); // CheckCastPP node
- if (!split_AddP(n, base, igvn)) continue; // wrong type
+ if (!split_AddP(n, base, igvn)) continue; // wrong type from dead path
tinst = igvn->type(base)->isa_oopptr();
} else if (n->is_Phi() ||
n->is_CheckCastPP() ||
@@ -1052,8 +1146,10 @@
PointsTo(ptset, n, igvn);
if (ptset.Size() == 1) {
uint elem = ptset.getelem(); // Allocation node's index
- if (elem == _phantom_object)
+ if (elem == _phantom_object) {
+ assert(false, "escaped allocation");
continue; // Assume the value was set outside this method.
+ }
Node *val = get_map(elem); // CheckCastPP node
TypeNode *tn = n->as_Type();
tinst = igvn->type(val)->isa_oopptr();
@@ -1068,8 +1164,7 @@
tn_t = tn_type->isa_oopptr();
}
- if (tn_t != NULL &&
- tinst->cast_to_instance_id(TypeOopPtr::InstanceBot)->higher_equal(tn_t)) {
+ if (tn_t != NULL && tinst->klass()->is_subtype_of(tn_t->klass())) {
if (tn_type->isa_narrowoop()) {
tn_type = tinst->make_narrowoop();
} else {
@@ -1081,33 +1176,25 @@
igvn->hash_insert(tn);
record_for_optimizer(n);
} else {
- continue; // wrong type
+ assert(tn_type == TypePtr::NULL_PTR ||
+ tn_t != NULL && !tinst->klass()->is_subtype_of(tn_t->klass()),
+ "unexpected type");
+ continue; // Skip dead path with different type
}
}
} else {
+ debug_only(n->dump();)
+ assert(false, "EA: unexpected node");
continue;
}
- // push users on appropriate worklist
+ // push allocation's users on appropriate worklist
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node *use = n->fast_out(i);
if(use->is_Mem() && use->in(MemNode::Address) == n) {
- memnode_worklist.append_if_missing(use);
- } else if (use->is_Initialize()) {
+ // Load/store to instance's field
memnode_worklist.append_if_missing(use);
- } else if (use->is_MergeMem()) {
- mergemem_worklist.append_if_missing(use);
- } else if (use->is_SafePoint() && tinst != NULL) {
- // Look for MergeMem nodes for calls which reference unique allocation
- // (through CheckCastPP nodes) even for debug info.
- Node* m = use->in(TypeFunc::Memory);
- uint iid = tinst->instance_id();
- while (m->is_Proj() && m->in(0)->is_SafePoint() &&
- m->in(0) != use && !m->in(0)->_idx != iid) {
- m = m->in(0)->in(TypeFunc::Memory);
- }
- if (m->is_MergeMem()) {
- mergemem_worklist.append_if_missing(m);
- }
+ } else if (use->is_MemBar()) {
+ memnode_worklist.append_if_missing(use);
} else if (use->is_AddP() && use->outcnt() > 0) { // No dead nodes
Node* addp2 = find_second_addp(use, n);
if (addp2 != NULL) {
@@ -1120,6 +1207,29 @@
use->is_DecodeN() ||
(use->is_ConstraintCast() && use->Opcode() == Op_CastPP)) {
alloc_worklist.append_if_missing(use);
+#ifdef ASSERT
+ } else if (use->is_Mem()) {
+ assert(use->in(MemNode::Address) != n, "EA: missing allocation reference path");
+ } else if (use->is_MergeMem()) {
+ assert(_mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist");
+ } else if (use->is_SafePoint()) {
+ // Look for MergeMem nodes for calls which reference unique allocation
+ // (through CheckCastPP nodes) even for debug info.
+ Node* m = use->in(TypeFunc::Memory);
+ if (m->is_MergeMem()) {
+ assert(_mergemem_worklist.contains(m->as_MergeMem()), "EA: missing MergeMem node in the worklist");
+ }
+ } else {
+ uint op = use->Opcode();
+ if (!(op == Op_CmpP || op == Op_Conv2B ||
+ op == Op_CastP2X || op == Op_StoreCM ||
+ op == Op_FastLock || op == Op_AryEq || op == Op_StrComp ||
+ op == Op_StrEquals || op == Op_StrIndexOf)) {
+ n->dump();
+ use->dump();
+ assert(false, "EA: missing allocation reference path");
+ }
+#endif
}
}
@@ -1137,19 +1247,16 @@
Node *n = memnode_worklist.pop();
if (visited.test_set(n->_idx))
continue;
- if (n->is_Phi()) {
- assert(n->as_Phi()->adr_type() != TypePtr::BOTTOM, "narrow memory slice required");
- // we don't need to do anything, but the users must be pushed if we haven't processed
- // this Phi before
- } else if (n->is_Initialize()) {
- // we don't need to do anything, but the users of the memory projection must be pushed
- n = n->as_Initialize()->proj_out(TypeFunc::Memory);
+ if (n->is_Phi() || n->is_ClearArray()) {
+ // 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);
if (n == NULL)
continue;
} else {
assert(n->is_Mem(), "memory node required.");
Node *addr = n->in(MemNode::Address);
- assert(addr->is_AddP(), "AddP required");
const Type *addr_t = igvn->type(addr);
if (addr_t == Type::TOP)
continue;
@@ -1161,6 +1268,10 @@
return;
}
if (mem != n->in(MemNode::Memory)) {
+ // We delay the memory edge update since we need old one in
+ // MergeMem code below when instances memory slices are separated.
+ debug_only(Node* pn = ptnode_adr(n->_idx)->_node;)
+ assert(pn == NULL || pn == n, "wrong node");
set_map(n->_idx, mem);
ptnode_adr(n->_idx)->_node = n;
}
@@ -1181,36 +1292,55 @@
// push user on appropriate worklist
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node *use = n->fast_out(i);
- if (use->is_Phi()) {
+ if (use->is_Phi() || use->is_ClearArray()) {
memnode_worklist.append_if_missing(use);
} else if(use->is_Mem() && use->in(MemNode::Memory) == n) {
+ if (use->Opcode() == Op_StoreCM) // Ignore cardmark stores
+ continue;
memnode_worklist.append_if_missing(use);
- } else if (use->is_Initialize()) {
+ } else if (use->is_MemBar()) {
memnode_worklist.append_if_missing(use);
+#ifdef ASSERT
+ } else if(use->is_Mem()) {
+ assert(use->in(MemNode::Memory) != n, "EA: missing memory path");
} else if (use->is_MergeMem()) {
- mergemem_worklist.append_if_missing(use);
+ assert(_mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist");
+ } else {
+ uint op = use->Opcode();
+ if (!(op == Op_StoreCM ||
+ (op == Op_CallLeaf && use->as_CallLeaf()->_name != NULL &&
+ strcmp(use->as_CallLeaf()->_name, "g1_wb_pre") == 0) ||
+ op == Op_AryEq || op == Op_StrComp ||
+ op == Op_StrEquals || op == Op_StrIndexOf)) {
+ n->dump();
+ use->dump();
+ assert(false, "EA: missing memory path");
+ }
+#endif
}
}
}
// Phase 3: Process MergeMem nodes from mergemem_worklist.
- // Walk each memory moving the first node encountered of each
+ // Walk each memory slice moving the first node encountered of each
// instance type to the the input corresponding to its alias index.
- while (mergemem_worklist.length() != 0) {
- Node *n = mergemem_worklist.pop();
- assert(n->is_MergeMem(), "MergeMem node required.");
- if (visited.test_set(n->_idx))
- continue;
- MergeMemNode *nmm = n->as_MergeMem();
+ uint length = _mergemem_worklist.length();
+ for( uint next = 0; next < length; ++next ) {
+ MergeMemNode* nmm = _mergemem_worklist.at(next);
+ assert(!visited.test_set(nmm->_idx), "should not be visited before");
// Note: we don't want to use MergeMemStream here because we only want to
- // scan inputs which exist at the start, not ones we add during processing.
+ // scan inputs which exist at the start, not ones we add during processing.
+ // Note 2: MergeMem may already contains instance memory slices added
+ // during find_inst_mem() call when memory nodes were processed above.
+ igvn->hash_delete(nmm);
uint nslices = nmm->req();
- igvn->hash_delete(nmm);
for (uint i = Compile::AliasIdxRaw+1; i < nslices; i++) {
Node* mem = nmm->in(i);
Node* cur = NULL;
if (mem == NULL || mem->is_top())
continue;
+ // First, update mergemem by moving memory nodes to corresponding slices
+ // if their type became more precise since this mergemem was created.
while (mem->is_Mem()) {
const Type *at = igvn->type(mem->in(MemNode::Address));
if (at != Type::TOP) {
@@ -1229,7 +1359,7 @@
}
nmm->set_memory_at(i, (cur != NULL) ? cur : mem);
// Find any instance of the current type if we haven't encountered
- // a value of the instance along the chain.
+ // already a memory slice of the instance along the memory chain.
for (uint ni = new_index_start; ni < new_index_end; ni++) {
if((uint)_compile->get_general_index(ni) == i) {
Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni);
@@ -1245,11 +1375,11 @@
}
// Find the rest of instances values
for (uint ni = new_index_start; ni < new_index_end; ni++) {
- const TypeOopPtr *tinst = igvn->C->get_adr_type(ni)->isa_oopptr();
+ const TypeOopPtr *tinst = _compile->get_adr_type(ni)->isa_oopptr();
Node* result = step_through_mergemem(nmm, ni, tinst);
if (result == nmm->base_memory()) {
// Didn't find instance memory, search through general slice recursively.
- result = nmm->memory_at(igvn->C->get_general_index(ni));
+ result = nmm->memory_at(_compile->get_general_index(ni));
result = find_inst_mem(result, ni, orig_phis, igvn);
if (_compile->failing()) {
return;
@@ -1259,41 +1389,6 @@
}
igvn->hash_insert(nmm);
record_for_optimizer(nmm);
-
- // Propagate new memory slices to following MergeMem nodes.
- for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
- Node *use = n->fast_out(i);
- if (use->is_Call()) {
- CallNode* in = use->as_Call();
- if (in->proj_out(TypeFunc::Memory) != NULL) {
- Node* m = in->proj_out(TypeFunc::Memory);
- for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) {
- Node* mm = m->fast_out(j);
- if (mm->is_MergeMem()) {
- mergemem_worklist.append_if_missing(mm);
- }
- }
- }
- if (use->is_Allocate()) {
- use = use->as_Allocate()->initialization();
- if (use == NULL) {
- continue;
- }
- }
- }
- if (use->is_Initialize()) {
- InitializeNode* in = use->as_Initialize();
- if (in->proj_out(TypeFunc::Memory) != NULL) {
- Node* m = in->proj_out(TypeFunc::Memory);
- for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) {
- Node* mm = m->fast_out(j);
- if (mm->is_MergeMem()) {
- mergemem_worklist.append_if_missing(mm);
- }
- }
- }
- }
- }
}
// Phase 4: Update the inputs of non-instance memory Phis and
@@ -1322,19 +1417,48 @@
}
// Update the memory inputs of MemNodes with the value we computed
- // in Phase 2.
+ // in Phase 2 and move stores memory users to corresponding memory slices.
+#ifdef ASSERT
+ visited.Clear();
+ Node_Stack old_mems(arena, _compile->unique() >> 2);
+#endif
for (uint i = 0; i < nodes_size(); i++) {
Node *nmem = get_map(i);
if (nmem != NULL) {
Node *n = ptnode_adr(i)->_node;
- if (n != NULL && n->is_Mem()) {
+ assert(n != NULL, "sanity");
+ if (n->is_Mem()) {
+#ifdef ASSERT
+ Node* old_mem = n->in(MemNode::Memory);
+ if (!visited.test_set(old_mem->_idx)) {
+ old_mems.push(old_mem, old_mem->outcnt());
+ }
+#endif
+ assert(n->in(MemNode::Memory) != nmem, "sanity");
+ if (!n->is_Load()) {
+ // Move memory users of a store first.
+ move_inst_mem(n, orig_phis, igvn);
+ }
+ // Now update memory input
igvn->hash_delete(n);
n->set_req(MemNode::Memory, nmem);
igvn->hash_insert(n);
record_for_optimizer(n);
+ } else {
+ assert(n->is_Allocate() || n->is_CheckCastPP() ||
+ n->is_AddP() || n->is_Phi(), "unknown node used for set_map()");
}
}
}
+#ifdef ASSERT
+ // Verify that memory was split correctly
+ while (old_mems.is_nonempty()) {
+ Node* old_mem = old_mems.node();
+ uint old_cnt = old_mems.index();
+ old_mems.pop();
+ assert(old_cnt = old_mem->outcnt(), "old mem could be lost");
+ }
+#endif
}
bool ConnectionGraph::has_candidates(Compile *C) {
@@ -1381,8 +1505,20 @@
ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) {
has_allocations = true;
}
- if(n->is_AddP())
- cg_worklist.append(n->_idx);
+ if(n->is_AddP()) {
+ // Collect address nodes which directly reference an allocation.
+ // Use them during stage 3 below to build initial connection graph
+ // field edges. Other field edges could be added after StoreP/LoadP
+ // nodes are processed during stage 4 below.
+ Node* base = get_addp_base(n);
+ if(base->is_Proj() && base->in(0)->is_Allocate()) {
+ cg_worklist.append(n->_idx);
+ }
+ } else if (n->is_MergeMem()) {
+ // Collect all MergeMem nodes to add memory slices for
+ // scalar replaceable objects in split_unique_types().
+ _mergemem_worklist.append(n->as_MergeMem());
+ }
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node* m = n->fast_out(i); // Get user
worklist_init.push(m);
@@ -1423,12 +1559,13 @@
}
}
- VectorSet ptset(Thread::current()->resource_area());
+ Arena* arena = Thread::current()->resource_area();
+ VectorSet ptset(arena);
GrowableArray<uint> deferred_edges;
- VectorSet visited(Thread::current()->resource_area());
+ VectorSet visited(arena);
- // 5. Remove deferred edges from the graph and collect
- // information needed for type splitting.
+ // 5. Remove deferred edges from the graph and adjust
+ // escape state of nonescaping objects.
cg_length = cg_worklist.length();
for( uint next = 0; next < cg_length; ++next ) {
int ni = cg_worklist.at(next);
@@ -1438,98 +1575,9 @@
remove_deferred(ni, &deferred_edges, &visited);
Node *n = ptn->_node;
if (n->is_AddP()) {
- // Search for objects which are not scalar replaceable.
- // Mark their escape state as ArgEscape to propagate the state
- // to referenced objects.
- // Note: currently there are no difference in compiler optimizations
- // for ArgEscape objects and NoEscape objects which are not
- // scalar replaceable.
-
- int offset = ptn->offset();
- Node *base = get_addp_base(n);
- ptset.Clear();
- PointsTo(ptset, base, igvn);
- int ptset_size = ptset.Size();
-
- // Check if a field's initializing value is recorded and add
- // a corresponding NULL field's value if it is not recorded.
- // Connection Graph does not record a default initialization by NULL
- // captured by Initialize node.
- //
- // Note: it will disable scalar replacement in some cases:
- //
- // Point p[] = new Point[1];
- // p[0] = new Point(); // Will be not scalar replaced
- //
- // but it will save us from incorrect optimizations in next cases:
- //
- // Point p[] = new Point[1];
- // if ( x ) p[0] = new Point(); // Will be not scalar replaced
- //
- // Without a control flow analysis we can't distinguish above cases.
- //
- if (offset != Type::OffsetBot && ptset_size == 1) {
- uint elem = ptset.getelem(); // Allocation node's index
- // It does not matter if it is not Allocation node since
- // only non-escaping allocations are scalar replaced.
- if (ptnode_adr(elem)->_node->is_Allocate() &&
- ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) {
- AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate();
- InitializeNode* ini = alloc->initialization();
- Node* value = NULL;
- if (ini != NULL) {
- BasicType ft = UseCompressedOops ? T_NARROWOOP : T_OBJECT;
- Node* store = ini->find_captured_store(offset, type2aelembytes(ft), igvn);
- if (store != NULL && store->is_Store())
- value = store->in(MemNode::ValueIn);
- }
- if (value == NULL || value != ptnode_adr(value->_idx)->_node) {
- // A field's initializing value was not recorded. Add NULL.
- uint null_idx = UseCompressedOops ? _noop_null : _oop_null;
- add_pointsto_edge(ni, null_idx);
- }
- }
- }
-
- // An object is not scalar replaceable if the field which may point
- // to it has unknown offset (unknown element of an array of objects).
- //
- if (offset == Type::OffsetBot) {
- uint e_cnt = ptn->edge_count();
- for (uint ei = 0; ei < e_cnt; ei++) {
- uint npi = ptn->edge_target(ei);
- set_escape_state(npi, PointsToNode::ArgEscape);
- ptnode_adr(npi)->_scalar_replaceable = false;
- }
- }
-
- // Currently an object is not scalar replaceable if a LoadStore node
- // access its field since the field value is unknown after it.
- //
- bool has_LoadStore = false;
- for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
- Node *use = n->fast_out(i);
- if (use->is_LoadStore()) {
- has_LoadStore = true;
- break;
- }
- }
- // An object is not scalar replaceable if the address points
- // to unknown field (unknown element for arrays, offset is OffsetBot).
- //
- // Or the address may point to more then one object. This may produce
- // the false positive result (set scalar_replaceable to false)
- // since the flow-insensitive escape analysis can't separate
- // the case when stores overwrite the field's value from the case
- // when stores happened on different control branches.
- //
- if (ptset_size > 1 || ptset_size != 0 &&
- (has_LoadStore || offset == Type::OffsetBot)) {
- for( VectorSetI j(&ptset); j.test(); ++j ) {
- set_escape_state(j.elem, PointsToNode::ArgEscape);
- ptnode_adr(j.elem)->_scalar_replaceable = false;
- }
- }
+ // Search for objects which are not scalar replaceable
+ // and adjust their escape state.
+ verify_escape_state(ni, ptset, igvn);
}
}
}
@@ -1646,6 +1694,150 @@
return has_non_escaping_obj;
}
+// Search for objects which are not scalar replaceable.
+void ConnectionGraph::verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase) {
+ PointsToNode* ptn = ptnode_adr(nidx);
+ Node* n = ptn->_node;
+ assert(n->is_AddP(), "Should be called for AddP nodes only");
+ // Search for objects which are not scalar replaceable.
+ // Mark their escape state as ArgEscape to propagate the state
+ // to referenced objects.
+ // Note: currently there are no difference in compiler optimizations
+ // for ArgEscape objects and NoEscape objects which are not
+ // scalar replaceable.
+
+ Compile* C = _compile;
+
+ int offset = ptn->offset();
+ Node* base = get_addp_base(n);
+ ptset.Clear();
+ PointsTo(ptset, base, phase);
+ int ptset_size = ptset.Size();
+
+ // Check if a oop field's initializing value is recorded and add
+ // a corresponding NULL field's value if it is not recorded.
+ // Connection Graph does not record a default initialization by NULL
+ // captured by Initialize node.
+ //
+ // Note: it will disable scalar replacement in some cases:
+ //
+ // Point p[] = new Point[1];
+ // p[0] = new Point(); // Will be not scalar replaced
+ //
+ // but it will save us from incorrect optimizations in next cases:
+ //
+ // Point p[] = new Point[1];
+ // if ( x ) p[0] = new Point(); // Will be not scalar replaced
+ //
+ // Do a simple control flow analysis to distinguish above cases.
+ //
+ if (offset != Type::OffsetBot && ptset_size == 1) {
+ uint elem = ptset.getelem(); // Allocation node's index
+ // It does not matter if it is not Allocation node since
+ // only non-escaping allocations are scalar replaced.
+ if (ptnode_adr(elem)->_node->is_Allocate() &&
+ ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) {
+ AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate();
+ InitializeNode* ini = alloc->initialization();
+
+ // Check only oop fields.
+ const Type* adr_type = n->as_AddP()->bottom_type();
+ BasicType basic_field_type = T_INT;
+ if (adr_type->isa_instptr()) {
+ ciField* field = C->alias_type(adr_type->isa_instptr())->field();
+ if (field != NULL) {
+ basic_field_type = field->layout_type();
+ } else {
+ // Ignore non field load (for example, klass load)
+ }
+ } else if (adr_type->isa_aryptr()) {
+ const Type* elemtype = adr_type->isa_aryptr()->elem();
+ basic_field_type = elemtype->array_element_basic_type();
+ } else {
+ // Raw pointers are used for initializing stores so skip it.
+ assert(adr_type->isa_rawptr() && base->is_Proj() &&
+ (base->in(0) == alloc),"unexpected pointer type");
+ }
+ if (basic_field_type == T_OBJECT ||
+ basic_field_type == T_NARROWOOP ||
+ basic_field_type == T_ARRAY) {
+ Node* value = NULL;
+ if (ini != NULL) {
+ BasicType ft = UseCompressedOops ? T_NARROWOOP : T_OBJECT;
+ Node* store = ini->find_captured_store(offset, type2aelembytes(ft), phase);
+ if (store != NULL && store->is_Store()) {
+ value = store->in(MemNode::ValueIn);
+ } else if (ptn->edge_count() > 0) { // Are there oop stores?
+ // Check for a store which follows allocation without branches.
+ // For example, a volatile field store is not collected
+ // by Initialize node. TODO: it would be nice to use idom() here.
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+ store = n->fast_out(i);
+ if (store->is_Store() && store->in(0) != NULL) {
+ Node* ctrl = store->in(0);
+ while(!(ctrl == ini || ctrl == alloc || ctrl == NULL ||
+ ctrl == C->root() || ctrl == C->top() || ctrl->is_Region() ||
+ ctrl->is_IfTrue() || ctrl->is_IfFalse())) {
+ ctrl = ctrl->in(0);
+ }
+ if (ctrl == ini || ctrl == alloc) {
+ value = store->in(MemNode::ValueIn);
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (value == NULL || value != ptnode_adr(value->_idx)->_node) {
+ // A field's initializing value was not recorded. Add NULL.
+ uint null_idx = UseCompressedOops ? _noop_null : _oop_null;
+ add_pointsto_edge(nidx, null_idx);
+ }
+ }
+ }
+ }
+
+ // An object is not scalar replaceable if the field which may point
+ // to it has unknown offset (unknown element of an array of objects).
+ //
+ if (offset == Type::OffsetBot) {
+ uint e_cnt = ptn->edge_count();
+ for (uint ei = 0; ei < e_cnt; ei++) {
+ uint npi = ptn->edge_target(ei);
+ set_escape_state(npi, PointsToNode::ArgEscape);
+ ptnode_adr(npi)->_scalar_replaceable = false;
+ }
+ }
+
+ // Currently an object is not scalar replaceable if a LoadStore node
+ // access its field since the field value is unknown after it.
+ //
+ bool has_LoadStore = false;
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+ Node *use = n->fast_out(i);
+ if (use->is_LoadStore()) {
+ has_LoadStore = true;
+ break;
+ }
+ }
+ // An object is not scalar replaceable if the address points
+ // to unknown field (unknown element for arrays, offset is OffsetBot).
+ //
+ // Or the address may point to more then one object. This may produce
+ // the false positive result (set scalar_replaceable to false)
+ // since the flow-insensitive escape analysis can't separate
+ // the case when stores overwrite the field's value from the case
+ // when stores happened on different control branches.
+ //
+ if (ptset_size > 1 || ptset_size != 0 &&
+ (has_LoadStore || offset == Type::OffsetBot)) {
+ for( VectorSetI j(&ptset); j.test(); ++j ) {
+ set_escape_state(j.elem, PointsToNode::ArgEscape);
+ ptnode_adr(j.elem)->_scalar_replaceable = false;
+ }
+ }
+}
+
void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) {
switch (call->Opcode()) {
@@ -1657,6 +1849,7 @@
assert(false, "should be done already");
break;
#endif
+ case Op_CallLeaf:
case Op_CallLeafNoFP:
{
// Stub calls, objects do not escape but they are not scale replaceable.
@@ -1667,9 +1860,23 @@
const Type* at = d->field_at(i);
Node *arg = call->in(i)->uncast();
const Type *aat = phase->type(arg);
- if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr()) {
+ if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() &&
+ ptnode_adr(arg->_idx)->escape_state() < PointsToNode::ArgEscape) {
+
assert(aat == Type::TOP || aat == TypePtr::NULL_PTR ||
aat->isa_ptr() != NULL, "expecting an Ptr");
+#ifdef ASSERT
+ if (!(call->Opcode() == Op_CallLeafNoFP &&
+ call->as_CallLeaf()->_name != NULL &&
+ (strstr(call->as_CallLeaf()->_name, "arraycopy") != 0) ||
+ call->as_CallLeaf()->_name != NULL &&
+ (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 ))
+ ) {
+ call->dump();
+ assert(false, "EA: unexpected CallLeaf");
+ }
+#endif
set_escape_state(arg->_idx, PointsToNode::ArgEscape);
if (arg->is_AddP()) {
//
@@ -1706,9 +1913,10 @@
for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
const Type* at = d->field_at(i);
int k = i - TypeFunc::Parms;
+ Node *arg = call->in(i)->uncast();
- if (at->isa_oopptr() != NULL) {
- Node *arg = call->in(i)->uncast();
+ if (at->isa_oopptr() != NULL &&
+ ptnode_adr(arg->_idx)->escape_state() < PointsToNode::ArgEscape) {
bool global_escapes = false;
bool fields_escapes = false;
@@ -1942,20 +2150,23 @@
record_for_optimizer(n);
_processed.set(n->_idx);
} else {
- // Have to process call's arguments first.
+ // Don't mark as processed since call's arguments have to be processed.
PointsToNode::NodeType nt = PointsToNode::UnknownType;
+ PointsToNode::EscapeState es = PointsToNode::UnknownEscape;
// Check if a call returns an object.
const TypeTuple *r = n->as_Call()->tf()->range();
- if (n->is_CallStaticJava() && r->cnt() > TypeFunc::Parms &&
+ if (r->cnt() > TypeFunc::Parms &&
+ r->field_at(TypeFunc::Parms)->isa_ptr() &&
n->as_Call()->proj_out(TypeFunc::Parms) != NULL) {
- // Note: use isa_ptr() instead of isa_oopptr() here because
- // the _multianewarray functions return a TypeRawPtr.
- if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) {
- nt = PointsToNode::JavaObject;
+ nt = PointsToNode::JavaObject;
+ if (!n->is_CallStaticJava()) {
+ // Since the called mathod is statically unknown assume
+ // the worst case that the returned value globally escapes.
+ es = PointsToNode::GlobalEscape;
}
}
- add_node(n, nt, PointsToNode::UnknownEscape, false);
+ add_node(n, nt, es, false);
}
return;
}
@@ -2088,18 +2299,27 @@
}
case Op_Proj:
{
- // we are only interested in the result projection from a call
+ // we are only interested in the oop result projection from a call
if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() ) {
- add_node(n, PointsToNode::LocalVar, PointsToNode::UnknownEscape, false);
- process_call_result(n->as_Proj(), phase);
- if (!_processed.test(n->_idx)) {
- // The call's result may need to be processed later if the call
- // returns it's argument and the argument is not processed yet.
- _delayed_worklist.push(n);
+ const TypeTuple *r = n->in(0)->as_Call()->tf()->range();
+ assert(r->cnt() > TypeFunc::Parms, "sanity");
+ if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) {
+ add_node(n, PointsToNode::LocalVar, PointsToNode::UnknownEscape, false);
+ int ti = n->in(0)->_idx;
+ // The call may not be registered yet (since not all its inputs are registered)
+ // if this is the projection from backbranch edge of Phi.
+ if (ptnode_adr(ti)->node_type() != PointsToNode::UnknownType) {
+ process_call_result(n->as_Proj(), phase);
+ }
+ if (!_processed.test(n->_idx)) {
+ // The call's result may need to be processed later if the call
+ // returns it's argument and the argument is not processed yet.
+ _delayed_worklist.push(n);
+ }
+ break;
}
- } else {
- _processed.set(n->_idx);
}
+ _processed.set(n->_idx);
break;
}
case Op_Return:
@@ -2160,6 +2380,15 @@
}
break;
}
+ case Op_AryEq:
+ case Op_StrComp:
+ case Op_StrEquals:
+ case Op_StrIndexOf:
+ {
+ // char[] arrays passed to string intrinsics are not scalar replaceable.
+ add_node(n, PointsToNode::UnknownType, PointsToNode::UnknownEscape, false);
+ break;
+ }
case Op_ThreadLocal:
{
add_node(n, PointsToNode::JavaObject, PointsToNode::ArgEscape, true);
@@ -2174,6 +2403,7 @@
void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
uint n_idx = n->_idx;
+ assert(ptnode_adr(n_idx)->_node != NULL, "node should be registered");
// Don't set processed bit for AddP, LoadP, StoreP since
// they may need more then one pass to process.
@@ -2211,6 +2441,7 @@
case Op_DecodeN:
{
int ti = n->in(1)->_idx;
+ assert(ptnode_adr(ti)->node_type() != PointsToNode::UnknownType, "all nodes should be registered");
if (ptnode_adr(ti)->node_type() == PointsToNode::JavaObject) {
add_pointsto_edge(n_idx, ti);
} else {
@@ -2250,7 +2481,6 @@
#endif
Node* adr = n->in(MemNode::Address)->uncast();
- const Type *adr_type = phase->type(adr);
Node* adr_base;
if (adr->is_AddP()) {
adr_base = get_addp_base(adr);
@@ -2302,13 +2532,19 @@
}
case Op_Proj:
{
- // we are only interested in the result projection from a call
+ // we are only interested in the oop result projection from a call
if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() ) {
- process_call_result(n->as_Proj(), phase);
- assert(_processed.test(n_idx), "all call results should be processed");
- } else {
- assert(false, "Op_Proj");
+ assert(ptnode_adr(n->in(0)->_idx)->node_type() != PointsToNode::UnknownType,
+ "all nodes should be registered");
+ const TypeTuple *r = n->in(0)->as_Call()->tf()->range();
+ assert(r->cnt() > TypeFunc::Parms, "sanity");
+ if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) {
+ process_call_result(n->as_Proj(), phase);
+ assert(_processed.test(n_idx), "all call results should be processed");
+ break;
+ }
}
+ assert(false, "Op_Proj");
break;
}
case Op_Return:
@@ -2320,6 +2556,7 @@
}
#endif
int ti = n->in(TypeFunc::Parms)->_idx;
+ assert(ptnode_adr(ti)->node_type() != PointsToNode::UnknownType, "node should be registered");
if (ptnode_adr(ti)->node_type() == PointsToNode::JavaObject) {
add_pointsto_edge(n_idx, ti);
} else {
@@ -2354,14 +2591,38 @@
}
break;
}
+ case Op_AryEq:
+ case Op_StrComp:
+ case Op_StrEquals:
+ case Op_StrIndexOf:
+ {
+ // char[] arrays passed to string intrinsic do not escape but
+ // they are not scalar replaceable. Adjust escape state for them.
+ // Start from in(2) edge since in(1) is memory edge.
+ for (uint i = 2; i < n->req(); i++) {
+ Node* adr = n->in(i)->uncast();
+ const Type *at = phase->type(adr);
+ if (!adr->is_top() && at->isa_ptr()) {
+ assert(at == Type::TOP || at == TypePtr::NULL_PTR ||
+ at->isa_ptr() != NULL, "expecting an Ptr");
+ if (adr->is_AddP()) {
+ adr = get_addp_base(adr);
+ }
+ // Mark as ArgEscape everything "adr" could point to.
+ set_escape_state(adr->_idx, PointsToNode::ArgEscape);
+ }
+ }
+ _processed.set(n_idx);
+ break;
+ }
case Op_ThreadLocal:
{
assert(false, "Op_ThreadLocal");
break;
}
default:
- ;
- // nothing to do
+ // This method should be called only for EA specific nodes.
+ ShouldNotReachHere();
}
}
--- a/hotspot/src/share/vm/opto/escape.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/escape.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -210,6 +210,8 @@
Unique_Node_List _delayed_worklist; // Nodes to be processed before
// the call build_connection_graph().
+ GrowableArray<MergeMemNode *> _mergemem_worklist; // List of all MergeMem nodes
+
VectorSet _processed; // Records which nodes have been
// processed.
@@ -289,7 +291,7 @@
bool split_AddP(Node *addp, Node *base, PhaseGVN *igvn);
PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn, bool &new_created);
PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn);
- Node *find_mem(Node *mem, int alias_idx, PhaseGVN *igvn);
+ void move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phis, PhaseGVN *igvn);
Node *find_inst_mem(Node *mem, int alias_idx,GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn);
// Propagate unique types created for unescaped allocated objects
@@ -298,7 +300,6 @@
// manage entries in _node_map
void set_map(int idx, Node *n) { _node_map.map(idx, n); }
- void set_map_phi(int idx, PhiNode *p) { _node_map.map(idx, (Node *) p); }
Node *get_map(int idx) { return _node_map[idx]; }
PhiNode *get_map_phi(int idx) {
Node *phi = _node_map[idx];
@@ -315,6 +316,9 @@
// Set the escape state of a node
void set_escape_state(uint ni, PointsToNode::EscapeState es);
+ // Search for objects which are not scalar replaceable.
+ void verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase);
+
public:
ConnectionGraph(Compile *C);
--- a/hotspot/src/share/vm/opto/graphKit.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/graphKit.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1351,8 +1351,8 @@
}
//------------------------------set_all_memory_call----------------------------
-void GraphKit::set_all_memory_call(Node* call) {
- Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) );
+void GraphKit::set_all_memory_call(Node* call, bool separate_io_proj) {
+ Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory, separate_io_proj) );
set_all_memory(newmem);
}
@@ -1573,7 +1573,7 @@
//---------------------------set_edges_for_java_call---------------------------
// Connect a newly created call into the current JVMS.
// A return value node (if any) is returned from set_edges_for_java_call.
-void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw) {
+void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw, bool separate_io_proj) {
// Add the predefined inputs:
call->init_req( TypeFunc::Control, control() );
@@ -1595,13 +1595,13 @@
// Re-use the current map to produce the result.
set_control(_gvn.transform(new (C, 1) ProjNode(call, TypeFunc::Control)));
- set_i_o( _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O )));
- set_all_memory_call(xcall);
+ set_i_o( _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O , separate_io_proj)));
+ set_all_memory_call(xcall, separate_io_proj);
//return xcall; // no need, caller already has it
}
-Node* GraphKit::set_results_for_java_call(CallJavaNode* call) {
+Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_proj) {
if (stopped()) return top(); // maybe the call folded up?
// Capture the return value, if any.
@@ -1614,8 +1614,15 @@
// Note: Since any out-of-line call can produce an exception,
// we always insert an I_O projection from the call into the result.
- make_slow_call_ex(call, env()->Throwable_klass(), false);
-
+ make_slow_call_ex(call, env()->Throwable_klass(), separate_io_proj);
+
+ if (separate_io_proj) {
+ // The caller requested separate projections be used by the fall
+ // through and exceptional paths, so replace the projections for
+ // the fall through path.
+ set_i_o(_gvn.transform( new (C, 1) ProjNode(call, TypeFunc::I_O) ));
+ set_all_memory(_gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) ));
+ }
return ret;
}
@@ -1678,6 +1685,64 @@
}
}
+
+// Replace the call with the current state of the kit.
+void GraphKit::replace_call(CallNode* call, Node* result) {
+ JVMState* ejvms = NULL;
+ if (has_exceptions()) {
+ ejvms = transfer_exceptions_into_jvms();
+ }
+
+ SafePointNode* final_state = stop();
+
+ // Find all the needed outputs of this call
+ CallProjections callprojs;
+ call->extract_projections(&callprojs, true);
+
+ // Replace all the old call edges with the edges from the inlining result
+ C->gvn_replace_by(callprojs.fallthrough_catchproj, final_state->in(TypeFunc::Control));
+ C->gvn_replace_by(callprojs.fallthrough_memproj, final_state->in(TypeFunc::Memory));
+ C->gvn_replace_by(callprojs.fallthrough_ioproj, final_state->in(TypeFunc::I_O));
+
+ // Replace the result with the new result if it exists and is used
+ if (callprojs.resproj != NULL && result != NULL) {
+ C->gvn_replace_by(callprojs.resproj, result);
+ }
+
+ if (ejvms == NULL) {
+ // No exception edges to simply kill off those paths
+ C->gvn_replace_by(callprojs.catchall_catchproj, C->top());
+ C->gvn_replace_by(callprojs.catchall_memproj, C->top());
+ C->gvn_replace_by(callprojs.catchall_ioproj, C->top());
+
+ // Replace the old exception object with top
+ if (callprojs.exobj != NULL) {
+ C->gvn_replace_by(callprojs.exobj, C->top());
+ }
+ } else {
+ GraphKit ekit(ejvms);
+
+ // Load my combined exception state into the kit, with all phis transformed:
+ SafePointNode* ex_map = ekit.combine_and_pop_all_exception_states();
+
+ Node* ex_oop = ekit.use_exception_state(ex_map);
+
+ C->gvn_replace_by(callprojs.catchall_catchproj, ekit.control());
+ C->gvn_replace_by(callprojs.catchall_memproj, ekit.reset_memory());
+ C->gvn_replace_by(callprojs.catchall_ioproj, ekit.i_o());
+
+ // Replace the old exception object with the newly created one
+ if (callprojs.exobj != NULL) {
+ C->gvn_replace_by(callprojs.exobj, ex_oop);
+ }
+ }
+
+ // Disconnect the call from the graph
+ call->disconnect_inputs(NULL);
+ C->gvn_replace_by(call, C->top());
+}
+
+
//------------------------------increment_counter------------------------------
// for statistics: increment a VM counter by 1
@@ -3459,4 +3524,3 @@
sync_kit(ideal);
}
#undef __
-
--- a/hotspot/src/share/vm/opto/graphKit.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/graphKit.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -279,6 +279,34 @@
}
Node* basic_plus_adr(Node* base, Node* ptr, Node* offset);
+
+ // Some convenient shortcuts for common nodes
+ Node* IfTrue(IfNode* iff) { return _gvn.transform(new (C,1) IfTrueNode(iff)); }
+ Node* IfFalse(IfNode* iff) { return _gvn.transform(new (C,1) IfFalseNode(iff)); }
+
+ Node* AddI(Node* l, Node* r) { return _gvn.transform(new (C,3) AddINode(l, r)); }
+ Node* SubI(Node* l, Node* r) { return _gvn.transform(new (C,3) SubINode(l, r)); }
+ Node* MulI(Node* l, Node* r) { return _gvn.transform(new (C,3) MulINode(l, r)); }
+ Node* DivI(Node* ctl, Node* l, Node* r) { return _gvn.transform(new (C,3) DivINode(ctl, l, r)); }
+
+ Node* AndI(Node* l, Node* r) { return _gvn.transform(new (C,3) AndINode(l, r)); }
+ Node* OrI(Node* l, Node* r) { return _gvn.transform(new (C,3) OrINode(l, r)); }
+ Node* XorI(Node* l, Node* r) { return _gvn.transform(new (C,3) XorINode(l, r)); }
+
+ Node* MaxI(Node* l, Node* r) { return _gvn.transform(new (C,3) MaxINode(l, r)); }
+ Node* MinI(Node* l, Node* r) { return _gvn.transform(new (C,3) MinINode(l, r)); }
+
+ Node* LShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) LShiftINode(l, r)); }
+ Node* RShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) RShiftINode(l, r)); }
+ Node* URShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) URShiftINode(l, r)); }
+
+ Node* CmpI(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpINode(l, r)); }
+ Node* CmpL(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpLNode(l, r)); }
+ Node* CmpP(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpPNode(l, r)); }
+ Node* Bool(Node* cmp, BoolTest::mask relop) { return _gvn.transform(new (C,2) BoolNode(cmp, relop)); }
+
+ Node* AddP(Node* b, Node* a, Node* o) { return _gvn.transform(new (C,4) AddPNode(b, a, o)); }
+
// Convert between int and long, and size_t.
// (See macros ConvI2X, etc., in type.hpp for ConvI2X, etc.)
Node* ConvI2L(Node* offset);
@@ -400,7 +428,7 @@
void set_all_memory(Node* newmem);
// Create a memory projection from the call, then set_all_memory.
- void set_all_memory_call(Node* call);
+ void set_all_memory_call(Node* call, bool separate_io_proj = false);
// Create a LoadNode, reading from the parser's memory state.
// (Note: require_atomic_access is useful only with T_LONG.)
@@ -543,12 +571,12 @@
// Transform the call, and update the basics: control, i_o, memory.
// (The next step is usually to call set_results_for_java_call.)
void set_edges_for_java_call(CallJavaNode* call,
- bool must_throw = false);
+ bool must_throw = false, bool separate_io_proj = false);
// Finish up a java call that was started by set_edges_for_java_call.
// Call add_exception on any throw arising from the call.
// Return the call result (transformed).
- Node* set_results_for_java_call(CallJavaNode* call);
+ Node* set_results_for_java_call(CallJavaNode* call, bool separate_io_proj = false);
// Similar to set_edges_for_java_call, but simplified for runtime calls.
void set_predefined_output_for_runtime_call(Node* call) {
@@ -559,6 +587,11 @@
const TypePtr* hook_mem);
Node* set_predefined_input_for_runtime_call(SafePointNode* call);
+ // Replace the call with the current state of the kit. Requires
+ // that the call was generated with separate io_projs so that
+ // exceptional control flow can be handled properly.
+ void replace_call(CallNode* call, Node* result);
+
// helper functions for statistics
void increment_counter(address counter_addr); // increment a debug counter
void increment_counter(Node* counter_addr); // increment a debug counter
--- a/hotspot/src/share/vm/opto/lcm.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/lcm.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -616,8 +616,9 @@
assert(cfg->_bbs[oop_store->_idx]->_dom_depth <= this->_dom_depth, "oop_store must dominate card-mark");
}
}
- if( n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_MemBarAcquire &&
- n->req() > TypeFunc::Parms ) {
+ if( n->is_Mach() && n->req() > TypeFunc::Parms &&
+ (n->as_Mach()->ideal_Opcode() == Op_MemBarAcquire ||
+ n->as_Mach()->ideal_Opcode() == Op_MemBarVolatile) ) {
// MemBarAcquire could be created without Precedent edge.
// del_req() replaces the specified edge with the last input edge
// and then removes the last edge. If the specified edge > number of
--- a/hotspot/src/share/vm/opto/loopnode.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/loopnode.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1279,7 +1279,8 @@
// Visit all children, looking for Phis
for (DUIterator i = cl->outs(); cl->has_out(i); i++) {
Node *out = cl->out(i);
- if (!out->is_Phi() || out == phi) continue; // Looking for other phis
+ // Look for other phis (secondary IVs). Skip dead ones
+ if (!out->is_Phi() || out == phi || !phase->has_node(out)) continue;
PhiNode* phi2 = out->as_Phi();
Node *incr2 = phi2->in( LoopNode::LoopBackControl );
// Look for induction variables of the form: X += constant
--- a/hotspot/src/share/vm/opto/macro.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/macro.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -316,6 +316,21 @@
assert(adr_idx == Compile::AliasIdxRaw, "address must match or be raw");
}
mem = mem->in(MemNode::Memory);
+ } else if (mem->is_ClearArray()) {
+ if (!ClearArrayNode::step_through(&mem, alloc->_idx, phase)) {
+ // Can not bypass initialization of the instance
+ // we are looking.
+ debug_only(intptr_t offset;)
+ assert(alloc == AllocateNode::Ideal_allocation(mem->in(3), phase, offset), "sanity");
+ InitializeNode* init = alloc->as_Allocate()->initialization();
+ // We are looking for stored value, return Initialize node
+ // or memory edge from Allocate node.
+ if (init != NULL)
+ return init;
+ else
+ return alloc->in(TypeFunc::Memory); // It will produce zero value (see callers).
+ }
+ // Otherwise skip it (the call updated 'mem' value).
} else if (mem->Opcode() == Op_SCMemProj) {
assert(mem->in(0)->is_LoadStore(), "sanity");
const TypePtr* atype = mem->in(0)->in(MemNode::Address)->bottom_type()->is_ptr();
@@ -823,6 +838,18 @@
Node *n = use->last_out(k);
uint oc2 = use->outcnt();
if (n->is_Store()) {
+#ifdef ASSERT
+ // Verify that there is no dependent MemBarVolatile nodes,
+ // they should be removed during IGVN, see MemBarNode::Ideal().
+ for (DUIterator_Fast pmax, p = n->fast_outs(pmax);
+ p < pmax; p++) {
+ Node* mb = n->fast_out(p);
+ assert(mb->is_Initialize() || !mb->is_MemBar() ||
+ mb->req() <= MemBarNode::Precedent ||
+ mb->in(MemBarNode::Precedent) != n,
+ "MemBarVolatile should be eliminated for non-escaping object");
+ }
+#endif
_igvn.replace_node(n, n->in(MemNode::Memory));
} else {
eliminate_card_mark(n);
@@ -912,15 +939,29 @@
return false;
}
+ CompileLog* log = C->log();
+ if (log != NULL) {
+ Node* klass = alloc->in(AllocateNode::KlassNode);
+ const TypeKlassPtr* tklass = _igvn.type(klass)->is_klassptr();
+ log->head("eliminate_allocation type='%d'",
+ log->identify(tklass->klass()));
+ JVMState* p = alloc->jvms();
+ while (p != NULL) {
+ log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
+ p = p->caller();
+ }
+ log->tail("eliminate_allocation");
+ }
+
process_users_of_allocation(alloc);
#ifndef PRODUCT
-if (PrintEliminateAllocations) {
- if (alloc->is_AllocateArray())
- tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx);
- else
- tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx);
-}
+ if (PrintEliminateAllocations) {
+ if (alloc->is_AllocateArray())
+ tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx);
+ else
+ tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx);
+ }
#endif
return true;
@@ -1639,6 +1680,18 @@
} // if (!oldbox->is_eliminated())
} // if (alock->is_Lock() && !lock->is_coarsened())
+ CompileLog* log = C->log();
+ if (log != NULL) {
+ log->head("eliminate_lock lock='%d'",
+ alock->is_Lock());
+ JVMState* p = alock->jvms();
+ while (p != NULL) {
+ log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
+ p = p->caller();
+ }
+ log->tail("eliminate_lock");
+ }
+
#ifndef PRODUCT
if (PrintEliminateLocks) {
if (alock->is_Lock()) {
--- a/hotspot/src/share/vm/opto/matcher.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/matcher.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1832,67 +1832,23 @@
case Op_Binary: // These are introduced in the Post_Visit state.
ShouldNotReachHere();
break;
- case Op_StoreB: // Do match these, despite no ideal reg
- case Op_StoreC:
- case Op_StoreCM:
- case Op_StoreD:
- case Op_StoreF:
- case Op_StoreI:
- case Op_StoreL:
- case Op_StoreP:
- case Op_StoreN:
- case Op_Store16B:
- case Op_Store8B:
- case Op_Store4B:
- case Op_Store8C:
- case Op_Store4C:
- case Op_Store2C:
- case Op_Store4I:
- case Op_Store2I:
- case Op_Store2L:
- case Op_Store4F:
- case Op_Store2F:
- case Op_Store2D:
case Op_ClearArray:
case Op_SafePoint:
mem_op = true;
break;
- case Op_LoadB:
- case Op_LoadUS:
- case Op_LoadD:
- case Op_LoadF:
- case Op_LoadI:
- case Op_LoadKlass:
- case Op_LoadNKlass:
- case Op_LoadL:
- case Op_LoadS:
- case Op_LoadP:
- case Op_LoadN:
- case Op_LoadRange:
- case Op_LoadD_unaligned:
- case Op_LoadL_unaligned:
- case Op_Load16B:
- case Op_Load8B:
- case Op_Load4B:
- case Op_Load4C:
- case Op_Load2C:
- case Op_Load8C:
- case Op_Load8S:
- case Op_Load4S:
- case Op_Load2S:
- case Op_Load4I:
- case Op_Load2I:
- case Op_Load2L:
- case Op_Load4F:
- case Op_Load2F:
- case Op_Load2D:
- mem_op = true;
- // Must be root of match tree due to prior load conflict
- if( C->subsume_loads() == false ) {
- set_shared(n);
+ default:
+ if( n->is_Store() ) {
+ // Do match stores, despite no ideal reg
+ mem_op = true;
+ break;
+ }
+ if( n->is_Mem() ) { // Loads and LoadStores
+ mem_op = true;
+ // Loads must be root of match tree due to prior load conflict
+ if( C->subsume_loads() == false )
+ set_shared(n);
}
// Fall into default case
- default:
if( !n->ideal_reg() )
set_dontcare(n); // Unmatchable Nodes
} // end_switch
@@ -1913,15 +1869,15 @@
continue; // for(int i = ...)
}
- // Clone addressing expressions as they are "free" in most instructions
+ if( mop == Op_AddP && m->in(AddPNode::Base)->Opcode() == Op_DecodeN ) {
+ // Bases used in addresses must be shared but since
+ // they are shared through a DecodeN they may appear
+ // to have a single use so force sharing here.
+ set_shared(m->in(AddPNode::Base)->in(1));
+ }
+
+ // Clone addressing expressions as they are "free" in memory access instructions
if( mem_op && i == MemNode::Address && mop == Op_AddP ) {
- if (m->in(AddPNode::Base)->Opcode() == Op_DecodeN) {
- // Bases used in addresses must be shared but since
- // they are shared through a DecodeN they may appear
- // to have a single use so force sharing here.
- set_shared(m->in(AddPNode::Base)->in(1));
- }
-
// Some inputs for address expression are not put on stack
// to avoid marking them as shared and forcing them into register
// if they are used only in address expressions.
--- a/hotspot/src/share/vm/opto/memnode.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/memnode.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -123,6 +123,13 @@
} else {
assert(false, "unexpected projection");
}
+ } else if (result->is_ClearArray()) {
+ if (!ClearArrayNode::step_through(&result, instance_id, phase)) {
+ // Can not bypass initialization of the instance
+ // we are looking for.
+ break;
+ }
+ // Otherwise skip it (the call updated 'result' value).
} else if (result->is_MergeMem()) {
result = step_through_mergemem(phase, result->as_MergeMem(), t_adr, NULL, tty);
}
@@ -255,6 +262,13 @@
return NodeSentinel; // caller will return NULL
}
+ // Do NOT remove or optimize the next lines: ensure a new alias index
+ // is allocated for an oop pointer type before Escape Analysis.
+ // Note: C++ will not remove it since the call has side effect.
+ if ( t_adr->isa_oopptr() ) {
+ int alias_idx = phase->C->get_alias_index(t_adr->is_ptr());
+ }
+
#ifdef ASSERT
Node* base = NULL;
if (address->is_AddP())
@@ -530,6 +544,15 @@
} else if (mem->is_Proj() && mem->in(0)->is_MemBar()) {
mem = mem->in(0)->in(TypeFunc::Memory);
continue; // (a) advance through independent MemBar memory
+ } else if (mem->is_ClearArray()) {
+ if (ClearArrayNode::step_through(&mem, (uint)addr_t->instance_id(), phase)) {
+ // (the call updated 'mem' value)
+ continue; // (a) advance through independent allocation memory
+ } else {
+ // Can not bypass initialization of the instance
+ // we are looking for.
+ return mem;
+ }
} else if (mem->is_MergeMem()) {
int alias_idx = phase->C->get_alias_index(adr_type());
mem = mem->as_MergeMem()->memory_at(alias_idx);
@@ -1496,6 +1519,8 @@
}
}
} else if (tp->base() == Type::InstPtr) {
+ const TypeInstPtr* tinst = tp->is_instptr();
+ ciKlass* klass = tinst->klass();
assert( off != Type::OffsetBot ||
// arrays can be cast to Objects
tp->is_oopptr()->klass()->is_java_lang_Object() ||
@@ -1503,6 +1528,25 @@
phase->C->has_unsafe_access(),
"Field accesses must be precise" );
// For oop loads, we expect the _type to be precise
+ if (OptimizeStringConcat && klass == phase->C->env()->String_klass() &&
+ adr->is_AddP() && off != Type::OffsetBot) {
+ // For constant Strings treat the fields as compile time constants.
+ Node* base = adr->in(AddPNode::Base);
+ if (base->Opcode() == Op_ConP) {
+ const TypeOopPtr* t = phase->type(base)->isa_oopptr();
+ ciObject* string = t->const_oop();
+ ciConstant constant = string->as_instance()->field_value_by_offset(off);
+ if (constant.basic_type() == T_INT) {
+ return TypeInt::make(constant.as_int());
+ } else if (constant.basic_type() == T_ARRAY) {
+ if (adr->bottom_type()->is_ptr_to_narrowoop()) {
+ return TypeNarrowOop::make_from_constant(constant.as_object());
+ } else {
+ return TypeOopPtr::make_from_constant(constant.as_object());
+ }
+ }
+ }
+ }
} else if (tp->base() == Type::KlassPtr) {
assert( off != Type::OffsetBot ||
// arrays can be cast to Objects
@@ -2426,6 +2470,31 @@
return mem;
}
+//----------------------------step_through----------------------------------
+// Return allocation input memory edge if it is different instance
+// or itself if it is the one we are looking for.
+bool ClearArrayNode::step_through(Node** np, uint instance_id, PhaseTransform* phase) {
+ Node* n = *np;
+ assert(n->is_ClearArray(), "sanity");
+ intptr_t offset;
+ AllocateNode* alloc = AllocateNode::Ideal_allocation(n->in(3), phase, offset);
+ // This method is called only before Allocate nodes are expanded during
+ // macro nodes expansion. Before that ClearArray nodes are only generated
+ // in LibraryCallKit::generate_arraycopy() which follows allocations.
+ assert(alloc != NULL, "should have allocation");
+ if (alloc->_idx == instance_id) {
+ // Can not bypass initialization of the instance we are looking for.
+ return false;
+ }
+ // Otherwise skip it.
+ InitializeNode* init = alloc->initialization();
+ if (init != NULL)
+ *np = init->in(TypeFunc::Memory);
+ else
+ *np = alloc->in(TypeFunc::Memory);
+ return true;
+}
+
//----------------------------clear_memory-------------------------------------
// Generate code to initialize object storage to zero.
Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
@@ -2599,7 +2668,30 @@
// Return a node which is more "ideal" than the current node. Strip out
// control copies
Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) {
- return remove_dead_region(phase, can_reshape) ? this : NULL;
+ if (remove_dead_region(phase, can_reshape)) return this;
+
+ // Eliminate volatile MemBars for scalar replaced objects.
+ if (can_reshape && req() == (Precedent+1) &&
+ (Opcode() == Op_MemBarAcquire || Opcode() == Op_MemBarVolatile)) {
+ // Volatile field loads and stores.
+ Node* my_mem = in(MemBarNode::Precedent);
+ if (my_mem != NULL && my_mem->is_Mem()) {
+ const TypeOopPtr* t_oop = my_mem->in(MemNode::Address)->bottom_type()->isa_oopptr();
+ // Check for scalar replaced object reference.
+ if( t_oop != NULL && t_oop->is_known_instance_field() &&
+ t_oop->offset() != Type::OffsetBot &&
+ t_oop->offset() != Type::OffsetTop) {
+ // Replace MemBar projections by its inputs.
+ PhaseIterGVN* igvn = phase->is_IterGVN();
+ igvn->replace_node(proj_out(TypeFunc::Memory), in(TypeFunc::Memory));
+ igvn->replace_node(proj_out(TypeFunc::Control), in(TypeFunc::Control));
+ // Must return either the original node (now dead) or a new node
+ // (Do not return a top here, since that would break the uniqueness of top.)
+ return new (phase->C, 1) ConINode(TypeInt::ZERO);
+ }
+ }
+ }
+ return NULL;
}
//------------------------------Value------------------------------------------
--- a/hotspot/src/share/vm/opto/memnode.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/memnode.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -717,7 +717,10 @@
//------------------------------ClearArray-------------------------------------
class ClearArrayNode: public Node {
public:
- ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base ) : Node(ctrl,arymem,word_cnt,base) {}
+ ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base )
+ : Node(ctrl,arymem,word_cnt,base) {
+ init_class_id(Class_ClearArray);
+ }
virtual int Opcode() const;
virtual const Type *bottom_type() const { return Type::MEMORY; }
// ClearArray modifies array elements, and so affects only the
@@ -743,6 +746,9 @@
Node* start_offset,
Node* end_offset,
PhaseGVN* phase);
+ // Return allocation input memory edge if it is different instance
+ // or itself if it is the one we are looking for.
+ static bool step_through(Node** np, uint instance_id, PhaseTransform* phase);
};
//------------------------------StrComp-------------------------------------
--- a/hotspot/src/share/vm/opto/node.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/node.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -47,6 +47,7 @@
class CatchNode;
class CatchProjNode;
class CheckCastPPNode;
+class ClearArrayNode;
class CmpNode;
class CodeBuffer;
class ConstraintCastNode;
@@ -599,8 +600,9 @@
DEFINE_CLASS_ID(BoxLock, Node, 10)
DEFINE_CLASS_ID(Add, Node, 11)
DEFINE_CLASS_ID(Mul, Node, 12)
+ DEFINE_CLASS_ID(ClearArray, Node, 13)
- _max_classes = ClassMask_Mul
+ _max_classes = ClassMask_ClearArray
};
#undef DEFINE_CLASS_ID
@@ -661,18 +663,25 @@
return (_flags & Flag_is_Call) != 0;
}
+ CallNode* isa_Call() const {
+ return is_Call() ? as_Call() : NULL;
+ }
+
CallNode *as_Call() const { // Only for CallNode (not for MachCallNode)
assert((_class_id & ClassMask_Call) == Class_Call, "invalid node class");
return (CallNode*)this;
}
- #define DEFINE_CLASS_QUERY(type) \
- bool is_##type() const { \
+ #define DEFINE_CLASS_QUERY(type) \
+ bool is_##type() const { \
return ((_class_id & ClassMask_##type) == Class_##type); \
- } \
- type##Node *as_##type() const { \
- assert(is_##type(), "invalid node class"); \
- return (type##Node*)this; \
+ } \
+ type##Node *as_##type() const { \
+ assert(is_##type(), "invalid node class"); \
+ return (type##Node*)this; \
+ } \
+ type##Node* isa_##type() const { \
+ return (is_##type()) ? as_##type() : NULL; \
}
DEFINE_CLASS_QUERY(AbstractLock)
@@ -691,6 +700,7 @@
DEFINE_CLASS_QUERY(CatchProj)
DEFINE_CLASS_QUERY(CheckCastPP)
DEFINE_CLASS_QUERY(ConstraintCast)
+ DEFINE_CLASS_QUERY(ClearArray)
DEFINE_CLASS_QUERY(CMove)
DEFINE_CLASS_QUERY(Cmp)
DEFINE_CLASS_QUERY(CountedLoop)
@@ -1249,6 +1259,24 @@
#undef I_VDUI_ONLY
#undef VDUI_ONLY
+// An Iterator that truly follows the iterator pattern. Doesn't
+// support deletion but could be made to.
+//
+// for (SimpleDUIterator i(n); i.has_next(); i.next()) {
+// Node* m = i.get();
+//
+class SimpleDUIterator : public StackObj {
+ private:
+ Node* node;
+ DUIterator_Fast i;
+ DUIterator_Fast imax;
+ public:
+ SimpleDUIterator(Node* n): node(n), i(n->fast_outs(imax)) {}
+ bool has_next() { return i < imax; }
+ void next() { i++; }
+ Node* get() { return node->fast_out(i); }
+};
+
//-----------------------------------------------------------------------------
// Map dense integer indices to Nodes. Uses classic doubling-array trick.
@@ -1290,6 +1318,12 @@
public:
Node_List() : Node_Array(Thread::current()->resource_area()), _cnt(0) {}
Node_List(Arena *a) : Node_Array(a), _cnt(0) {}
+ bool contains(Node* n) {
+ for (uint e = 0; e < size(); e++) {
+ if (at(e) == n) return true;
+ }
+ return false;
+ }
void insert( uint i, Node *n ) { Node_Array::insert(i,n); _cnt++; }
void remove( uint i ) { Node_Array::remove(i); _cnt--; }
void push( Node *b ) { map(_cnt++,b); }
--- a/hotspot/src/share/vm/opto/parse1.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/parse1.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -231,12 +231,13 @@
// Use the raw liveness computation to make sure that unexpected
// values don't propagate into the OSR frame.
- MethodLivenessResult live_locals = method()->raw_liveness_at_bci(osr_bci());
+ MethodLivenessResult live_locals = method()->liveness_at_bci(osr_bci());
if (!live_locals.is_valid()) {
// Degenerate or breakpointed method.
C->record_method_not_compilable("OSR in empty or breakpointed method");
return;
}
+ MethodLivenessResult raw_live_locals = method()->raw_liveness_at_bci(osr_bci());
// Extract the needed locals from the interpreter frame.
Node *locals_addr = basic_plus_adr(osr_buf, osr_buf, (max_locals-1)*wordSize);
@@ -316,6 +317,10 @@
continue;
}
}
+ if (type->basic_type() == T_ADDRESS && !raw_live_locals.at(index)) {
+ // Skip type check for dead address locals
+ continue;
+ }
set_local(index, check_interpreter_type(l, type, bad_type_exit));
}
--- a/hotspot/src/share/vm/opto/parse3.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/parse3.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -240,19 +240,19 @@
// membar is dependent on the store, keeping any other membars generated
// below from floating up past the store.
int adr_idx = C->get_alias_index(adr_type);
- insert_mem_bar_volatile(Op_MemBarVolatile, adr_idx);
+ insert_mem_bar_volatile(Op_MemBarVolatile, adr_idx, store);
// Now place a membar for AliasIdxBot for the unknown yet-to-be-parsed
// volatile alias indices. Skip this if the membar is redundant.
if (adr_idx != Compile::AliasIdxBot) {
- insert_mem_bar_volatile(Op_MemBarVolatile, Compile::AliasIdxBot);
+ insert_mem_bar_volatile(Op_MemBarVolatile, Compile::AliasIdxBot, store);
}
// Finally, place alias-index-specific membars for each volatile index
// that isn't the adr_idx membar. Typically there's only 1 or 2.
for( int i = Compile::AliasIdxRaw; i < C->num_alias_types(); i++ ) {
if (i != adr_idx && C->alias_type(i)->is_volatile()) {
- insert_mem_bar_volatile(Op_MemBarVolatile, i);
+ insert_mem_bar_volatile(Op_MemBarVolatile, i, store);
}
}
}
--- a/hotspot/src/share/vm/opto/parseHelper.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/parseHelper.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -221,6 +221,14 @@
// Push resultant oop onto stack
push(obj);
+
+ // Keep track of whether opportunities exist for StringBuilder
+ // optimizations.
+ if (OptimizeStringConcat &&
+ (klass == C->env()->StringBuilder_klass() ||
+ klass == C->env()->StringBuffer_klass())) {
+ C->set_has_stringbuilder(true);
+ }
}
#ifndef PRODUCT
--- a/hotspot/src/share/vm/opto/phase.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/phase.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -44,6 +44,7 @@
BlockLayout, // Linear ordering of blocks
Register_Allocation, // Register allocation, duh
LIVE, // Dragon-book LIVE range problem
+ StringOpts, // StringBuilder related optimizations
Interference_Graph, // Building the IFG
Coalesce, // Coalescing copies
Ideal_Loop, // Find idealized trip-counted loops
--- a/hotspot/src/share/vm/opto/phaseX.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/phaseX.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -345,7 +345,11 @@
Node *hash_find(const Node *n) { return _table.hash_find(n); }
// Used after parsing to eliminate values that are no longer in program
- void remove_useless_nodes(VectorSet &useful) { _table.remove_useless_nodes(useful); }
+ void remove_useless_nodes(VectorSet &useful) {
+ _table.remove_useless_nodes(useful);
+ // this may invalidate cached cons so reset the cache
+ init_con_caches();
+ }
virtual ConNode* uncached_makecon(const Type* t); // override from PhaseTransform
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/opto/stringopts.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,1395 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_stringopts.cpp.incl"
+
+#define __ kit.
+
+class StringConcat : public ResourceObj {
+ private:
+ PhaseStringOpts* _stringopts;
+ Node* _string_alloc;
+ AllocateNode* _begin; // The allocation the begins the pattern
+ CallStaticJavaNode* _end; // The final call of the pattern. Will either be
+ // SB.toString or or String.<init>(SB.toString)
+ bool _multiple; // indicates this is a fusion of two or more
+ // separate StringBuilders
+
+ Node* _arguments; // The list of arguments to be concatenated
+ GrowableArray<int> _mode; // into a String along with a mode flag
+ // indicating how to treat the value.
+
+ Node_List _control; // List of control nodes that will be deleted
+ Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten
+ // to restart at the initial JVMState.
+ public:
+ // Mode for converting arguments to Strings
+ enum {
+ StringMode,
+ IntMode,
+ CharMode
+ };
+
+ StringConcat(PhaseStringOpts* stringopts, CallStaticJavaNode* end):
+ _end(end),
+ _begin(NULL),
+ _multiple(false),
+ _string_alloc(NULL),
+ _stringopts(stringopts) {
+ _arguments = new (_stringopts->C, 1) Node(1);
+ _arguments->del_req(0);
+ }
+
+ bool validate_control_flow();
+
+ void merge_add() {
+#if 0
+ // XXX This is place holder code for reusing an existing String
+ // allocation but the logic for checking the state safety is
+ // probably inadequate at the moment.
+ CallProjections endprojs;
+ sc->end()->extract_projections(&endprojs, false);
+ if (endprojs.resproj != NULL) {
+ for (SimpleDUIterator i(endprojs.resproj); i.has_next(); i.next()) {
+ CallStaticJavaNode *use = i.get()->isa_CallStaticJava();
+ if (use != NULL && use->method() != NULL &&
+ use->method()->holder() == C->env()->String_klass() &&
+ use->method()->name() == ciSymbol::object_initializer_name() &&
+ use->in(TypeFunc::Parms + 1) == endprojs.resproj) {
+ // Found useless new String(sb.toString()) so reuse the newly allocated String
+ // when creating the result instead of allocating a new one.
+ sc->set_string_alloc(use->in(TypeFunc::Parms));
+ sc->set_end(use);
+ }
+ }
+ }
+#endif
+ }
+
+ StringConcat* merge(StringConcat* other, Node* arg);
+
+ void set_allocation(AllocateNode* alloc) {
+ _begin = alloc;
+ }
+
+ void append(Node* value, int mode) {
+ _arguments->add_req(value);
+ _mode.append(mode);
+ }
+ void push(Node* value, int mode) {
+ _arguments->ins_req(0, value);
+ _mode.insert_before(0, mode);
+ }
+ void push_string(Node* value) {
+ push(value, StringMode);
+ }
+ void push_int(Node* value) {
+ push(value, IntMode);
+ }
+ void push_char(Node* value) {
+ push(value, CharMode);
+ }
+
+ Node* argument(int i) {
+ return _arguments->in(i);
+ }
+ void set_argument(int i, Node* value) {
+ _arguments->set_req(i, value);
+ }
+ int num_arguments() {
+ return _mode.length();
+ }
+ int mode(int i) {
+ return _mode.at(i);
+ }
+ void add_control(Node* ctrl) {
+ assert(!_control.contains(ctrl), "only push once");
+ _control.push(ctrl);
+ }
+ CallStaticJavaNode* end() { return _end; }
+ AllocateNode* begin() { return _begin; }
+ Node* string_alloc() { return _string_alloc; }
+
+ void eliminate_unneeded_control();
+ void eliminate_initialize(InitializeNode* init);
+ void eliminate_call(CallNode* call);
+
+ void maybe_log_transform() {
+ CompileLog* log = _stringopts->C->log();
+ if (log != NULL) {
+ log->head("replace_string_concat arguments='%d' string_alloc='%d' multiple='%d'",
+ num_arguments(),
+ _string_alloc != NULL,
+ _multiple);
+ JVMState* p = _begin->jvms();
+ while (p != NULL) {
+ log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
+ p = p->caller();
+ }
+ log->tail("replace_string_concat");
+ }
+ }
+
+ void convert_uncommon_traps(GraphKit& kit, const JVMState* jvms) {
+ for (uint u = 0; u < _uncommon_traps.size(); u++) {
+ Node* uct = _uncommon_traps.at(u);
+
+ // Build a new call using the jvms state of the allocate
+ address call_addr = SharedRuntime::uncommon_trap_blob()->instructions_begin();
+ const TypeFunc* call_type = OptoRuntime::uncommon_trap_Type();
+ int size = call_type->domain()->cnt();
+ const TypePtr* no_memory_effects = NULL;
+ Compile* C = _stringopts->C;
+ CallStaticJavaNode* call = new (C, size) CallStaticJavaNode(call_type, call_addr, "uncommon_trap",
+ jvms->bci(), no_memory_effects);
+ for (int e = 0; e < TypeFunc::Parms; e++) {
+ call->init_req(e, uct->in(e));
+ }
+ // Set the trap request to record intrinsic failure if this trap
+ // is taken too many times. Ideally we would handle then traps by
+ // doing the original bookkeeping in the MDO so that if it caused
+ // the code to be thrown out we could still recompile and use the
+ // optimization. Failing the uncommon traps doesn't really mean
+ // that the optimization is a bad idea but there's no other way to
+ // do the MDO updates currently.
+ int trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_intrinsic,
+ Deoptimization::Action_make_not_entrant);
+ call->init_req(TypeFunc::Parms, __ intcon(trap_request));
+ kit.add_safepoint_edges(call);
+
+ _stringopts->gvn()->transform(call);
+ C->gvn_replace_by(uct, call);
+ uct->disconnect_inputs(NULL);
+ }
+ }
+
+ void cleanup() {
+ // disconnect the hook node
+ _arguments->disconnect_inputs(NULL);
+ }
+};
+
+
+void StringConcat::eliminate_unneeded_control() {
+ eliminate_initialize(begin()->initialization());
+ for (uint i = 0; i < _control.size(); i++) {
+ Node* n = _control.at(i);
+ if (n->is_Call()) {
+ if (n != _end) {
+ eliminate_call(n->as_Call());
+ }
+ } else if (n->is_IfTrue()) {
+ Compile* C = _stringopts->C;
+ C->gvn_replace_by(n, n->in(0)->in(0));
+ C->gvn_replace_by(n->in(0), C->top());
+ }
+ }
+}
+
+
+StringConcat* StringConcat::merge(StringConcat* other, Node* arg) {
+ StringConcat* result = new StringConcat(_stringopts, _end);
+ for (uint x = 0; x < _control.size(); x++) {
+ Node* n = _control.at(x);
+ if (n->is_Call()) {
+ result->_control.push(n);
+ }
+ }
+ for (uint x = 0; x < other->_control.size(); x++) {
+ Node* n = other->_control.at(x);
+ if (n->is_Call()) {
+ result->_control.push(n);
+ }
+ }
+ assert(result->_control.contains(other->_end), "what?");
+ assert(result->_control.contains(_begin), "what?");
+ for (int x = 0; x < num_arguments(); x++) {
+ if (argument(x) == arg) {
+ // replace the toString result with the all the arguments that
+ // made up the other StringConcat
+ for (int y = 0; y < other->num_arguments(); y++) {
+ result->append(other->argument(y), other->mode(y));
+ }
+ } else {
+ result->append(argument(x), mode(x));
+ }
+ }
+ result->set_allocation(other->_begin);
+ result->_multiple = true;
+ return result;
+}
+
+
+void StringConcat::eliminate_call(CallNode* call) {
+ Compile* C = _stringopts->C;
+ CallProjections projs;
+ call->extract_projections(&projs, false);
+ if (projs.fallthrough_catchproj != NULL) {
+ C->gvn_replace_by(projs.fallthrough_catchproj, call->in(TypeFunc::Control));
+ }
+ if (projs.fallthrough_memproj != NULL) {
+ C->gvn_replace_by(projs.fallthrough_memproj, call->in(TypeFunc::Memory));
+ }
+ if (projs.catchall_memproj != NULL) {
+ C->gvn_replace_by(projs.catchall_memproj, C->top());
+ }
+ if (projs.fallthrough_ioproj != NULL) {
+ C->gvn_replace_by(projs.fallthrough_ioproj, call->in(TypeFunc::I_O));
+ }
+ if (projs.catchall_ioproj != NULL) {
+ C->gvn_replace_by(projs.catchall_ioproj, C->top());
+ }
+ if (projs.catchall_catchproj != NULL) {
+ // EA can't cope with the partially collapsed graph this
+ // creates so put it on the worklist to be collapsed later.
+ for (SimpleDUIterator i(projs.catchall_catchproj); i.has_next(); i.next()) {
+ Node *use = i.get();
+ int opc = use->Opcode();
+ if (opc == Op_CreateEx || opc == Op_Region) {
+ _stringopts->record_dead_node(use);
+ }
+ }
+ C->gvn_replace_by(projs.catchall_catchproj, C->top());
+ }
+ if (projs.resproj != NULL) {
+ C->gvn_replace_by(projs.resproj, C->top());
+ }
+ C->gvn_replace_by(call, C->top());
+}
+
+void StringConcat::eliminate_initialize(InitializeNode* init) {
+ Compile* C = _stringopts->C;
+
+ // 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);
+ if (ctrl_proj != NULL) {
+ C->gvn_replace_by(ctrl_proj, init->in(TypeFunc::Control));
+ }
+ Node *mem_proj = init->proj_out(TypeFunc::Memory);
+ if (mem_proj != NULL) {
+ Node *mem = init->in(TypeFunc::Memory);
+ C->gvn_replace_by(mem_proj, mem);
+ }
+ C->gvn_replace_by(init, C->top());
+ init->disconnect_inputs(NULL);
+}
+
+Node_List PhaseStringOpts::collect_toString_calls() {
+ Node_List string_calls;
+ Node_List worklist;
+
+ _visited.Clear();
+
+ // Prime the worklist
+ for (uint i = 1; i < C->root()->len(); i++) {
+ Node* n = C->root()->in(i);
+ if (n != NULL && !_visited.test_set(n->_idx)) {
+ worklist.push(n);
+ }
+ }
+
+ while (worklist.size() > 0) {
+ Node* ctrl = worklist.pop();
+ if (ctrl->is_CallStaticJava()) {
+ CallStaticJavaNode* csj = ctrl->as_CallStaticJava();
+ ciMethod* m = csj->method();
+ if (m != NULL &&
+ (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString ||
+ m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) {
+ string_calls.push(csj);
+ }
+ }
+ if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) {
+ worklist.push(ctrl->in(0));
+ }
+ if (ctrl->is_Region()) {
+ for (uint i = 1; i < ctrl->len(); i++) {
+ if (ctrl->in(i) != NULL && !_visited.test_set(ctrl->in(i)->_idx)) {
+ worklist.push(ctrl->in(i));
+ }
+ }
+ }
+ }
+ return string_calls;
+}
+
+
+StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
+ ciMethod* m = call->method();
+ ciSymbol* string_sig;
+ ciSymbol* int_sig;
+ ciSymbol* char_sig;
+ if (m->holder() == C->env()->StringBuilder_klass()) {
+ string_sig = ciSymbol::String_StringBuilder_signature();
+ int_sig = ciSymbol::int_StringBuilder_signature();
+ char_sig = ciSymbol::char_StringBuilder_signature();
+ } else if (m->holder() == C->env()->StringBuffer_klass()) {
+ string_sig = ciSymbol::String_StringBuffer_signature();
+ int_sig = ciSymbol::int_StringBuffer_signature();
+ char_sig = ciSymbol::char_StringBuffer_signature();
+ } else {
+ return NULL;
+ }
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print("considering toString call in ");
+ call->jvms()->dump_spec(tty); tty->cr();
+ }
+#endif
+
+ StringConcat* sc = new StringConcat(this, call);
+
+ AllocateNode* alloc = NULL;
+ InitializeNode* init = NULL;
+
+ // possible opportunity for StringBuilder fusion
+ CallStaticJavaNode* cnode = call;
+ while (cnode) {
+ Node* recv = cnode->in(TypeFunc::Parms)->uncast();
+ if (recv->is_Proj()) {
+ recv = recv->in(0);
+ }
+ cnode = recv->isa_CallStaticJava();
+ if (cnode == NULL) {
+ alloc = recv->isa_Allocate();
+ if (alloc == NULL) {
+ break;
+ }
+ // Find the constructor call
+ Node* result = alloc->result_cast();
+ if (result == NULL || !result->is_CheckCastPP()) {
+ // strange looking allocation
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print("giving up because allocation looks strange ");
+ alloc->jvms()->dump_spec(tty); tty->cr();
+ }
+#endif
+ break;
+ }
+ Node* constructor = NULL;
+ for (SimpleDUIterator i(result); i.has_next(); i.next()) {
+ CallStaticJavaNode *use = i.get()->isa_CallStaticJava();
+ if (use != NULL && use->method() != NULL &&
+ use->method()->name() == ciSymbol::object_initializer_name() &&
+ use->method()->holder() == m->holder()) {
+ // Matched the constructor.
+ ciSymbol* sig = use->method()->signature()->as_symbol();
+ if (sig == ciSymbol::void_method_signature() ||
+ sig == ciSymbol::int_void_signature() ||
+ sig == ciSymbol::string_void_signature()) {
+ if (sig == ciSymbol::string_void_signature()) {
+ // StringBuilder(String) so pick this up as the first argument
+ assert(use->in(TypeFunc::Parms + 1) != NULL, "what?");
+ sc->push_string(use->in(TypeFunc::Parms + 1));
+ }
+ // The int variant takes an initial size for the backing
+ // array so just treat it like the void version.
+ constructor = use;
+ } else {
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print("unexpected constructor signature: %s", sig->as_utf8());
+ }
+#endif
+ }
+ break;
+ }
+ }
+ if (constructor == NULL) {
+ // couldn't find constructor
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print("giving up because couldn't find constructor ");
+ alloc->jvms()->dump_spec(tty);
+ }
+#endif
+ break;
+ }
+
+ // Walked all the way back and found the constructor call so see
+ // if this call converted into a direct string concatenation.
+ sc->add_control(call);
+ sc->add_control(constructor);
+ sc->add_control(alloc);
+ sc->set_allocation(alloc);
+ if (sc->validate_control_flow()) {
+ return sc;
+ } else {
+ return NULL;
+ }
+ } else if (cnode->method() == NULL) {
+ break;
+ } else if (cnode->method()->holder() == m->holder() &&
+ cnode->method()->name() == ciSymbol::append_name() &&
+ (cnode->method()->signature()->as_symbol() == string_sig ||
+ cnode->method()->signature()->as_symbol() == char_sig ||
+ cnode->method()->signature()->as_symbol() == int_sig)) {
+ sc->add_control(cnode);
+ Node* arg = cnode->in(TypeFunc::Parms + 1);
+ if (cnode->method()->signature()->as_symbol() == int_sig) {
+ sc->push_int(arg);
+ } else if (cnode->method()->signature()->as_symbol() == char_sig) {
+ sc->push_char(arg);
+ } else {
+ if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) {
+ CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava();
+ if (csj->method() != NULL &&
+ csj->method()->holder() == C->env()->Integer_klass() &&
+ csj->method()->name() == ciSymbol::toString_name()) {
+ sc->add_control(csj);
+ sc->push_int(csj->in(TypeFunc::Parms));
+ continue;
+ }
+ }
+ sc->push_string(arg);
+ }
+ continue;
+ } else {
+ // some unhandled signature
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print("giving up because encountered unexpected signature ");
+ cnode->tf()->dump(); tty->cr();
+ cnode->in(TypeFunc::Parms + 1)->dump();
+ }
+#endif
+ break;
+ }
+ }
+ return NULL;
+}
+
+
+PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*):
+ Phase(StringOpts),
+ _gvn(gvn),
+ _visited(Thread::current()->resource_area()) {
+
+ assert(OptimizeStringConcat, "shouldn't be here");
+
+ size_table_field = C->env()->Integer_klass()->get_field_by_name(ciSymbol::make("sizeTable"),
+ ciSymbol::make("[I"), true);
+ if (size_table_field == NULL) {
+ // Something wrong so give up.
+ assert(false, "why can't we find Integer.sizeTable?");
+ return;
+ }
+
+ // Collect the types needed to talk about the various slices of memory
+ const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
+ false, NULL, 0);
+
+ const TypePtr* value_field_type = string_type->add_offset(java_lang_String::value_offset_in_bytes());
+ const TypePtr* offset_field_type = string_type->add_offset(java_lang_String::offset_offset_in_bytes());
+ const TypePtr* count_field_type = string_type->add_offset(java_lang_String::count_offset_in_bytes());
+
+ value_field_idx = C->get_alias_index(value_field_type);
+ count_field_idx = C->get_alias_index(count_field_type);
+ offset_field_idx = C->get_alias_index(offset_field_type);
+ char_adr_idx = C->get_alias_index(TypeAryPtr::CHARS);
+
+ // For each locally allocated StringBuffer see if the usages can be
+ // collapsed into a single String construction.
+
+ // Run through the list of allocation looking for SB.toString to see
+ // if it's possible to fuse the usage of the SB into a single String
+ // construction.
+ GrowableArray<StringConcat*> concats;
+ Node_List toStrings = collect_toString_calls();
+ while (toStrings.size() > 0) {
+ StringConcat* sc = build_candidate(toStrings.pop()->as_CallStaticJava());
+ if (sc != NULL) {
+ concats.push(sc);
+ }
+ }
+
+ // try to coalesce separate concats
+ restart:
+ for (int c = 0; c < concats.length(); c++) {
+ StringConcat* sc = concats.at(c);
+ for (int i = 0; i < sc->num_arguments(); i++) {
+ Node* arg = sc->argument(i);
+ if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) {
+ CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava();
+ if (csj->method() != NULL &&
+ (csj->method()->holder() == C->env()->StringBuffer_klass() ||
+ csj->method()->holder() == C->env()->StringBuilder_klass()) &&
+ csj->method()->name() == ciSymbol::toString_name()) {
+ for (int o = 0; o < concats.length(); o++) {
+ if (c == o) continue;
+ StringConcat* other = concats.at(o);
+ if (other->end() == csj) {
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print_cr("considering stacked concats");
+ }
+#endif
+
+ StringConcat* merged = sc->merge(other, arg);
+ if (merged->validate_control_flow()) {
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print_cr("stacking would succeed");
+ }
+#endif
+ if (c < o) {
+ concats.remove_at(o);
+ concats.at_put(c, merged);
+ } else {
+ concats.remove_at(c);
+ concats.at_put(o, merged);
+ }
+ goto restart;
+ } else {
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print_cr("stacking would fail");
+ }
+#endif
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ for (int c = 0; c < concats.length(); c++) {
+ StringConcat* sc = concats.at(c);
+ replace_string_concat(sc);
+ }
+
+ remove_dead_nodes();
+}
+
+void PhaseStringOpts::record_dead_node(Node* dead) {
+ dead_worklist.push(dead);
+}
+
+void PhaseStringOpts::remove_dead_nodes() {
+ // Delete any dead nodes to make things clean enough that escape
+ // analysis doesn't get unhappy.
+ while (dead_worklist.size() > 0) {
+ Node* use = dead_worklist.pop();
+ int opc = use->Opcode();
+ switch (opc) {
+ case Op_Region: {
+ uint i = 1;
+ for (i = 1; i < use->req(); i++) {
+ if (use->in(i) != C->top()) {
+ break;
+ }
+ }
+ if (i >= use->req()) {
+ for (SimpleDUIterator i(use); i.has_next(); i.next()) {
+ Node* m = i.get();
+ if (m->is_Phi()) {
+ dead_worklist.push(m);
+ }
+ }
+ C->gvn_replace_by(use, C->top());
+ }
+ break;
+ }
+ case Op_AddP:
+ case Op_CreateEx: {
+ // Recurisvely clean up references to CreateEx so EA doesn't
+ // get unhappy about the partially collapsed graph.
+ for (SimpleDUIterator i(use); i.has_next(); i.next()) {
+ Node* m = i.get();
+ if (m->is_AddP()) {
+ dead_worklist.push(m);
+ }
+ }
+ C->gvn_replace_by(use, C->top());
+ break;
+ }
+ case Op_Phi:
+ if (use->in(0) == C->top()) {
+ C->gvn_replace_by(use, C->top());
+ }
+ break;
+ }
+ }
+}
+
+
+bool StringConcat::validate_control_flow() {
+ // We found all the calls and arguments now lets see if it's
+ // safe to transform the graph as we would expect.
+
+ // Check to see if this resulted in too many uncommon traps previously
+ if (Compile::current()->too_many_traps(_begin->jvms()->method(), _begin->jvms()->bci(),
+ Deoptimization::Reason_intrinsic)) {
+ return false;
+ }
+
+ // Walk backwards over the control flow from toString to the
+ // allocation and make sure all the control flow is ok. This
+ // means it's either going to be eliminated once the calls are
+ // removed or it can safely be transformed into an uncommon
+ // trap.
+
+ int null_check_count = 0;
+ Unique_Node_List ctrl_path;
+
+ assert(_control.contains(_begin), "missing");
+ assert(_control.contains(_end), "missing");
+
+ // Collect the nodes that we know about and will eliminate into ctrl_path
+ for (uint i = 0; i < _control.size(); i++) {
+ // Push the call and it's control projection
+ Node* n = _control.at(i);
+ if (n->is_Allocate()) {
+ AllocateNode* an = n->as_Allocate();
+ InitializeNode* init = an->initialization();
+ ctrl_path.push(init);
+ ctrl_path.push(init->as_Multi()->proj_out(0));
+ }
+ if (n->is_Call()) {
+ CallNode* cn = n->as_Call();
+ ctrl_path.push(cn);
+ ctrl_path.push(cn->proj_out(0));
+ ctrl_path.push(cn->proj_out(0)->unique_out());
+ ctrl_path.push(cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0));
+ } else {
+ ShouldNotReachHere();
+ }
+ }
+
+ // Skip backwards through the control checking for unexpected contro flow
+ Node* ptr = _end;
+ bool fail = false;
+ while (ptr != _begin) {
+ if (ptr->is_Call() && ctrl_path.member(ptr)) {
+ ptr = ptr->in(0);
+ } else if (ptr->is_CatchProj() && ctrl_path.member(ptr)) {
+ ptr = ptr->in(0)->in(0)->in(0);
+ assert(ctrl_path.member(ptr), "should be a known piece of control");
+ } else if (ptr->is_IfTrue()) {
+ IfNode* iff = ptr->in(0)->as_If();
+ BoolNode* b = iff->in(1)->isa_Bool();
+ Node* cmp = b->in(1);
+ Node* v1 = cmp->in(1);
+ Node* v2 = cmp->in(2);
+ Node* otherproj = iff->proj_out(1 - ptr->as_Proj()->_con);
+
+ // Null check of the return of append which can simply be eliminated
+ if (b->_test._test == BoolTest::ne &&
+ v2->bottom_type() == TypePtr::NULL_PTR &&
+ v1->is_Proj() && ctrl_path.member(v1->in(0))) {
+ // NULL check of the return value of the append
+ null_check_count++;
+ if (otherproj->outcnt() == 1) {
+ CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava();
+ if (call != NULL && call->_name != NULL && strcmp(call->_name, "uncommon_trap") == 0) {
+ ctrl_path.push(call);
+ }
+ }
+ _control.push(ptr);
+ ptr = ptr->in(0)->in(0);
+ continue;
+ }
+
+ // A test which leads to an uncommon trap which should be safe.
+ // Later this trap will be converted into a trap that restarts
+ // at the beginning.
+ if (otherproj->outcnt() == 1) {
+ CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava();
+ if (call != NULL && call->_name != NULL && strcmp(call->_name, "uncommon_trap") == 0) {
+ // control flow leads to uct so should be ok
+ _uncommon_traps.push(call);
+ ctrl_path.push(call);
+ ptr = ptr->in(0)->in(0);
+ continue;
+ }
+ }
+
+#ifndef PRODUCT
+ // Some unexpected control flow we don't know how to handle.
+ if (PrintOptimizeStringConcat) {
+ tty->print_cr("failing with unknown test");
+ b->dump();
+ cmp->dump();
+ v1->dump();
+ v2->dump();
+ tty->cr();
+ }
+#endif
+ break;
+ } else if (ptr->is_Proj() && ptr->in(0)->is_Initialize()) {
+ ptr = ptr->in(0)->in(0);
+ } else if (ptr->is_Region()) {
+ Node* copy = ptr->as_Region()->is_copy();
+ if (copy != NULL) {
+ ptr = copy;
+ continue;
+ }
+ if (ptr->req() == 3 &&
+ ptr->in(1) != NULL && ptr->in(1)->is_Proj() &&
+ ptr->in(2) != NULL && ptr->in(2)->is_Proj() &&
+ ptr->in(1)->in(0) == ptr->in(2)->in(0) &&
+ ptr->in(1)->in(0) != NULL && ptr->in(1)->in(0)->is_If()) {
+ // Simple diamond.
+ // XXX should check for possibly merging stores. simple data merges are ok.
+ ptr = ptr->in(1)->in(0)->in(0);
+ continue;
+ }
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print_cr("fusion would fail for region");
+ _begin->dump();
+ ptr->dump(2);
+ }
+#endif
+ fail = true;
+ break;
+ } else {
+ // other unknown control
+ if (!fail) {
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ tty->print_cr("fusion would fail for");
+ _begin->dump();
+ }
+#endif
+ fail = true;
+ }
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ ptr->dump();
+ }
+#endif
+ ptr = ptr->in(0);
+ }
+ }
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat && fail) {
+ tty->cr();
+ }
+#endif
+ if (fail) return !fail;
+
+ // Validate that all these results produced are contained within
+ // this cluster of objects. First collect all the results produced
+ // by calls in the region.
+ _stringopts->_visited.Clear();
+ Node_List worklist;
+ Node* final_result = _end->proj_out(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;
+ if (result != NULL && result != final_result) {
+ worklist.push(result);
+ }
+ }
+
+ Node* last_result = NULL;
+ while (worklist.size() > 0) {
+ Node* result = worklist.pop();
+ if (_stringopts->_visited.test_set(result->_idx))
+ continue;
+ for (SimpleDUIterator i(result); i.has_next(); i.next()) {
+ Node *use = i.get();
+ if (ctrl_path.member(use)) {
+ // already checked this
+ continue;
+ }
+ int opc = use->Opcode();
+ if (opc == Op_CmpP || opc == Op_Node) {
+ ctrl_path.push(use);
+ continue;
+ }
+ if (opc == Op_CastPP || opc == Op_CheckCastPP) {
+ for (SimpleDUIterator j(use); j.has_next(); j.next()) {
+ worklist.push(j.get());
+ }
+ worklist.push(use->in(1));
+ ctrl_path.push(use);
+ continue;
+ }
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat) {
+ if (result != last_result) {
+ last_result = result;
+ tty->print_cr("extra uses for result:");
+ last_result->dump();
+ }
+ use->dump();
+ }
+#endif
+ fail = true;
+ break;
+ }
+ }
+
+#ifndef PRODUCT
+ if (PrintOptimizeStringConcat && !fail) {
+ ttyLocker ttyl;
+ tty->cr();
+ tty->print("fusion would succeed (%d %d) for ", null_check_count, _uncommon_traps.size());
+ _begin->jvms()->dump_spec(tty); tty->cr();
+ for (int i = 0; i < num_arguments(); i++) {
+ argument(i)->dump();
+ }
+ _control.dump();
+ tty->cr();
+ }
+#endif
+
+ return !fail;
+}
+
+Node* PhaseStringOpts::fetch_static_field(GraphKit& kit, ciField* field) {
+ const TypeKlassPtr* klass_type = TypeKlassPtr::make(field->holder());
+ Node* klass_node = __ makecon(klass_type);
+ BasicType bt = field->layout_type();
+ ciType* field_klass = field->type();
+
+ const Type *type;
+ if( bt == T_OBJECT ) {
+ if (!field->type()->is_loaded()) {
+ type = TypeInstPtr::BOTTOM;
+ } else if (field->is_constant()) {
+ // This can happen if the constant oop is non-perm.
+ ciObject* con = field->constant_value().as_object();
+ // Do not "join" in the previous type; it doesn't add value,
+ // and may yield a vacuous result if the field is of interface type.
+ type = TypeOopPtr::make_from_constant(con)->isa_oopptr();
+ assert(type != NULL, "field singleton type must be consistent");
+ } else {
+ type = TypeOopPtr::make_from_klass(field_klass->as_klass());
+ }
+ } else {
+ type = Type::get_const_basic_type(bt);
+ }
+
+ return kit.make_load(NULL, kit.basic_plus_adr(klass_node, field->offset_in_bytes()),
+ type, T_OBJECT,
+ C->get_alias_index(klass_type->add_offset(field->offset_in_bytes())));
+}
+
+Node* PhaseStringOpts::int_stringSize(GraphKit& kit, Node* arg) {
+ RegionNode *final_merge = new (C, 3) RegionNode(3);
+ kit.gvn().set_type(final_merge, Type::CONTROL);
+ Node* final_size = new (C, 3) PhiNode(final_merge, TypeInt::INT);
+ kit.gvn().set_type(final_size, TypeInt::INT);
+
+ IfNode* iff = kit.create_and_map_if(kit.control(),
+ __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne),
+ PROB_FAIR, COUNT_UNKNOWN);
+ Node* is_min = __ IfFalse(iff);
+ final_merge->init_req(1, is_min);
+ final_size->init_req(1, __ intcon(11));
+
+ kit.set_control(__ IfTrue(iff));
+ if (kit.stopped()) {
+ final_merge->init_req(2, C->top());
+ final_size->init_req(2, C->top());
+ } else {
+
+ // int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
+ RegionNode *r = new (C, 3) RegionNode(3);
+ kit.gvn().set_type(r, Type::CONTROL);
+ Node *phi = new (C, 3) PhiNode(r, TypeInt::INT);
+ kit.gvn().set_type(phi, TypeInt::INT);
+ Node *size = new (C, 3) PhiNode(r, TypeInt::INT);
+ kit.gvn().set_type(size, TypeInt::INT);
+ Node* chk = __ CmpI(arg, __ intcon(0));
+ Node* p = __ Bool(chk, BoolTest::lt);
+ IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_FAIR, COUNT_UNKNOWN);
+ Node* lessthan = __ IfTrue(iff);
+ Node* greaterequal = __ IfFalse(iff);
+ r->init_req(1, lessthan);
+ phi->init_req(1, __ SubI(__ intcon(0), arg));
+ size->init_req(1, __ intcon(1));
+ r->init_req(2, greaterequal);
+ phi->init_req(2, arg);
+ size->init_req(2, __ intcon(0));
+ kit.set_control(r);
+ C->record_for_igvn(r);
+ C->record_for_igvn(phi);
+ C->record_for_igvn(size);
+
+ // for (int i=0; ; i++)
+ // if (x <= sizeTable[i])
+ // return i+1;
+ RegionNode *loop = new (C, 3) RegionNode(3);
+ loop->init_req(1, kit.control());
+ kit.gvn().set_type(loop, Type::CONTROL);
+
+ Node *index = new (C, 3) PhiNode(loop, TypeInt::INT);
+ index->init_req(1, __ intcon(0));
+ kit.gvn().set_type(index, TypeInt::INT);
+ kit.set_control(loop);
+ Node* sizeTable = fetch_static_field(kit, size_table_field);
+
+ Node* value = kit.load_array_element(NULL, sizeTable, index, TypeAryPtr::INTS);
+ C->record_for_igvn(value);
+ Node* limit = __ CmpI(phi, value);
+ Node* limitb = __ Bool(limit, BoolTest::le);
+ IfNode* iff2 = kit.create_and_map_if(kit.control(), limitb, PROB_MIN, COUNT_UNKNOWN);
+ Node* lessEqual = __ IfTrue(iff2);
+ Node* greater = __ IfFalse(iff2);
+
+ loop->init_req(2, greater);
+ index->init_req(2, __ AddI(index, __ intcon(1)));
+
+ kit.set_control(lessEqual);
+ C->record_for_igvn(loop);
+ C->record_for_igvn(index);
+
+ final_merge->init_req(2, kit.control());
+ final_size->init_req(2, __ AddI(__ AddI(index, size), __ intcon(1)));
+ }
+
+ kit.set_control(final_merge);
+ C->record_for_igvn(final_merge);
+ C->record_for_igvn(final_size);
+
+ return final_size;
+}
+
+void PhaseStringOpts::int_getChars(GraphKit& kit, Node* arg, Node* char_array, Node* start, Node* end) {
+ RegionNode *final_merge = new (C, 4) RegionNode(4);
+ kit.gvn().set_type(final_merge, Type::CONTROL);
+ Node *final_mem = PhiNode::make(final_merge, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS);
+ kit.gvn().set_type(final_mem, Type::MEMORY);
+
+ // need to handle Integer.MIN_VALUE specially because negating doesn't make it positive
+ {
+ // i == MIN_VALUE
+ IfNode* iff = kit.create_and_map_if(kit.control(),
+ __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne),
+ PROB_FAIR, COUNT_UNKNOWN);
+
+ Node* old_mem = kit.memory(char_adr_idx);
+
+ kit.set_control(__ IfFalse(iff));
+ if (kit.stopped()) {
+ // Statically not equal to MIN_VALUE so this path is dead
+ final_merge->init_req(3, kit.control());
+ } else {
+ copy_string(kit, __ makecon(TypeInstPtr::make(C->env()->the_min_jint_string())),
+ char_array, start);
+ final_merge->init_req(3, kit.control());
+ final_mem->init_req(3, kit.memory(char_adr_idx));
+ }
+
+ kit.set_control(__ IfTrue(iff));
+ kit.set_memory(old_mem, char_adr_idx);
+ }
+
+
+ // Simplified version of Integer.getChars
+
+ // int q, r;
+ // int charPos = index;
+ Node* charPos = end;
+
+ // char sign = 0;
+
+ Node* i = arg;
+ Node* sign = __ intcon(0);
+
+ // if (i < 0) {
+ // sign = '-';
+ // i = -i;
+ // }
+ {
+ IfNode* iff = kit.create_and_map_if(kit.control(),
+ __ Bool(__ CmpI(arg, __ intcon(0)), BoolTest::lt),
+ PROB_FAIR, COUNT_UNKNOWN);
+
+ RegionNode *merge = new (C, 3) RegionNode(3);
+ kit.gvn().set_type(merge, Type::CONTROL);
+ i = new (C, 3) PhiNode(merge, TypeInt::INT);
+ kit.gvn().set_type(i, TypeInt::INT);
+ sign = new (C, 3) PhiNode(merge, TypeInt::INT);
+ kit.gvn().set_type(sign, TypeInt::INT);
+
+ merge->init_req(1, __ IfTrue(iff));
+ i->init_req(1, __ SubI(__ intcon(0), arg));
+ sign->init_req(1, __ intcon('-'));
+ merge->init_req(2, __ IfFalse(iff));
+ i->init_req(2, arg);
+ sign->init_req(2, __ intcon(0));
+
+ kit.set_control(merge);
+
+ C->record_for_igvn(merge);
+ C->record_for_igvn(i);
+ C->record_for_igvn(sign);
+ }
+
+ // for (;;) {
+ // q = i / 10;
+ // r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
+ // buf [--charPos] = digits [r];
+ // i = q;
+ // if (i == 0) break;
+ // }
+
+ {
+ RegionNode *head = new (C, 3) RegionNode(3);
+ head->init_req(1, kit.control());
+ kit.gvn().set_type(head, Type::CONTROL);
+ Node *i_phi = new (C, 3) PhiNode(head, TypeInt::INT);
+ i_phi->init_req(1, i);
+ kit.gvn().set_type(i_phi, TypeInt::INT);
+ charPos = PhiNode::make(head, charPos);
+ kit.gvn().set_type(charPos, TypeInt::INT);
+ Node *mem = PhiNode::make(head, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS);
+ kit.gvn().set_type(mem, Type::MEMORY);
+ kit.set_control(head);
+ kit.set_memory(mem, char_adr_idx);
+
+ Node* q = __ DivI(kit.null(), i_phi, __ intcon(10));
+ Node* r = __ SubI(i_phi, __ AddI(__ LShiftI(q, __ intcon(3)),
+ __ LShiftI(q, __ intcon(1))));
+ Node* m1 = __ SubI(charPos, __ intcon(1));
+ Node* ch = __ AddI(r, __ intcon('0'));
+
+ Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR),
+ ch, T_CHAR, char_adr_idx);
+
+
+ IfNode* iff = kit.create_and_map_if(head, __ Bool(__ CmpI(q, __ intcon(0)), BoolTest::ne),
+ PROB_FAIR, COUNT_UNKNOWN);
+ Node* ne = __ IfTrue(iff);
+ Node* eq = __ IfFalse(iff);
+
+ head->init_req(2, ne);
+ mem->init_req(2, st);
+ i_phi->init_req(2, q);
+ charPos->init_req(2, m1);
+
+ charPos = m1;
+
+ kit.set_control(eq);
+ kit.set_memory(st, char_adr_idx);
+
+ C->record_for_igvn(head);
+ C->record_for_igvn(mem);
+ C->record_for_igvn(i_phi);
+ C->record_for_igvn(charPos);
+ }
+
+ {
+ // if (sign != 0) {
+ // buf [--charPos] = sign;
+ // }
+ IfNode* iff = kit.create_and_map_if(kit.control(),
+ __ Bool(__ CmpI(sign, __ intcon(0)), BoolTest::ne),
+ PROB_FAIR, COUNT_UNKNOWN);
+
+ final_merge->init_req(2, __ IfFalse(iff));
+ final_mem->init_req(2, kit.memory(char_adr_idx));
+
+ kit.set_control(__ IfTrue(iff));
+ if (kit.stopped()) {
+ final_merge->init_req(1, C->top());
+ final_mem->init_req(1, C->top());
+ } else {
+ Node* m1 = __ SubI(charPos, __ intcon(1));
+ Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR),
+ sign, T_CHAR, char_adr_idx);
+
+ final_merge->init_req(1, kit.control());
+ final_mem->init_req(1, st);
+ }
+
+ kit.set_control(final_merge);
+ kit.set_memory(final_mem, char_adr_idx);
+
+ C->record_for_igvn(final_merge);
+ C->record_for_igvn(final_mem);
+ }
+}
+
+
+Node* PhaseStringOpts::copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start) {
+ Node* string = str;
+ Node* offset = kit.make_load(NULL,
+ kit.basic_plus_adr(string, string, java_lang_String::offset_offset_in_bytes()),
+ TypeInt::INT, T_INT, offset_field_idx);
+ Node* count = kit.make_load(NULL,
+ kit.basic_plus_adr(string, string, java_lang_String::count_offset_in_bytes()),
+ TypeInt::INT, T_INT, count_field_idx);
+ const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull,
+ TypeAry::make(TypeInt::CHAR,TypeInt::POS),
+ ciTypeArrayKlass::make(T_CHAR), true, 0);
+ Node* value = kit.make_load(NULL,
+ kit.basic_plus_adr(string, string, java_lang_String::value_offset_in_bytes()),
+ value_type, T_OBJECT, value_field_idx);
+
+ // copy the contents
+ if (offset->is_Con() && count->is_Con() && value->is_Con() && count->get_int() < unroll_string_copy_length) {
+ // For small constant strings just emit individual stores.
+ // A length of 6 seems like a good space/speed tradeof.
+ int c = count->get_int();
+ int o = offset->get_int();
+ const TypeOopPtr* t = kit.gvn().type(value)->isa_oopptr();
+ ciTypeArray* value_array = t->const_oop()->as_type_array();
+ for (int e = 0; e < c; e++) {
+ __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR),
+ __ intcon(value_array->char_at(o + e)), T_CHAR, char_adr_idx);
+ start = __ AddI(start, __ intcon(1));
+ }
+ } else {
+ Node* src_ptr = kit.array_element_address(value, offset, T_CHAR);
+ Node* dst_ptr = kit.array_element_address(char_array, start, T_CHAR);
+ Node* c = count;
+ Node* extra = NULL;
+#ifdef _LP64
+ c = __ ConvI2L(c);
+ extra = C->top();
+#endif
+ Node* call = kit.make_runtime_call(GraphKit::RC_LEAF|GraphKit::RC_NO_FP,
+ OptoRuntime::fast_arraycopy_Type(),
+ CAST_FROM_FN_PTR(address, StubRoutines::jshort_disjoint_arraycopy()),
+ "jshort_disjoint_arraycopy", TypeAryPtr::CHARS,
+ src_ptr, dst_ptr, c, extra);
+ start = __ AddI(start, count);
+ }
+ return start;
+}
+
+
+void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
+ // Log a little info about the transformation
+ sc->maybe_log_transform();
+
+ // pull the JVMState of the allocation into a SafePointNode to serve as
+ // as a shim for the insertion of the new code.
+ JVMState* jvms = sc->begin()->jvms()->clone_shallow(C);
+ uint size = sc->begin()->req();
+ SafePointNode* map = new (C, size) SafePointNode(size, jvms);
+
+ // copy the control and memory state from the final call into our
+ // new starting state. This allows any preceeding tests to feed
+ // into the new section of code.
+ for (uint i1 = 0; i1 < TypeFunc::Parms; i1++) {
+ map->init_req(i1, sc->end()->in(i1));
+ }
+ // blow away old allocation arguments
+ for (uint i1 = TypeFunc::Parms; i1 < jvms->debug_start(); i1++) {
+ map->init_req(i1, C->top());
+ }
+ // Copy the rest of the inputs for the JVMState
+ for (uint i1 = jvms->debug_start(); i1 < sc->begin()->req(); i1++) {
+ map->init_req(i1, sc->begin()->in(i1));
+ }
+ // Make sure the memory state is a MergeMem for parsing.
+ if (!map->in(TypeFunc::Memory)->is_MergeMem()) {
+ map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory)));
+ }
+
+ jvms->set_map(map);
+ map->ensure_stack(jvms, jvms->method()->max_stack());
+
+
+ // disconnect all the old StringBuilder calls from the graph
+ sc->eliminate_unneeded_control();
+
+ // At this point all the old work has been completely removed from
+ // the graph and the saved JVMState exists at the point where the
+ // final toString call used to be.
+ GraphKit kit(jvms);
+
+ // There may be uncommon traps which are still using the
+ // intermediate states and these need to be rewritten to point at
+ // the JVMState at the beginning of the transformation.
+ sc->convert_uncommon_traps(kit, jvms);
+
+ // Now insert the logic to compute the size of the string followed
+ // by all the logic to construct array and resulting string.
+
+ Node* null_string = __ makecon(TypeInstPtr::make(C->env()->the_null_string()));
+
+ // Create a region for the overflow checks to merge into.
+ int args = MAX2(sc->num_arguments(), 1);
+ RegionNode* overflow = new (C, args) RegionNode(args);
+ kit.gvn().set_type(overflow, Type::CONTROL);
+
+ // Create a hook node to hold onto the individual sizes since they
+ // are need for the copying phase.
+ Node* string_sizes = new (C, args) Node(args);
+
+ Node* length = __ intcon(0);
+ for (int argi = 0; argi < sc->num_arguments(); argi++) {
+ Node* arg = sc->argument(argi);
+ switch (sc->mode(argi)) {
+ case StringConcat::IntMode: {
+ Node* string_size = int_stringSize(kit, arg);
+
+ // accumulate total
+ length = __ AddI(length, string_size);
+
+ // Cache this value for the use by int_toString
+ string_sizes->init_req(argi, string_size);
+ break;
+ }
+ case StringConcat::StringMode: {
+ const Type* type = kit.gvn().type(arg);
+ if (type == TypePtr::NULL_PTR) {
+ // replace the argument with the null checked version
+ arg = null_string;
+ sc->set_argument(argi, arg);
+ } else if (!type->higher_equal(TypeInstPtr::NOTNULL)) {
+ // s = s != null ? s : "null";
+ // length = length + (s.count - s.offset);
+ RegionNode *r = new (C, 3) RegionNode(3);
+ kit.gvn().set_type(r, Type::CONTROL);
+ Node *phi = new (C, 3) PhiNode(r, type->join(TypeInstPtr::NOTNULL));
+ kit.gvn().set_type(phi, phi->bottom_type());
+ Node* p = __ Bool(__ CmpP(arg, kit.null()), BoolTest::ne);
+ IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_MIN, COUNT_UNKNOWN);
+ Node* notnull = __ IfTrue(iff);
+ Node* isnull = __ IfFalse(iff);
+ r->init_req(1, notnull);
+ phi->init_req(1, arg);
+ r->init_req(2, isnull);
+ phi->init_req(2, null_string);
+ kit.set_control(r);
+ C->record_for_igvn(r);
+ C->record_for_igvn(phi);
+ // replace the argument with the null checked version
+ arg = phi;
+ sc->set_argument(argi, arg);
+ }
+ // Node* offset = kit.make_load(NULL, kit.basic_plus_adr(arg, arg, offset_offset),
+ // TypeInt::INT, T_INT, offset_field_idx);
+ Node* count = kit.make_load(NULL, kit.basic_plus_adr(arg, arg, java_lang_String::count_offset_in_bytes()),
+ TypeInt::INT, T_INT, count_field_idx);
+ length = __ AddI(length, count);
+ string_sizes->init_req(argi, NULL);
+ break;
+ }
+ case StringConcat::CharMode: {
+ // one character only
+ length = __ AddI(length, __ intcon(1));
+ break;
+ }
+ default:
+ ShouldNotReachHere();
+ }
+ if (argi > 0) {
+ // Check that the sum hasn't overflowed
+ IfNode* iff = kit.create_and_map_if(kit.control(),
+ __ Bool(__ CmpI(length, __ intcon(0)), BoolTest::lt),
+ PROB_MIN, COUNT_UNKNOWN);
+ kit.set_control(__ IfFalse(iff));
+ overflow->set_req(argi, __ IfTrue(iff));
+ }
+ }
+
+ {
+ // Hook
+ PreserveJVMState pjvms(&kit);
+ kit.set_control(overflow);
+ kit.uncommon_trap(Deoptimization::Reason_intrinsic,
+ Deoptimization::Action_make_not_entrant);
+ }
+
+ // length now contains the number of characters needed for the
+ // char[] so create a new AllocateArray for the char[]
+ Node* char_array = NULL;
+ {
+ PreserveReexecuteState preexecs(&kit);
+ // The original jvms is for an allocation of either a String or
+ // StringBuffer so no stack adjustment is necessary for proper
+ // reexecution. If we deoptimize in the slow path the bytecode
+ // will be reexecuted and the char[] allocation will be thrown away.
+ kit.jvms()->set_should_reexecute(true);
+ char_array = kit.new_array(__ makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_CHAR))),
+ length, 1);
+ }
+
+ // Mark the allocation so that zeroing is skipped since the code
+ // below will overwrite the entire array
+ AllocateArrayNode* char_alloc = AllocateArrayNode::Ideal_array_allocation(char_array, _gvn);
+ char_alloc->maybe_set_complete(_gvn);
+
+ // Now copy the string representations into the final char[]
+ Node* start = __ intcon(0);
+ for (int argi = 0; argi < sc->num_arguments(); argi++) {
+ Node* arg = sc->argument(argi);
+ switch (sc->mode(argi)) {
+ case StringConcat::IntMode: {
+ Node* end = __ AddI(start, string_sizes->in(argi));
+ // getChars words backwards so pass the ending point as well as the start
+ int_getChars(kit, arg, char_array, start, end);
+ start = end;
+ break;
+ }
+ case StringConcat::StringMode: {
+ start = copy_string(kit, arg, char_array, start);
+ break;
+ }
+ case StringConcat::CharMode: {
+ __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR),
+ arg, T_CHAR, char_adr_idx);
+ start = __ AddI(start, __ intcon(1));
+ break;
+ }
+ default:
+ ShouldNotReachHere();
+ }
+ }
+
+ // If we're not reusing an existing String allocation then allocate one here.
+ Node* result = sc->string_alloc();
+ if (result == NULL) {
+ PreserveReexecuteState preexecs(&kit);
+ // The original jvms is for an allocation of either a String or
+ // StringBuffer so no stack adjustment is necessary for proper
+ // reexecution.
+ kit.jvms()->set_should_reexecute(true);
+ result = kit.new_instance(__ makecon(TypeKlassPtr::make(C->env()->String_klass())));
+ }
+
+ // Intialize the string
+ kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::offset_offset_in_bytes()),
+ __ intcon(0), T_INT, offset_field_idx);
+ kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::count_offset_in_bytes()),
+ length, T_INT, count_field_idx);
+ kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::value_offset_in_bytes()),
+ char_array, T_OBJECT, value_field_idx);
+
+ // hook up the outgoing control and result
+ kit.replace_call(sc->end(), result);
+
+ // Unhook any hook nodes
+ string_sizes->disconnect_inputs(NULL);
+ sc->cleanup();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/opto/stringopts.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+class StringConcat;
+
+class PhaseStringOpts : public Phase {
+ friend class StringConcat;
+
+ private:
+ PhaseGVN* _gvn;
+
+ // List of dead nodes to clean up aggressively at the end
+ Unique_Node_List dead_worklist;
+
+ // Memory slices needed for code gen
+ int char_adr_idx;
+ int value_field_idx;
+ int count_field_idx;
+ int offset_field_idx;
+
+ // Integer.sizeTable - used for int to String conversion
+ ciField* size_table_field;
+
+ // A set for use by various stages
+ VectorSet _visited;
+
+ // Collect a list of all SB.toString calls
+ Node_List collect_toString_calls();
+
+ // Examine the use of the SB alloc to see if it can be replace with
+ // a single string construction.
+ StringConcat* build_candidate(CallStaticJavaNode* call);
+
+ // Replace all the SB calls in concat with an optimization String allocation
+ void replace_string_concat(StringConcat* concat);
+
+ // Load the value of a static field, performing any constant folding.
+ Node* fetch_static_field(GraphKit& kit, ciField* field);
+
+ // Compute the number of characters required to represent the int value
+ Node* int_stringSize(GraphKit& kit, Node* value);
+
+ // Copy the characters representing value into char_array starting at start
+ void int_getChars(GraphKit& kit, Node* value, Node* char_array, Node* start, Node* end);
+
+ // Copy of the contents of the String str into char_array starting at index start.
+ Node* copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start);
+
+ // Clean up any leftover nodes
+ void record_dead_node(Node* node);
+ void remove_dead_nodes();
+
+ PhaseGVN* gvn() { return _gvn; }
+
+ enum {
+ // max length of constant string copy unrolling in copy_string
+ unroll_string_copy_length = 6
+ };
+
+ public:
+ PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List* worklist);
+};
--- a/hotspot/src/share/vm/opto/superword.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/superword.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1921,6 +1921,11 @@
}
// Match AddP(base, AddP(ptr, k*iv [+ invariant]), constant)
Node* base = adr->in(AddPNode::Base);
+ //unsafe reference could not be aligned appropriately without runtime checking
+ if (base == NULL || base->bottom_type() == Type::TOP) {
+ assert(!valid(), "unsafe access");
+ return;
+ }
for (int i = 0; i < 3; i++) {
if (!scaled_iv_plus_offset(adr->in(AddPNode::Offset))) {
assert(!valid(), "too complex");
--- a/hotspot/src/share/vm/opto/type.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/opto/type.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -847,9 +847,6 @@
// Constant pointer to array
static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot);
- // Convenience
- static const TypeAryPtr *make(ciObject* o);
-
// Return a 'ptr' version of this type
virtual const Type *cast_to_ptr_type(PTR ptr) const;
--- a/hotspot/src/share/vm/prims/jni.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/prims/jni.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -3231,6 +3231,21 @@
jint result = JNI_ERR;
DT_RETURN_MARK(CreateJavaVM, jint, (const jint&)result);
+ // We're about to use Atomic::xchg for synchronization. Some Zero
+ // platforms use the GCC builtin __sync_lock_test_and_set for this,
+ // but __sync_lock_test_and_set is not guaranteed to do what we want
+ // on all architectures. So we check it works before relying on it.
+#if defined(ZERO) && defined(ASSERT)
+ {
+ jint a = 0xcafebabe;
+ jint b = Atomic::xchg(0xdeadbeef, &a);
+ void *c = &a;
+ void *d = Atomic::xchg_ptr(&b, &c);
+ assert(a == 0xdeadbeef && b == (jint) 0xcafebabe, "Atomic::xchg() works");
+ assert(c == &b && d == &a, "Atomic::xchg_ptr() works");
+ }
+#endif // ZERO && ASSERT
+
// At the moment it's only possible to have one Java VM,
// since some of the runtime state is in global variables.
--- a/hotspot/src/share/vm/prims/jvm.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/prims/jvm.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1318,19 +1318,20 @@
return NULL;
}
- symbolOop simple_name = NULL;
+ bool inner_is_member = false;
klassOop outer_klass
= instanceKlass::cast(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass))
- )->compute_enclosing_class(simple_name, CHECK_NULL);
+ )->compute_enclosing_class(&inner_is_member, CHECK_NULL);
if (outer_klass == NULL) return NULL; // already a top-level class
- if (simple_name == NULL) return NULL; // an anonymous class (inside a method)
+ if (!inner_is_member) return NULL; // an anonymous class (inside a method)
return (jclass) JNIHandles::make_local(env, Klass::cast(outer_klass)->java_mirror());
}
JVM_END
// should be in instanceKlass.cpp, but is here for historical reasons
klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle k,
- symbolOop& simple_name_result, TRAPS) {
+ bool* inner_is_member,
+ TRAPS) {
Thread* thread = THREAD;
const int inner_class_info_index = inner_class_inner_class_info_offset;
const int outer_class_info_index = inner_class_outer_class_info_offset;
@@ -1347,8 +1348,7 @@
bool found = false;
klassOop ok;
instanceKlassHandle outer_klass;
- bool inner_is_member = false;
- int simple_name_index = 0;
+ *inner_is_member = false;
// Find inner_klass attribute
for (int i = 0; i < i_length && !found; i += inner_class_next_offset) {
@@ -1364,8 +1364,7 @@
if (found && ooff != 0) {
ok = i_cp->klass_at(ooff, CHECK_NULL);
outer_klass = instanceKlassHandle(thread, ok);
- simple_name_index = noff;
- inner_is_member = true;
+ *inner_is_member = true;
}
}
}
@@ -1377,7 +1376,7 @@
if (encl_method_class_idx != 0) {
ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL);
outer_klass = instanceKlassHandle(thread, ok);
- inner_is_member = false;
+ *inner_is_member = false;
}
}
@@ -1387,9 +1386,7 @@
// Throws an exception if outer klass has not declared k as an inner klass
// We need evidence that each klass knows about the other, or else
// the system could allow a spoof of an inner class to gain access rights.
- Reflection::check_for_inner_class(outer_klass, k, inner_is_member, CHECK_NULL);
-
- simple_name_result = (inner_is_member ? i_cp->symbol_at(simple_name_index) : symbolOop(NULL));
+ Reflection::check_for_inner_class(outer_klass, k, *inner_is_member, CHECK_NULL);
return outer_klass();
}
@@ -2257,10 +2254,8 @@
switch (cp->tag_at(cp_index).value()) {
case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_Methodref:
+ case JVM_CONSTANT_NameAndType: // for invokedynamic
return cp->uncached_name_ref_at(cp_index)->as_utf8();
- case JVM_CONSTANT_NameAndType:
- // for invokedynamic
- return cp->nt_name_ref_at(cp_index)->as_utf8();
default:
fatal("JVM_GetCPMethodNameUTF: illegal constant");
}
@@ -2277,10 +2272,8 @@
switch (cp->tag_at(cp_index).value()) {
case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_Methodref:
+ case JVM_CONSTANT_NameAndType: // for invokedynamic
return cp->uncached_signature_ref_at(cp_index)->as_utf8();
- case JVM_CONSTANT_NameAndType:
- // for invokedynamic
- return cp->nt_signature_ref_at(cp_index)->as_utf8();
default:
fatal("JVM_GetCPMethodSignatureUTF: illegal constant");
}
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,15 +32,15 @@
// FIXLATER: hook into JvmtiTrace
#define TraceJVMTICalls false
-JvmtiEnv::JvmtiEnv() : JvmtiEnvBase() {
+JvmtiEnv::JvmtiEnv(jint version) : JvmtiEnvBase(version) {
}
JvmtiEnv::~JvmtiEnv() {
}
JvmtiEnv*
-JvmtiEnv::create_a_jvmti() {
- return new JvmtiEnv();
+JvmtiEnv::create_a_jvmti(jint version) {
+ return new JvmtiEnv(version);
}
// VM operation class to copy jni function table at safepoint.
@@ -411,8 +411,15 @@
if (phase == JVMTI_PHASE_ONLOAD) {
Arguments::append_sysclasspath(segment);
return JVMTI_ERROR_NONE;
- } else {
- assert(phase == JVMTI_PHASE_LIVE, "sanity check");
+ } else if (use_version_1_0_semantics()) {
+ // This JvmtiEnv requested version 1.0 semantics and this function
+ // is only allowed in the ONLOAD phase in version 1.0 so we need to
+ // return an error here.
+ return JVMTI_ERROR_WRONG_PHASE;
+ } else if (phase == JVMTI_PHASE_LIVE) {
+ // The phase is checked by the wrapper that called this function,
+ // but this thread could be racing with the thread that is
+ // terminating the VM so we check one more time.
// create the zip entry
ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment);
@@ -433,6 +440,8 @@
}
ClassLoader::add_to_list(zip_entry);
return JVMTI_ERROR_NONE;
+ } else {
+ return JVMTI_ERROR_WRONG_PHASE;
}
} /* end AddToBootstrapClassLoaderSearch */
@@ -451,11 +460,12 @@
}
}
return JVMTI_ERROR_NONE;
- } else {
+ } else if (phase == JVMTI_PHASE_LIVE) {
+ // The phase is checked by the wrapper that called this function,
+ // but this thread could be racing with the thread that is
+ // terminating the VM so we check one more time.
HandleMark hm;
- assert(phase == JVMTI_PHASE_LIVE, "sanity check");
-
// create the zip entry (which will open the zip file and hence
// check that the segment is indeed a zip file).
ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment);
@@ -504,6 +514,8 @@
}
return JVMTI_ERROR_NONE;
+ } else {
+ return JVMTI_ERROR_WRONG_PHASE;
}
} /* end AddToSystemClassLoaderSearch */
@@ -2863,6 +2875,14 @@
// is_obsolete_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::IsMethodObsolete(methodOop method_oop, jboolean* is_obsolete_ptr) {
+ if (use_version_1_0_semantics() &&
+ get_capabilities()->can_redefine_classes == 0) {
+ // This JvmtiEnv requested version 1.0 semantics and this function
+ // requires the can_redefine_classes capability in version 1.0 so
+ // we need to return an error here.
+ return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
+ }
+
if (method_oop == NULL || method_oop->is_obsolete()) {
*is_obsolete_ptr = true;
} else {
--- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -123,7 +123,26 @@
}
-JvmtiEnvBase::JvmtiEnvBase() : _env_event_enable() {
+bool
+JvmtiEnvBase::use_version_1_0_semantics() {
+ int major, minor, micro;
+
+ JvmtiExport::decode_version_values(_version, &major, &minor, µ);
+ return major == 1 && minor == 0; // micro version doesn't matter here
+}
+
+
+bool
+JvmtiEnvBase::use_version_1_1_semantics() {
+ int major, minor, micro;
+
+ JvmtiExport::decode_version_values(_version, &major, &minor, µ);
+ return major == 1 && minor == 1; // micro version doesn't matter here
+}
+
+
+JvmtiEnvBase::JvmtiEnvBase(jint version) : _env_event_enable() {
+ _version = version;
_env_local_storage = NULL;
_tag_map = NULL;
_native_method_prefix_count = 0;
--- a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -76,6 +76,7 @@
jvmtiEnv _jvmti_external;
jint _magic;
+ jint _version; // version value passed to JNI GetEnv()
JvmtiEnvBase* _next;
bool _is_retransformable;
const void *_env_local_storage; // per env agent allocated data.
@@ -91,7 +92,7 @@
int _native_method_prefix_count;
protected:
- JvmtiEnvBase();
+ JvmtiEnvBase(jint version);
~JvmtiEnvBase();
void dispose();
void env_dispose();
@@ -122,6 +123,9 @@
bool is_valid();
+ bool use_version_1_0_semantics(); // agent asked for version 1.0
+ bool use_version_1_1_semantics(); // agent asked for version 1.1
+
bool is_retransformable() { return _is_retransformable; }
static ByteSize jvmti_external_offset() {
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -319,7 +319,27 @@
jint
JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) {
- /* To Do: add version checks */
+ // The JVMTI_VERSION_INTERFACE_JVMTI part of the version number
+ // has already been validated in JNI GetEnv().
+ int major, minor, micro;
+
+ // micro version doesn't matter here (yet?)
+ decode_version_values(version, &major, &minor, µ);
+ switch (major) {
+ case 1:
+ switch (minor) {
+ case 0: // version 1.0.<micro> is recognized
+ case 1: // version 1.1.<micro> is recognized
+ break;
+
+ default:
+ return JNI_EVERSION; // unsupported minor version number
+ }
+ break;
+
+ default:
+ return JNI_EVERSION; // unsupported major version number
+ }
if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
JavaThread* current_thread = (JavaThread*) ThreadLocalStorage::thread();
@@ -328,13 +348,13 @@
__ENTRY(jvmtiEnv*, JvmtiExport::get_jvmti_interface, current_thread)
debug_only(VMNativeEntryWrapper __vew;)
- JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti();
+ JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(version);
*penv = jvmti_env->jvmti_external(); // actual type is jvmtiEnv* -- not to be confused with JvmtiEnv*
return JNI_OK;
} else if (JvmtiEnv::get_phase() == JVMTI_PHASE_ONLOAD) {
// not live, no thread to transition
- JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti();
+ JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(version);
*penv = jvmti_env->jvmti_external(); // actual type is jvmtiEnv* -- not to be confused with JvmtiEnv*
return JNI_OK;
@@ -345,6 +365,15 @@
}
}
+
+void
+JvmtiExport::decode_version_values(jint version, int * major, int * minor,
+ int * micro) {
+ *major = (version & JVMTI_VERSION_MASK_MAJOR) >> JVMTI_VERSION_SHIFT_MAJOR;
+ *minor = (version & JVMTI_VERSION_MASK_MINOR) >> JVMTI_VERSION_SHIFT_MINOR;
+ *micro = (version & JVMTI_VERSION_MASK_MICRO) >> JVMTI_VERSION_SHIFT_MICRO;
+}
+
void JvmtiExport::enter_primordial_phase() {
JvmtiEnvBase::set_phase(JVMTI_PHASE_PRIMORDIAL);
}
--- a/hotspot/src/share/vm/prims/jvmtiExport.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -236,6 +236,8 @@
static bool is_jvmti_version(jint version) { return (version & JVMTI_VERSION_MASK) == JVMTI_VERSION_VALUE; }
static bool is_jvmdi_version(jint version) { return (version & JVMTI_VERSION_MASK) == JVMDI_VERSION_VALUE; }
static jint get_jvmti_interface(JavaVM *jvm, void **penv, jint version);
+ static void decode_version_values(jint version, int * major, int * minor,
+ int * micro);
// single stepping management methods
static void at_single_stepping_point(JavaThread *thread, methodOop method, address location) KERNEL_RETURN;
--- a/hotspot/src/share/vm/prims/jvmtiHpp.xsl Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiHpp.xsl Wed Jul 05 17:04:53 2017 +0200
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
- Copyright 2002-2005 Sun Microsystems, Inc. All Rights Reserved.
+ Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it
@@ -48,12 +48,12 @@
private:
- JvmtiEnv();
+ JvmtiEnv(jint version);
~JvmtiEnv();
public:
- static JvmtiEnv* create_a_jvmti();
+ static JvmtiEnv* create_a_jvmti(jint version);
</xsl:text>
<xsl:apply-templates select="functionsection"/>
--- a/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -115,8 +115,10 @@
jvmtiCapabilities jc;
memset(&jc, 0, sizeof(jc));
+#ifndef CC_INTERP
jc.can_pop_frame = 1;
jc.can_force_early_return = 1;
+#endif // !CC_INTERP
jc.can_get_source_debug_extension = 1;
jc.can_access_local_variables = 1;
jc.can_maintain_original_method_order = 1;
--- a/hotspot/src/share/vm/prims/methodHandles.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -2347,9 +2347,9 @@
JVM_ENTRY(void, MH_linkCallSite(JNIEnv *env, jobject igcls, jobject site_jh, jobject target_jh)) {
// No special action required, yet.
oop site_oop = JNIHandles::resolve(site_jh);
- if (site_oop == NULL || site_oop->klass() != SystemDictionary::CallSiteImpl_klass())
+ if (site_oop == NULL || site_oop->klass() != SystemDictionary::CallSite_klass())
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "call site");
- sun_dyn_CallSiteImpl::set_target(site_oop, JNIHandles::resolve(target_jh));
+ java_dyn_CallSite::set_target(site_oop, JNIHandles::resolve(target_jh));
}
JVM_END
@@ -2365,6 +2365,7 @@
#define OBJ LANG"Object;"
#define CLS LANG"Class;"
#define STRG LANG"String;"
+#define CST JDYN"CallSite;"
#define MT JDYN"MethodType;"
#define MH JDYN"MethodHandle;"
#define MHI IDYN"MethodHandleImpl;"
@@ -2372,7 +2373,6 @@
#define AMH IDYN"AdapterMethodHandle;"
#define BMH IDYN"BoundMethodHandle;"
#define DMH IDYN"DirectMethodHandle;"
-#define CSTI IDYN"CallSiteImpl;"
#define CC (char*) /*cast a literal from (const char*)*/
#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
@@ -2398,7 +2398,7 @@
// More entry points specifically for EnableInvokeDynamic.
static JNINativeMethod methods2[] = {
- {CC"linkCallSite", CC"("CSTI MH")V", FN_PTR(MH_linkCallSite)}
+ {CC"linkCallSite", CC"("CST MH")V", FN_PTR(MH_linkCallSite)}
};
--- a/hotspot/src/share/vm/runtime/arguments.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -37,7 +37,6 @@
const char* Arguments::_gc_log_filename = NULL;
bool Arguments::_has_profile = false;
bool Arguments::_has_alloc_profile = false;
-uintx Arguments::_initial_heap_size = 0;
uintx Arguments::_min_heap_size = 0;
Arguments::Mode Arguments::_mode = _mixed;
bool Arguments::_java_compiler = false;
@@ -182,6 +181,9 @@
{ "ProcessingToTenuringRatio", JDK_Version::jdk(5), JDK_Version::jdk(7) },
{ "MinTrainLength", JDK_Version::jdk(5), JDK_Version::jdk(7) },
{ "AppendRatio", JDK_Version::jdk_update(6,10), JDK_Version::jdk(7) },
+ { "DefaultMaxRAM", JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) },
+ { "DefaultInitialRAMFraction",
+ JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) },
{ NULL, JDK_Version(0), JDK_Version(0) }
};
@@ -555,6 +557,10 @@
if (!is_neg && CommandLineFlags::uintxAtPut(name, &uintx_v, origin)) {
return true;
}
+ uint64_t uint64_t_v = (uint64_t) v;
+ if (!is_neg && CommandLineFlags::uint64_tAtPut(name, &uint64_t_v, origin)) {
+ return true;
+ }
return false;
}
@@ -947,7 +953,7 @@
// UseParNewGC and not explicitly set ParallelGCThreads we
// set it, unless this is a single cpu machine.
void Arguments::set_parnew_gc_flags() {
- assert(!UseSerialGC && !UseParallelGC && !UseG1GC,
+ assert(!UseSerialGC && !UseParallelOldGC && !UseParallelGC && !UseG1GC,
"control point invariant");
assert(UseParNewGC, "Error");
@@ -960,13 +966,13 @@
if (ParallelGCThreads == 0) {
FLAG_SET_DEFAULT(ParallelGCThreads,
Abstract_VM_Version::parallel_worker_threads());
- if (FLAG_IS_DEFAULT(ParallelGCThreads) && ParallelGCThreads == 1) {
+ if (ParallelGCThreads == 1) {
FLAG_SET_DEFAULT(UseParNewGC, false);
+ FLAG_SET_DEFAULT(ParallelGCThreads, 0);
}
}
- if (!UseParNewGC) {
- FLAG_SET_DEFAULT(ParallelGCThreads, 0);
- } else {
+ if (UseParNewGC) {
+ // CDS doesn't work with ParNew yet
no_shared_spaces();
// By default YoungPLABSize and OldPLABSize are set to 4096 and 1024 respectively,
@@ -980,7 +986,7 @@
FLAG_SET_DEFAULT(OldPLABSize, (intx)1024);
}
- // AlwaysTenure flag should make ParNew to promote all at first collection.
+ // AlwaysTenure flag should make ParNew promote all at first collection.
// See CR 6362902.
if (AlwaysTenure) {
FLAG_SET_CMDLINE(intx, MaxTenuringThreshold, 0);
@@ -1003,7 +1009,7 @@
// further optimization and tuning efforts, and would almost
// certainly gain from analysis of platform and environment.
void Arguments::set_cms_and_parnew_gc_flags() {
- assert(!UseSerialGC && !UseParallelGC, "Error");
+ assert(!UseSerialGC && !UseParallelOldGC && !UseParallelGC, "Error");
assert(UseConcMarkSweepGC, "CMS is expected to be on here");
// If we are using CMS, we prefer to UseParNewGC,
@@ -1068,7 +1074,7 @@
} else {
FLAG_SET_ERGO(uintx, MaxNewSize, preferred_max_new_size);
}
- if(PrintGCDetails && Verbose) {
+ if (PrintGCDetails && Verbose) {
// Too early to use gclog_or_tty
tty->print_cr("Ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize);
}
@@ -1097,15 +1103,15 @@
} else {
min_new = NewSize;
}
- size_t prev_initial_size = initial_heap_size();
- if (prev_initial_size != 0 && prev_initial_size < min_new+OldSize) {
- set_initial_heap_size(min_new+OldSize);
+ size_t prev_initial_size = InitialHeapSize;
+ if (prev_initial_size != 0 && prev_initial_size < min_new + OldSize) {
+ FLAG_SET_ERGO(uintx, InitialHeapSize, min_new + OldSize);
// Currently minimum size and the initial heap sizes are the same.
- set_min_heap_size(initial_heap_size());
+ set_min_heap_size(InitialHeapSize);
if (PrintGCDetails && Verbose) {
warning("Initial heap size increased to " SIZE_FORMAT " M from "
SIZE_FORMAT " M; use -XX:NewSize=... for finer control.",
- initial_heap_size()/M, prev_initial_size/M);
+ InitialHeapSize/M, prev_initial_size/M);
}
}
@@ -1114,12 +1120,12 @@
align_size_down(MaxHeapSize,
CardTableRS::ct_max_alignment_constraint());
- if(PrintGCDetails && Verbose) {
+ if (PrintGCDetails && Verbose) {
// Too early to use gclog_or_tty
tty->print_cr("CMS set min_heap_size: " SIZE_FORMAT
" initial_heap_size: " SIZE_FORMAT
" max_heap: " SIZE_FORMAT,
- min_heap_size(), initial_heap_size(), max_heap);
+ min_heap_size(), InitialHeapSize, max_heap);
}
if (max_heap > min_new) {
// Unless explicitly requested otherwise, make young gen
@@ -1127,7 +1133,7 @@
if (FLAG_IS_DEFAULT(NewSize)) {
FLAG_SET_ERGO(uintx, NewSize, MAX2(NewSize, min_new));
FLAG_SET_ERGO(uintx, NewSize, MIN2(preferred_max_new_size, NewSize));
- if(PrintGCDetails && Verbose) {
+ if (PrintGCDetails && Verbose) {
// Too early to use gclog_or_tty
tty->print_cr("Ergo set NewSize: " SIZE_FORMAT, NewSize);
}
@@ -1137,8 +1143,8 @@
// later NewRatio will decide how it grows; see above.
if (FLAG_IS_DEFAULT(OldSize)) {
if (max_heap > NewSize) {
- FLAG_SET_ERGO(uintx, OldSize, MIN2(3*NewSize, max_heap - NewSize));
- if(PrintGCDetails && Verbose) {
+ FLAG_SET_ERGO(uintx, OldSize, MIN2(3*NewSize, max_heap - NewSize));
+ if (PrintGCDetails && Verbose) {
// Too early to use gclog_or_tty
tty->print_cr("Ergo set OldSize: " SIZE_FORMAT, OldSize);
}
@@ -1186,7 +1192,7 @@
inline uintx max_heap_for_compressed_oops() {
LP64_ONLY(return oopDesc::OopEncodingHeapMax - MaxPermSize - os::vm_page_size());
- NOT_LP64(return DefaultMaxRAM);
+ NOT_LP64(ShouldNotReachHere(); return 0);
}
bool Arguments::should_auto_select_low_pause_collector() {
@@ -1205,7 +1211,7 @@
void Arguments::set_ergonomics_flags() {
// Parallel GC is not compatible with sharing. If one specifies
- // that they want sharing explicitly, do not set ergonmics flags.
+ // that they want sharing explicitly, do not set ergonomics flags.
if (DumpSharedSpaces || ForceSharedSpaces) {
return;
}
@@ -1234,9 +1240,11 @@
// Check that UseCompressedOops can be set with the max heap size allocated
// by ergonomics.
if (MaxHeapSize <= max_heap_for_compressed_oops()) {
+#ifndef COMPILER1
if (FLAG_IS_DEFAULT(UseCompressedOops) && !UseG1GC) {
FLAG_SET_ERGO(bool, UseCompressedOops, true);
}
+#endif
#ifdef _WIN64
if (UseLargePages && UseCompressedOops) {
// Cannot allocate guard pages for implicit checks in indexed addressing
@@ -1271,8 +1279,6 @@
FLAG_SET_ERGO(uintx, ParallelGCThreads,
Abstract_VM_Version::parallel_worker_threads());
- // PS is a server collector, setup the heap sizes accordingly.
- set_server_heap_size();
// If InitialSurvivorRatio or MinSurvivorRatio were not specified, but the
// SurvivorRatio has been set, reset their default values to SurvivorRatio +
// 2. By doing this we make SurvivorRatio also work for Parallel Scavenger.
@@ -1302,8 +1308,6 @@
void Arguments::set_g1_gc_flags() {
assert(UseG1GC, "Error");
- // G1 is a server collector, setup the heap sizes accordingly.
- set_server_heap_size();
#ifdef COMPILER1
FastTLABRefill = false;
#endif
@@ -1321,50 +1325,79 @@
}
}
-void Arguments::set_server_heap_size() {
+void Arguments::set_heap_size() {
+ if (!FLAG_IS_DEFAULT(DefaultMaxRAMFraction)) {
+ // Deprecated flag
+ FLAG_SET_CMDLINE(uintx, MaxRAMFraction, DefaultMaxRAMFraction);
+ }
+
+ const julong phys_mem =
+ FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM)
+ : (julong)MaxRAM;
+
+ // If the maximum heap size has not been set with -Xmx,
+ // then set it as fraction of the size of physical memory,
+ // respecting the maximum and minimum sizes of the heap.
if (FLAG_IS_DEFAULT(MaxHeapSize)) {
- const uint64_t reasonable_fraction =
- os::physical_memory() / DefaultMaxRAMFraction;
- const uint64_t maximum_size = (uint64_t)
- (FLAG_IS_DEFAULT(DefaultMaxRAM) && UseCompressedOops ?
- MIN2(max_heap_for_compressed_oops(), DefaultMaxRAM) :
- DefaultMaxRAM);
- size_t reasonable_max =
- (size_t) os::allocatable_physical_memory(reasonable_fraction);
- if (reasonable_max > maximum_size) {
- reasonable_max = maximum_size;
+ julong reasonable_max = phys_mem / MaxRAMFraction;
+
+ if (phys_mem <= MaxHeapSize * MinRAMFraction) {
+ // Small physical memory, so use a minimum fraction of it for the heap
+ reasonable_max = phys_mem / MinRAMFraction;
+ } else {
+ // Not-small physical memory, so require a heap at least
+ // as large as MaxHeapSize
+ reasonable_max = MAX2(reasonable_max, (julong)MaxHeapSize);
+ }
+ if (!FLAG_IS_DEFAULT(ErgoHeapSizeLimit) && ErgoHeapSizeLimit != 0) {
+ // Limit the heap size to ErgoHeapSizeLimit
+ reasonable_max = MIN2(reasonable_max, (julong)ErgoHeapSizeLimit);
}
+ if (UseCompressedOops) {
+ // Limit the heap size to the maximum possible when using compressed oops
+ reasonable_max = MIN2(reasonable_max, (julong)max_heap_for_compressed_oops());
+ }
+ reasonable_max = os::allocatable_physical_memory(reasonable_max);
+
+ if (!FLAG_IS_DEFAULT(InitialHeapSize)) {
+ // An initial heap size was specified on the command line,
+ // so be sure that the maximum size is consistent. Done
+ // after call to allocatable_physical_memory because that
+ // method might reduce the allocation size.
+ reasonable_max = MAX2(reasonable_max, (julong)InitialHeapSize);
+ }
+
if (PrintGCDetails && Verbose) {
// Cannot use gclog_or_tty yet.
- tty->print_cr(" Max heap size for server class platform "
- SIZE_FORMAT, reasonable_max);
+ tty->print_cr(" Maximum heap size " SIZE_FORMAT, reasonable_max);
}
- // If the initial_heap_size has not been set with -Xms,
- // then set it as fraction of size of physical memory
- // respecting the maximum and minimum sizes of the heap.
- if (initial_heap_size() == 0) {
- const uint64_t reasonable_initial_fraction =
- os::physical_memory() / DefaultInitialRAMFraction;
- const size_t reasonable_initial =
- (size_t) os::allocatable_physical_memory(reasonable_initial_fraction);
- const size_t minimum_size = NewSize + OldSize;
- set_initial_heap_size(MAX2(MIN2(reasonable_initial, reasonable_max),
- minimum_size));
- // Currently the minimum size and the initial heap sizes are the same.
- set_min_heap_size(initial_heap_size());
- if (PrintGCDetails && Verbose) {
- // Cannot use gclog_or_tty yet.
- tty->print_cr(" Initial heap size for server class platform "
- SIZE_FORMAT, initial_heap_size());
- }
- } else {
- // A minimum size was specified on the command line. Be sure
- // that the maximum size is consistent.
- if (initial_heap_size() > reasonable_max) {
- reasonable_max = initial_heap_size();
- }
+ FLAG_SET_ERGO(uintx, MaxHeapSize, (uintx)reasonable_max);
+ }
+
+ // If the initial_heap_size has not been set with InitialHeapSize
+ // or -Xms, then set it as fraction of the size of physical memory,
+ // respecting the maximum and minimum sizes of the heap.
+ if (FLAG_IS_DEFAULT(InitialHeapSize)) {
+ julong reasonable_minimum = (julong)(OldSize + NewSize);
+
+ reasonable_minimum = MIN2(reasonable_minimum, (julong)MaxHeapSize);
+
+ reasonable_minimum = os::allocatable_physical_memory(reasonable_minimum);
+
+ julong reasonable_initial = phys_mem / InitialRAMFraction;
+
+ reasonable_initial = MAX2(reasonable_initial, reasonable_minimum);
+ reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize);
+
+ reasonable_initial = os::allocatable_physical_memory(reasonable_initial);
+
+ if (PrintGCDetails && Verbose) {
+ // Cannot use gclog_or_tty yet.
+ tty->print_cr(" Initial heap size " SIZE_FORMAT, (uintx)reasonable_initial);
+ tty->print_cr(" Minimum heap size " SIZE_FORMAT, (uintx)reasonable_minimum);
}
- FLAG_SET_ERGO(uintx, MaxHeapSize, (uintx) reasonable_max);
+ FLAG_SET_ERGO(uintx, InitialHeapSize, (uintx)reasonable_initial);
+ set_min_heap_size((uintx)reasonable_minimum);
}
}
@@ -1448,7 +1481,7 @@
return false;
}
-static void set_serial_gc_flags() {
+static void force_serial_gc() {
FLAG_SET_DEFAULT(UseSerialGC, true);
FLAG_SET_DEFAULT(UseParNewGC, false);
FLAG_SET_DEFAULT(UseConcMarkSweepGC, false);
@@ -1584,15 +1617,15 @@
// force sharing off.
if (DumpSharedSpaces || ForceSharedSpaces) {
jio_fprintf(defaultStream::error_stream(),
- "Reverting to Serial GC because of %s \n",
+ "Reverting to Serial GC because of %s\n",
ForceSharedSpaces ? " -Xshare:on" : "-Xshare:dump");
- set_serial_gc_flags();
+ force_serial_gc();
FLAG_SET_DEFAULT(SOLARIS_ONLY(UseISM) NOT_SOLARIS(UseLargePages), false);
} else {
- if (UseSharedSpaces) {
+ if (UseSharedSpaces && Verbose) {
jio_fprintf(defaultStream::error_stream(),
"Turning off use of shared archive because of "
- "choice of garbage collector or large pages \n");
+ "choice of garbage collector or large pages\n");
}
no_shared_spaces();
}
@@ -1925,8 +1958,8 @@
describe_range_error(errcode);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(uintx, MaxNewSize, (size_t) long_initial_eden_size);
- FLAG_SET_CMDLINE(uintx, NewSize, (size_t) long_initial_eden_size);
+ FLAG_SET_CMDLINE(uintx, MaxNewSize, (uintx)long_initial_eden_size);
+ FLAG_SET_CMDLINE(uintx, NewSize, (uintx)long_initial_eden_size);
// -Xms
} else if (match_option(option, "-Xms", &tail)) {
julong long_initial_heap_size = 0;
@@ -1937,9 +1970,9 @@
describe_range_error(errcode);
return JNI_EINVAL;
}
- set_initial_heap_size((size_t) long_initial_heap_size);
+ FLAG_SET_CMDLINE(uintx, InitialHeapSize, (uintx)long_initial_heap_size);
// Currently the minimum size and the initial heap sizes are the same.
- set_min_heap_size(initial_heap_size());
+ set_min_heap_size(InitialHeapSize);
// -Xmx
} else if (match_option(option, "-Xmx", &tail)) {
julong long_max_heap_size = 0;
@@ -1950,7 +1983,7 @@
describe_range_error(errcode);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(uintx, MaxHeapSize, (size_t) long_max_heap_size);
+ FLAG_SET_CMDLINE(uintx, MaxHeapSize, (uintx)long_max_heap_size);
// Xmaxf
} else if (match_option(option, "-Xmaxf", &tail)) {
int maxf = (int)(atof(tail) * 100);
@@ -2196,9 +2229,9 @@
if (FLAG_IS_DEFAULT(MaxHeapSize)) {
FLAG_SET_CMDLINE(uintx, MaxHeapSize, initHeapSize);
- set_initial_heap_size(MaxHeapSize);
+ FLAG_SET_CMDLINE(uintx, InitialHeapSize, initHeapSize);
// Currently the minimum size and the initial heap sizes are the same.
- set_min_heap_size(initial_heap_size());
+ set_min_heap_size(initHeapSize);
}
if (FLAG_IS_DEFAULT(NewSize)) {
// Make the young generation 3/8ths of the total heap.
@@ -2675,8 +2708,12 @@
}
}
+#if defined(_LP64) && defined(COMPILER1)
+ UseCompressedOops = false;
+#endif
+
#ifdef SERIALGC
- set_serial_gc_flags();
+ force_serial_gc();
#endif // SERIALGC
#ifdef KERNEL
no_shared_spaces();
@@ -2690,18 +2727,22 @@
return JNI_EINVAL;
}
- if (UseParallelGC || UseParallelOldGC) {
- // Set some flags for ParallelGC if needed.
- set_parallel_gc_flags();
- } else if (UseConcMarkSweepGC) {
- // Set some flags for CMS
+ if (UseConcMarkSweepGC) {
+ // Set flags for CMS and ParNew. Check UseConcMarkSweep first
+ // to ensure that when both UseConcMarkSweepGC and UseParNewGC
+ // are true, we don't call set_parnew_gc_flags() as well.
set_cms_and_parnew_gc_flags();
- } else if (UseParNewGC) {
- // Set some flags for ParNew
- set_parnew_gc_flags();
- } else if (UseG1GC) {
- // Set some flags for garbage-first, if needed.
- set_g1_gc_flags();
+ } else {
+ // Set heap size based on available physical memory
+ set_heap_size();
+ // Set per-collector flags
+ if (UseParallelGC || UseParallelOldGC) {
+ set_parallel_gc_flags();
+ } else if (UseParNewGC) {
+ set_parnew_gc_flags();
+ } else if (UseG1GC) {
+ set_g1_gc_flags();
+ }
}
#ifdef SERIALGC
--- a/hotspot/src/share/vm/runtime/arguments.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -254,7 +254,6 @@
static bool _has_profile;
static bool _has_alloc_profile;
static const char* _gc_log_filename;
- static uintx _initial_heap_size;
static uintx _min_heap_size;
// -Xrun arguments
@@ -300,8 +299,8 @@
static void set_g1_gc_flags();
// GC ergonomics
static void set_ergonomics_flags();
- // Setup heap size for a server platform
- static void set_server_heap_size();
+ // Setup heap size
+ static void set_heap_size();
// Based on automatic selection criteria, should the
// low pause collector be used.
static bool should_auto_select_low_pause_collector();
@@ -434,9 +433,7 @@
static bool has_profile() { return _has_profile; }
static bool has_alloc_profile() { return _has_alloc_profile; }
- // -Xms , -Xmx
- static uintx initial_heap_size() { return _initial_heap_size; }
- static void set_initial_heap_size(uintx v) { _initial_heap_size = v; }
+ // -Xms, -Xmx
static uintx min_heap_size() { return _min_heap_size; }
static void set_min_heap_size(uintx v) { _min_heap_size = v; }
--- a/hotspot/src/share/vm/runtime/frame.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/frame.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -1190,9 +1190,19 @@
void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache) {
- if (is_interpreted_frame()) { oops_interpreted_do(f, map, use_interpreter_oop_map_cache);
- } else if (is_entry_frame()) { oops_entry_do (f, map);
- } else if (CodeCache::contains(pc())) { oops_code_blob_do (f, cf, map);
+#ifndef PRODUCT
+ // simulate GC crash here to dump java thread in error report
+ if (CrashGCForDumpingJavaThread) {
+ char *t = NULL;
+ *t = 'c';
+ }
+#endif
+ if (is_interpreted_frame()) {
+ oops_interpreted_do(f, map, use_interpreter_oop_map_cache);
+ } else if (is_entry_frame()) {
+ oops_entry_do(f, map);
+ } else if (CodeCache::contains(pc())) {
+ oops_code_blob_do(f, cf, map);
} else {
ShouldNotReachHere();
}
--- a/hotspot/src/share/vm/runtime/globals.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/globals.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -46,7 +46,8 @@
bool Flag::is_unlocked() const {
if (strcmp(kind, "{diagnostic}") == 0) {
return UnlockDiagnosticVMOptions;
- } else if (strcmp(kind, "{experimental}") == 0) {
+ } else if (strcmp(kind, "{experimental}") == 0 ||
+ strcmp(kind, "{C2 experimental}") == 0) {
return UnlockExperimentalVMOptions;
} else {
return true;
@@ -69,9 +70,10 @@
void Flag::print_on(outputStream* st) {
st->print("%5s %-35s %c= ", type, name, (origin != DEFAULT ? ':' : ' '));
- if (is_bool()) st->print("%-16s", get_bool() ? "true" : "false");
- if (is_intx()) st->print("%-16ld", get_intx());
- if (is_uintx()) st->print("%-16lu", get_uintx());
+ if (is_bool()) st->print("%-16s", get_bool() ? "true" : "false");
+ if (is_intx()) st->print("%-16ld", get_intx());
+ if (is_uintx()) st->print("%-16lu", get_uintx());
+ if (is_uint64_t()) st->print("%-16lu", get_uint64_t());
if (is_ccstr()) {
const char* cp = get_ccstr();
if (cp != NULL) {
@@ -100,6 +102,8 @@
st->print("-XX:%s=" INTX_FORMAT, name, get_intx());
} else if (is_uintx()) {
st->print("-XX:%s=" UINTX_FORMAT, name, get_uintx());
+ } else if (is_uint64_t()) {
+ st->print("-XX:%s=" UINT64_FORMAT, name, get_uint64_t());
} else if (is_ccstr()) {
st->print("-XX:%s=", name);
const char* cp = get_ccstr();
@@ -166,6 +170,7 @@
#define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 product}", DEFAULT },
#define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C2 pd product}", DEFAULT },
#define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 diagnostic}", DEFAULT },
+#define C2_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 experimental}", DEFAULT },
#ifdef PRODUCT
#define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */
#define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */
@@ -187,7 +192,7 @@
C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, C1_PD_DEVELOP_FLAG_STRUCT, C1_PRODUCT_FLAG_STRUCT, C1_PD_PRODUCT_FLAG_STRUCT, C1_NOTPRODUCT_FLAG_STRUCT)
#endif
#ifdef COMPILER2
- C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, C2_PD_DEVELOP_FLAG_STRUCT, C2_PRODUCT_FLAG_STRUCT, C2_PD_PRODUCT_FLAG_STRUCT, C2_DIAGNOSTIC_FLAG_STRUCT, C2_NOTPRODUCT_FLAG_STRUCT)
+ C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, C2_PD_DEVELOP_FLAG_STRUCT, C2_PRODUCT_FLAG_STRUCT, C2_PD_PRODUCT_FLAG_STRUCT, C2_DIAGNOSTIC_FLAG_STRUCT, C2_EXPERIMENTAL_FLAG_STRUCT, C2_NOTPRODUCT_FLAG_STRUCT)
#endif
{0, NULL, NULL}
};
@@ -324,6 +329,32 @@
faddr->origin = origin;
}
+bool CommandLineFlags::uint64_tAt(char* name, size_t len, uint64_t* value) {
+ Flag* result = Flag::find_flag(name, len);
+ if (result == NULL) return false;
+ if (!result->is_uint64_t()) return false;
+ *value = result->get_uint64_t();
+ return true;
+}
+
+bool CommandLineFlags::uint64_tAtPut(char* name, size_t len, uint64_t* value, FlagValueOrigin origin) {
+ Flag* result = Flag::find_flag(name, len);
+ if (result == NULL) return false;
+ if (!result->is_uint64_t()) return false;
+ uint64_t old_value = result->get_uint64_t();
+ result->set_uint64_t(*value);
+ *value = old_value;
+ result->origin = origin;
+ return true;
+}
+
+void CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, FlagValueOrigin origin) {
+ Flag* faddr = address_of_flag(flag);
+ guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type");
+ faddr->set_uint64_t(value);
+ faddr->origin = origin;
+}
+
bool CommandLineFlags::doubleAt(char* name, size_t len, double* value) {
Flag* result = Flag::find_flag(name, len);
if (result == NULL) return false;
--- a/hotspot/src/share/vm/runtime/globals.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -47,8 +47,8 @@
define_pd_global(intx, OnStackReplacePercentage, 0);
define_pd_global(bool, ResizeTLAB, false);
define_pd_global(intx, FreqInlineSize, 0);
+define_pd_global(intx, InlineSmallCode, 0);
define_pd_global(intx, NewSizeThreadIncrease, 4*K);
-define_pd_global(intx, NewRatio, 4);
define_pd_global(intx, InlineClassNatives, true);
define_pd_global(intx, InlineUnsafeOps, true);
define_pd_global(intx, InitialCodeCacheSize, 160*K);
@@ -58,7 +58,7 @@
define_pd_global(uintx,PermSize, ScaleForWordSize(4*M));
define_pd_global(uintx,MaxPermSize, ScaleForWordSize(64*M));
define_pd_global(bool, NeverActAsServerClassMachine, true);
-define_pd_global(uintx, DefaultMaxRAM, 1*G);
+define_pd_global(uint64_t,MaxRAM, 1ULL*G);
#define CI_COMPILER_COUNT 0
#else
@@ -113,6 +113,10 @@
uintx get_uintx() const { return *((uintx*) addr); }
void set_uintx(uintx value) { *((uintx*) addr) = value; }
+ bool is_uint64_t() const { return strcmp(type, "uint64_t") == 0; }
+ uint64_t get_uint64_t() const { return *((uint64_t*) addr); }
+ void set_uint64_t(uint64_t value) { *((uint64_t*) addr) = value; }
+
bool is_double() const { return strcmp(type, "double") == 0; }
double get_double() const { return *((double*) addr); }
void set_double(double value) { *((double*) addr) = value; }
@@ -188,6 +192,11 @@
static bool uintxAtPut(char* name, size_t len, uintx* value, FlagValueOrigin origin);
static bool uintxAtPut(char* name, uintx* value, FlagValueOrigin origin) { return uintxAtPut(name, strlen(name), value, origin); }
+ static bool uint64_tAt(char* name, size_t len, uint64_t* value);
+ static bool uint64_tAt(char* name, uint64_t* value) { return uint64_tAt(name, strlen(name), value); }
+ static bool uint64_tAtPut(char* name, size_t len, uint64_t* value, FlagValueOrigin origin);
+ static bool uint64_tAtPut(char* name, uint64_t* value, FlagValueOrigin origin) { return uint64_tAtPut(name, strlen(name), value, origin); }
+
static bool doubleAt(char* name, size_t len, double* value);
static bool doubleAt(char* name, double* value) { return doubleAt(name, strlen(name), value); }
static bool doubleAtPut(char* name, size_t len, double* value, FlagValueOrigin origin);
@@ -785,7 +794,7 @@
product(bool, ProfilerRecordPC, false, \
"Collects tick for each 16 byte interval of compiled code") \
\
- product(bool, ProfileVM, false, \
+ product(bool, ProfileVM, false, \
"Profiles ticks that fall within VM (either in the VM Thread " \
"or VM code called through stubs)") \
\
@@ -815,7 +824,7 @@
\
product(bool, RegisterFinalizersAtInit, true, \
"Register finalizable objects at end of Object.<init> or " \
- "after allocation.") \
+ "after allocation") \
\
develop(bool, RegisterReferences, true, \
"Tells whether the VM should register soft/weak/final/phantom " \
@@ -862,14 +871,14 @@
product(bool, AlwaysLockClassLoader, false, \
"Require the VM to acquire the class loader lock before calling " \
"loadClass() even for class loaders registering " \
- "as parallel capable. Default false. ") \
+ "as parallel capable") \
\
product(bool, AllowParallelDefineClass, false, \
"Allow parallel defineClass requests for class loaders " \
- "registering as parallel capable. Default false") \
+ "registering as parallel capable") \
\
product(bool, MustCallLoadClassInternal, false, \
- "Call loadClassInternal() rather than loadClass().Default false") \
+ "Call loadClassInternal() rather than loadClass()") \
\
product_pd(bool, DontYieldALot, \
"Throw away obvious excess yield calls (for SOLARIS only)") \
@@ -921,9 +930,9 @@
"(Unstable, Linux-specific)" \
" avoid NPTL-FUTEX hang pthread_cond_timedwait" ) \
\
- product(bool, FilterSpuriousWakeups , true, \
- "Prevent spurious or premature wakeups from object.wait" \
- "(Solaris only)") \
+ product(bool, FilterSpuriousWakeups, true, \
+ "Prevent spurious or premature wakeups from object.wait " \
+ "(Solaris only)") \
\
product(intx, NativeMonitorTimeout, -1, "(Unstable)" ) \
product(intx, NativeMonitorFlags, 0, "(Unstable)" ) \
@@ -973,7 +982,7 @@
\
product(bool, UseAltSigs, false, \
"Use alternate signals instead of SIGUSR1 & SIGUSR2 for VM " \
- "internal signals. (Solaris only)") \
+ "internal signals (Solaris only)") \
\
product(bool, UseSpinning, false, \
"Use spinning in monitor inflation and before entry") \
@@ -1265,12 +1274,12 @@
"Always tenure objects in eden. (ParallelGC only)") \
\
product(bool, NeverTenure, false, \
- "Never tenure objects in eden, May tenure on overflow" \
- " (ParallelGC only)") \
+ "Never tenure objects in eden, May tenure on overflow " \
+ "(ParallelGC only)") \
\
product(bool, ScavengeBeforeFullGC, true, \
- "Scavenge youngest generation before each full GC," \
- " used with UseParallelGC") \
+ "Scavenge youngest generation before each full GC, " \
+ "used with UseParallelGC") \
\
develop(bool, ScavengeWithObjectsInToSpace, false, \
"Allow scavenges to occur when to_space contains objects.") \
@@ -1283,9 +1292,9 @@
" (effective only when UseConcMarkSweepGC)") \
\
product(bool, ExplicitGCInvokesConcurrentAndUnloadsClasses, false, \
- "A System.gc() request invokes a concurrent collection and" \
- " also unloads classes during such a concurrent gc cycle " \
- " (effective only when UseConcMarkSweepGC)") \
+ "A System.gc() request invokes a concurrent collection and " \
+ "also unloads classes during such a concurrent gc cycle " \
+ "(effective only when UseConcMarkSweepGC)") \
\
develop(bool, UseCMSAdaptiveFreeLists, true, \
"Use Adaptive Free Lists in the CMS generation") \
@@ -1340,8 +1349,8 @@
"Whether we should simulate work queue overflow in ParNew") \
\
notproduct(uintx, ParGCWorkQueueOverflowInterval, 1000, \
- "An `interval' counter that determines how frequently" \
- " we simulate overflow; a smaller number increases frequency") \
+ "An `interval' counter that determines how frequently " \
+ "we simulate overflow; a smaller number increases frequency") \
\
product(uintx, ParGCDesiredObjsFromOverflowList, 20, \
"The desired number of objects to claim from the overflow list") \
@@ -1354,12 +1363,12 @@
"It forces all freshly committed pages to be pre-touched.") \
\
product(bool, CMSUseOldDefaults, false, \
- "A flag temporarily introduced to allow reverting to some older" \
- "default settings; older as of 6.0 ") \
+ "A flag temporarily introduced to allow reverting to some " \
+ "older default settings; older as of 6.0") \
\
product(intx, CMSYoungGenPerWorker, 16*M, \
"The amount of young gen chosen by default per GC worker " \
- "thread available ") \
+ "thread available") \
\
product(bool, GCOverheadReporting, false, \
"Enables the GC overhead reporting facility") \
@@ -1380,43 +1389,44 @@
"automatically adjusted") \
\
product(uintx, CMSIncrementalDutyCycleMin, 0, \
- "Lower bound on the duty cycle when CMSIncrementalPacing is" \
- "enabled (a percentage, 0-100).") \
+ "Lower bound on the duty cycle when CMSIncrementalPacing is " \
+ "enabled (a percentage, 0-100)") \
\
product(uintx, CMSIncrementalSafetyFactor, 10, \
- "Percentage (0-100) used to add conservatism when computing the" \
- "duty cycle.") \
+ "Percentage (0-100) used to add conservatism when computing the " \
+ "duty cycle") \
\
product(uintx, CMSIncrementalOffset, 0, \
"Percentage (0-100) by which the CMS incremental mode duty cycle" \
- "is shifted to the right within the period between young GCs") \
+ " is shifted to the right within the period between young GCs") \
\
product(uintx, CMSExpAvgFactor, 25, \
- "Percentage (0-100) used to weight the current sample when" \
- "computing exponential averages for CMS statistics.") \
+ "Percentage (0-100) used to weight the current sample when " \
+ "computing exponential averages for CMS statistics") \
\
product(uintx, CMS_FLSWeight, 50, \
- "Percentage (0-100) used to weight the current sample when" \
- "computing exponentially decating averages for CMS FLS statistics.") \
+ "Percentage (0-100) used to weight the current sample when " \
+ "computing exponentially decating averages for CMS FLS statistics") \
\
product(uintx, CMS_FLSPadding, 2, \
- "The multiple of deviation from mean to use for buffering" \
+ "The multiple of deviation from mean to use for buffering " \
"against volatility in free list demand.") \
\
product(uintx, FLSCoalescePolicy, 2, \
"CMS: Aggression level for coalescing, increasing from 0 to 4") \
\
product(uintx, CMS_SweepWeight, 50, \
- "Percentage (0-100) used to weight the current sample when" \
- "computing exponentially decaying average for inter-sweep duration.") \
+ "Percentage (0-100) used to weight the current sample when " \
+ "computing exponentially decaying average for inter-sweep " \
+ "duration") \
\
product(uintx, CMS_SweepPadding, 2, \
- "The multiple of deviation from mean to use for buffering" \
+ "The multiple of deviation from mean to use for buffering " \
"against volatility in inter-sweep duration.") \
\
product(uintx, CMS_SweepTimerThresholdMillis, 10, \
"Skip block flux-rate sampling for an epoch unless inter-sweep " \
- " duration exceeds this threhold in milliseconds") \
+ "duration exceeds this threhold in milliseconds") \
\
develop(bool, CMSTraceIncrementalMode, false, \
"Trace CMS incremental mode") \
@@ -1617,35 +1627,36 @@
\
product(intx, CMSTriggerRatio, 80, \
"Percentage of MinHeapFreeRatio in CMS generation that is " \
- " allocated before a CMS collection cycle commences") \
+ "allocated before a CMS collection cycle commences") \
\
product(intx, CMSTriggerPermRatio, 80, \
- "Percentage of MinHeapFreeRatio in the CMS perm generation that" \
- " is allocated before a CMS collection cycle commences, that " \
- " also collects the perm generation") \
+ "Percentage of MinHeapFreeRatio in the CMS perm generation that " \
+ "is allocated before a CMS collection cycle commences, that " \
+ "also collects the perm generation") \
\
product(uintx, CMSBootstrapOccupancy, 50, \
"Percentage CMS generation occupancy at which to " \
- " initiate CMS collection for bootstrapping collection stats") \
+ "initiate CMS collection for bootstrapping collection stats") \
\
product(intx, CMSInitiatingOccupancyFraction, -1, \
"Percentage CMS generation occupancy to start a CMS collection " \
- " cycle (A negative value means that CMSTriggerRatio is used)") \
+ "cycle. A negative value means that CMSTriggerRatio is used") \
\
product(intx, CMSInitiatingPermOccupancyFraction, -1, \
- "Percentage CMS perm generation occupancy to start a CMScollection"\
- " cycle (A negative value means that CMSTriggerPermRatio is used)")\
+ "Percentage CMS perm generation occupancy to start a " \
+ "CMScollection cycle. A negative value means that " \
+ "CMSTriggerPermRatio is used") \
\
product(bool, UseCMSInitiatingOccupancyOnly, false, \
"Only use occupancy as a crierion for starting a CMS collection") \
\
product(intx, CMSIsTooFullPercentage, 98, \
- "An absolute ceiling above which CMS will always consider the" \
- " perm gen ripe for collection") \
+ "An absolute ceiling above which CMS will always consider the " \
+ "perm gen ripe for collection") \
\
develop(bool, CMSTestInFreeList, false, \
"Check if the coalesced range is already in the " \
- "free lists as claimed.") \
+ "free lists as claimed") \
\
notproduct(bool, CMSVerifyReturnedBytes, false, \
"Check that all the garbage collected was returned to the " \
@@ -1663,8 +1674,8 @@
"Enforce ScavengeALot/GCALot at all potential safepoints") \
\
product(bool, HandlePromotionFailure, true, \
- "The youngest generation collection does not require" \
- " a guarantee of full promotion of all live objects.") \
+ "The youngest generation collection does not require " \
+ "a guarantee of full promotion of all live objects.") \
\
notproduct(bool, PromotionFailureALot, false, \
"Use promotion failure handling on every youngest generation " \
@@ -1692,7 +1703,7 @@
"Ratio of hard spins to calls to yield") \
\
product(uintx, PreserveMarkStackSize, 1024, \
- "Size for stack used in promotion failure handling") \
+ "Size for stack used in promotion failure handling") \
\
product_pd(bool, UseTLAB, "Use thread-local object allocation") \
\
@@ -1720,14 +1731,27 @@
product(bool, AlwaysActAsServerClassMachine, false, \
"Always act like a server-class machine") \
\
- product_pd(uintx, DefaultMaxRAM, \
- "Maximum real memory size for setting server class heap size") \
+ product_pd(uint64_t, MaxRAM, \
+ "Real memory size (in bytes) used to set maximum heap size") \
+ \
+ product(uintx, ErgoHeapSizeLimit, 0, \
+ "Maximum ergonomically set heap size (in bytes); zero means use " \
+ "MaxRAM / MaxRAMFraction") \
+ \
+ product(uintx, MaxRAMFraction, 4, \
+ "Maximum fraction (1/n) of real memory used for maximum heap " \
+ "size") \
\
product(uintx, DefaultMaxRAMFraction, 4, \
- "Fraction (1/n) of real memory used for server class max heap") \
- \
- product(uintx, DefaultInitialRAMFraction, 64, \
- "Fraction (1/n) of real memory used for server class initial heap") \
+ "Maximum fraction (1/n) of real memory used for maximum heap " \
+ "size; deprecated: to be renamed to MaxRAMFraction") \
+ \
+ product(uintx, MinRAMFraction, 2, \
+ "Minimum fraction (1/n) of real memory used for maxmimum heap " \
+ "size on systems with small physical memory size") \
+ \
+ product(uintx, InitialRAMFraction, 64, \
+ "Fraction (1/n) of real memory used for initial heap size") \
\
product(bool, UseAutoGCSelectPolicy, false, \
"Use automatic collection selection policy") \
@@ -1778,7 +1802,7 @@
"Number of collections before the adaptive sizing is started") \
\
product(uintx, AdaptiveSizePolicyOutputInterval, 0, \
- "Collecton interval for printing information, zero => never") \
+ "Collecton interval for printing information; zero => never") \
\
product(bool, UseAdaptiveSizePolicyFootprintGoal, true, \
"Use adaptive minimum footprint as a goal") \
@@ -1808,7 +1832,8 @@
"Allowed collection cost difference between generations") \
\
product(uintx, AdaptiveSizePolicyCollectionCostMargin, 50, \
- "If collection costs are within margin, reduce both by full delta") \
+ "If collection costs are within margin, reduce both by full " \
+ "delta") \
\
product(uintx, YoungGenerationSizeIncrement, 20, \
"Adaptive size percentage change in young generation") \
@@ -2527,8 +2552,11 @@
\
develop(bool, VerifyCompiledCode, false, \
"Include miscellaneous runtime verifications in nmethod code; " \
- "off by default because it disturbs nmethod size heuristics.") \
- \
+ "default off because it disturbs nmethod size heuristics") \
+ \
+ notproduct(bool, CrashGCForDumpingJavaThread, false, \
+ "Manually make GC thread crash then dump java stack trace; " \
+ "Test only") \
\
/* compilation */ \
product(bool, UseCompiler, true, \
@@ -2789,20 +2817,28 @@
"an OS lock") \
\
/* gc parameters */ \
- product(uintx, MaxHeapSize, ScaleForWordSize(64*M), \
- "Default maximum size for object heap (in bytes)") \
- \
- product_pd(uintx, NewSize, \
- "Default size of new generation (in bytes)") \
+ product(uintx, InitialHeapSize, 0, \
+ "Initial heap size (in bytes); zero means OldSize + NewSize") \
+ \
+ product(uintx, MaxHeapSize, ScaleForWordSize(96*M), \
+ "Maximum heap size (in bytes)") \
+ \
+ product(uintx, OldSize, ScaleForWordSize(4*M), \
+ "Initial tenured generation size (in bytes)") \
+ \
+ product(uintx, NewSize, ScaleForWordSize(4*M), \
+ "Initial new generation size (in bytes)") \
\
product(uintx, MaxNewSize, max_uintx, \
- "Maximum size of new generation (in bytes)") \
+ "Maximum new generation size (in bytes), max_uintx means set " \
+ "ergonomically") \
\
product(uintx, PretenureSizeThreshold, 0, \
- "Max size in bytes of objects allocated in DefNew generation") \
- \
- product_pd(uintx, TLABSize, \
- "Default (or starting) size of TLAB (in bytes)") \
+ "Maximum size in bytes of objects allocated in DefNew " \
+ "generation; zero means no maximum") \
+ \
+ product(uintx, TLABSize, 0, \
+ "Starting TLAB size (in bytes); zero means set ergonomically") \
\
product(uintx, MinTLABSize, 2*K, \
"Minimum allowed TLAB size (in bytes)") \
@@ -2819,10 +2855,10 @@
product(uintx, TLABWasteIncrement, 4, \
"Increment allowed waste at slow allocation") \
\
- product_pd(intx, SurvivorRatio, \
+ product(intx, SurvivorRatio, 8, \
"Ratio of eden/survivor space size") \
\
- product_pd(intx, NewRatio, \
+ product(intx, NewRatio, 2, \
"Ratio of new/old generation sizes") \
\
product(uintx, MaxLiveObjectEvacuationRatio, 100, \
@@ -2832,11 +2868,8 @@
"Additional size added to desired new generation size per " \
"non-daemon thread (in bytes)") \
\
- product(uintx, OldSize, ScaleForWordSize(4096*K), \
- "Default size of tenured generation (in bytes)") \
- \
product_pd(uintx, PermSize, \
- "Default size of permanent generation (in bytes)") \
+ "Initial size of permanent generation (in bytes)") \
\
product_pd(uintx, MaxPermSize, \
"Maximum size of permanent generation (in bytes)") \
--- a/hotspot/src/share/vm/runtime/globals_extension.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/globals_extension.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -64,6 +64,7 @@
#define C2_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
#define C2_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name),
#define C2_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
+#define C2_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
#ifdef PRODUCT
#define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */
#define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) /* flag is constant */
@@ -84,7 +85,7 @@
C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER)
#endif
#ifdef COMPILER2
- C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, C2_PD_DEVELOP_FLAG_MEMBER, C2_PRODUCT_FLAG_MEMBER, C2_PD_PRODUCT_FLAG_MEMBER, C2_DIAGNOSTIC_FLAG_MEMBER, C2_NOTPRODUCT_FLAG_MEMBER)
+ C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, C2_PD_DEVELOP_FLAG_MEMBER, C2_PRODUCT_FLAG_MEMBER, C2_PD_PRODUCT_FLAG_MEMBER, C2_DIAGNOSTIC_FLAG_MEMBER, C2_EXPERIMENTAL_FLAG_MEMBER, C2_NOTPRODUCT_FLAG_MEMBER)
#endif
NUM_CommandLineFlag
} CommandLineFlag;
@@ -130,6 +131,7 @@
#define C2_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
#define C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type),
#define C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
+#define C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
#ifdef PRODUCT
#define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */
#define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) /* flag is constant */
@@ -181,6 +183,7 @@
C2_PRODUCT_FLAG_MEMBER_WITH_TYPE,
C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
+ C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE)
#endif
NUM_CommandLineFlagWithType
@@ -202,6 +205,7 @@
static void boolAtPut(CommandLineFlagWithType flag, bool value, FlagValueOrigin origin);
static void intxAtPut(CommandLineFlagWithType flag, intx value, FlagValueOrigin origin);
static void uintxAtPut(CommandLineFlagWithType flag, uintx value, FlagValueOrigin origin);
+ static void uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, FlagValueOrigin origin);
static void doubleAtPut(CommandLineFlagWithType flag, double value, FlagValueOrigin origin);
static void ccstrAtPut(CommandLineFlagWithType flag, ccstr value, FlagValueOrigin origin);
--- a/hotspot/src/share/vm/runtime/os.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -60,24 +60,26 @@
typedef void (*java_call_t)(JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread);
class os: AllStatic {
- private:
+ public:
enum { page_sizes_max = 9 }; // Size of _page_sizes array (8 plus a sentinel)
+ private:
static OSThread* _starting_thread;
static address _polling_page;
static volatile int32_t * _mem_serialize_page;
static uintptr_t _serialize_page_mask;
+ public:
static size_t _page_sizes[page_sizes_max];
+ private:
static void init_page_sizes(size_t default_page_size) {
_page_sizes[0] = default_page_size;
_page_sizes[1] = 0; // sentinel
}
public:
-
- static void init(void); // Called before command line parsing
- static jint init_2(void); // Called after command line parsing
+ static void init(void); // Called before command line parsing
+ static jint init_2(void); // Called after command line parsing
// File names are case-insensitive on windows only
// Override me as needed
@@ -141,6 +143,7 @@
static int processor_count() {
return _processor_count;
}
+ static void set_processor_count(int count) { _processor_count = count; }
// Returns the number of CPUs this process is currently allowed to run on.
// Note that on some OSes this can change dynamically.
@@ -294,19 +297,16 @@
}
static bool is_memory_serialize_page(JavaThread *thread, address addr) {
- address thr_addr;
if (UseMembar) return false;
- // Calculate thread specific address
+ // Previously this function calculated the exact address of this
+ // thread's serialize page, and checked if the faulting address
+ // was equal. However, some platforms mask off faulting addresses
+ // to the page size, so now we just check that the address is
+ // within the page. This makes the thread argument unnecessary,
+ // but we retain the NULL check to preserve existing behaviour.
if (thread == NULL) return false;
- // TODO-FIXME: some platforms mask off faulting addresses to the base pagesize.
- // Instead of using a test for equality we should probably use something
- // of the form:
- // return ((_mem_serialize_page ^ addr) & -pagesize) == 0
- //
- thr_addr = (address)(((uintptr_t)thread >>
- get_serialize_page_shift_count()) &
- get_serialize_page_mask()) + (uintptr_t)_mem_serialize_page;
- return (thr_addr == addr);
+ address page = (address) _mem_serialize_page;
+ return addr >= page && addr < (page + os::vm_page_size());
}
static void block_on_serialize_page_trap();
--- a/hotspot/src/share/vm/runtime/thread.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -884,6 +884,22 @@
vmSymbolHandles::void_method_signature(), CHECK);
}
+#ifdef KERNEL
+static void set_jkernel_boot_classloader_hook(TRAPS) {
+ klassOop k = SystemDictionary::sun_jkernel_DownloadManager_klass();
+ instanceKlassHandle klass (THREAD, k);
+
+ if (k == NULL) {
+ // sun.jkernel.DownloadManager may not present in the JDK; just return
+ return;
+ }
+
+ JavaValue result(T_VOID);
+ JavaCalls::call_static(&result, klass, vmSymbolHandles::setBootClassLoaderHook_name(),
+ vmSymbolHandles::void_method_signature(), CHECK);
+}
+#endif // KERNEL
+
static void reset_vm_info_property(TRAPS) {
// the vm info string
ResourceMark rm(THREAD);
@@ -975,6 +991,7 @@
// uniquely named instances should derive from this.
NamedThread::NamedThread() : Thread() {
_name = NULL;
+ _processed_thread = NULL;
}
NamedThread::~NamedThread() {
@@ -2317,6 +2334,27 @@
frames_do(frame_gc_prologue);
}
+// If the caller is a NamedThread, then remember, in the current scope,
+// the given JavaThread in its _processed_thread field.
+class RememberProcessedThread: public StackObj {
+ NamedThread* _cur_thr;
+public:
+ RememberProcessedThread(JavaThread* jthr) {
+ Thread* thread = Thread::current();
+ if (thread->is_Named_thread()) {
+ _cur_thr = (NamedThread *)thread;
+ _cur_thr->set_processed_thread(jthr);
+ } else {
+ _cur_thr = NULL;
+ }
+ }
+
+ ~RememberProcessedThread() {
+ if (_cur_thr) {
+ _cur_thr->set_processed_thread(NULL);
+ }
+ }
+};
void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
// Flush deferred store-barriers, if any, associated with
@@ -2333,6 +2371,8 @@
(has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
if (has_last_Java_frame()) {
+ // Record JavaThread to GC thread
+ RememberProcessedThread rpt(this);
// Traverse the privileged stack
if (_privileged_stack_top != NULL) {
@@ -3102,6 +3142,12 @@
vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
}
+#ifdef KERNEL
+ if (JDK_Version::is_gte_jdk17x_version()) {
+ set_jkernel_boot_classloader_hook(THREAD);
+ }
+#endif // KERNEL
+
#ifndef SERIALGC
// Support for ConcurrentMarkSweep. This should be cleaned up
// and better encapsulated. The ugly nested if test would go away
--- a/hotspot/src/share/vm/runtime/thread.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/thread.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -48,7 +48,12 @@
// Class hierarchy
// - Thread
-// - VMThread
+// - NamedThread
+// - VMThread
+// - ConcurrentGCThread
+// - WorkerThread
+// - GangWorker
+// - GCTaskThread
// - JavaThread
// - WatcherThread
@@ -249,6 +254,7 @@
virtual bool is_GC_task_thread() const { return false; }
virtual bool is_Watcher_thread() const { return false; }
virtual bool is_ConcurrentGC_thread() const { return false; }
+ virtual bool is_Named_thread() const { return false; }
virtual char* name() const { return (char*)"Unknown thread"; }
@@ -568,12 +574,18 @@
};
private:
char* _name;
+ // log JavaThread being processed by oops_do
+ JavaThread* _processed_thread;
+
public:
NamedThread();
~NamedThread();
// May only be called once per thread.
void set_name(const char* format, ...);
+ virtual bool is_Named_thread() const { return true; }
virtual char* name() const { return _name == NULL ? (char*)"Unknown Thread" : _name; }
+ JavaThread *processed_thread() { return _processed_thread; }
+ void set_processed_thread(JavaThread *thread) { _processed_thread = thread; }
};
// Worker threads are named and have an id of an assigned work.
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -666,6 +666,7 @@
nonstatic_field(Thread, _current_pending_monitor_is_from_java, bool) \
nonstatic_field(Thread, _current_waiting_monitor, ObjectMonitor*) \
nonstatic_field(NamedThread, _name, char*) \
+ nonstatic_field(NamedThread, _processed_thread, JavaThread*) \
nonstatic_field(JavaThread, _next, JavaThread*) \
nonstatic_field(JavaThread, _threadObj, oop) \
nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \
--- a/hotspot/src/share/vm/runtime/vmThread.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/vmThread.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -204,8 +204,8 @@
}
-VMThread::VMThread() : Thread() {
- // nothing to do
+VMThread::VMThread() : NamedThread() {
+ set_name("VM Thread");
}
void VMThread::destroy() {
--- a/hotspot/src/share/vm/runtime/vmThread.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/runtime/vmThread.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -83,7 +83,7 @@
// like scavenge, garbage_collect etc.
//
-class VMThread: public Thread {
+class VMThread: public NamedThread {
private:
static ThreadPriority _current_priority;
@@ -101,8 +101,6 @@
bool is_VM_thread() const { return true; }
bool is_GC_thread() const { return true; }
- char* name() const { return (char*)"VM Thread"; }
-
// The ever running loop for the VMThread
void loop();
--- a/hotspot/src/share/vm/services/attachListener.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/services/attachListener.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -207,7 +207,7 @@
int tmp;
int n = sscanf(arg1, "%d", &tmp);
if (n != 1) {
- out->print_cr("flag value has to be boolean (1 or 0)");
+ out->print_cr("flag value must be a boolean (1 or 0)");
return JNI_ERR;
}
value = (tmp != 0);
@@ -226,11 +226,11 @@
if ((arg1 = op->arg(1)) != NULL) {
int n = sscanf(arg1, INTX_FORMAT, &value);
if (n != 1) {
- out->print_cr("flag value has to be integer");
+ out->print_cr("flag value must be an integer");
return JNI_ERR;
}
}
- bool res = CommandLineFlags::intxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
+ bool res = CommandLineFlags::intxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
if (! res) {
out->print_cr("setting flag %s failed", name);
}
@@ -245,11 +245,30 @@
if ((arg1 = op->arg(1)) != NULL) {
int n = sscanf(arg1, UINTX_FORMAT, &value);
if (n != 1) {
- out->print_cr("flag value has to be integer");
+ out->print_cr("flag value must be an unsigned integer");
return JNI_ERR;
}
}
- bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
+ bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
+ if (! res) {
+ out->print_cr("setting flag %s failed", name);
+ }
+
+ return res? JNI_OK : JNI_ERR;
+}
+
+// set a uint64_t global flag using value from AttachOperation
+static jint set_uint64_t_flag(const char* name, AttachOperation* op, outputStream* out) {
+ uint64_t value;
+ const char* arg1;
+ if ((arg1 = op->arg(1)) != NULL) {
+ int n = sscanf(arg1, UINT64_FORMAT, &value);
+ if (n != 1) {
+ out->print_cr("flag value must be an unsigned 64-bit integer");
+ return JNI_ERR;
+ }
+ }
+ bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, ATTACH_ON_DEMAND);
if (! res) {
out->print_cr("setting flag %s failed", name);
}
@@ -261,10 +280,10 @@
static jint set_ccstr_flag(const char* name, AttachOperation* op, outputStream* out) {
const char* value;
if ((value = op->arg(1)) == NULL) {
- out->print_cr("flag value has to be a string");
+ out->print_cr("flag value must be a string");
return JNI_ERR;
}
- bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, ATTACH_ON_DEMAND);
+ bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, ATTACH_ON_DEMAND);
if (res) {
FREE_C_HEAP_ARRAY(char, value);
} else {
@@ -291,6 +310,8 @@
return set_intx_flag(name, op, out);
} else if (f->is_uintx()) {
return set_uintx_flag(name, op, out);
+ } else if (f->is_uint64_t()) {
+ return set_uint64_t_flag(name, op, out);
} else if (f->is_ccstr()) {
return set_ccstr_flag(name, op, out);
} else {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/services/g1MemoryPool.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_g1MemoryPool.cpp.incl"
+
+G1MemoryPoolSuper::G1MemoryPoolSuper(G1CollectedHeap* g1h,
+ const char* name,
+ size_t init_size,
+ size_t max_size,
+ bool support_usage_threshold) :
+ _g1h(g1h), CollectedMemoryPool(name,
+ MemoryPool::Heap,
+ init_size,
+ max_size,
+ support_usage_threshold) {
+ assert(UseG1GC, "sanity");
+}
+
+// See the comment at the top of g1MemoryPool.hpp
+size_t G1MemoryPoolSuper::eden_space_committed(G1CollectedHeap* g1h) {
+ return MAX2(eden_space_used(g1h), (size_t) HeapRegion::GrainBytes);
+}
+
+// See the comment at the top of g1MemoryPool.hpp
+size_t G1MemoryPoolSuper::eden_space_used(G1CollectedHeap* g1h) {
+ size_t young_list_length = g1h->young_list_length();
+ size_t eden_used = young_list_length * HeapRegion::GrainBytes;
+ size_t survivor_used = survivor_space_used(g1h);
+ eden_used = subtract_up_to_zero(eden_used, survivor_used);
+ return eden_used;
+}
+
+// See the comment at the top of g1MemoryPool.hpp
+size_t G1MemoryPoolSuper::eden_space_max(G1CollectedHeap* g1h) {
+ // This should ensure that it returns a value no smaller than the
+ // region size. Currently, eden_space_committed() guarantees that.
+ return eden_space_committed(g1h);
+}
+
+// See the comment at the top of g1MemoryPool.hpp
+size_t G1MemoryPoolSuper::survivor_space_committed(G1CollectedHeap* g1h) {
+ return MAX2(survivor_space_used(g1h), (size_t) HeapRegion::GrainBytes);
+}
+
+// See the comment at the top of g1MemoryPool.hpp
+size_t G1MemoryPoolSuper::survivor_space_used(G1CollectedHeap* g1h) {
+ size_t survivor_num = g1h->g1_policy()->recorded_survivor_regions();
+ size_t survivor_used = survivor_num * HeapRegion::GrainBytes;
+ return survivor_used;
+}
+
+// See the comment at the top of g1MemoryPool.hpp
+size_t G1MemoryPoolSuper::survivor_space_max(G1CollectedHeap* g1h) {
+ // This should ensure that it returns a value no smaller than the
+ // region size. Currently, survivor_space_committed() guarantees that.
+ return survivor_space_committed(g1h);
+}
+
+// See the comment at the top of g1MemoryPool.hpp
+size_t G1MemoryPoolSuper::old_space_committed(G1CollectedHeap* g1h) {
+ size_t committed = overall_committed(g1h);
+ size_t eden_committed = eden_space_committed(g1h);
+ size_t survivor_committed = survivor_space_committed(g1h);
+ committed = subtract_up_to_zero(committed, eden_committed);
+ committed = subtract_up_to_zero(committed, survivor_committed);
+ committed = MAX2(committed, (size_t) HeapRegion::GrainBytes);
+ return committed;
+}
+
+// See the comment at the top of g1MemoryPool.hpp
+size_t G1MemoryPoolSuper::old_space_used(G1CollectedHeap* g1h) {
+ size_t used = overall_used(g1h);
+ size_t eden_used = eden_space_used(g1h);
+ size_t survivor_used = survivor_space_used(g1h);
+ used = subtract_up_to_zero(used, eden_used);
+ used = subtract_up_to_zero(used, survivor_used);
+ return used;
+}
+
+// See the comment at the top of g1MemoryPool.hpp
+size_t G1MemoryPoolSuper::old_space_max(G1CollectedHeap* g1h) {
+ size_t max = overall_max(g1h);
+ size_t eden_max = eden_space_max(g1h);
+ size_t survivor_max = survivor_space_max(g1h);
+ max = subtract_up_to_zero(max, eden_max);
+ max = subtract_up_to_zero(max, survivor_max);
+ max = MAX2(max, (size_t) HeapRegion::GrainBytes);
+ return max;
+}
+
+G1EdenPool::G1EdenPool(G1CollectedHeap* g1h) :
+ G1MemoryPoolSuper(g1h,
+ "G1 Eden",
+ eden_space_committed(g1h), /* init_size */
+ eden_space_max(g1h), /* max_size */
+ false /* support_usage_threshold */) {
+}
+
+MemoryUsage G1EdenPool::get_memory_usage() {
+ size_t initial_sz = initial_size();
+ size_t max_sz = max_size();
+ size_t used = used_in_bytes();
+ size_t committed = eden_space_committed(_g1h);
+
+ return MemoryUsage(initial_sz, used, committed, max_sz);
+}
+
+G1SurvivorPool::G1SurvivorPool(G1CollectedHeap* g1h) :
+ G1MemoryPoolSuper(g1h,
+ "G1 Survivor",
+ survivor_space_committed(g1h), /* init_size */
+ survivor_space_max(g1h), /* max_size */
+ false /* support_usage_threshold */) {
+}
+
+MemoryUsage G1SurvivorPool::get_memory_usage() {
+ size_t initial_sz = initial_size();
+ size_t max_sz = max_size();
+ size_t used = used_in_bytes();
+ size_t committed = survivor_space_committed(_g1h);
+
+ return MemoryUsage(initial_sz, used, committed, max_sz);
+}
+
+G1OldGenPool::G1OldGenPool(G1CollectedHeap* g1h) :
+ G1MemoryPoolSuper(g1h,
+ "G1 Old Gen",
+ old_space_committed(g1h), /* init_size */
+ old_space_max(g1h), /* max_size */
+ true /* support_usage_threshold */) {
+}
+
+MemoryUsage G1OldGenPool::get_memory_usage() {
+ size_t initial_sz = initial_size();
+ size_t max_sz = max_size();
+ size_t used = used_in_bytes();
+ size_t committed = old_space_committed(_g1h);
+
+ return MemoryUsage(initial_sz, used, committed, max_sz);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/services/g1MemoryPool.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+class G1CollectedHeap;
+
+// This file contains the three classes that represent the memory
+// pools of the G1 spaces: G1EdenPool, G1SurvivorPool, and
+// G1OldGenPool. In G1, unlike our other GCs, we do not have a
+// physical space for each of those spaces. Instead, we allocate
+// regions for all three spaces out of a single pool of regions (that
+// pool basically covers the entire heap). As a result, the eden,
+// survivor, and old gen are considered logical spaces in G1, as each
+// is a set of non-contiguous regions. This is also reflected in the
+// way we map them to memory pools here. The easiest way to have done
+// this would have been to map the entire G1 heap to a single memory
+// pool. However, it's helpful to show how large the eden and survivor
+// get, as this does affect the performance and behavior of G1. Which
+// is why we introduce the three memory pools implemented here.
+//
+// The above approach inroduces a couple of challenging issues in the
+// implementation of the three memory pools:
+//
+// 1) The used space calculation for a pool is not necessarily
+// independent of the others. We can easily get from G1 the overall
+// used space in the entire heap, the number of regions in the young
+// generation (includes both eden and survivors), and the number of
+// survivor regions. So, from that we calculate:
+//
+// survivor_used = survivor_num * region_size
+// eden_used = young_region_num * region_size - survivor_used
+// old_gen_used = overall_used - eden_used - survivor_used
+//
+// Note that survivor_used and eden_used are upper bounds. To get the
+// actual value we would have to iterate over the regions and add up
+// ->used(). But that'd be expensive. So, we'll accept some lack of
+// accuracy for those two. But, we have to be careful when calculating
+// old_gen_used, in case we subtract from overall_used more then the
+// actual number and our result goes negative.
+//
+// 2) Calculating the used space is straightforward, as described
+// above. However, how do we calculate the committed space, given that
+// we allocate space for the eden, survivor, and old gen out of the
+// same pool of regions? One way to do this is to use the used value
+// as also the committed value for the eden and survivor spaces and
+// then calculate the old gen committed space as follows:
+//
+// old_gen_committed = overall_committed - eden_committed - survivor_committed
+//
+// Maybe a better way to do that would be to calculate used for eden
+// and survivor as a sum of ->used() over their regions and then
+// calculate committed as region_num * region_size (i.e., what we use
+// to calculate the used space now). This is something to consider
+// in the future.
+//
+// 3) Another decision that is again not straightforward is what is
+// the max size that each memory pool can grow to. Right now, we set
+// that the committed size for the eden and the survivors and
+// calculate the old gen max as follows (basically, it's a similar
+// pattern to what we use for the committed space, as described
+// above):
+//
+// old_gen_max = overall_max - eden_max - survivor_max
+//
+// 4) Now, there is a very subtle issue with all the above. The
+// framework will call get_memory_usage() on the three pools
+// asynchronously. As a result, each call might get a different value
+// for, say, survivor_num which will yield inconsistent values for
+// eden_used, survivor_used, and old_gen_used (as survivor_num is used
+// in the calculation of all three). This would normally be
+// ok. However, it's possible that this might cause the sum of
+// eden_used, survivor_used, and old_gen_used to go over the max heap
+// size and this seems to sometimes cause JConsole (and maybe other
+// clients) to get confused. There's not a really an easy / clean
+// solution to this problem, due to the asynchrounous nature of the
+// framework.
+
+
+// This class is shared by the three G1 memory pool classes
+// (G1EdenPool, G1SurvivorPool, G1OldGenPool). Given that the way we
+// calculate used / committed bytes for these three pools is related
+// (see comment above), we put the calculations in this class so that
+// we can easily share them among the subclasses.
+class G1MemoryPoolSuper : public CollectedMemoryPool {
+private:
+ // It returns x - y if x > y, 0 otherwise.
+ // As described in the comment above, some of the inputs to the
+ // calculations we have to do are obtained concurrently and hence
+ // may be inconsistent with each other. So, this provides a
+ // defensive way of performing the subtraction and avoids the value
+ // going negative (which would mean a very large result, given that
+ // the parameter are size_t).
+ static size_t subtract_up_to_zero(size_t x, size_t y) {
+ if (x > y) {
+ return x - y;
+ } else {
+ return 0;
+ }
+ }
+
+protected:
+ G1CollectedHeap* _g1h;
+
+ // Would only be called from subclasses.
+ G1MemoryPoolSuper(G1CollectedHeap* g1h,
+ const char* name,
+ size_t init_size,
+ size_t max_size,
+ bool support_usage_threshold);
+
+ // The reason why all the code is in static methods is so that it
+ // can be safely called from the constructors of the subclasses.
+
+ static size_t overall_committed(G1CollectedHeap* g1h) {
+ return g1h->capacity();
+ }
+ static size_t overall_used(G1CollectedHeap* g1h) {
+ return g1h->used_unlocked();
+ }
+ static size_t overall_max(G1CollectedHeap* g1h) {
+ return g1h->g1_reserved_obj_bytes();
+ }
+
+ static size_t eden_space_committed(G1CollectedHeap* g1h);
+ static size_t eden_space_used(G1CollectedHeap* g1h);
+ static size_t eden_space_max(G1CollectedHeap* g1h);
+
+ static size_t survivor_space_committed(G1CollectedHeap* g1h);
+ static size_t survivor_space_used(G1CollectedHeap* g1h);
+ static size_t survivor_space_max(G1CollectedHeap* g1h);
+
+ static size_t old_space_committed(G1CollectedHeap* g1h);
+ static size_t old_space_used(G1CollectedHeap* g1h);
+ static size_t old_space_max(G1CollectedHeap* g1h);
+};
+
+// Memory pool that represents the G1 eden.
+class G1EdenPool : public G1MemoryPoolSuper {
+public:
+ G1EdenPool(G1CollectedHeap* g1h);
+
+ size_t used_in_bytes() {
+ return eden_space_used(_g1h);
+ }
+ size_t max_size() const {
+ return eden_space_max(_g1h);
+ }
+ MemoryUsage get_memory_usage();
+};
+
+// Memory pool that represents the G1 survivor.
+class G1SurvivorPool : public G1MemoryPoolSuper {
+public:
+ G1SurvivorPool(G1CollectedHeap* g1h);
+
+ size_t used_in_bytes() {
+ return survivor_space_used(_g1h);
+ }
+ size_t max_size() const {
+ return survivor_space_max(_g1h);
+ }
+ MemoryUsage get_memory_usage();
+};
+
+// Memory pool that represents the G1 old gen.
+class G1OldGenPool : public G1MemoryPoolSuper {
+public:
+ G1OldGenPool(G1CollectedHeap* g1h);
+
+ size_t used_in_bytes() {
+ return old_space_used(_g1h);
+ }
+ size_t max_size() const {
+ return old_space_max(_g1h);
+ }
+ MemoryUsage get_memory_usage();
+};
--- a/hotspot/src/share/vm/services/management.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/services/management.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -790,7 +790,7 @@
assert(!has_undefined_init_size, "Undefined init size");
assert(!has_undefined_max_size, "Undefined max size");
- MemoryUsage usage((heap ? Arguments::initial_heap_size() : total_init),
+ MemoryUsage usage((heap ? InitialHeapSize : total_init),
total_used,
total_committed,
(heap ? Universe::heap()->max_capacity() : total_max));
@@ -1507,16 +1507,17 @@
return (jobjectArray)JNIHandles::make_local(env, flags_ah());
JVM_END
-// utility function used by jmm_GetVMGlobals
-void add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, TRAPS) {
+// Utility function used by jmm_GetVMGlobals. Returns false if flag type
+// can't be determined, true otherwise. If false is returned, then *global
+// will be incomplete and invalid.
+bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, TRAPS) {
Handle flag_name;
if (name() == NULL) {
- flag_name = java_lang_String::create_from_str(flag->name, CHECK);
+ flag_name = java_lang_String::create_from_str(flag->name, CHECK_false);
} else {
flag_name = name;
}
global->name = (jstring)JNIHandles::make_local(env, flag_name());
- global->type = JMM_VMGLOBAL_TYPE_UNKNOWN;
if (flag->is_bool()) {
global->value.z = flag->get_bool() ? JNI_TRUE : JNI_FALSE;
@@ -1527,10 +1528,17 @@
} else if (flag->is_uintx()) {
global->value.j = (jlong)flag->get_uintx();
global->type = JMM_VMGLOBAL_TYPE_JLONG;
+ } else if (flag->is_uint64_t()) {
+ global->value.j = (jlong)flag->get_uint64_t();
+ global->type = JMM_VMGLOBAL_TYPE_JLONG;
} else if (flag->is_ccstr()) {
- Handle str = java_lang_String::create_from_str(flag->get_ccstr(), CHECK);
+ Handle str = java_lang_String::create_from_str(flag->get_ccstr(), CHECK_false);
global->value.l = (jobject)JNIHandles::make_local(env, str());
global->type = JMM_VMGLOBAL_TYPE_JSTRING;
+ } else {
+ global->type = JMM_VMGLOBAL_TYPE_UNKNOWN;
+ assert(false, "Unsupported VMGlobal Type");
+ return false;
}
global->writeable = flag->is_writeable();
@@ -1557,6 +1565,8 @@
default:
global->origin = JMM_VMGLOBAL_ORIGIN_OTHER;
}
+
+ return true;
}
// Fill globals array of count length with jmmVMGlobal entries
@@ -1599,8 +1609,8 @@
Handle sh(THREAD, s);
char* str = java_lang_String::as_utf8_string(s);
Flag* flag = Flag::find_flag(str, strlen(str));
- if (flag != NULL) {
- add_global_entry(env, sh, &globals[i], flag, THREAD);
+ if (flag != NULL &&
+ add_global_entry(env, sh, &globals[i], flag, THREAD)) {
num_entries++;
} else {
globals[i].name = NULL;
@@ -1617,8 +1627,8 @@
for (int i = 0; i < nFlags && num_entries < count; i++) {
Flag* flag = &Flag::flags[i];
// Exclude the locked (diagnostic, experimental) flags
- if (flag->is_unlocked() || flag->is_unlocker()) {
- add_global_entry(env, null_h, &globals[num_entries], flag, THREAD);
+ if ((flag->is_unlocked() || flag->is_unlocker()) &&
+ add_global_entry(env, null_h, &globals[num_entries], flag, THREAD)) {
num_entries++;
}
}
@@ -1650,11 +1660,14 @@
bool bvalue = (new_value.z == JNI_TRUE ? true : false);
succeed = CommandLineFlags::boolAtPut(name, &bvalue, MANAGEMENT);
} else if (flag->is_intx()) {
- intx ivalue = new_value.j;
+ intx ivalue = (intx)new_value.j;
succeed = CommandLineFlags::intxAtPut(name, &ivalue, MANAGEMENT);
} else if (flag->is_uintx()) {
- uintx uvalue = new_value.j;
+ uintx uvalue = (uintx)new_value.j;
succeed = CommandLineFlags::uintxAtPut(name, &uvalue, MANAGEMENT);
+ } else if (flag->is_uint64_t()) {
+ uint64_t uvalue = (uint64_t)new_value.j;
+ succeed = CommandLineFlags::uint64_tAtPut(name, &uvalue, MANAGEMENT);
} else if (flag->is_ccstr()) {
oop str = JNIHandles::resolve_external_guard(new_value.l);
if (str == NULL) {
--- a/hotspot/src/share/vm/services/memoryManager.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/services/memoryManager.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -72,6 +72,14 @@
return (GCMemoryManager*) new PSMarkSweepMemoryManager();
}
+GCMemoryManager* MemoryManager::get_g1YoungGen_memory_manager() {
+ return (GCMemoryManager*) new G1YoungGenMemoryManager();
+}
+
+GCMemoryManager* MemoryManager::get_g1OldGen_memory_manager() {
+ return (GCMemoryManager*) new G1OldGenMemoryManager();
+}
+
instanceOop MemoryManager::get_memory_manager_instance(TRAPS) {
// Must do an acquire so as to force ordering of subsequent
// loads from anything _memory_mgr_obj points to or implies.
--- a/hotspot/src/share/vm/services/memoryManager.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/services/memoryManager.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -54,7 +54,9 @@
ParNew,
ConcurrentMarkSweep,
PSScavenge,
- PSMarkSweep
+ PSMarkSweep,
+ G1YoungGen,
+ G1OldGen
};
MemoryManager();
@@ -85,6 +87,8 @@
static GCMemoryManager* get_cms_memory_manager();
static GCMemoryManager* get_psScavenge_memory_manager();
static GCMemoryManager* get_psMarkSweep_memory_manager();
+ static GCMemoryManager* get_g1YoungGen_memory_manager();
+ static GCMemoryManager* get_g1OldGen_memory_manager();
};
@@ -231,3 +235,21 @@
MemoryManager::Name kind() { return MemoryManager::PSMarkSweep; }
const char* name() { return "PS MarkSweep"; }
};
+
+class G1YoungGenMemoryManager : public GCMemoryManager {
+private:
+public:
+ G1YoungGenMemoryManager() : GCMemoryManager() {}
+
+ MemoryManager::Name kind() { return MemoryManager::G1YoungGen; }
+ const char* name() { return "G1 Young Generation"; }
+};
+
+class G1OldGenMemoryManager : public GCMemoryManager {
+private:
+public:
+ G1OldGenMemoryManager() : GCMemoryManager() {}
+
+ MemoryManager::Name kind() { return MemoryManager::G1OldGen; }
+ const char* name() { return "G1 Old Generation"; }
+};
--- a/hotspot/src/share/vm/services/memoryService.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/services/memoryService.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -60,8 +60,8 @@
break;
}
case CollectedHeap::G1CollectedHeap : {
- G1CollectedHeap::g1_unimplemented();
- return;
+ add_g1_heap_info(G1CollectedHeap::heap());
+ break;
}
#endif // SERIALGC
default: {
@@ -164,6 +164,19 @@
add_psOld_memory_pool(heap->old_gen(), _major_gc_manager);
add_psPerm_memory_pool(heap->perm_gen(), _major_gc_manager);
}
+
+void MemoryService::add_g1_heap_info(G1CollectedHeap* g1h) {
+ assert(UseG1GC, "sanity");
+
+ _minor_gc_manager = MemoryManager::get_g1YoungGen_memory_manager();
+ _major_gc_manager = MemoryManager::get_g1OldGen_memory_manager();
+ _managers_list->append(_minor_gc_manager);
+ _managers_list->append(_major_gc_manager);
+
+ add_g1YoungGen_memory_pool(g1h, _major_gc_manager, _minor_gc_manager);
+ add_g1OldGen_memory_pool(g1h, _major_gc_manager);
+ add_g1PermGen_memory_pool(g1h, _major_gc_manager);
+}
#endif // SERIALGC
MemoryPool* MemoryService::add_gen(Generation* gen,
@@ -384,6 +397,64 @@
mgr->add_pool(perm_gen);
_pools_list->append(perm_gen);
}
+
+void MemoryService::add_g1YoungGen_memory_pool(G1CollectedHeap* g1h,
+ MemoryManager* major_mgr,
+ MemoryManager* minor_mgr) {
+ assert(major_mgr != NULL && minor_mgr != NULL, "should have two managers");
+
+ G1EdenPool* eden = new G1EdenPool(g1h);
+ G1SurvivorPool* survivor = new G1SurvivorPool(g1h);
+
+ major_mgr->add_pool(eden);
+ major_mgr->add_pool(survivor);
+ minor_mgr->add_pool(eden);
+ minor_mgr->add_pool(survivor);
+ _pools_list->append(eden);
+ _pools_list->append(survivor);
+}
+
+void MemoryService::add_g1OldGen_memory_pool(G1CollectedHeap* g1h,
+ MemoryManager* mgr) {
+ assert(mgr != NULL, "should have one manager");
+
+ G1OldGenPool* old_gen = new G1OldGenPool(g1h);
+ mgr->add_pool(old_gen);
+ _pools_list->append(old_gen);
+}
+
+void MemoryService::add_g1PermGen_memory_pool(G1CollectedHeap* g1h,
+ MemoryManager* mgr) {
+ assert(mgr != NULL, "should have one manager");
+
+ CompactingPermGenGen* perm_gen = (CompactingPermGenGen*) g1h->perm_gen();
+ PermanentGenerationSpec* spec = perm_gen->spec();
+ size_t max_size = spec->max_size() - spec->read_only_size()
+ - spec->read_write_size();
+ MemoryPool* pool = add_space(perm_gen->unshared_space(),
+ "G1 Perm Gen",
+ false, /* is_heap */
+ max_size,
+ true /* support_usage_threshold */);
+ mgr->add_pool(pool);
+
+ // in case we support CDS in G1
+ if (UseSharedSpaces) {
+ pool = add_space(perm_gen->ro_space(),
+ "G1 Perm Gen [shared-ro]",
+ false, /* is_heap */
+ spec->read_only_size(),
+ true /* support_usage_threshold */);
+ mgr->add_pool(pool);
+
+ pool = add_space(perm_gen->rw_space(),
+ "G1 Perm Gen [shared-rw]",
+ false, /* is_heap */
+ spec->read_write_size(),
+ true /* support_usage_threshold */);
+ mgr->add_pool(pool);
+ }
+}
#endif // SERIALGC
void MemoryService::add_code_heap_memory_pool(CodeHeap* heap) {
--- a/hotspot/src/share/vm/services/memoryService.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/services/memoryService.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -40,6 +40,7 @@
class ParallelScavengeHeap;
class CompactingPermGenGen;
class CMSPermGenGen;
+class G1CollectedHeap;
// VM Monitoring and Management Support
@@ -88,6 +89,13 @@
static void add_psPerm_memory_pool(PSPermGen* perm,
MemoryManager* mgr);
+ static void add_g1YoungGen_memory_pool(G1CollectedHeap* g1h,
+ MemoryManager* major_mgr,
+ MemoryManager* minor_mgr);
+ static void add_g1OldGen_memory_pool(G1CollectedHeap* g1h,
+ MemoryManager* mgr);
+ static void add_g1PermGen_memory_pool(G1CollectedHeap* g1h,
+ MemoryManager* mgr);
static MemoryPool* add_space(ContiguousSpace* space,
const char* name,
@@ -111,6 +119,7 @@
static void add_gen_collected_heap_info(GenCollectedHeap* heap);
static void add_parallel_scavenge_heap_info(ParallelScavengeHeap* heap);
+ static void add_g1_heap_info(G1CollectedHeap* g1h);
public:
static void set_universe_heap(CollectedHeap* heap);
--- a/hotspot/src/share/vm/utilities/growableArray.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/utilities/growableArray.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -278,6 +278,17 @@
_len--;
}
+ // inserts the given element before the element at index i
+ void insert_before(const int idx, const E& elem) {
+ check_nesting();
+ if (_len == _max) grow(_len);
+ for (int j = _len - 1; j >= idx; j--) {
+ _data[j + 1] = _data[j];
+ }
+ _len++;
+ _data[idx] = elem;
+ }
+
void appendAll(const GrowableArray<E>* l) {
for (int i = 0; i < l->_len; i++) {
raw_at_put_grow(_len, l->_data[i], 0);
--- a/hotspot/src/share/vm/utilities/numberSeq.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/utilities/numberSeq.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -241,3 +241,33 @@
return b0 + b1 * num;
}
+
+
+// Printing/Debugging Support
+
+void AbsSeq::dump() { dump_on(gclog_or_tty); }
+
+void AbsSeq::dump_on(outputStream* s) {
+ s->print_cr("\t _num = %d, _sum = %7.3f, _sum_of_squares = %7.3f",
+ _num, _sum, _sum_of_squares);
+ s->print_cr("\t _davg = %7.3f, _dvariance = %7.3f, _alpha = %7.3f",
+ _davg, _dvariance, _alpha);
+}
+
+void NumberSeq::dump_on(outputStream* s) {
+ AbsSeq::dump_on(s);
+ s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f");
+}
+
+void TruncatedSeq::dump_on(outputStream* s) {
+ AbsSeq::dump_on(s);
+ s->print_cr("\t\t _length = %d, _next = %d", _length, _next);
+ for (int i = 0; i < _length; i++) {
+ if (i%5 == 0) {
+ s->cr();
+ s->print("\t");
+ }
+ s->print("\t[%d]=%7.3f", i, _sequence[i]);
+ }
+ s->print_cr("");
+}
--- a/hotspot/src/share/vm/utilities/numberSeq.hpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/utilities/numberSeq.hpp Wed Jul 05 17:04:53 2017 +0200
@@ -74,6 +74,10 @@
double davg() const; // decaying average
double dvariance() const; // decaying variance
double dsd() const; // decaying "standard deviation"
+
+ // Debugging/Printing
+ virtual void dump();
+ virtual void dump_on(outputStream* s);
};
class NumberSeq: public AbsSeq {
@@ -91,6 +95,9 @@
virtual void add(double val);
virtual double maximum() const { return _maximum; }
virtual double last() const { return _last; }
+
+ // Debugging/Printing
+ virtual void dump_on(outputStream* s);
};
class TruncatedSeq: public AbsSeq {
@@ -114,4 +121,7 @@
double oldest() const; // the oldest valid value in the sequence
double predict_next() const; // prediction based on linear regression
+
+ // Debugging/Printing
+ virtual void dump_on(outputStream* s);
};
--- a/hotspot/src/share/vm/utilities/vmError.cpp Wed Jan 13 15:16:06 2010 -0800
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Wed Jul 05 17:04:53 2017 +0200
@@ -502,6 +502,23 @@
#endif // ZERO
}
+ STEP(135, "(printing target Java thread stack)" )
+
+ // printing Java thread stack trace if it is involved in GC crash
+ if (_verbose && (_thread->is_Named_thread())) {
+ JavaThread* jt = ((NamedThread *)_thread)->processed_thread();
+ if (jt != NULL) {
+ st->print_cr("JavaThread " PTR_FORMAT " (nid = " UINTX_FORMAT ") was being processed", jt, jt->osthread()->thread_id());
+ if (jt->has_last_Java_frame()) {
+ st->print_cr("Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)");
+ for(StackFrameStream sfs(jt); !sfs.is_done(); sfs.next()) {
+ sfs.current()->print_on_error(st, buf, sizeof(buf), true);
+ st->cr();
+ }
+ }
+ }
+ }
+
STEP(140, "(printing VM operation)" )
if (_verbose && _thread && _thread->is_VM_thread()) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6769124/TestArrayCopy6769124.java Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 6769124
+ * @summary arraycopy may crash the VM with c1 on 64 bit
+ */
+
+public class TestArrayCopy6769124 {
+
+ public static void main(String[] args) {
+
+ int k = 1 << 31;
+
+
+ for(int j = 0; j <1000000; j++) {
+ int i = -1;
+ while(i < 10) {
+ i++;
+ }
+
+ int m = k * i;
+
+ int[] O1 = new int[20];
+ int[] O2 = new int[20];
+
+ System.arraycopy(O1, i, O2, i, 1); //will crash on amd64
+ System.arraycopy(O1, m, O2, m, 1); //will crash on sparcv9
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6769124/TestDeoptInt6769124.java Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 6769124
+ * @summary int value might not be correctly decoded on deopt with c1 on 64 bit
+ *
+ * @run main/othervm -Xcomp -XX:CompileOnly=TestDeoptInt6769124.m TestDeoptInt6769124
+ */
+
+public class TestDeoptInt6769124 {
+
+ static class A {
+ volatile int vl;
+ A(int v) {
+ vl = v;
+ }
+ }
+
+ static void m(int b) {
+ A a = new A(10);
+ int c;
+ c = b + a.vl; //accessing volatile field of class not loaded at compile time forces a deopt
+ if(c != 20) {
+ System.out.println("a (= " + a.vl + ") + b (= " + b + ") = c (= " + c + ") != 20");
+ throw new InternalError();
+ }
+ }
+
+ public static void main(String[] args) {
+ m(10);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6769124/TestUnalignedLoad6769124.java Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 6769124
+ * @summary unaligned load may fail with c1 on 64 bit
+ */
+
+public class TestUnalignedLoad6769124 {
+
+ static long l1v = 0x200000003L;
+ static long l2v = 0x400000005L;
+ static double d1v = Double.MAX_VALUE;
+ static double d2v = Double.MIN_VALUE;
+
+ public static void main(String[] args) {
+ long l1 = l1v;
+ double d1 = d1v;
+ long l2 = l2v;
+ double d2 = d2v;
+
+ // Run long enough to induce an OSR
+ for (int i = 0; i < 10000000; i++) {
+ }
+ boolean error = false;
+
+ if (l1 != l1v) {
+ System.out.println(l1 + " != " + l1v);
+ error = true;
+ }
+ if (l2 != l2v) {
+ System.out.println(l2 + " != " + l2v);
+ error = true;
+ }
+ if (d1 != d1v) {
+ System.out.println(d1 + " != " + d1v);
+ error = true;
+ }
+ if (d2 != d2v) {
+ System.out.println(d2 + " != " + d2v);
+ error = true;
+ }
+ if (error) {
+ throw new InternalError();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6852078/Test6852078.java Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 6852078
+ * @summary Disable SuperWord optimization for unsafe read/write
+ *
+ * @run main/othervm Test6852078
+ */
+
+import java.util.*;
+import java.nio.ByteBuffer;
+import com.sun.corba.se.impl.encoding.ByteBufferWithInfo;
+import com.sun.jndi.toolkit.corba.CorbaUtils;
+
+public class Test6852078 {
+
+ public Test6852078(String [] args) {
+
+ int capacity = 128;
+ ByteBuffer bb = ByteBuffer.allocateDirect(capacity);
+ ByteBufferWithInfo bbwi = new ByteBufferWithInfo( CorbaUtils.getOrb(null, -1, new Hashtable()), bb);
+ byte[] tmpBuf;
+ tmpBuf = new byte[bbwi.buflen];
+
+ for (int i = 0; i < capacity; i++)
+ tmpBuf[i] = bbwi.byteBuffer.get(i);
+ }
+
+ public static void main(String [] args) {
+ for (int i=0; i<2000; i++) {
+ Test6852078 t = new Test6852078(args);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6895383/Test.java Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 6895383
+ * @summary JCK test throws NPE for method compiled with Escape Analysis
+ *
+ * @run main/othervm -Xcomp Test
+ */
+
+public class Test {
+ public static void main(String argv[]) {
+ Test test = new Test();
+ test.testRemove1_IndexOutOfBounds();
+ test.testAddAll1_IndexOutOfBoundsException();
+ }
+
+ public void testRemove1_IndexOutOfBounds() {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ }
+
+ public void testAddAll1_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.addAll(-1, new LinkedList()); // should throw IndexOutOfBoundsException
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6896727/Test.java Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 6896727
+ * @summary nsk/logging/LoggingPermission/LoggingPermission/logperm002 fails with G1, EscapeAnalisys w/o COOPs
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:+DoEscapeAnalysis -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC Test
+ */
+
+public class Test {
+
+ final static String testString = "abracadabra";
+ public static void main(String args[]) {
+ String params[][] = {
+ {"control", testString}
+ };
+ for (int i=0; i<params.length; i++) {
+ try {
+ System.out.println("Params :" + testString + " and " + params[i][0] + ", " + params[i][1]);
+ if (params[i][1] == null) {
+ System.exit(97);
+ }
+ } catch (Exception e) {}
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6901572/Test.java Wed Jul 05 17:04:53 2017 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6901572
+ * @summary JVM 1.6.16 crash on loops: assert(has_node(i),"")
+ *
+ * @run main/othervm Test
+ */
+
+
+public class Test {
+
+ public static void main(String[] args) {
+ for (int i = 0; i < 2; i++)
+ NestedLoop();
+ }
+
+ public static long NestedLoop() {
+ final int n = 50;
+ long startTime = System.currentTimeMillis();
+ int x = 0;
+ for(int a = 0; a < n; a++)
+ for(int b = 0; b < n; b++)
+ for(int c = 0; c < n; c++)
+ for(int d = 0; d < n; d++)
+ for(int e = 0; e < n; e++)
+ for(int f = 0; f < n; f++)
+ x++;
+ long stopTime = System.currentTimeMillis();
+
+ return stopTime - startTime;
+ }
+}